-- v1.1.4: Extend the triggers framework to recognise `cron` as the -- fourth concrete kind (after `kv` v1.1.1, `dead_letter` v1.1.1, `docs` -- v1.1.2). Mirrors the 0014 docs extension: two CHECK constraints widen -- (strictly gaining `'cron'`), one new detail table. -- -- Cron rows route through the SAME generic dispatcher path as kv/docs/ -- dead_letter (single match-arm extension on the Rust side). The only -- new machinery is a scheduler task that enqueues due cron triggers -- into the outbox; dispatch itself is unchanged. -- Extend triggers.kind to include 'cron'. No existing row carries a -- value outside the widened set, so the drop+add is safe. ALTER TABLE triggers DROP CONSTRAINT triggers_kind_check; ALTER TABLE triggers ADD CONSTRAINT triggers_kind_check CHECK (kind IN ('kv', 'dead_letter', 'docs', 'cron')); -- Extend outbox.source_kind to include 'cron'. v1.1.x's existing -- source_kinds ('http', 'kv', 'dead_letter', 'docs') 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', 'cron')); -- One row per cron trigger. -- schedule — 6-field cron expression (with seconds), validated -- at insert time by the `cron` crate. -- timezone — IANA tz name (e.g. "America/Los_Angeles"), validated -- via chrono-tz. Required so schedules like "every -- weekday at 9am" are unambiguous. Defaults to UTC. -- last_fired_at — set transactionally with each enqueue. NULL until -- the trigger first fires. The scheduler computes the -- next fire time in-process from -- (schedule, timezone, last_fired_at); there is no -- stored next_fire column (kept stateless on purpose). CREATE TABLE cron_trigger_details ( trigger_id UUID PRIMARY KEY REFERENCES triggers(id) ON DELETE CASCADE, schedule TEXT NOT NULL, timezone TEXT NOT NULL DEFAULT 'UTC', last_fired_at TIMESTAMPTZ ); -- Hot lookup for the scheduler: "all enabled cron triggers due now" -- scans by last_fired_at. CREATE INDEX idx_cron_triggers_due ON cron_trigger_details (last_fired_at);