Aggregate Roots¶
Target Architecture — Final-State Design
This page describes the final-state domain model of the Integration Platform. Each aggregate root is a consistency boundary owned by exactly one bounded context and persisted via NHibernate (relational) or Key Vault references (secrets). All aggregates carry the cross-cutting metadata fields and emit events in the canonical envelope.
The platform has 8 aggregate roots. Together they model the full lifecycle of external connectivity: which providers exist (IntegrationProvider, ExternalApiClient), how the factory connects (IntegrationConnection, IntegrationCredential), what crosses the boundary inbound and outbound (WebhookSubscription, WebhookDelivery), and the operational record of every attempt (IntegrationRun, IntegrationFailure).
IntegrationConnection¶
Purpose. Represents a configured, testable link between a tenant/project and an external provider. The unit of "we can talk to this vendor for this customer."
Fields. connectionId (PK, conn- prefix), tenantId, projectId, providerId, displayName, authMode, credentialId, status (Pending / Active / Degraded / Retired), health (Healthy / Degraded / Unhealthy / Unknown), configuration (provider-specific JSON), lastCheckedAt, establishedAt, plus standard metadata.
Entities. ConnectionEndpoint (resolved base URL / region per operation class), ConnectionScope (granted capability scopes).
Value Objects. ProviderId, CredentialRef, HealthStatus, RateLimitBudget, RetryPolicy.
Invariants.
- A connection cannot be Active without a resolvable credentialId and a passing initial health test.
- providerId must reference a registered, Active IntegrationProvider.
- Cannot execute runs while status is Retired.
Domain Events. IntegrationConnectionEstablished, IntegrationConnectionRetired, IntegrationFailed (on health failure).
Repository. IntegrationConnectionRepository.
Persistence. Azure SQL / PostgreSQL via NHibernate; configuration stored as a JSON column. Tenant-partitioned.
IntegrationProvider¶
Purpose. The Vendor Registry catalogue entry for a supported external system — its category, capabilities, and auth model.
Fields. providerId (PK, prov- prefix), tenantId (or global for shared providers), key, displayName, category (SourceControl / Model / Cloud / Communication / Commerce / BusinessSystem), authModel, baseUrl, status (Registered / Active / Deprecated), capabilities[], plus standard metadata.
Entities. ProviderCapability (a declared operation such as sms.send), ProviderEnvironment (sandbox vs production endpoints).
Value Objects. ProviderKey, AuthModel, Capability, RateLimitProfile.
Invariants.
- key is unique within its scope (tenant or global).
- At least one ExternalApiClient must be registered before the provider can be Active.
- A Deprecated provider accepts no new connections.
Domain Events. IntegrationProviderRegistered, IntegrationProviderDeprecated.
Repository. IntegrationProviderRepository.
Persistence. Azure SQL / PostgreSQL via NHibernate; capability list normalised into a child table.
IntegrationCredential¶
Purpose. A reference to externally-held secret material plus its rotation metadata. Never stores plaintext — only Key Vault references.
Fields. credentialId (PK, cred- prefix), tenantId, providerId, connectionId, keyVaultRef, currentVersion, authMode (ApiKey / OAuth2ClientCredentials / OAuth2AuthorizationCode / ManagedIdentity), rotationPolicy, lastRotatedAt, expiresAt, status (Active / Rotating / Revoked), plus standard metadata.
Entities. CredentialVersion (historical Key Vault version pointers with activation timestamps).
Value Objects. KeyVaultRef, RotationPolicy, AuthMode, SecretFingerprint (hash for change detection, not the secret).
Invariants.
- No field ever contains secret material; only keyVaultRef and a non-reversible SecretFingerprint.
- Exactly one CredentialVersion is active at a time.
- Rotation keeps the prior version active until the new version passes verification.
Domain Events. CredentialRotated, CredentialRevoked, IntegrationFailed (on verification failure).
Repository. IntegrationCredentialRepository.
Persistence. Azure SQL / PostgreSQL via NHibernate for metadata; secret bytes live only in Azure Key Vault.
WebhookSubscription¶
Purpose. A registration that the factory will deliver a given event type to an external endpoint (outbound egress).
Fields. subscriptionId (PK, sub- prefix), tenantId, projectId, eventType, endpointUrl, signingSecretRef, active, filter (optional payload predicate), createdAt, plus standard metadata.
Entities. SubscriptionAttemptPolicy (per-subscription retry/backoff overrides).
Value Objects. EndpointUrl, SigningSecretRef, EventTypeFilter, RetryPolicy.
Invariants.
- endpointUrl must be HTTPS and pass SSRF allow-list validation.
- A signingSecretRef is required so deliveries can be HMAC-signed.
- Inactive subscriptions are skipped by WebhookDeliveryWorker.
Domain Events. WebhookSubscribed, WebhookSubscriptionDeactivated.
Repository. WebhookSubscriptionRepository.
Persistence. Azure SQL / PostgreSQL via NHibernate.
WebhookDelivery¶
Purpose. A single inbound (normalised) or outbound delivery attempt and its lifecycle — the auditable record of one webhook crossing the boundary.
Fields. deliveryId (PK, del- prefix), tenantId, direction (Inbound / Outbound), subscriptionId (outbound) / providerId (inbound), providerDeliveryId, eventType, payloadRef (Blob), signatureStatus, status (Pending / Accepted / Delivered / Failed / DeadLettered), attempts, lastAttemptAt, nextAttemptAt, plus standard metadata.
Entities. DeliveryAttempt (per-attempt status code, latency, response excerpt).
Value Objects. PayloadRef, SignatureStatus, HttpResult, Backoff.
Invariants.
- An inbound delivery is Accepted only after signature verification and tenant resolution.
- attempts cannot exceed the resolved RetryPolicy max before moving to DeadLettered.
- A delivery is idempotent on providerDeliveryId (inbound) or deliveryId (outbound).
Domain Events. WebhookDelivered, IntegrationFailed (on rejection or exhausted retries).
Repository. WebhookDeliveryRepository.
Persistence. Azure SQL / PostgreSQL via NHibernate for metadata; raw payload bodies in Azure Blob (payloadRef).
ExternalApiClient¶
Purpose. A versioned, reusable client binding for a provider — the catalogued, governed code asset (e.g. ConnectSoft.Bill.ApiClient) that performs the actual HTTP/SDK calls.
Fields. apiClientId (PK, client- prefix), tenantId (or global), providerId, assemblyName, version (semver), capabilities[], authMode, rateLimitProfile, status (Registered / Active / Deprecated), plus standard metadata.
Entities. ClientOperation (mapped operation → method binding), ClientVersion (semver history).
Value Objects. AssemblyName, SemanticVersion, RateLimitProfile, Capability.
Invariants.
- assemblyName + version is globally unique.
- A client may only declare capabilities its provider supports.
- Deprecating the last Active client of a provider forces the provider to Deprecated.
Domain Events. ExternalApiClientRegistered, ExternalApiClientDeprecated.
Repository. ExternalApiClientRepository.
Persistence. Azure SQL / PostgreSQL via NHibernate. Reusable library identity grounds factory-wide reuse.
IntegrationRun¶
Purpose. The operational record of a single governed outbound operation (open a PR, send an SMS, create a charge), including attempts and outcome.
Fields. runId (PK, run- prefix), tenantId, projectId, connectionId, providerId, operation, requestRef / responseRef (Blob), status (Pending / Running / Completed / Failed), attempts, externalRef, startedAt, completedAt, latencyMs, plus standard metadata.
Entities. RunAttempt (per-attempt status, error class, latency).
Value Objects. Operation, ExternalReference, RetryPolicy, LatencyMeasurement.
Invariants.
- A run executes only against an Active, Healthy (or Degraded-permitted) connection.
- status transitions are monotonic: Pending → Running → (Completed | Failed).
- Each attempt is recorded; attempts never decreases.
Domain Events. IntegrationRunCompleted, IntegrationFailed.
Repository. IntegrationRunRepository.
Persistence. Azure SQL / PostgreSQL via NHibernate; request/response bodies in Azure Blob.
IntegrationFailure¶
Purpose. A first-class record of a failed integration run, delivery, or health probe, with classification driving retry and escalation.
Fields. failureId (PK, fail- prefix), tenantId, runId / deliveryId (source), providerId, category (Transient / RateLimited / Auth / Validation / Poison), errorCode, message, attempt, nextAction (Retry / DeadLetter / Escalate), resolvedAt, plus standard metadata.
Entities. FailureAttempt (history across retries), EscalationRecord.
Value Objects. FailureCategory, ErrorCode, RetryDecision.
Invariants.
- Every failure is classified; Poison failures are never auto-retried.
- A failure is resolved only when its source run/delivery reaches a terminal success or dead-letter state.
- Escalation requires a recorded EscalationRecord for audit.
Domain Events. IntegrationFailed, IntegrationFailureEscalated, IntegrationFailureResolved.
Repository. IntegrationFailureRepository.
Persistence. Azure SQL / PostgreSQL via NHibernate.
Aggregate Relationships¶
flowchart LR
Provider["IntegrationProvider"] --> Client["ExternalApiClient"]
Provider --> Connection["IntegrationConnection"]
Connection --> Credential["IntegrationCredential"]
Connection --> Run["IntegrationRun"]
Run --> Failure["IntegrationFailure"]
Subscription["WebhookSubscription"] --> Delivery["WebhookDelivery"]
Delivery --> Failure