Skip to content

saas-EPIC-TEN — Tenants template gaps

Epic ID: saas-EPIC-TEN
Area path: ConnectSoft\SaaS\Tenants
Priority: P1
Status: Not Started
Repository scope: ConnectSoft.Saas.TenantsTemplate
Source gap analysis: Tenants deep analysis

Tenants wave-1 implementation delivers flat ITenant aggregate, five ServiceModel operations, canonical outbound topics, and Orleans grain scaffold — but diverges from DDD blueprint child entities, JSON descriptor, lifecycle saga completeness, architecture tests, and write-path actor wiring. Evidence paths cite ITenant.cs, TenantsConstants, ConnectSoft.Saas.Tenants.json, placeholder architecture tests, and TenantLifecycleSaga create-only stub.


[010] saas-TEN-F01 — Rich tenant aggregate OR formal flat-tenant ADR

Type: Feature
Parent: saas-EPIC-TEN
Implementation order: 010
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, aggregate, adr
Priority: P1
Effort: XL
Dependencies:
Blocks: saas-TEN-F02, saas-TEN-F04
Source gap analysis: Tenants entity model

Description (full):

Canonical DDD blueprint (saas-platform-ddd-entities.md) defines a rich tenant aggregate with value objects and child entities: TenantProfile, TenantRegionResidency, Contact, and TenantConfiguration. Wave-1 code implements a flat ITenant interface with scalar properties only (TenantAggregateId, TenantId, TenantKey, DisplayName, ResidencyRegion, LifecycleStatus, AggregateVersion, timestamps).

Evidence:

  • ConnectSoft.Saas.TenantsTemplate/src/ConnectSoft.Saas.Tenants.EntityModel/ITenant.cs — no child collections or profile VOs.
  • JSON descriptor ConnectSoft.Saas.Tenants.jsonvalueObjects: [], entities: [], hasMany: [].
  • ADR stub: docs/adr/0001-one-aggregate-root-per-repo.md — one root enforced but does not decide flat vs rich shape.
  • Deep analysis finding T-001 — status Missing.

Strategic decision (ADR-TEN-001):

  • Option A — Rich aggregate: Implement missing VOs/entities with NHibernate mappings, migrations, and processor updates.
  • Option B — Flat tenant + ADR: Accept wave-1 flat model; document intentional deferral of child entities with mapping notes to future waves.

Target state: Accepted ADR-TEN-001. If Option A, entity model and migrations match blueprint. If Option B, ADR explains which blueprint concepts are collapsed into scalars on ITenant (e.g., ResidencyRegion stands in for TenantRegionResidency.RegionCode).

Why it matters: Downstream Billing and Entitlements assume tenant partition stability and residency metadata. Without a decision, JSON descriptor regeneration and cross-repo contracts remain ambiguous.

Acceptance criteria (testable):

  • AC-1: ADR-TEN-001 published with Accepted status and chosen option.
  • AC-2: If Option A: ITenant or associated entities expose TenantProfile, Contact, TenantConfiguration per blueprint; unit tests cover mapping.
  • AC-3: If Option B: ADR lists each deferred blueprint type with flat-field mapping table; no orphan blueprint references in Tenants docs without ADR caveat.
  • AC-4: OneAggregateRootPerRepoTests (once real) still passes — child entities must not declare separate aggregate roots.

Implementation notes (full):

  • Files: ITenant.cs, TenantEntity.cs, NHibernate mappings, ConnectSoft.Saas.Tenants.json, docs/adr/ADR-TEN-001-flat-tenant-vs-rich-aggregate.md.
  • Reference enumeration: TenantLifecycleStatusEnumeration vs JSON TenantLifecycleStatus values.
  • Do not break TenantId string partition key semantics on ITenantScopedEntity.

Out of scope:

  • EditionRef / BillingAccountRef — saas-TEN-F02.
  • Orleans grain changes — saas-TEN-F08.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-S01.1 — Decide and implement tenant aggregate shape per ADR-TEN-001

Type: User Story
Parent: saas-TEN-F01
Implementation order: 010
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1
Priority: P1
Effort: XL
Dependencies:
Blocks: saas-TEN-T01.1.1, saas-TEN-T01.1.2
Source gap analysis: Tenants entity model

Description (full):

As a Tenants domain developer, I need a clear decision on flat vs rich aggregate and corresponding code or ADR, so entity model work does not stall Billing provisioning and JSON descriptor alignment.

Acceptance criteria (testable):

  • AC-1: ADR-TEN-001 Accepted with explicit Option A or B.
  • AC-2: Entity model code and ADR agree — no undocumented missing VOs after story completes.

Implementation notes (full):

  • Review blueprint table in deep analysis §4.1 (TenantProfile, Contact, TenantConfiguration rows all Missing).

Out of scope:

  • External reference fields.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-T01.1.1 — Author and accept ADR-TEN-001 flat vs rich aggregate

Type: Task
Parent: saas-TEN-S01.1
Implementation order: 010
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, adr
Priority: P1
Effort: S
Dependencies:
Blocks: saas-TEN-T01.1.2
Source gap analysis: Tenants entity model

Description (full):

Draft ADR-TEN-001 comparing Option A (implement TenantProfile, TenantRegionResidency, Contact, TenantConfiguration) vs Option B (flat ITenant with ADR). Include evidence from ITenant.cs and empty JSON valueObjects array. Obtain program acceptance and update deep analysis decision log row from Pending to Accepted.

