ADR-0004: Webhook ingestion and provider apps ​
Status: accepted (2026-10-12); the enqueue path is superseded by ADR-0005, system access by ADR-0006
Decision ​
- A provider app (e.g. a GitHub App: App ID, private key, webhook secret, client secret) belongs to the deployment, not to a tenant. It is stored in the system-only table
provider_apps. Credentials are one JSON document encrypted with@quavon/crypto(AES-256-GCM envelope, per-record data key wrapped byQUAVON_ENCRYPTION_KEY), bound to the contextprovider_apps:<id>. provider_apps.default_tenant_idassigns new installations to a tenant. Self-hosted installs set it during setup. Installations of an app without a default tenant are recorded as ignored deliveries until tenant claiming exists.- Webhook deliveries arrive before the tenant is known, so
webhook_deliveriesis system-only. System-only tables have RLS forced with no policy and no grants forquavon_app; onlywithSystemcan read or write them. - The API verifies the HMAC over the raw body using the webhook secret of the app identified by
X-GitHub-Hook-Installation-Target-ID, inserts the delivery (unique per provider and delivery id), enqueuesingestwith job idgithub_<delivery>_<attempt>and returns 202. A duplicate delivery returns 200 without enqueueing, unless the stored delivery failed, in which caseattemptsis incremented and a new job is enqueued. - Queue payloads carry ids only. Webhook bodies live in
webhook_deliveries.payloadwith limited retention; downstream handlers re-fetch current state from the provider instead of trusting event order. - BullMQ job ids must not contain
:; ids are built withjobId()from@quavon/shared-types. - Trace context travels with every job envelope (
trace), so one trace spans webhook, queue and worker. - Setup uses one-time setup tokens (
setup_tokens, stored hashed). The GitHub manifeststateis bound to the setup session and expires with the one-hour manifest code window.
Consequences ​
- The API needs the system database connection (
DATABASE_SYSTEM_URL) for webhook ingestion and setup, and must use it only on those routes. - Multi-tenant SaaS installation claiming is handled by the hosted edition (ADR-0015).