-- §4.5 M5: STATEFUL group trigger templates (cron / queue / email) via
-- per-descendant MATERIALIZATION.
--
-- The event kinds (kv/docs/files/pubsub) resolve a group template LIVE at
-- dispatch via the chain CTE — no per-app rows. The stateful kinds can't:
--   * cron  needs a per-app `last_fired_at` the scheduler advances;
--   * queue needs the one-consumer-per-(app_id, queue_name) advisory lock;
--   * email needs a per-app SEALED inbound secret.
-- So a group stateful template is instead MATERIALIZED into an app-owned
-- trigger row per descendant app (created/removed as the tree changes), and the
-- unchanged dispatch paths (scheduler, queue consumer, email webhook) only ever
-- see app-owned rows.
--
-- `materialized_from` links a managed app-owned row back to the group template
-- it was expanded from: NULL = a hand-authored trigger; set = a reconciler-owned
-- copy (dropped + re-created as descendants come and go). ON DELETE CASCADE so
-- deleting the group template (RESTRICT-guarded elsewhere) or the group cleans
-- up the copies; a plain app delete CASCADEs the row away via `triggers.app_id`.

ALTER TABLE triggers
    ADD COLUMN materialized_from UUID REFERENCES triggers(id) ON DELETE CASCADE;

-- The reconciler looks up existing copies by their source template.
CREATE INDEX idx_triggers_materialized_from
    ON triggers (materialized_from) WHERE materialized_from IS NOT NULL;
