Skip to content

Generated SaaS Storage

Target Architecture — Final-State Design

This page describes the storage topology of a Generated SaaS Product. Each store has a single owning service (per the documentation standards storage-owner rule); no service reads another service's primary store directly. Stores are provisioned by Pulumi IaC and accessed through generated data-access code.

A generated product follows database-per-service with shared infrastructure for cross-cutting concerns (cache, secrets, blobs). Relational data uses NHibernate over Azure SQL or PostgreSQL; large artifacts use Blob Storage; hot read paths use Redis; secrets use Key Vault — and nothing else holds secret material.

Storage map

Data Store Owner Service Access Pattern Retention Notes
Tenant registry Azure SQL / PostgreSQL Tenant Management Read-heavy lookups, low write Tenant lifetime Source of the tenantId discriminator
Users, roles, permissions Azure SQL / PostgreSQL Identity Service Read-heavy (authz), moderate write Tenant lifetime Permissions are a platform-level catalog
OpenIddict tokens/clients Azure SQL / PostgreSQL Authorization Server High read on validation Token lifetime Refresh/auth-code records pruned on expiry
Subscriptions, editions, billing Azure SQL / PostgreSQL Subscription & Billing Transactional Tenant lifetime + financial retention Editions are a platform-level catalog
Feature flags, configuration Azure SQL / PostgreSQL Configuration Service Read-very-heavy Tenant lifetime Hot values cached in Redis
Domain data Azure SQL / PostgreSQL Each domain microservice Mixed Tenant lifetime Product-specific schemas
Audit entries Append-only Azure SQL / PostgreSQL Audit Trail Service Append + query Long-term (e.g. 7 yr) Exported to Blob archive
Notifications Azure SQL / PostgreSQL + Blob Notification Service Write + delivery state 90 days hot, then archive Large bodies/attachments in Blob
Integration connections Azure SQL / PostgreSQL Integration Service Mixed Tenant lifetime Secrets as Key Vault references only
Report definitions, runs Azure SQL / PostgreSQL Reporting & Analytics Mixed Tenant lifetime Generated artifacts in Blob
Report / export artifacts Blob Storage Reporting & Analytics Write-once, read-many Configurable (e.g. 1 yr) Lifecycle policy enforced
Audit archive Blob Storage (immutable) Audit Trail Service Write-once Long-term Immutable/WORM container
Notification attachments Blob Storage Notification Service Write-once, read-many 90 days then archive
Session / hot read cache Redis API Gateway, Configuration, Identity Low-latency read/write Ephemeral / TTL Cache keys prefixed by tenantId
Rate-limit counters Redis API Gateway High-frequency increment Sliding window TTL Per-tenant + per-route limits
Outbox messages Azure SQL / PostgreSQL (per service) Each publishing service Write + drain Until published Drained by OutboxWorker
Secrets & connection strings Key Vault All services (read) Read on startup / rotation Until rotated Referenced via SecretReference, never stored elsewhere

Store ownership rules

  • Single owner. Each store is owned by exactly one service; other services obtain data through that service's API or by subscribing to its events.
  • Tenant scoping. Every tenant-owned store enforces the tenantId discriminator (or schema/database-per-tenant) described in the data model.
  • No secrets outside Key Vault. Connection strings, signing keys, and integration credentials live only in Key Vault; aggregates store SecretReference pointers.
  • Cache is derived, never authoritative. Redis holds derived/hot copies with TTLs; the relational store is always the source of truth.
  • Blob is for artifacts. Reports, audit archives, and attachments go to Blob with lifecycle policies; relational stores hold metadata and references.

Provisioning

All stores are provisioned by Pulumi IaC (see Deployment) per environment, with private networking, encryption at rest, and managed identities for access. No store is created or mutated outside the IaC pipeline.

How storage contributes to the pillars

  • Traceability — outbox tables tie state changes to published events; audit archive preserves immutable history with traceId.
  • Reusability — the storage topology is generated identically across products from shared templates and IaC modules.
  • Autonomy — schemas, migrations, and IaC are generated and applied by agents and pipelines.
  • Governance — immutable audit, Key Vault-only secrets, and retention policies enforce compliance at the storage layer.
  • Observability — per-store metrics (latency, throughput, size) are emitted and tagged by tenant.
  • Multi-tenant scale — discriminator-based isolation, per-tenant cache keys, and the option of schema/database-per-tenant scale to many tenants.