Skip to content

Generated SaaS Aggregate Roots

Target Architecture — Final-State Design

This page documents the thirteen common platform-level aggregate roots present in every Generated SaaS Product. Each follows the naming conventions (singular PascalCase noun) and is persisted via NHibernate to Azure SQL or PostgreSQL. Products add domain-specific aggregates; these form the reusable SaaS spine. Every aggregate is the consistency boundary and the only entry point to its entities.

All aggregates below carry a TenantId value object (except Tenant itself, which is the tenant boundary), enforce their invariants within a single transaction, and emit domain events in the canonical envelope. Repositories follow the {AggregateRoot}Repository convention.


Tenant

  • Purpose — represents a customer organization and is the root isolation boundary for all data and traffic in the product.
  • FieldsTenantId, Name, Slug, Status (Provisioning, Active, Suspended, Decommissioned), EditionCode, CreatedAt, ProvisionedAt.
  • EntitiesTenantOwner (the founding admin user reference), ProvisioningStep (ordered provisioning tasks).
  • Value ObjectsTenantId, Slug, TenantStatus, ContactEmail.
  • Invariants — slug is globally unique and immutable once Active; cannot transition to Active until all ProvisioningSteps succeed; suspended tenants reject all write operations downstream.
  • Domain EventsTenantRegistered, TenantProvisioned, TenantSuspended, TenantDecommissioned.
  • RepositoryTenantRepository.
  • Persistence — NHibernate to Azure SQL/PostgreSQL; tenant registry table; the source of the tenantId discriminator used by every other store.

User

  • Purpose — an authenticatable principal within a tenant, with profile and role assignments.
  • FieldsUserId, TenantId, Email, DisplayName, Status (Invited, Active, Disabled), CreatedAt, LastLoginAt.
  • EntitiesRoleAssignment (links user to a Role), Invitation (pending invite with expiry).
  • Value ObjectsUserId, TenantId, EmailAddress, UserStatus.
  • Invariants — email is unique within a tenant; an Invitation cannot be accepted after expiry; a disabled user holds no effective permissions.
  • Domain EventsUserInvited, UserActivated, UserDisabled, RoleAssigned, RoleUnassigned.
  • RepositoryUserRepository.
  • Persistence — NHibernate to Azure SQL/PostgreSQL; users and role-assignment tables, tenant-scoped.

Role

  • Purpose — a named bundle of permissions assignable to users within a tenant (RBAC).
  • FieldsRoleId, TenantId, Code, Name, IsSystem, Description.
  • EntitiesRolePermission (grant linking role to a Permission).
  • Value ObjectsRoleId, RoleCode, TenantId.
  • Invariants — code is unique within a tenant; system roles (IsSystem) cannot be deleted or have their core permissions removed; a role must reference only existing permissions.
  • Domain EventsRoleCreated, RoleUpdated, PermissionGrantedToRole, PermissionRevokedFromRole, RoleDeleted.
  • RepositoryRoleRepository.
  • Persistence — NHibernate to Azure SQL/PostgreSQL; roles and role-permission tables.

Permission

  • Purpose — an atomic, named capability (e.g. subscription.manage) that can be granted to roles.
  • FieldsPermissionId, Code, Name, Category, IsSystem.
  • Entities — none (permissions are leaf grants).
  • Value ObjectsPermissionId, PermissionCode, PermissionCategory.
  • Invariants — code is globally unique and stable; system permissions are immutable; a permission cannot be deleted while referenced by any role.
  • Domain EventsPermissionDefined, PermissionDeprecated.
  • RepositoryPermissionRepository.
  • Persistence — NHibernate to Azure SQL/PostgreSQL; typically a platform-level (cross-tenant) catalog table seeded from the product blueprint.

Subscription

  • Purpose — a tenant's active commercial agreement on an edition, governing entitlements and billing.
  • FieldsSubscriptionId, TenantId, EditionCode, Status (Trial, Active, PastDue, Cancelled), BillingCycle, CurrentPeriodStart, CurrentPeriodEnd, CancelledAt.
  • EntitiesBillingPeriod (per-cycle billing record), EntitlementOverride (per-subscription override of an edition entitlement).
  • Value ObjectsSubscriptionId, TenantId, BillingCycle, Money, SubscriptionStatus.
  • Invariants — exactly one Active subscription per tenant; cannot activate without referencing a published Edition; CurrentPeriodEnd is always after CurrentPeriodStart; cancellation is terminal for the current period.
  • Domain EventsSubscriptionActivated, SubscriptionRenewed, SubscriptionPastDue, SubscriptionCancelled, EntitlementOverridden.
  • RepositorySubscriptionRepository.
  • Persistence — NHibernate to Azure SQL/PostgreSQL; subscription and billing-period tables, tenant-scoped.

