SaaS factory generation wiring¶
Contract between each ConnectSoft.Saas.<Context>Template repo and the ConnectSoft AI Software Factory. Pairs with:
- microservice-generator-agent.md
- template-catalog.md
- SaaS Aggregate Root Assignment
- SaaS Baseline Checklist
Inputs and outputs¶
Single-input contract per repo:
| Artifact | Role |
|---|---|
<Context>.json |
Source of truth for the aggregate (one entityModel.aggregateRoot, plus child entities / VOs / enums / published events). |
<Context>.schema.json |
JSON Schema validating <Context>.json. |
<Context>.entitymodel.schema.json |
Schema the factory uses to emit EntityModel classes. |
Microservice.schema.json |
Shared microservice descriptor (pinned to BaseTemplate's version). |
Generation targets (the factory writes into these projects; humans do not hand-edit generated files):
<Context>.EntityModel— persistence entities + NHibernate mappings.<Context>.PersistenceModel.NHibernate— repositories + queries.<Context>.DatabaseModel.Migrations— FluentMigrator migrations (dialect-agnostic; no outbox).<Context>.ServiceModel— DTOs + typed client facades.<Context>.ServiceModel.RestApi— controllers / minimal endpoint descriptors.<Context>.ServiceModel.Grpc— code-firstGrpc<Name>Serviceadapter classes implementing the C#[ServiceContract]interfaces from<Context>.ServiceModel(ServiceModel.Grpc — no.proto).<Context>.MessagingModel— integration event DTOs (matchingpublishedEventsin descriptor).
Generation leaves alone (never overwrites):
<Context>.DomainModel.Impl— invariants, domain services.<Context>.FlowModel+<Context>.FlowModel.MassTransit— sagas / process managers.<Context>.ActorModel.Orleans— grain implementations.<Context>.Application+<Context>.ApplicationModel— composition root.<Context>.InfrastructureModel— IaC.<Context>.DiagramAsCodeModel,docs/,Deployment/,observability/, pipelines, build scripts.
Per-repo wiring¶
Each SaaS repo ships:
build/regenerate.ps1— idempotent entry point. Validates<Context>.json; if$env:CONNECTSOFT_FACTORY_ENDPOINTis set, dispatches to the microservice-generator-agent; otherwise validates the descriptor and returns.<Context>.jsonat repo root (1 aggregate root only — enforced by schema).- Nightly
azure-pipelines-template.ymlalready composes + gates; a futureazure-pipelines-regeneration.ymlcan wrapbuild/regenerate.ps1behind a scheduled trigger once the factory endpoint stabilizes.
SaaS descriptor shape (summary)¶
{
"$schema": "./<Context>.schema.json",
"entityModel": {
"boundedContext": "<BoundedContext>",
"repository": "<Namespace>Template",
"aggregateRoot": {
"name": "<AggregateRoot>",
"primaryKey": { "type": "guid", "name": "<AggregateRoot>Id" },
"table": "<TableName>",
"tenantScoped": true,
"properties": [ /* ... */ ],
"hasMany": [ /* in-aggregate children */ ],
"references": [ /* external refs by ID only */ ]
},
"entities": [ /* in-aggregate entity descriptors */ ],
"valueObjects": [ /* VOs */ ],
"enumerations": [ /* smart enums */ ],
"publishedEvents": [ "context.topic.v1.event-name", "..." ]
}
}
Hard rules the schema enforces:
entityModel.aggregateRootis a single object, not a list.- Every entity in
entities[]has aprimaryKeydistinct from the aggregate root's primary key. - Every reference in
references[]is{ "externalContext": "...", "refName": "...Ref", "type": "guid|string" }. No structural fields are pulled from external repos. publishedEvents[]follows the canonical topic matrix in saas-cross-repo-published-language.md.
Template catalog entries (to add to AI.SoftwareFactory.Documentation)¶
| Short name | Template | Aggregate root | Descriptor |
|---|---|---|---|
connectsoft-saas-tenants |
ConnectSoft.Saas.TenantsTemplate |
Tenant |
ConnectSoft.Saas.Tenants.json |
connectsoft-saas-productscatalog |
ConnectSoft.Saas.ProductsCatalogTemplate |
Product |
ConnectSoft.Saas.ProductsCatalog.json |
connectsoft-saas-entitlements |
ConnectSoft.Saas.EntitlementsTemplate |
Entitlement |
ConnectSoft.Saas.Entitlements.json |
connectsoft-saas-billing |
ConnectSoft.Saas.BillingTemplate |
Subscription |
ConnectSoft.Saas.Billing.json |
connectsoft-saas-metering |
ConnectSoft.Saas.MeteringTemplate |
UsageMeter |
ConnectSoft.Saas.Metering.json |
Observability of generation runs¶
build/regenerate.ps1 must emit a structured JSON line (stdout) per run:
{ "repo": "ConnectSoft.Saas.TenantsTemplate", "descriptor": "ConnectSoft.Saas.Tenants.json", "aggregateRoot": "Tenant", "factory": "http(s)://...", "status": "validated|dispatched|skipped", "durationMs": 1234 }
The AI Software Factory harvests these lines for its generation-catalog dashboard.