GeneratedSaasFoundations¶
Target
This page describes intended behaviour or structure. No implementation is claimed unless a section is explicitly marked Current implementation or Evidence.
| Bounded context | BC-31 Generated Tenant & Commercial Foundations |
| Platform / plane | Generated SaaS / Generated SaaS pack |
| Deployment granularity | standalone host |
| Status | target · ConnectSoft.Factory.Generated.Saas |
| Built from | connectsoft-saas-tenants · libraries: connectsoft-extensions-saas-abstractions, connectsoft-extensions-saas-asp-net-core, connectsoft-extensions-messaging-model, connectsoft-extensions-persistence-model-nhibernate |
| Decisions | ADR-0015, ADR-0020 |
| Traceability | FR-06 FR-09 FUX-08 NFR-14 NFR-15 XL-13 |
Purpose and responsibilities¶
GeneratedSaasFoundations is the representative instance of the five ConnectSoft SaaS templates (Tenants, ProductsCatalog, Entitlements, Billing, Metering) inside a generated product. It gives the product its own tenants (customers of the product, with canonical ADR-0100 isolation modes and residency), its editions and entitlements from the Agentic SaaS Product Blueprint, subscriptions the product sells to its customers and metered usage the product bills. The one bridge to the Factory is the tenant mapping: every product tenant carries an opaque customer-tenant id the fleet uses for instances, rollouts, incidents and off-boarding — never customer identity. The Factory's own commercial context (BC-34) bills the product owner for the Factory; the product bills its customers itself.
Context and boundaries¶
flowchart LR
S["GeneratedSaasFoundations"]
GeneratedProductHost["GeneratedProductHost"] -->|grpc| S
FleetInventoryService["FleetInventoryService"] -->|sync-http| S
S -->|sync-http| ext_identity_platform["ext-identity-platform"]
S -->|sync-http| ext_saas_templates["ext-saas-templates"]
S -. "ProductTenantProvisioned" .-> E_ProductTenantProvisioned(("event"))
S -. "ProductTenantStateChanged" .-> E_ProductTenantStateChanged(("event"))
S -. "ProductSubscriptionChanged" .-> E_ProductSubscriptionChanged(("event"))
S -. "ProductUsageMetered" .-> E_ProductUsageMetered(("event"))
The same templates serve the Factory's own tenancy and commerce (BC-33, BC-34) and the marketplace's licensing (BC-28): one foundation, three instances with different subjects.
Domain model¶
ProductTenant — A customer tenant inside the generated product (SaaS Tenants template) with its mapping to the Factory's customer-tenant id used by fleet operations, its isolation mode, region and state. (catalog entry)
| Field | Type | Required | Description |
|---|---|---|---|
productTenantId |
string |
yes | |
factoryTenantId |
string |
yes | The Factory tenant that owns the product. |
customerTenantId |
string |
yes | Opaque id the fleet uses; never carries customer identity. |
name |
string |
yes | |
isolationMode |
string |
yes | |
region |
string |
yes | |
state |
enum:ProductTenantState |
yes | |
createdAt |
datetime |
yes |
Invariants:
- Identity and authorization of customer users live in the product (ADR-0101 through the Authorization Server); the Factory sees only the opaque customer-tenant id.
- A tenant's region satisfies the product owner's residency rule (D31).
stateDiagram-v2
Provisioning --> Active : Provisioned
Active --> Suspended : SubscriptionLapsed
Suspended --> Active : Restored
Active --> Offboarding : OffboardingRequested
Offboarding --> Deleted : DeletionCompleted
Events: ProductTenantProvisioned, ProductTenantStateChanged · Tables: ProductTenants · Repository: ProductTenantRepository
ProductSubscription — The customer's subscription to an edition of the product (SaaS Billing and Entitlements templates): entitlements, seats, metering dimensions and state; for managed products the product's editions map to the owner's Factory subscription for fleet objectives, never for billing the customer (the product bills its own customers). (catalog entry)
| Field | Type | Required | Description |
|---|---|---|---|
subscriptionId |
guid |
yes | |
productTenantId |
string |
yes | |
factoryTenantId |
string |
yes | |
edition |
string |
yes | |
entitlements |
json |
yes | |
seats |
int |
no | |
meteringDimensions |
list:string |
yes | |
state |
string |
yes | |
changedAt |
datetime |
yes |
Invariants:
- Editions and entitlements come from the Agentic SaaS Product Blueprint and the ProductsCatalog template; the product never invents entitlements at run time.
Events: ProductSubscriptionChanged, ProductUsageMetered · Tables: ProductSubscriptions, ProductUsage · Repository: ProductSubscriptionRepository
erDiagram
ProductTenant {
string productTenantId PK
string factoryTenantId
string customerTenantId
string name
string isolationMode
string region
enum_ProductTenantState state
datetime createdAt
}
ProductSubscription {
guid subscriptionId PK
string productTenantId
string factoryTenantId
string edition
json entitlements
int seats
list_string meteringDimensions
string state
datetime changedAt
}
Entities and value objects¶
None modelled
No entities or value objects are modelled for this item yet.
Data model and storage¶
| Store | Role | Engine / profile | Tables |
|---|---|---|---|
| Generated product store (representative) | primary | azure-sql / nhibernate-sqlserver | ProductTenants, ProductSubscriptions, ProductUsage |
| Table | Owner | Columns | Indexes |
|---|---|---|---|
dbo.ProductTenants |
ProductTenant | 8 | 1 |
dbo.ProductSubscriptions |
ProductSubscription | 9 | 0 |
dbo.ProductUsage |
ProductSubscription | 6 | 0 |
Full DDL: appendix.
APIs¶
| Method | Path | Operation | Scope | Side effects | Idempotency | Gateway | Summary |
|---|---|---|---|---|---|---|---|
GET |
/product/tenants |
ListProductTenants | product.admin.read |
read | natural | GW-07 | Product tenants with state, region and the opaque customer-tenant id (product owner and fleet). |
POST |
/product/tenants |
ProvisionProductTenant | product.admin.write |
shared-write | key-header | GW-07 | Provision a customer tenant in the product (self-service sign-up or owner action). |
GET |
/product/tenants/{productTenantId}/subscription |
GetProductSubscription | product.admin.read |
read | natural | GW-07 | Edition, entitlements, seats and metered usage. |
PUT |
/product/tenants/{productTenantId}/subscription |
ChangeProductSubscription | product.admin.write |
shared-write | natural | GW-07 | Change edition or seats (the product's own commerce). |
| gRPC service | Method | Streaming | Visibility | Side effects | Summary |
|---|---|---|---|---|---|
Foundations |
ResolveTenant |
none | internal | read | Resolve a request's tenant and entitlements for the product's services (per-request claim). |
Messages¶
| Event | Topic | Scope / v | Aggregate | Consumers | Summary |
|---|---|---|---|---|---|
| ProductTenantProvisioned | product-tenancy.tenants.v1.product-tenant-provisioned |
integration / 1 | ProductTenant | FleetInventoryService, AuditService | A customer tenant exists in the product (the fleet gets an instance). |
| ProductTenantStateChanged | product-tenancy.tenants.v1.product-tenant-state-changed |
integration / 1 | ProductTenant | FleetInventoryService, FleetIncidentService, AuditService | Suspended, restored, off-boarding or deleted. |
| ProductSubscriptionChanged | product-tenancy.subscriptions.v1.product-subscription-changed |
integration / 1 | ProductSubscription | FleetInventoryService, AuditService | A customer's edition or seats changed. |
| ProductUsageMetered | product-tenancy.usage.v1.product-usage-metered |
integration / 1 | ProductSubscription | FleetInventoryService | Metered usage for a period (the product's own billing; mirrored to the Factory for managed-product cost attribution later). |
ProductTenantProvisioned payload:
| Field | Type | Required | Description |
|---|---|---|---|
productTenantId |
string |
yes | |
factoryTenantId |
string |
yes | |
customerTenantId |
string |
yes | |
region |
string |
yes |
ProductTenantStateChanged payload:
| Field | Type | Required | Description |
|---|---|---|---|
productTenantId |
string |
yes | |
factoryTenantId |
string |
yes | |
customerTenantId |
string |
yes | |
fromState |
enum:ProductTenantState |
yes | |
toState |
enum:ProductTenantState |
yes |
ProductSubscriptionChanged payload:
| Field | Type | Required | Description |
|---|---|---|---|
subscriptionId |
guid |
yes | |
factoryTenantId |
string |
yes | |
customerTenantId |
string |
yes | |
edition |
string |
yes | |
state |
string |
yes |
ProductUsageMetered payload:
| Field | Type | Required | Description |
|---|---|---|---|
subscriptionId |
guid |
yes | |
factoryTenantId |
string |
yes | |
customerTenantId |
string |
yes | |
dimension |
string |
yes | |
period |
string |
yes | |
quantity |
decimal |
yes |
| Command | Handled by | Result events | Summary |
|---|---|---|---|
ProvisionProductTenant |
ProductTenant | ProductTenantProvisioned | |
ChangeProductSubscription |
ProductSubscription | ProductSubscriptionChanged |
None modelled
No consumed events are modelled for this item yet.
Workers and jobs¶
| Worker | Trigger | Output events | Retry | Idempotency key | Summary |
|---|---|---|---|---|---|
| UsageMeter | schedule 0 * * * * |
ProductUsageMetered | fixed | subscriptionId + dimension + period |
Aggregates metered events per dimension and period (the Metering template) and emits period totals. |
Actors and grains¶
None modelled
No grains are modelled for this item yet.
Sagas and long-running flows¶
None modelled
No sagas are modelled for this item yet.
stateDiagram-v2
[*] --> Provisioning
Provisioning --> Active: Provisioned
Active --> Suspended: SubscriptionLapsed
Suspended --> Active: Restored
Active --> Offboarding: OffboardingRequested (fleet order)
Offboarding --> Deleted: DeletionCompleted (after acknowledged handover)
Deleted --> [*]
Options and configuration¶
| Section | Key | Type | Default | Reloadable | Secret | Summary |
|---|---|---|---|---|---|---|
Saas:Tenants |
IsolationMode |
string | RowFilter |
no | no | ADR-0100 mode from the blueprint. |
Saas:Editions |
Catalog |
json | { starter: {}, professional: {}, enterprise: {} } |
yes | no | Editions and entitlements from the Agentic SaaS Product Blueprint. |
Metrics and observability¶
| Metric | Instrument | Unit | Dimensions | Summary |
|---|---|---|---|---|
connectsoft.factory.product.tenants |
updown | {tenant} | productId, state | Product tenants by state. |
connectsoft.factory.product.subscriptions |
updown | {subscription} | productId, edition | Subscriptions by edition. |
Security¶
| Authentication | oauth2-jwt |
| Scopes | product.admin.read (Tenants and subscriptions (product owner, fleet).); product.admin.write (Provision and change (product owner, self-service flows).) |
| Roles | ProductOwner, FleetOperator, Observer |
| Tenant isolation | per-request-claim |
| Data classification | confidential |
| Max side-effect class | shared-write |
| Secrets | product-sql (key-vault, rotate 90 d) |
Dependencies¶
Outbound
| Target | Kind | Purpose | Failure mode | Required |
|---|---|---|---|---|
| ext-identity-platform | sync-http | Customer identity through the Authorization Server (ADR-0101). | fail-fast | yes |
| ext-saas-templates | sync-http | The SaaS templates this foundation instantiates. | fail-fast | yes |
Inbound
| Target | Kind | Purpose | Failure mode | Required |
|---|---|---|---|---|
| GeneratedProductHost | grpc | ResolveTenant on every request. | — | yes |
| FleetInventoryService | sync-http | Tenants and subscriptions through GW-07. | — | yes |
Failure and recovery¶
| Scenario | Detection | Recovery | Data impact | RTO (min) |
|---|---|---|---|---|
| Subscription lapses | billing state | tenant Suspended; product refuses tenant requests with a clear state; restore on payment | none | 0 |
NFR targets¶
| Target | Class value (pilot-interactive) | Override |
|---|---|---|
| latency_p95_ms | 2000 | — |
| availability_pct | 99.5 | — |
| throughput_rps | 50 | — |
| rpo_minutes | 15 | — |
| rto_minutes | 240 | — |
| cost_class | low | — |
Deployment¶
| Granularity | standalone host |
| Topologies | saas-default, hybrid, on-prem |
| Runtime | aks; replicas 2–6 |
| Ports | https 9010, grpc 9012, silo 13010, gateway 32010 |
Current implementation¶
The SaaS templates exist with the SaaS Control Plane prototype as their UI; DerechHaLev uses the tenancy foundations. No product-to-fleet tenant mapping exists.
Later capabilities¶
Usage mirrored to the Factory for managed-product cost attribution; customer self-service edition changes through the product's own shell on the SaaS shell template.
Decisions and traceability¶
| Family | Ids |
|---|---|
| FR | FR-06, FR-09 |
| FUX | FUX-08 |
| NFR | NFR-14, NFR-15 |
| XL | XL-13 |