Storage¶
Target Architecture — Final-State Design
This page maps every class of Integration Platform data to its physical store, owning service, access pattern, and retention. The guiding rule is single ownership: each store is owned by exactly one service, and credentials never exist as plaintext anywhere outside Azure Key Vault.
The platform uses three physical store families: a relational store (Azure SQL / PostgreSQL via NHibernate) for connection, provider, run, and delivery metadata; Azure Key Vault for all secret material; and Azure Blob for raw webhook payloads and large request/response bodies. Azure Service Bus is the transport (not a store of record), and Redis provides hot caches for provider lookups and rate-limit buckets.
Storage Map¶
| Data | Store | Owner Service | Access Pattern | Retention | Notes |
|---|---|---|---|---|---|
| Integration connections | Azure SQL / PostgreSQL | Owning integration service (e.g. GitHubIntegrationService) |
Read-heavy point lookups by connectionId / tenantId |
Lifetime + 90 days | Tenant-partitioned; configuration as JSON column |
| Providers & API clients | Azure SQL / PostgreSQL | VendorApiClientRegistryService |
Read-heavy catalogue reads; cached in Redis | Lifetime | global rows shared read-only across tenants |
| Credential metadata | Azure SQL / PostgreSQL | VendorApiClientRegistryService |
Point lookups + rotation writes | Lifetime + audit window | References only — keyVaultRef, version, fingerprint; no secret bytes |
| Credential secrets | Azure Key Vault | VendorApiClientRegistryService (custodian) |
Resolve at call time; rotate by version | Per Key Vault rotation policy | Never plaintext in any DB, log, or event; tenant-namespaced |
| Integration runs | Azure SQL / PostgreSQL | Owning integration service | Append-heavy writes; query by runId / connectionId |
180 days hot, then archive | One row per run + child RunAttempt rows |
| Integration failures | Azure SQL / PostgreSQL | Owning integration service / WebhookGatewayService |
Write on failure; sweep by IntegrationRetryWorker |
180 days | Drives retry and escalation analytics |
| Webhook subscriptions | Azure SQL / PostgreSQL | WebhookGatewayService |
Read on every matching event; write on subscribe | Lifetime | signingSecretRef points to Key Vault |
| Webhook delivery metadata | Azure SQL / PostgreSQL | WebhookGatewayService |
Append + status updates; query by deliveryId |
90 days hot, then archive | payloadRef points to Blob |
| Raw webhook payloads | Azure Blob | WebhookGatewayService |
Write once on ingress; read on replay | 30 days, then tiered/purged | Container partitioned by tenantId; short-lived SAS |
| Request / response bodies | Azure Blob | Owning integration service | Write on run; read for diagnostics/replay | 30 days, then tiered/purged | Large model/cloud payloads kept off the relational store |
| Provider lookups & rate-limit buckets | Redis | VendorApiClientRegistryService |
Hot read/write; TTL-based | Ephemeral (cache) | Rebuildable from SQL; never a source of record |
| Events (transport) | Azure Service Bus | MassTransit (all services) | Publish/subscribe; dead-letter on poison | Per subscription TTL | Carries canonical envelope; not a store of record |
Ownership & Isolation Rules¶
- One owner per store. Only the owning service writes to a given table or container; other services read via APIs or react to events. No shared databases.
- Secrets are custodied, not owned by the domain.
IntegrationCredentialrows hold only references; theVendorApiClientRegistryServiceis the Key Vault custodian and the only component with rotation rights. - Plaintext-free guarantee. Secret material is resolved transiently at call time (via
ConnectSoft.Extensions.Http.OAuth2/ Key Vault SDK), used in-memory, and never persisted, logged, or placed in an event payload. Logs and events carry onlycredentialRefandSecretFingerprint. - Tenant partitioning.
tenantIdis the partition key in SQL, the namespace in Key Vault, and the container prefix in Blob. - Caches are rebuildable. Redis holds derived data (provider capabilities, rate-limit counters) that can always be reconstructed from the relational store.
Backup & Durability¶
- Relational stores use geo-redundant backups with point-in-time restore; migrations are managed via the
DatabaseModel.Migrationsproject per service. - Key Vault uses soft-delete and purge protection; rotation retains prior versions until verification succeeds.
- Blob containers use lifecycle management to tier hot → cool → archive and to enforce purge of expired payloads.