Skip to content

SaaS factory generation wiring

Contract between each ConnectSoft.Saas.<Context>Template repo and the ConnectSoft AI Software Factory. Pairs with:

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-first Grpc<Name>Service adapter classes implementing the C# [ServiceContract] interfaces from <Context>.ServiceModel (ServiceModel.Grpc — no .proto).
  • <Context>.MessagingModel — integration event DTOs (matching publishedEvents in 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_ENDPOINT is set, dispatches to the microservice-generator-agent; otherwise validates the descriptor and returns.
  • <Context>.json at repo root (1 aggregate root only — enforced by schema).
  • Nightly azure-pipelines-template.yml already composes + gates; a future azure-pipelines-regeneration.yml can wrap build/regenerate.ps1 behind 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:

  1. entityModel.aggregateRoot is a single object, not a list.
  2. Every entity in entities[] has a primaryKey distinct from the aggregate root's primary key.
  3. Every reference in references[] is { "externalContext": "...", "refName": "...Ref", "type": "guid|string" }. No structural fields are pulled from external repos.
  4. 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.