Acceptance criteria (testable):

  • AC-1: ADR file at ConnectSoft.Saas.TenantsTemplate/docs/adr/ADR-TEN-001-flat-tenant-vs-rich-aggregate.md with Accepted status.
  • AC-2: Deep analysis §5 ADR-TEN-001 row updated.

Implementation notes (full):

  • Link to 0001-one-aggregate-root-per-repo.md — child entities allowed, only one aggregate root marker.

Out of scope:

  • Code changes until decision recorded.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-T01.1.2 — Implement chosen aggregate shape in entity model and JSON descriptor

Type: Task
Parent: saas-TEN-S01.1
Implementation order: 010
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1
Priority: P1
Effort: L
Dependencies: saas-TEN-T01.1.1
Blocks: saas-TEN-F04
Source gap analysis: Tenants entity model

Description (full):

If Option A: add entity/VO types, NHibernate mappings, migrations, update DefaultTenantsProcessor create/update paths. If Option B: update ConnectSoft.Saas.Tenants.json and inline docs to document flat mapping; add comments on ITenant properties referencing ADR deferred types. Add entity unit tests (replace any placeholder aggregate tests).

Acceptance criteria (testable):

  • AC-1: Option A — new types persisted and loaded in repository integration test.
  • AC-2: Option B — JSON descriptor description fields note ADR-TEN-001 deferral; no false hasMany entries.
  • AC-3: ResidencyRegion on ITenant documented relative to blueprint TenantRegionResidency.

