-- v1.1.7: inbound email triggers (email:receive). -- -- A configured provider (Mailgun / Postmark / SendGrid / SES) POSTs -- inbound email to POST /api/v1/email-inbound/{app_id}/{trigger_id}; -- the receiver normalizes it into a TriggerEvent::Email and enqueues an -- outbox row for the trigger's handler. v1.1.7 ships the webhook path; -- a native SMTP listener is v1.3+. -- Widen the trigger-kind + outbox-source CHECK constraints to admit -- 'email'. ALTER TABLE triggers DROP CONSTRAINT triggers_kind_check; ALTER TABLE triggers ADD CONSTRAINT triggers_kind_check CHECK (kind IN ('kv', 'dead_letter', 'docs', 'cron', 'files', 'pubsub', 'email')); ALTER TABLE outbox DROP CONSTRAINT outbox_source_kind_check; ALTER TABLE outbox ADD CONSTRAINT outbox_source_kind_check CHECK (source_kind IN ('http', 'kv', 'dead_letter', 'docs', 'cron', 'files', 'pubsub', 'email')); -- Per-trigger inbound config. The HMAC secret used to verify provider -- signatures is stored ENCRYPTED at rest (AES-256-GCM under the process -- master key) — a deviation from the original brief's plaintext column, -- chosen to keep all operationally-secret material encrypted. The -- receiver decrypts it per inbound request. NULL columns mean the -- trigger has no signature verification (accepts any POST to its URL — -- relies on URL secrecy). CREATE TABLE email_trigger_details ( trigger_id UUID PRIMARY KEY REFERENCES triggers(id) ON DELETE CASCADE, inbound_secret_encrypted BYTEA, -- ciphertext incl. GCM auth tag (NULL = unsigned) inbound_secret_nonce BYTEA -- 12 bytes (NULL = unsigned) );