Edition

  • Purpose — a defined product plan (e.g. Starter, Professional, Enterprise) bundling features, limits, and price.
  • FieldsEditionId, Code, Name, Status (Draft, Published, Retired), Price, EffectiveFrom.
  • EntitiesEditionEntitlement (feature/limit included in the edition), PriceTier.
  • Value ObjectsEditionId, EditionCode, Money, Limit, EditionStatus.
  • Invariants — code is unique; a Published edition's entitlements are immutable (new versions require a new edition); a retired edition accepts no new subscriptions.
  • Domain EventsEditionDefined, EditionPublished, EditionRetired.
  • RepositoryEditionRepository.
  • Persistence — NHibernate to Azure SQL/PostgreSQL; platform-level edition catalog (cross-tenant), seeded from blueprint.

FeatureFlag

  • Purpose — a toggle controlling feature availability and progressive rollout, scoped per tenant or globally.
  • FieldsFeatureFlagId, Key, TenantId (nullable for global), Enabled, RolloutPercentage, UpdatedAt.
  • EntitiesFlagRule (targeting rule, e.g. by tenant segment or user attribute).
  • Value ObjectsFeatureFlagKey, RolloutPercentage, TenantId.
  • Invariants — key is unique per scope; RolloutPercentage is within 0–100; a tenant-scoped flag overrides the global flag for that tenant.
  • Domain EventsFeatureFlagToggled, FeatureFlagRuleChanged.
  • RepositoryFeatureFlagRepository.
  • Persistence — NHibernate to Azure SQL/PostgreSQL; flags cached in Redis for low-latency evaluation.

AuditEntry

  • Purpose — an immutable record of a security- or compliance-relevant action.
  • FieldsAuditEntryId, TenantId, Actor, Action, ResourceType, ResourceId, OccurredAt, TraceId, Outcome.
  • Entities — none (audit entries are immutable leaf records).
  • Value ObjectsAuditEntryId, TenantId, Actor, ActionCode, TraceId.
  • Invariants — entries are append-only and never updated or deleted; OccurredAt and TraceId are always populated; outcome is one of Success/Denied/Failure.
  • Domain EventsAuditEntryRecorded.
  • RepositoryAuditEntryRepository (write-once; query-only thereafter).
  • Persistence — append-only Azure SQL/PostgreSQL table; periodically exported to immutable Blob archive by the Audit Export Worker.

Notification

  • Purpose — a message to be delivered to one or more recipients across one or more channels.
  • FieldsNotificationId, TenantId, TemplateCode, Status (Pending, Sent, Failed), Channel, RequestedAt, SentAt.
  • EntitiesNotificationRecipient (per-recipient delivery state), DeliveryAttempt (per-attempt result).
  • Value ObjectsNotificationId, TenantId, Channel (Email, SMS, InApp, Webhook), TemplateCode, NotificationStatus.
  • Invariants — a notification references a valid template; status becomes Sent only when all required recipients have a successful DeliveryAttempt; retries are bounded.
  • Domain EventsNotificationRequested, NotificationSent, NotificationFailed.
  • RepositoryNotificationRepository.
  • Persistence — NHibernate to Azure SQL/PostgreSQL; large bodies/attachments in Blob; processed by NotificationDispatchWorker.

IntegrationConnection

  • Purpose — a configured connection to an external system, including credentials and sync settings.
  • FieldsIntegrationConnectionId, TenantId, SystemType, Status (Configured, Connected, Error, Disabled), LastSyncAt, SyncSchedule.
  • EntitiesSyncRun (per-execution record), FieldMapping (external↔internal field map).
  • Value ObjectsIntegrationConnectionId, TenantId, SecretReference (Key Vault pointer, never the secret), SyncSchedule.
  • Invariants — secrets are stored only as SecretReference to Key Vault; a connection cannot sync while Disabled or Error without remediation; one in-flight SyncRun per connection.
  • Domain EventsIntegrationConnected, IntegrationSyncRequested, IntegrationSucceeded, IntegrationFailed, IntegrationDisabled.
  • RepositoryIntegrationConnectionRepository.
  • Persistence — NHibernate to Azure SQL/PostgreSQL; secret material referenced in Key Vault; processed by IntegrationSyncWorker.