Implementation notes (full):

  • Files: EntityModel/*, PersistenceModel/*, ConnectSoft.Saas.Tenants.json.
  • Preserve TenantAggregateId Guid PK vs string TenantId partition distinction.

Out of scope:

  • ServiceModel API shape changes unless Option A requires new request fields.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[011] saas-TEN-F02 — External references EditionRef and BillingAccountRef

Type: Feature
Parent: saas-EPIC-TEN
Implementation order: 011
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, references
Priority: P1
Effort: M
Dependencies: saas-TEN-F01
Blocks: saas-BIL-F01
Source gap analysis: Tenants entity model

Description (full):

Blueprint specifies external references on tenant aggregate: EditionRef (Products Catalog edition identifier) and BillingAccountRef (Billing bounded context account key). Current ITenant has no such properties; JSON descriptor references: [] is empty. Deep analysis finding T-002 — status Missing.

Without these refs, tenant activation cannot link to default edition selection or billing account provisioning triggers expected in E2E onboarding flows.

Target state: ITenant (or approved ADR location for refs) stores EditionRef and BillingAccountRef with validation rules. CreateDraft/Activate requests accept or default refs. Outbound TenantActivatedEvent includes refs for Billing consumer sagas.

Acceptance criteria (testable):

  • AC-1: Entity and migration add nullable or required ref columns per ADR.
  • AC-2: TenantActivatedEvent exposes edition and billing account ref fields consumed by Billing inbound DTOs.
  • AC-3: Unit test: Activate tenant with refs persists and publishes refs on event.
  • AC-4: JSON descriptor documents reference fields.

Implementation notes (full):

  • Files: ITenant.cs, TenantActivatedEvent.cs, CreateTenantDraftRequest.cs, NHibernate mapping, migration.
  • Coordinate with Billing DefaultSubscriptionsProcessor tenant-activated handler expectations.
  • Ref format: string opaque ids matching Catalog/Billing aggregate keys — document in published language.

Out of scope:

  • Validating refs exist in Catalog/Billing at write time (optional saga in future wave).
  • Subscription creation logic — Billing domain.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-S02.1 — Add EditionRef and BillingAccountRef to tenant aggregate and activation event

Type: User Story
Parent: saas-TEN-F02
Implementation order: 011
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1
Priority: P1
Effort: M
Dependencies: saas-TEN-F01
Blocks: saas-TEN-T02.1.1, saas-TEN-T02.1.2
Source gap analysis: Tenants entity model

Description (full):

As a Billing integrator, I need tenant-activated events to carry edition and billing account references, so subscription provisioning can bind to the correct catalog edition and billing account without extra lookup tables.

Acceptance criteria (testable):

  • AC-1: Activate flow persists refs on ITenant row.
  • AC-2: Published TenantActivatedEvent JSON includes ref properties matching Billing inbound ACL field names.

Implementation notes (full):

  • Align property names with Billing inbound tenant-activated DTO after saas-INTEG-F01 topic fix.

Out of scope:

  • Catalog edition existence validation.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-T02.1.1 — Extend ITenant entity, migration, and ServiceModel requests with refs

Type: Task
Parent: saas-TEN-S02.1
Implementation order: 011
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1
Priority: P1
Effort: M
Dependencies: saas-TEN-F01
Blocks: saas-TEN-T02.1.2
Source gap analysis: Tenants entity model

Description (full):

Add EditionRef and BillingAccountRef properties to ITenant and concrete entity. Create NHibernate migration. Extend CreateTenantDraftRequest / ActivateTenantRequest (or dedicated update operation) to accept refs. Update validators.

Acceptance criteria (testable):

  • AC-1: Database migration applies cleanly on empty and existing databases.
  • AC-2: REST and gRPC contracts expose ref fields with XML documentation.

Implementation notes (full):

  • Files: ITenant.cs, TenantEntity.cs, mapping files, ServiceModel/*Request.cs, TenantsController.cs, GrpcTenantManagementService.cs.

Out of scope:

  • Event publish changes.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-T02.1.2 — Publish refs on TenantActivatedEvent and update JSON descriptor

Type: Task
Parent: saas-TEN-S02.1
Implementation order: 011
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, messaging
Priority: P1
Effort: S
Dependencies: saas-TEN-T02.1.1
Blocks: saas-BIL-F01
Source gap analysis: Tenants entity model

Description (full):

Add ref properties to TenantActivatedEvent (and optionally TenantCreatedEvent if draft carries refs). Update DefaultTenantsProcessor publish mapping. Document fields in ConnectSoft.Saas.Tenants.json published event schema notes.

Acceptance criteria (testable):

  • AC-1: Processor unit test asserts event carries edition and billing refs after Activate.
  • AC-2: MassTransit topology unchanged on topic names (TenantsConstants.EventTopics.TenantActivated).

Implementation notes (full):

  • File: MessagingModel/Events/TenantActivatedEvent.cs, processor publish site.

Out of scope:

  • Billing consumer mapping — saas-BIL-F01.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[012] saas-TEN-F03 — Full lifecycle saga replacing create-only stub

Type: Feature
Parent: saas-EPIC-TEN
Implementation order: 012
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, saga
Priority: P1
Effort: L
Dependencies: saas-INTEG-F05
Blocks:
Source gap analysis: Tenants messaging

Description (full):

TenantLifecycleSaga is a create-only stub: it correlates on TenantCreatedEvent, logs, sets StartedAt, and finalizes immediately (ConnectSoft.Saas.Tenants.FlowModel.MassTransit/TenantLifecycleSaga.cs). No states exist for activate, suspend, decommission, or residency change despite five operations on ITenantManagementService (CreateDraftAsync, ActivateAsync, SuspendAsync, DecommissionAsync, ChangeResidencyAsync).

Deep analysis finding T-003 — status Partial.

Target state: Saga orchestrates multi-step lifecycle hooks (internal compensation, timed transitions, or publish-side effects) aligned with processor commands. Minimum: saga instance transitions on each outbound domain event (TenantActivated, TenantSuspended, TenantDeleted, ResidencyChanged) with durable state per saas-INTEG-F05.

Acceptance criteria (testable):

  • AC-1: Saga defines states beyond Initial/Final for activate, suspend, decommission, residency paths.
  • AC-2: Each ITenantManagementService command that publishes integration event updates saga state in integration test.
  • AC-3: Saga unit tests cover happy path create → activate and suspend → decommission sequences.
  • AC-4: Saga uses durable repository (not in-memory) per INTEG-F05 outcome.

Implementation notes (full):

  • Files: TenantLifecycleSaga.cs, TenantLifecycleSagaState.cs, MassTransitExtensions.cs saga registration.
  • Correlate events by TenantAggregateId consistently with create handler.
  • Do not duplicate processor business rules — saga handles orchestration hooks only.

Out of scope:

  • Cross-service choreography (Billing subscription creation) — Billing sagas consume Tenants events.
  • Compensation transactions across databases.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-S03.1 — Expand TenantLifecycleSaga to cover full tenant lifecycle

Type: User Story
Parent: saas-TEN-F03
Implementation order: 012
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, saga
Priority: P1
Effort: L
Dependencies: saas-INTEG-F05
Blocks: saas-TEN-T03.1.1, saas-TEN-T03.1.2
Source gap analysis: Tenants messaging

Description (full):

As a Tenants maintainer, I need the lifecycle saga to react to all tenant domain events, so orchestration state reflects activate/suspend/decommission/residency operations instead of stopping after create.

Acceptance criteria (testable):

  • AC-1: Saga state machine includes event handlers for all five published topics in TenantsConstants.EventTopics.
  • AC-2: Invalid transition (e.g., suspend before activate) handled per processor rules — saga logs and does not corrupt state.

Implementation notes (full):

  • Reference TenantLifecycleStatusEnumeration values: Draft, Active, Suspended, Decommissioned.

Out of scope:

  • New outbound events beyond existing five topics.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-T03.1.1 — Define saga states and event correlations for lifecycle events

Type: Task
Parent: saas-TEN-S03.1
Implementation order: 012
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, saga
Priority: P1
Effort: M
Dependencies: saas-INTEG-F05
Blocks: saas-TEN-T03.1.2
Source gap analysis: Tenants messaging

Description (full):

Extend TenantLifecycleSaga with Event<T> registrations for TenantActivatedEvent, TenantSuspendedEvent, TenantDeletedEvent, ResidencyChangedEvent. Define saga states (e.g., Draft, Active, Suspended, Decommissioned) on TenantLifecycleSagaState. Implement During/When transitions updating state timestamps and lifecycle flags.

Acceptance criteria (testable):

  • AC-1: State diagram documented in saga class XML summary matches implemented transitions.
  • AC-2: TenantLifecycleSagaState persists new fields via durable saga repository.

Implementation notes (full):

  • Files: TenantLifecycleSaga.cs, TenantLifecycleSagaState.cs.
  • Import event types from ConnectSoft.Saas.Tenants.MessagingModel.Events.

Out of scope:

  • Saga tests (next task).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-T03.1.2 — Add saga unit and integration tests for lifecycle sequences

Type: Task
Parent: saas-TEN-S03.1
Implementation order: 012
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, testing
Priority: P1
Effort: M
Dependencies: saas-TEN-T03.1.1
Blocks:
Source gap analysis: Tenants messaging

Description (full):

Add TenantLifecycleSagaTests using MassTransit test harness verifying create → activate → suspend → decommission event sequence updates saga state correctly. Cover residency change on Active tenant. Deep analysis notes "No saga unit tests" — this task closes that gap for Tenants.

Acceptance criteria (testable):

  • AC-1: Test harness asserts saga reaches expected state after each published event.
  • AC-2: Tests run in CI without external broker (in-memory harness acceptable for unit tier).

Implementation notes (full):

  • Place tests in ConnectSoft.Saas.Tenants.UnitTests or dedicated FlowModel test project.
  • Pattern: Billing/Entitlements saga test projects if present.

Out of scope:

  • Acceptance tests across five services.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[013] saas-TEN-F04 — JSON descriptor reconciliation with code

Type: Feature
Parent: saas-EPIC-TEN
Implementation order: 013
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, json-descriptor
Priority: P1
Effort: M
Dependencies: saas-TEN-F01
Blocks:
Source gap analysis: Tenants entity model

Description (full):

Design-time JSON descriptor ConnectSoft.Saas.Tenants.json diverges from runtime entity model in several fields:

Concept JSON descriptor Code (ITenant.cs) Gap
Primary key TenantId (guid) TenantAggregateId (Guid) + TenantId (string partition) Partial — dual id model not reflected
Region RegionCode ResidencyRegion Name mismatch
Status enum Decommissioned in JSON TenantLifecycleStatusEnumeration includes Decommissioned; event topic uses tenant-deleted Vocabulary drift
TenantKey Not in JSON properties Present on entity + migration Missing in descriptor
AggregateVersion Not in JSON Present on ITenant Missing in descriptor

Deep analysis finding T-004 — status Partial.

Target state: JSON descriptor accurately documents code properties, PK strategy, published events, and enumeration values. Factory/codegen tools (if used) regenerate without drift warnings.

Acceptance criteria (testable):

  • AC-1: ConnectSoft.Saas.Tenants.json primaryKey section documents TenantAggregateId vs partition TenantId string.
  • AC-2: Property names align: ResidencyRegion documented (or JSON renamed with migration — prefer code as runtime truth).
  • AC-3: TenantKey and AggregateVersion appear in descriptor properties.
  • AC-4: Architecture or schema validation test compares JSON to ITenant public surface and fails on drift.

Implementation notes (full):

  • Files: ConnectSoft.Saas.Tenants.json, optional schema ConnectSoft.Saas.Tenants.schema.json.
  • Coordinate tenant-deleted topic vs Decommissioned status in F05 envelope story.
  • Reference deep analysis entity model table rows for saas-TEN-F04.

Out of scope:

  • Regenerating entire repo from JSON — manual reconciliation only unless tooling owned elsewhere.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-S04.1 — Reconcile ConnectSoft.Saas.Tenants.json with ITenant runtime model

Type: User Story
Parent: saas-TEN-F04
Implementation order: 013
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1
Priority: P1
Effort: M
Dependencies: saas-TEN-F01
Blocks: saas-TEN-T04.1.1, saas-TEN-T04.1.2
Source gap analysis: Tenants entity model

Description (full):

As a template tooling maintainer, I need the JSON descriptor to match ITenant.cs, so design-time docs and codegen do not mislead integrators about tenant ids, region fields, and aggregate version.

Acceptance criteria (testable):

  • AC-1: Descriptor validation test passes against entity model.
  • AC-2: publishedEvents array still matches TenantsConstants.EventTopics five canonical strings.

Implementation notes (full):

  • publishedEvents in JSON already lists five canonical topics — preserve alignment verified in deep analysis §4.1 Messaging.

Out of scope:

  • F01 rich entity JSON for child types until ADR resolves.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-T04.1.1 — Update JSON descriptor fields for PK, TenantKey, AggregateVersion, region

Type: Task
Parent: saas-TEN-S04.1
Implementation order: 013
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1
Priority: P1
Effort: S
Dependencies: saas-TEN-F01
Blocks: saas-TEN-T04.1.2
Source gap analysis: Tenants entity model

Description (full):

Edit ConnectSoft.Saas.Tenants.json: fix primaryKey to TenantAggregateId (guid) with separate partition property TenantId (string); rename RegionCode property to ResidencyRegion; add TenantKey (string, required) and AggregateVersion (long, required). Update enumeration documentation for lifecycle states.

Acceptance criteria (testable):

  • AC-1: JSON validates against ConnectSoft.Saas.Tenants.schema.json if schema enforces property set.
  • AC-2: Manual review checklist maps each ITenant property to a JSON property entry.

Implementation notes (full):

  • File: repo root ConnectSoft.Saas.Tenants.json lines 9–67 (aggregateRoot.properties).

Out of scope:

  • NHibernate mapping changes unless JSON-driven codegen requires it.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-T04.1.2 — Add descriptor drift architecture test

Type: Task
Parent: saas-TEN-S04.1
Implementation order: 013
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, testing
Priority: P1
Effort: S
Dependencies: saas-TEN-T04.1.1
Blocks:
Source gap analysis: Tenants entity model

Description (full):

Implement test in ArchitectureTests that loads ConnectSoft.Saas.Tenants.json and asserts property name set matches ITenant public properties (minus navigation props). Fail CI on drift. Pattern similar to Products Catalog descriptor tests if available.

Acceptance criteria (testable):

  • AC-1: Test fails if TenantKey removed from JSON but remains on ITenant.
  • AC-2: Test passes after T04.1.1 reconciliation.

Implementation notes (full):

  • File: new JsonDescriptorEntityAlignmentTests.cs in ArchitectureTests project.

Out of scope:

  • Cross-repo JSON comparisons.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[014] saas-TEN-F05 — Event envelope adoption and Pending/Deleted vocabulary decision

Type: Feature
Parent: saas-EPIC-TEN
Implementation order: 014
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, envelope
Priority: P1
Effort: M
Dependencies: saas-INTEG-F03
Blocks:
Source gap analysis: Integration event envelope

Description (full):

Tenants outbound events (TenantCreatedEvent, etc.) implement partial envelope: TenantId, aggregate id, AggregateVersion, OccurredOn — but omit schemaVersion, correlationId, and causationId per deep analysis X-004. This feature adopts the common envelope from saas-INTEG-F03 on all Tenants MessagingModel event types and processor publish paths.

Vocabulary decision: JSON descriptor enumeration uses Decommissioned lifecycle state; integration topic uses tenants.domain.v1.tenant-deleted (TenantsConstants.EventTopics.TenantDeleted). Document mapping: Deleted event represents decommission terminal state (not physical row delete) OR rename topic in breaking change — decision recorded in Tenants ADR snippet.

Acceptance criteria (testable):

  • AC-1: All five Tenants outbound events include envelope fields from INTEG-F03 helper.
  • AC-2: ADR or published-language note documents Decommissioned ↔ tenant-deleted event mapping.
  • AC-3: Serialization tests include envelope fields in golden JSON files.
  • AC-4: CrossRepoPublishedLanguageTests validates event types implement envelope interface once placeholder replaced (coordinate with F06).

Implementation notes (full):

  • Files: MessagingModel/Events/*.cs, DefaultTenantsProcessor.cs publish paths, TenantsMassTransitTopology.cs.
  • Wire correlation from ASP.NET Core trace context in REST/gRPC adapters before processor call.

Out of scope:

  • Changing topic names (already canonical).
  • Inbound events (Tenants is publish-only for integration).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-S05.1 — Adopt common event envelope on Tenants integration events

Type: User Story
Parent: saas-TEN-F05
Implementation order: 014
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1
Priority: P1
Effort: M
Dependencies: saas-INTEG-F03
Blocks: saas-TEN-T05.1.1, saas-TEN-T05.1.2
Source gap analysis: Integration event envelope

Description (full):

As a platform integrator tracing tenant activation, I need Tenants events to carry schemaVersion and correlationId, so downstream Billing sagas join logs with the originating API request.

Acceptance criteria (testable):

  • AC-1: TenantCreatedEvent golden JSON snapshot includes schemaVersion: 1 and non-empty correlationId.
  • AC-2: Decommissioned/deleted vocabulary documented in repo docs/ or ADR.

Implementation notes (full):

  • Depends on shared envelope type from INTEG-F03 T03.1.1.

Out of scope:

  • Billing inbound envelope fields.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-T05.1.1 — Apply envelope properties to all MessagingModel event types

Type: Task
Parent: saas-TEN-S05.1
Implementation order: 014
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1
Priority: P1
Effort: M
Dependencies: saas-INTEG-F03
Blocks: saas-TEN-T05.1.2
Source gap analysis: Integration event envelope

Description (full):

Update all event classes under ConnectSoft.Saas.Tenants.MessagingModel/Events/ to implement shared envelope interface. Map TenantAggregateId to canonical JSON aggregateId. Integrate publish helper in processor for all five lifecycle publishes.

Acceptance criteria (testable):

  • AC-1: Each event type has [Required] on SchemaVersion, CorrelationId, AggregateVersion, OccurredOn.
  • AC-2: Processor unit tests verify helper invoked on publish (mock IPublishEndpoint).

Implementation notes (full):

  • Start from TenantCreatedEvent.cs structure; replicate across activated/suspended/deleted/residency events.

Out of scope:

  • Vocabulary ADR (next task).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-T05.1.2 — Document tenant-deleted vs Decommissioned vocabulary decision

Type: Task
Parent: saas-TEN-S05.1
Implementation order: 014
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, docs
Priority: P1
Effort: S
Dependencies: saas-TEN-T05.1.1
Blocks:
Source gap analysis: Integration event envelope

Description (full):

Author short ADR or published-language appendix entry explaining why integration topic is tenant-deleted while domain enumeration uses Decommissioned and ServiceModel exposes DecommissionAsync. Include consumer guidance for Billing/Entitlements sagas. Optionally add [Obsolete] aliases — prefer documentation-only for wave-1.

Acceptance criteria (testable):

  • AC-1: ADR section linked from TenantDeleted event XML docs.
  • AC-2: Deep analysis glossary updated if needed (Flat tenant / Deleted vocabulary).

Implementation notes (full):

  • Reference TenantsConstants.EventTopics.TenantDeleted and DecommissionAsync on ITenantManagementService.

Out of scope:

  • Renaming public topic string (breaking change).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[015] saas-TEN-F06 — Replace placeholder architecture tests

Type: Feature
Parent: saas-EPIC-TEN
Implementation order: 015
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, architecture-tests
Priority: P1
Effort: M
Dependencies: saas-TEN-F04, saas-TEN-F05
Blocks: saas-TEN-F07
Source gap analysis: Tenants tests

Description (full):

Tenants ArchitectureTests project contains placeholder tests that always pass:

  • OneAggregateRootPerRepoTests.csAssert.IsTrue(true) with TODO to replace NetArchTest rule (references docs/adr/0001-one-aggregate-root-per-repo.md).
  • CrossRepoPublishedLanguageTests.cs — placeholder enforcing published-language surface rule.

Products Catalog template implements real NetArch tests (OneAggregateRootPerRepo, CrossRepoPublishedLanguage assembly scan) — use as reference implementation.

Deep analysis finding T-005 — status Missing.

Target state: Real NetArchTest rules fail CI on violations: more than one aggregate root in DomainModel, illegal cross-repo type references, envelope interface compliance on MessagingModel events.

Acceptance criteria (testable):

  • AC-1: OneAggregateRootPerRepoTests.Only_one_aggregate_root_is_declared uses NetArchTest and fails if second IAggregateRoot<> declared in Tenants domain assemblies.
  • AC-2: CrossRepoPublishedLanguageTests fails if DomainModel type referenced from forbidden assembly graph simulation.
  • AC-3: Optional TenantAggregateTests validates single ITenant root marker — no placeholder asserts.
  • AC-4: All architecture tests pass on current codebase after implementation.

Implementation notes (full):

  • Files: tests/ConnectSoft.Saas.Tenants.ArchitectureTests/*.cs.
  • Reference: ConnectSoft.Saas.ProductsCatalogTemplate/tests/ConnectSoft.Saas.ProductsCatalog.ArchitectureTests/.
  • ServiceModelLayeringNetArchTests.cs already Implemented — do not regress.

Out of scope:

  • Processor unit tests — saas-TEN-F07.
  • Orleans silo tests — saas-TEN-F08 / future grain tests.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-S06.1 — Enable real NetArch architecture tests in Tenants template

Type: User Story
Parent: saas-TEN-F06
Implementation order: 015
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, testing
Priority: P1
Effort: M
Dependencies: saas-TEN-F04, saas-TEN-F05
Blocks: saas-TEN-T06.1.1, saas-TEN-T06.1.2
Source gap analysis: Tenants tests

Description (full):

As a template quality owner, I need architecture tests that actually enforce aggregate-root and published-language rules, so Tenants template regressions are caught in CI like Products Catalog.

Acceptance criteria (testable):

  • AC-1: Removing Assert.IsTrue(true) placeholders — tests use NetArchTest predicates.
  • AC-2: CI pipeline runs ArchitectureTests project on every PR.

Implementation notes (full):

  • Load base-template NetArch harness if available in Tenants base-template subtree.

Out of scope:

  • Billing architecture tests.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-T06.1.1 — Implement OneAggregateRootPerRepoTests with NetArchTest

Type: Task
Parent: saas-TEN-S06.1
Implementation order: 015
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, testing
Priority: P1
Effort: S
Dependencies: saas-TEN-F04
Blocks: saas-TEN-T06.1.2
Source gap analysis: Tenants tests

Description (full):

Replace placeholder in OneAggregateRootPerRepoTests.cs with NetArchTest rule: types in assemblies matching ConnectSoft.Saas.Tenants.DomainModel or implementing IAggregateRoot<> in EntityModel — exactly one aggregate root (ITenant). Follow Catalog test structure.

Acceptance criteria (testable):

  • AC-1: Test fails when dummy second aggregate root class added to test sandbox.
  • AC-2: Test passes on current Tenants codebase.

Implementation notes (full):

  • File: tests/ConnectSoft.Saas.Tenants.ArchitectureTests/OneAggregateRootPerRepoTests.cs.
  • ADR: docs/adr/0001-one-aggregate-root-per-repo.md.

Out of scope:

  • CrossRepoPublishedLanguage test.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-T06.1.2 — Implement CrossRepoPublishedLanguageTests and envelope rule

Type: Task
Parent: saas-TEN-S06.1
Implementation order: 015
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, testing
Priority: P1
Effort: S
Dependencies: saas-TEN-T06.1.1, saas-TEN-F05
Blocks: saas-TEN-F07
Source gap analysis: Tenants tests

Description (full):

Replace placeholder in CrossRepoPublishedLanguageTests.cs with rules: (1) only ServiceModel, MessagingModel, ActorModel assemblies export public API surfaces consumed cross-repo; (2) all types in MessagingModel.Events implement envelope interface from INTEG-F03. Use assembly scanning like Catalog.

Acceptance criteria (testable):

  • AC-1: Test fails if domain entity type marked public in wrong assembly.
  • AC-2: Test fails if event type missing envelope property after F05.

Implementation notes (full):

  • File: CrossRepoPublishedLanguageTests.cs — comments already link published-language doc URL.

Out of scope:

  • NuGet package version pin — INTEG-F07 (Tenants is publisher not consumer).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[016] saas-TEN-F07 — Processor, validator, REST, gRPC, and saga test coverage

Type: Feature
Parent: saas-EPIC-TEN
Implementation order: 016
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, testing
Priority: P1
Effort: L
Dependencies: saas-TEN-F03, saas-TEN-F06
Blocks:
Source gap analysis: Tenants tests

Description (full):

Deep analysis §4.1 Tests: processor/saga coverage Missing; Orleans tests Missing (only base-template BankAccount examples). ITenantManagementService exposes five commands but unit tests do not comprehensively cover DefaultTenantsProcessor validation, conflict rules, REST/gRPC adapters, and saga interactions.

Target state: Unit tests for each processor command (create draft, activate, suspend, decommission, change residency) including validation faults and aggregate version increments. Adapter tests for TenantsController and GrpcTenantManagementService mocking processor. Saga tests linked from F03 included in coverage gate.

Acceptance criteria (testable):

  • AC-1: Unit test class DefaultTenantsProcessorTests with minimum one happy-path and one fault-path test per public processor method.
  • AC-2: REST adapter tests verify HTTP status codes for ValidationFault and ConflictFault mapping.
  • AC-3: gRPC adapter tests verify fault translation for at least Activate and Suspend.
  • AC-4: Code coverage threshold for DomainModel.Impl and ServiceModel meets program minimum (≥70% line coverage on processor/adapters — adjust in CI config).
  • AC-5: No [Ignore] placeholder tests remain in Tenants unit test projects for processor/saga areas.

Implementation notes (full):

  • Files: DefaultTenantsProcessor.cs, validators, TenantsController.cs, GrpcTenantManagementService.cs.
  • Use in-memory NHibernate or repository fakes from base-template patterns.
  • Reference ITenantManagementService.cs five operations as checklist.

Out of scope:

  • Acceptance tests spanning five services — separate demo checklist.
  • Orleans grain silo tests — saas-TEN-F08 if ADR-INTEG-001 Option A.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-S07.1 — Achieve comprehensive unit test coverage for Tenants write and adapter paths

Type: User Story
Parent: saas-TEN-F07
Implementation order: 016
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, testing
Priority: P1
Effort: L
Dependencies: saas-TEN-F03, saas-TEN-F06
Blocks: saas-TEN-T07.1.1, saas-TEN-T07.1.2
Source gap analysis: Tenants tests

Description (full):

As a Tenants maintainer, I need automated tests for all five management commands and both adapters, so lifecycle bug fixes do not regress silently.

Acceptance criteria (testable):

  • AC-1: Test count ≥ 5 processor happy paths + ≥ 3 fault scenarios (validation, not found, conflict).
  • AC-2: CI publishes test results for Tenants.UnitTests on every build.

Implementation notes (full):

  • Map tests to TenantLifecycleStatusEnumeration transitions.

Out of scope:

  • Query service tests (ITenantQueryService — lower priority P2 unless gaps found).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-T07.1.1 — Add DefaultTenantsProcessor and validator unit tests

Type: Task
Parent: saas-TEN-S07.1
Implementation order: 016
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, testing
Priority: P1
Effort: M
Dependencies: saas-TEN-F03
Blocks: saas-TEN-T07.1.2
Source gap analysis: Tenants tests

Description (full):

Create DefaultTenantsProcessorTests covering CreateDraft, Activate, Suspend, Decommission, ChangeResidency with mocked repository and publish endpoint. Assert aggregate version increments, lifecycle status transitions, and event publish calls with correct topic constants from TenantsConstants.EventTopics.

Acceptance criteria (testable):

  • AC-1: Each processor method has ≥1 test; Activate after CreateDraft transitions Draft → Active.
  • AC-2: Suspend on Draft tenant throws expected fault type.

Implementation notes (full):

  • Project: ConnectSoft.Saas.Tenants.UnitTests.
  • Mock IPublishEndpoint or MassTransit publish abstraction used by processor.

Out of scope:

  • REST/gRPC tests.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-T07.1.2 — Add REST and gRPC adapter tests for ITenantManagementService

Type: Task
Parent: saas-TEN-S07.1
Implementation order: 016
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, testing
Priority: P1
Effort: M
Dependencies: saas-TEN-T07.1.1
Blocks:
Source gap analysis: Tenants tests

Description (full):

Add adapter tests using WebApplicationFactory (REST) and gRPC test server pattern verifying controllers/services delegate to ITenantsProcessor and map faults to HTTP/gRPC status codes. Cover at least CreateDraft + Activate for REST and Suspend for gRPC.

Acceptance criteria (testable):

  • AC-1: REST test returns 400 on validation fault from processor mock.
  • AC-2: gRPC test throws RpcException with correct status on ResourceNotFoundFault.

Implementation notes (full):

  • Files: TenantsController.cs, GrpcTenantManagementService.cs.
  • May extend AcceptanceTests project if already hosts test server (CONNECTSOFT_ACCEPTANCE_TEST_HOST).

Out of scope:

  • Full OpenAPI contract snapshot tests.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

[017] saas-TEN-F08 — Wire writes through TenantLifecycleGrain

Type: Feature
Parent: saas-EPIC-TEN
Implementation order: 017
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, orleans
Priority: P1
Effort: M
Dependencies: saas-INTEG-F06
Blocks:
Source gap analysis: Orleans write-path

Description (full):

Orleans grain TenantLifecycleGrain (TenantEditorGrain.cs) implements ITenantLifecycleActor but ServiceModel write path bypasses grains: TenantsController and GrpcTenantManagementService call ITenantsProcessor directly. Deep analysis §4.1 Actor — Write path via grain: Missing.

This feature executes the outcome of ADR-INTEG-001 (saas-INTEG-F06):

  • If Option A (wire grains): REST/gRPC → IGrainFactory.GetGrain<ITenantLifecycleActor>(tenantKey) → grain → processor.
  • If Option B (processor-only ADR): Document bypass in Tenants ADR; optionally remove misleading direct processor calls from docs; architecture test asserts documented pattern; cancel grain wiring AC.

Acceptance criteria (testable):

  • AC-1: ADR-INTEG-001 Accepted and Tenants implementation matches chosen option.
  • AC-2: Option A: No direct ITenantsProcessor injection in ServiceModel adapters — grains mediate all five commands; grain unit or silo test passes for Activate.
  • AC-3: Option B: ADR in Tenants repo states processor-only write path; TenantEditorGrain marked experimental or test-only; architecture test enforces no GetGrain requirement.
  • AC-4: Existing ITenantLifecycleActor interface methods cover all five ServiceModel operations or ADR explains gap.

Implementation notes (full):

  • Files: TenantEditorGrain.cs, ITenantEditorActor.cs / ITenantLifecycleActor, TenantsController.cs, GrpcTenantManagementService.cs, DI registration in ApplicationModel.
  • Grain key: align with TenantId string partition or TenantAggregateId Guid — document choice.
  • Reference Catalog ProductEditorGrainSiloTests.cs for silo test pattern if Option A.

Out of scope:

  • Other repos' grain wiring — respective saas-CAT-F01, saas-ENT-F07, etc.
  • Orleans cluster production hosting tuning.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-S08.1 — Align Tenants write path with ADR-INTEG-001 Orleans decision

Type: User Story
Parent: saas-TEN-F08
Implementation order: 017
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, orleans
Priority: P1
Effort: M
Dependencies: saas-INTEG-F06
Blocks: saas-TEN-T08.1.1, saas-TEN-T08.1.2
Source gap analysis: Orleans write-path

Description (full):

As a platform architect enforcing a consistent actor model, I need Tenants API writes to follow the program-wide Orleans decision, so template users are not misled by unused grains.

Acceptance criteria (testable):

  • AC-1: Code inspection checklist in PR template matches ADR outcome (grain routed or bypass documented).
  • AC-2: At least one automated test validates write path pattern (silo test or architecture rule).

Implementation notes (full):

  • Blocked until saas-INTEG-T06.1.2 completes.

Out of scope:

  • Read path through grains (query service stays direct).

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-T08.1.1 — Refactor ServiceModel adapters per ADR-INTEG-001 outcome

Type: Task
Parent: saas-TEN-S08.1
Implementation order: 017
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, orleans
Priority: P1
Effort: M
Dependencies: saas-INTEG-F06
Blocks: saas-TEN-T08.1.2
Source gap analysis: Orleans write-path

Description (full):

If Option A: inject IGrainFactory into TenantsController and GrpcTenantManagementService; route each of five commands to TenantLifecycleGrain methods that delegate to ITenantsProcessor. If Option B: add Tenants ADR mirroring ADR-INTEG-001 Option B; update XML docs on grains stating not used on API path; ensure adapters remain processor-direct intentionally.

Acceptance criteria (testable):

  • AC-1: Option A — grep ServiceModel layer shows GetGrain usage for all write operations.
  • AC-2: Option B — Tenants ADR file exists; grains documented as non-write-path.

Implementation notes (full):

  • Files: TenantsController.cs, GrpcTenantManagementService.cs, TenantEditorGrain.cs.
  • Preserve fault contracts on ITenantManagementService.

Out of scope:

  • Processor logic changes.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

saas-TEN-T08.1.2 — Add grain silo test or architecture enforcement for write path

Type: Task
Parent: saas-TEN-S08.1
Implementation order: 017
Status: Not Started
Area path: ConnectSoft\SaaS\Tenants
Iteration: TBD
Tags: saas-platform, gap, tenants, p1, testing, orleans
Priority: P1
Effort: M
Dependencies: saas-TEN-T08.1.1
Blocks:
Source gap analysis: Orleans write-path

Description (full):

If Option A: add TenantLifecycleGrainSiloTests activating silo, calling grain Activate method, asserting processor invoked and state persisted — mirror Catalog ProductEditorGrainSiloTests.cs. If Option B: extend ArchitectureTests to assert ServiceModel does not reference IGrainFactory and document exception list empty.

Acceptance criteria (testable):

  • AC-1: Option A — silo test passes in CI (may use collection fixture for Orleans test cluster).
  • AC-2: Option B — architecture test passes documenting processor-only pattern.

Implementation notes (full):

  • Deep analysis notes "Orleans tests Missing" and "Only base-template BankAccount examples" — replace with Tenants-specific tests if Option A.

Out of scope:

  • Multi-silo cluster deployment tests.

Definition of done:

  • All AC pass
  • Tests added/updated and green
  • Docs updated
  • Status updated in master + mirrors

Implementation ordering (P0 → P1 → P2)

P0 — Cross-epic prerequisites (execute before Tenants E2E slice)

Tenants features depend on integration epic outcomes:

  1. [001][002] saas-INTEG-F01, F02 — topics and quota payload (Billing consumes Tenants events)
  2. [003] saas-INTEG-F03 — envelope contract (blocks [014] saas-TEN-F05)
  3. [005] saas-INTEG-F05 — durable saga (blocks [012] saas-TEN-F03)
  4. [006] saas-INTEG-F06 — Orleans ADR (blocks [017] saas-TEN-F08)

P1 — Tenants epic (this file, global order)

Execute in [NNN] order after relevant INTEG dependencies satisfied:

  1. [010] saas-TEN-F01 — Rich tenant aggregate OR flat-tenant ADR
  2. [011] saas-TEN-F02 — External references EditionRef, BillingAccountRef
  3. [012] saas-TEN-F03 — Full lifecycle saga (after INTEG-F05)
  4. [013] saas-TEN-F04 — JSON descriptor reconciliation
  5. [014] saas-TEN-F05 — Event envelope + Deleted/Decommissioned vocabulary (after INTEG-F03)
  6. [015] saas-TEN-F06 — Replace placeholder architecture tests
  7. [016] saas-TEN-F07 — Processor / adapter / saga test coverage
  8. [017] saas-TEN-F08 — Wire writes through TenantLifecycleGrain (after INTEG-F06)

P2 — Follow-on enhancements

  • Query service expansion and list/filter APIs beyond wave-1 ITenantQueryService
  • Cross-service ref validation sagas (verify EditionRef exists in Catalog on activate)
  • Tenant acceptance tests spanning full five-repo demo harness
  • Documentation-only updates in CompanyDocumentation program epics (saas-DOCS-*)