-- v1.1.2: Extend the triggers framework to recognise `docs` as the -- second concrete kind (after `kv` in v1.1.1). -- -- Two CHECK constraints widen (no narrowing — both lists strictly -- gain `'docs'`); one new detail table mirrors `kv_trigger_details`'s -- shape with `DocsEventOp` ops instead of `KvEventOp`. Dispatcher -- routing is generic across kinds — the same code path that handles -- `Kv | DeadLetter` outbox rows now also handles `Docs` (single match -- arm extension on the Rust side; no migration needed). -- Extend triggers.kind to include 'docs'. Constraint is in-line on the -- column so Postgres auto-named it `triggers_kind_check`. Dropping the -- old and adding the widened constraint is safe — no existing rows -- carry a value outside the new set. ALTER TABLE triggers DROP CONSTRAINT triggers_kind_check; ALTER TABLE triggers ADD CONSTRAINT triggers_kind_check CHECK (kind IN ('kv', 'dead_letter', 'docs')); -- Extend outbox.source_kind to include 'docs'. Same shape as above; -- v1.1.1's existing source_kinds ('http', 'kv', 'dead_letter') stay. 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')); -- One row per docs trigger. Same shape as `kv_trigger_details`: -- collection_glob — "*" matches all, "foo*" prefix-matches, "foo" -- exact-matches (Rust-side via collection_matches). -- ops — subset of {create, update, delete}. Empty array -- means "any op" (matches every docs mutation in -- the collection). The admin endpoint rejects -- empty collection_glob; ops can be empty. CREATE TABLE docs_trigger_details ( trigger_id UUID PRIMARY KEY REFERENCES triggers(id) ON DELETE CASCADE, collection_glob TEXT NOT NULL, ops TEXT[] NOT NULL );