# Integration -- Interfaces **Module:** Integration (Cross-cutting) **Tables:** 2 --- ## Provided Interfaces ### Structural: NONE Neither `webhook_events` nor `integration_outbox` is referenced by foreign key from any table in any module. No other module has a structural dependency on the integration module. ### Behavioral While no structural interfaces exist, the integration module provides two behavioral interfaces that other modules consume at runtime: #### webhook_events: Sync Pipeline Entry Point The `webhook_events` table is the entry point for the inbound sync pipeline that populates projection tables across the system. Under the Stripe strategy (Decision 90), Category B billing tables -- `subscriptions`, `subscription_items`, `subscription_changes`, `invoices`, `invoice_line_items`, `payments`, `payment_methods`, `refunds`, `disputes`, `products`, `prices`, `coupons`, `promotion_codes`, `discounts` -- are populated via webhook events processed by Temporal workflows. **Behavioral consumers:** | Module | Relationship | Notes | |--------|-------------|-------| | **billing** | Primary consumer. Webhook events drive the sync pipeline that populates Category B projection tables. Temporal workflows read from `webhook_events`, transform provider objects, and write to core billing tables. | This is the highest-volume behavioral interface in the system. | | **entitlements** | Future consumer. Infrastructure provisioning callbacks (e.g., Nextcloud reporting instance creation complete) arrive as webhook events and update `resource_provisions` state. | Not yet active; depends on infrastructure provider integration. | #### integration_outbox: Outbound Event Relay The `integration_outbox` captures domain state changes from any module that require external action. Any module may write to the outbox within its domain transactions. **Behavioral consumers:** | Module | Relationship | Notes | |--------|-------------|-------| | **All modules** | Any module may INSERT into `integration_outbox` within its domain transaction to trigger external actions. The outbox is a general-purpose relay, not scoped to a specific module. | Examples: billing writes outbox entries for Stripe product sync; entitlements writes entries for Nextcloud provisioning; organization could write entries for notification delivery. | --- ## Consumed Interfaces ### Structural: NONE Neither `webhook_events` nor `integration_outbox` contains a foreign key reference to any table in any module. Both tables use text fields for entity identification: - `webhook_events.provider` and `webhook_events.provider_event_id` are text fields identifying the source provider and its event identifier. - `integration_outbox.aggregate_type` and `integration_outbox.aggregate_id` are a text discriminator and UUID identifying the originating domain entity, with no FK constraint. - `integration_outbox.target_provider` is a text field identifying the destination provider. This text-based identification follows the same rationale as the audit log's bare polymorphic association on entity references (Decision 23): these tables must accept references to any entity type in the system, and FK constraints would be structurally impractical. --- ## Interface Contracts ### Idempotency Guarantee The `UNIQUE(provider, provider_event_id)` constraint on `webhook_events` guarantees that duplicate webhook deliveries are detected at insert time. Consumers of the sync pipeline can rely on this invariant: a given provider event will appear at most once in the table. The webhook endpoint returns HTTP 200 on constraint violation, signaling to the provider that the event was already received. ### At-Least-Once Delivery Semantics The `integration_outbox` guarantees at-least-once delivery for outbound integration actions. Because the outbox INSERT occurs in the same transaction as the domain state change, any committed domain change will have a corresponding outbox entry. The background polling worker may deliver the same event more than once (e.g., if it crashes after executing the external action but before marking the entry `completed`). Provider handlers must be idempotent. ### Payload PII-Free Invariant Both `webhook_events.payload` and `integration_outbox.payload` are governed by the JSONB Governance Policy (Decision 34): PII is categorically prohibited in all JSONB columns. Webhook payloads containing PII must be scrubbed before storage; outbox payloads must be composed without PII. This invariant enables the integration tables to participate in retention and archival policies without triggering GDPR anonymization obligations. ### Isolation Guarantee The integration module imposes no structural constraints on any other module. No module need consult the integration tables to answer a domain question. The self-sufficiency principle (applied via Decision 87 and the five boundary heuristics) ensures that every business-answerable concept has a domain module representation. The integration module's coupling to other modules is entirely behavioral and unidirectional at the schema level.