WebhookSubscription

  • Purpose — an external subscriber's registration to receive product events via outbound HTTP callbacks.
  • FieldsWebhookSubscriptionId, TenantId, CallbackUrl, EventTypes, Status (Active, Paused, Disabled), SecretReference, CreatedAt.
  • EntitiesDeliveryRecord (per-event delivery attempt and response).
  • Value ObjectsWebhookSubscriptionId, TenantId, CallbackUrl, EventTypeFilter, SecretReference.
  • Invariants — callback URL must be HTTPS; signing secret is stored as a SecretReference; failed deliveries retry with backoff and auto-pause the subscription after a threshold.
  • Domain EventsWebhookSubscribed, WebhookDelivered, WebhookDeliveryFailed, WebhookPaused.
  • RepositoryWebhookSubscriptionRepository.
  • Persistence — NHibernate to Azure SQL/PostgreSQL; delivery handled by the Integration Service / workers.

ReportDefinition

  • Purpose — a parameterized definition of a report or analytics view that can be run to produce artifacts.
  • FieldsReportDefinitionId, TenantId, Name, Category, SupportedFormats, ParameterSchema, CreatedAt.
  • EntitiesReportRun (per-execution record with status and artifact reference), ReportParameter.
  • Value ObjectsReportDefinitionId, TenantId, ReportFormat (Pdf, Csv, Xlsx), ParameterSchema.
  • Invariants — a run's parameters must validate against ParameterSchema; requested format must be in SupportedFormats; artifacts are immutable once produced.
  • Domain EventsReportRequested, ReportGenerated, ReportFailed.
  • RepositoryReportDefinitionRepository.
  • Persistence — NHibernate to Azure SQL/PostgreSQL for definitions/runs; artifacts in Blob; processed by ReportGenerationWorker.

ConfigurationSetting

  • Purpose — a tenant- or product-scoped configuration value governing runtime behavior.
  • FieldsConfigurationSettingId, Key, TenantId (nullable for product-default), Value, ValueType, UpdatedAt, UpdatedBy.
  • Entities — none (settings are leaf records; history kept via audit).
  • Value ObjectsConfigurationKey, ConfigurationValue, ValueType, TenantId.
  • Invariants — key is unique per scope; value must conform to ValueType; tenant-scoped settings override product defaults; secret-typed settings are stored as Key Vault references.
  • Domain EventsConfigurationChanged.
  • RepositoryConfigurationSettingRepository.
  • Persistence — NHibernate to Azure SQL/PostgreSQL; hot settings cached in Redis; secret values referenced in Key Vault.

Aggregate relationships

flowchart TB
    Tenant["Tenant"] --> User["User"]
    Tenant --> Subscription["Subscription"]
    Tenant --> FeatureFlag["FeatureFlag"]
    Tenant --> ConfigurationSetting["ConfigurationSetting"]
    Tenant --> IntegrationConnection["IntegrationConnection"]
    Tenant --> WebhookSubscription["WebhookSubscription"]
    Tenant --> Notification["Notification"]
    Tenant --> ReportDefinition["ReportDefinition"]
    Tenant --> AuditEntry["AuditEntry"]
    User --> Role["Role"]
    Role --> Permission["Permission"]
    Subscription --> Edition["Edition"]
Hold "Alt" / "Option" to enable pan & zoom

How aggregates contribute to the pillars

  • Traceability — every aggregate emits enveloped events carrying traceId; AuditEntry explicitly stores TraceId.
  • Reusability — the thirteen roots are generated identically across products from the ConnectSoft.Saas.* and ConnectSoft.MicroserviceTemplate families.
  • Autonomy — agents generate aggregates, repositories, and migrations from the domain model in the blueprint.
  • Governance — invariants (append-only audit, immutable published editions, secret references) encode policy in the domain.
  • Observability — domain events are first-class telemetry; aggregate operations are traced and metered.
  • Multi-tenant scaleTenantId is a value object on every root, and Tenant is the explicit isolation boundary.