Skip to content

SaaS Template Program — Deep Gap Analysis

Last verified: 2026-05-27
Program: Gap Implementation (saas-EPIC-*)
Companion backlog: saas-gap-implementation-backlog.md


1. Executive summary

This document is the single source of evidence for the SaaS template gap program. It compares wave-1 implementations in the five ConnectSoft.Saas.*Template repositories against the canonical DDD blueprint, JSON descriptors, cross-repo published language, and baseline checklist.

Rollup by service

Service Implemented Partial Missing Deferred Linked Features
Cross-cutting (INTEG) 2 4 1 0 saas-INTEG-F01..F07
Tenants 8 9 6 1 saas-TEN-F01..F08
Products Catalog 14 5 2 1 saas-CAT-F01..F07
Entitlements 10 7 5 1 saas-ENT-F01..F08
Billing 11 8 7 2 saas-BIL-F01..F11
Metering 9 8 8 1 saas-MET-F01..F09

P0 blockers (E2E integration)

# Finding Evidence Closes with
1 Billing inbound tenant topic uses saas.tenants.v1.tenant-activated instead of canonical tenants.domain.v1.tenant-activated BillingConstants.InboundEventTopics.TenantActivated saas-INTEG-F01, saas-BIL-F02
2 Billing quota topic uses metering.quotas.v1.quota-exceeded vs canonical metering.quota.v1.quota-exceeded BillingConstants.InboundEventTopics.MeteringQuotaExceeded vs MeteringConstants.EventTopics.QuotaExceeded saas-INTEG-F01, saas-BIL-F02
3 Quota payload field mismatch: Metering publishes Dimension; Billing expects MeterKey QuotaExceededIntegrationEvent.Dimension vs MeteringQuotaExceededInboundIntegrationEvent.MeterKey saas-INTEG-F02, saas-MET-F04
4 Integration events lack common envelope fields (schemaVersion, correlationId, causationId) Cross-repo published language §Non-negotiable rules vs event DTOs saas-INTEG-F03
5 Orleans grains exist but no service routes writes through them All five repos: REST/gRPC → Default*Processor directly saas-INTEG-F06, per-repo F08/F01/F07/F10/F05

Strategic decisions still required

Decision Options Owner Feature
Flat tenant vs rich aggregate Accept flat Tenant + ADR, or implement TenantProfile, Contact, etc. saas-TEN-F01
Orleans write-path Wire grains on all writes, or ADR bypass with processor-only path saas-INTEG-F06
Invoice scope Minimal read-model projection vs defer (events only) saas-BIL-F03
Payment provider ACL Skeleton adapter + webhook saga vs defer saas-BIL-F04
EffectiveEntitlementDescriptor Materialize VO on assign/activate vs summary-only ADR saas-ENT-F01
Catalog structural APIs SLA/Pricing/BusinessModel write ops vs defer ADR saas-CAT-F03

2. Methodology

Source documents

Layer Path Role
Canonical DDD entities ConnectSoft.CompanyDocumentation/docs/saas/framework/saas-platform-ddd-entities.md Target aggregate shapes
DDD blueprint ConnectSoft.CompanyDocumentation/docs/saas/framework/saas-platform-ddd-blueprint.md Bounded contexts, collaboration
Bounded contexts matrix ConnectSoft.Documentation/Docs/starters/saas-bounded-contexts-and-templates.md Repo ↔ aggregate mapping
Cross-repo language ConnectSoft.Documentation/Docs/starters/saas-cross-repo-published-language.md Topics, envelope, ACL rules
Baseline checklist ConnectSoft.Documentation/Docs/starters/saas-template-baseline-checklist.md Repo compliance
JSON descriptors ConnectSoft.Saas.*Template/ConnectSoft.Saas.*.json Design-time model
Code ConnectSoft.Saas.*Template/src/** Runtime truth

Classification taxonomy

Status Meaning
Implemented Code and tests verify the capability matches canonical intent
Partial Scaffold or subset exists; gaps remain
Missing Not present in code or tests
Deferred Explicitly out of scope this wave (ADR or out-of-scope.md)

Evidence rules

Every finding cites at least one of: source file path + symbol, test class, ADR, or doc anchor. Findings map to one or more saas-*-F## backlog Features.


3. Cross-cutting findings

3.1 Topic harmonization

Status: Partial
Closes with: saas-INTEG-F01, saas-BIL-F02

Canonical topics are defined in saas-cross-repo-published-language.md. Tenants and Products Catalog outbound topics align with constants in TenantsConstants.EventTopics and ProductsCatalogConstants.EventTopics.

Drift evidence:

Consumer Constant Value in code Canonical
Billing InboundEventTopics.TenantActivated saas.tenants.v1.tenant-activated tenants.domain.v1.tenant-activated
Billing InboundEventTopics.MeteringQuotaExceeded metering.quotas.v1.quota-exceeded metering.quota.v1.quota-exceeded

File: ConnectSoft.Saas.BillingTemplate/src/ConnectSoft.Saas.Billing/BillingConstants.cs

3.2 Quota payload alignment

Status: Missing (contract mismatch)
Closes with: saas-INTEG-F02, saas-MET-F04, saas-BIL-F02

Metering publishes QuotaExceededIntegrationEvent with property Dimension. Billing inbound DTO MeteringQuotaExceededInboundIntegrationEvent expects MeterKey. MassTransit deserialization will not map across different property names without explicit mapping or contract change.

Files:

  • ConnectSoft.Saas.MeteringTemplate/src/ConnectSoft.Saas.Metering.MessagingModel/Events/QuotaExceededIntegrationEvent.csDimension
  • ConnectSoft.Saas.BillingTemplate/src/ConnectSoft.Saas.Billing.MessagingModel/Inbound/MeteringQuotaExceededInboundIntegrationEvent.csMeterKey

3.3 Integration event envelope

Status: Partial
Closes with: saas-INTEG-F03, saas-TEN-F05

Published language requires: tenantId, aggregateId, aggregateVersion, schemaVersion, correlationId, causationId, occurredOn. Current event DTOs implement subsets (typically TenantId, AggregateVersion, OccurredOn) without schemaVersion, correlationId, or causationId.

3.4 Redis inbox dedupe

Status: Partial
Closes with: saas-INTEG-F04

BaseTemplate provides Redis cache keys; saga idempotency patterns exist in processors but cross-repo (sourceContext, eventId) dedupe is not uniformly enforced across all inbound sagas.

3.5 MassTransit outbox + saga durability

Status: Partial
Closes with: saas-INTEG-F05, saas-CAT-F05

Tenants saga uses in-memory repository (TenantLifecycleSaga + MassTransitExtensions). Published language mandates MassTransit built-in outbox. NHibernate transactional outbox deferred per Products Catalog ADR-0003.

3.6 Orleans write-path

Status: Partial (grains implemented, not on API path)
Closes with: saas-INTEG-F06, saas-TEN-F08, saas-CAT-F01, saas-ENT-F07, saas-BIL-F10, saas-MET-F05

All five repos register Orleans, define grains implementing actor interfaces, and delegate to Default*Processor. REST/gRPC adapters call processors directly — no GetGrain usage in write paths.

Evidence (Tenants): GrpcTenantManagementService.cs, TenantsController.csITenantsProcessor; grain at TenantEditorGrain.cs (TenantLifecycleGrain).

3.7 MessagingModel NuGet pin policy

Status: Partial
Closes with: saas-INTEG-F07, saas-ENT-F08

Entitlements references ConnectSoft.Saas.ProductsCatalog.MessagingModel for catalog events. Version pin strategy across repos is not documented or CI-enforced.


4. Per-service deep analysis

4.1 Tenants

Repository: ConnectSoft.Saas.TenantsTemplate
Aggregate root: Tenant
Closes with: saas-TEN-F01..F08

Entity model

Concept Blueprint JSON descriptor Code Status Feature
TenantId (string partition) Yes TenantId as guid PK TenantAggregateId (Guid) + TenantId (string) Partial saas-TEN-F04
TenantProfile VO Yes Missing saas-TEN-F01
TenantRegionResidency VO Yes RegionCode ResidencyRegion Partial saas-TEN-F01, F04
Contact entity Yes Missing saas-TEN-F01
TenantConfiguration entity Yes Missing saas-TEN-F01
TenantKey Yes Present in entity/migration Partial saas-TEN-F04
AggregateVersion Yes Present Partial saas-TEN-F04, F05
EditionRef, BillingAccountRef Yes Missing saas-TEN-F02

Evidence: ConnectSoft.Saas.Tenants.json, ITenant.cs, docs/adr/0001-one-aggregate-root-per-repo.md

ServiceModel

Capability Status Evidence
ITenantManagementService (5 ops) Implemented ITenantManagementService.cs
REST + gRPC adapters Implemented TenantsController.cs, GrpcTenantManagementService.cs
Query service Implemented ITenantQueryService.cs

Actor / Orleans

Capability Status Evidence
ITenantLifecycleActor Implemented ITenantEditorActor.cs
TenantLifecycleGrain Implemented TenantEditorGrain.cs
Write path via grain Missing No GetGrain in ServiceModel/DomainModel.Impl
Orleans tests Missing Only base-template BankAccount examples

Messaging

Capability Status Evidence
Outbound topics (5) Implemented TenantsConstants.EventTopics, TenantsMassTransitTopology.cs
Descriptor alignment Implemented ConnectSoft.Saas.Tenants.json publishedEvents
Saga orchestration Partial TenantLifecycleSaga — create-only stub, no multi-step lifecycle
Event envelope fields Partial Missing schemaVersion, correlationId, causationId

Tests

Test area Status Evidence
NetArch layering Implemented ServiceModelLayeringNetArchTests.cs
OneAggregateRootPerRepo Missing (placeholder) OneAggregateRootPerRepoTests.csAssert.IsTrue(true)
CrossRepoPublishedLanguage Missing (placeholder) CrossRepoPublishedLanguageTests.cs
Processor/saga coverage Missing No saga unit tests

4.2 Products Catalog

Repository: ConnectSoft.Saas.ProductsCatalogTemplate
Aggregate root: Product
Closes with: saas-CAT-F01..F07

Entity model

Capability Status Evidence
Rich IProduct + editions, SLA, features Implemented IProduct.cs, ProductEntity.cs, JSON descriptor
Peer entities (Feature, PricingModel, BusinessModel) Implemented EntityModel, processor
AggregateVersion on events Implemented MessagingModel events
POCO + processor pattern (no domain aggregate class) Partial By design; entity tests only

ServiceModel

Capability Status Evidence
Management + query + catalog services Implemented ServiceModel, gRPC, REST controllers
ListEditions / get-by-id pricing/business Partial Some query gaps

Actor / Orleans

Capability Status Evidence
IProductEditorGrain Implemented ProductEditorGrain.cs
Write path via grain Missing ServiceModel → processor directly
Grain tests Partial ProductEditorGrainSiloTests.cs — CreateProduct only

Messaging

Capability Status Evidence
7 outbound topics Implemented ProductsCatalogConstants, CatalogMassTransitTopology.cs
Publish-only (no inbound sagas) Implemented By design
EntitlementsChanged fan-out on pricing/SLA bindings Missing When structural APIs ship

Architecture tests

Test Status Evidence
OneAggregateRootPerRepo Implemented Real NetArchTest
CrossRepoPublishedLanguage Implemented Assembly scan
Layering, gRPC, repository confinement Implemented ArchitectureTests project

4.3 Entitlements

Repository: ConnectSoft.Saas.EntitlementsTemplate
Aggregate root: Entitlement
Closes with: saas-ENT-F01..F08

Entity model

Concept Blueprint Code Status Feature
IEntitlement + assignments/overrides Yes Yes Implemented
EffectiveEntitlementDescriptor VO Yes Missing saas-ENT-F01
Suspend / Decommission lifecycle Yes Partial Partial saas-ENT-F02

ServiceModel

Capability Status Evidence
Draft/activate/assign/override + query Implemented ServiceModel, gRPC, REST
Catalog integrity on assign Missing No existence check

Messaging

Capability Status Evidence
3 outbound topics Implemented EntitlementsConstants, processor publish
ProductRetired saga Implemented ProductCatalogReactionStateMachine.cs
ProductCreated/Updated topology without consumers Partial EntitlementsMassTransitTopology.cs
Per-row assignment-changed on catalog retirement Partial saas-ENT-F03

Architecture tests

Test Status Evidence
Layering, gRPC, repository Implemented ArchitectureTests
OneAggregateRootPerRepo Missing (placeholder) OneAggregateRootPerRepoTests.cs
CrossRepoPublishedLanguage Missing (placeholder) CrossRepoPublishedLanguageTests.cs

4.4 Billing

Repository: ConnectSoft.Saas.BillingTemplate
Aggregate root: Subscription
Closes with: saas-BIL-F01..F11

Entity model

Concept Blueprint JSON Code Status Feature
Subscription lifecycle Yes Partial Yes Partial saas-BIL-F01
Create → Draft Yes Creates Active Missing saas-BIL-F01
Decommissioned vs Canceled Yes Decommissioned Canceled Partial saas-BIL-F01, F04
Invoice aggregate Out of scope Events only Deferred saas-BIL-F03
Payment provider domain Out of scope Deferred saas-BIL-F04
PromotionApplication, ProrationPolicy, SeatPolicy Yes Partial/mis-copied Partial saas-BIL-F05, F11

Evidence: docs/out-of-scope.md, DefaultSubscriptionsProcessor.cs, SubscriptionSeatPolicy naming drift

Inbound events

Capability Status Evidence
6 inbound DTOs Implemented MessagingModel/Inbound/
5 reaction sagas Implemented FlowModel.MassTransit/
Topic name alignment Missing BillingConstants.InboundEventTopics
Quota payload mapping Missing Dimension vs MeterKey
consumedEvents in JSON descriptor Missing ConnectSoft.Saas.Billing.json
Suspend-on-quota outbound event Missing Processor suspends silently
rating-window to Metering Missing

ServiceModel gaps

Operation Status Feature
Create/Upgrade/ChangeEdition/Cancel Implemented
RecordInvoiceIssued, RecordPaymentCaptured, RequestEntitlementsSync Missing from public API saas-BIL-F08

4.5 Metering

Repository: ConnectSoft.Saas.MeteringTemplate
Aggregate root: UsageMeter
Closes with: saas-MET-F01..F09

Entity model

Concept Blueprint Code Status Feature
IUsageMeter (tenant + dimension) Yes Yes Implemented
UsageRecord VO + idempotency Yes Missing saas-MET-F01
Window VO + roll semantics Yes Partial Partial saas-MET-F02

Messaging

Capability Status Evidence
4 outbound topics Implemented MeteringConstants, topology
4 inbound sagas Implemented FlowModel.MassTransit/
UsageReportedForQuota topology Missing Event + saga exist, no SetEntityName
QuotaExceeded Dimension field Partial Billing expects MeterKey

Dead / orphan code

Item Status Evidence
AssignEditionInput, ActivateUsageMeterInput, OverrideTenantFeatureInput, CatalogProductRetiredReactionInput Missing from processor DomainModel — not on IUsageMetersProcessor
Misnamed Orleans surrogates Partial Surrogates folder — copy-paste filenames
MeteringOrleansGrainPartitionTests Missing (ignored) ArchitectureTests
UsageMeterAggregateTests Missing (placeholder) UnitTests

Actor / Orleans

Capability Status Feature
UsageMeterGrain + composite key Implemented
Write path via grain Missing saas-MET-F05

5. Decision log (ADRs needed)

ID Decision Options Owner Status
ADR-TEN-001 Flat tenant vs rich aggregate (A) Flat + ADR (B) Implement child VOs/entities saas-TEN-F01 Pending
ADR-INTEG-001 Orleans write-path (A) Wire grains (B) Processor-only + ADR saas-INTEG-F06 Pending
ADR-BIL-001 Invoice scope (A) Read-model projection (B) Defer events-only saas-BIL-F03 Pending
ADR-BIL-002 Payment ACL (A) Adapter skeleton (B) Defer saas-BIL-F04 Pending
ADR-ENT-001 EffectiveEntitlementDescriptor (A) Materialize VO (B) Summary-only ADR saas-ENT-F01 Pending
ADR-CAT-001 Structural write APIs (A) Implement SLA/pricing/business writes (B) Defer saas-CAT-F03 Pending
ADR-CAT-003 NHibernate outbox Future work per existing stub saas-CAT-F05 Deferred

Per-repo ADR stub files will be authored under each template's docs/adr/ directory.


6. Priority rationale

Priority Scope Rationale
P0 saas-INTEG-F01..F07 E2E demo cannot run until topics, payloads, envelope, and cross-service contracts align
P0 saas-BIL-F02, saas-MET-F04 Direct consumers of INTEG fixes
P1 Per-repo lifecycle, entity model, tests Required for production-grade templates
P1 Orleans write-path (saas-INTEG-F06 + per-repo) Architectural compliance vs documented actor model
P2 Query extensions, optional cross-repo edges (saas-MET-F08) Enhancements after core path works
P2 Documentation/governance (saas-DOCS-F01..F10) Ongoing; some items complete with this program

7. Traceability matrix

Finding ID Description Repo Status Feature(s)
X-001 Billing tenant topic drift Billing Missing saas-INTEG-F01, saas-BIL-F02
X-002 Billing quota topic drift Billing Missing saas-INTEG-F01, saas-BIL-F02
X-003 Quota Dimension vs MeterKey Metering, Billing Missing saas-INTEG-F02, saas-MET-F04
X-004 Event envelope incomplete All Partial saas-INTEG-F03, saas-TEN-F05
X-005 Inbox dedupe not uniform All Partial saas-INTEG-F04
X-006 Saga outbox in-memory Tenants Partial saas-INTEG-F05
X-007 Orleans not on write path All Partial saas-INTEG-F06, saas-*-F0*
X-008 MessagingModel pin policy Entitlements Partial saas-INTEG-F07, saas-ENT-F08
T-001 Rich tenant aggregate Tenants Missing saas-TEN-F01
T-002 External refs Tenants Missing saas-TEN-F02
T-003 Lifecycle saga stub Tenants Partial saas-TEN-F03
T-004 JSON descriptor drift Tenants Partial saas-TEN-F04
T-005 Placeholder arch tests Tenants Missing saas-TEN-F06
C-001 Grain not on write path Catalog Partial saas-CAT-F01
C-002 Doc drift aggregate-root.md Catalog Partial saas-CAT-F02
E-001 EffectiveEntitlementDescriptor Entitlements Missing saas-ENT-F01
E-002 Suspend/decommission E2E Entitlements Partial saas-ENT-F02
B-001 Create creates Active not Draft Billing Partial saas-BIL-F01
B-002 Invoice projection Billing Deferred saas-BIL-F03
B-003 Payment ACL Billing Deferred saas-BIL-F04
M-001 UsageRecord idempotency Metering Missing saas-MET-F01
M-002 UsageReported topology Metering Missing saas-MET-F03
M-003 Dead domain inputs Metering Missing saas-MET-F06

8. Appendices

A. Canonical topic list

See saas-cross-repo-published-language.md — Canonical topic plan table.

B. Integration event envelope schema

Required fields per published language:

tenantId: string (required)
aggregateId: string (required)
aggregateVersion: long
schemaVersion: int (starts at 1)
correlationId: guid
causationId: guid (optional)
occurredOn: datetime UTC

C. Glossary

Term Definition
Aggregate root Single DDD root per repo (Tenant, Product, Entitlement, Subscription, UsageMeter)
ACL Anti-corruption layer for external providers
Published language Cross-repo event and ServiceModel contracts
Flat tenant Wave-1 simplified tenant without child VOs

D. Source document inventory

Document Version / date
This analysis 2026-05-27
saas-cross-repo-published-language.md Current in Documentation repo
saas-platform-ddd-entities.md CompanyDocumentation canonical
Template JSON descriptors Per-repo at analysis date