Phase 3 Slice 3 cutover-window guard. BEFORE INSERT/UPDATE/DELETE trigger on paliad.event_deadlines raises EXCEPTION with a message pointing the writer at paliad.deadline_rules. SELECT remains unaffected. Why: Slice 3 just moved 77 rows into the unified backend (mig 085). Until Slice 4 cuts every reader over and Slice 9 drops the legacy table, the two sides must not diverge. Letting any write through event_deadlines would silently regress "Was kommt nach…" parity. Supabase service_role bypasses RLS but NOT triggers — direct DB maintenance (psql, migration scripts, MCP) is also blocked. That's intentional: every further edit to event_deadlines pre-Slice-9 is a mistake. Slice 9's mig ~090 will drop the table + this trigger together as part of the legacy cleanup. Function is plain (not SECURITY DEFINER): the trigger function only RAISE EXCEPTIONs, no INSERTs anywhere, so it doesn't need elevated privileges. Caller's RLS / role context doesn't matter — the raise fires unconditionally before any tuple lock is taken.
59 lines
2.6 KiB
PL/PgSQL
59 lines
2.6 KiB
PL/PgSQL
-- t-paliad-184 / Fristen Phase 3 Slice 3 — wrap paliad.event_deadlines
|
|
-- in a read-only trigger so nobody can edit either side mid-cutover.
|
|
--
|
|
-- Slice 3 just moved 77 rows from event_deadlines → deadline_rules (mig
|
|
-- 085). Until Slice 4 cuts every reader over and Slice 9 drops the
|
|
-- legacy table, event_deadlines stays in place as the audit anchor and
|
|
-- (briefly) a compat-read source. We must not let any writer mutate it
|
|
-- behind the unified backend's back — diverging the two sides would
|
|
-- silently regress "Was kommt nach…" parity.
|
|
--
|
|
-- The trigger fires AFTER INSERT / UPDATE / DELETE and raises an
|
|
-- EXCEPTION with a clear message pointing the writer at the unified
|
|
-- table. SELECT is unaffected — the legacy EventDeadlineService's
|
|
-- pre-Slice-3 SELECT path keeps working until Slice 4 swaps it.
|
|
--
|
|
-- The supabase service_role bypasses RLS but NOT triggers — so
|
|
-- direct DB maintenance (psql, migration scripts) is also blocked.
|
|
-- This is intentional: any further edit to event_deadlines is a
|
|
-- mistake until Slice 9 drops the table.
|
|
--
|
|
-- Removed by Slice 9 (Step E, mig ~090) when paliad.event_deadlines is
|
|
-- dropped. Until then the trigger is the only thing keeping the two
|
|
-- tables in sync.
|
|
|
|
CREATE OR REPLACE FUNCTION paliad.event_deadlines_readonly_trigger()
|
|
RETURNS trigger
|
|
LANGUAGE plpgsql
|
|
AS $$
|
|
BEGIN
|
|
RAISE EXCEPTION
|
|
'paliad.event_deadlines is read-only after Phase 3 Slice 3 — '
|
|
'writes must go through paliad.deadline_rules (Pipeline C is '
|
|
'unified; the source table is preserved as an audit anchor '
|
|
'until Slice 9 drops it). Operation: %', TG_OP;
|
|
END;
|
|
$$;
|
|
|
|
COMMENT ON FUNCTION paliad.event_deadlines_readonly_trigger() IS
|
|
'BEFORE INSERT/UPDATE/DELETE trigger function that raises on any '
|
|
'write to paliad.event_deadlines. Lives only between Slice 3 and '
|
|
'Slice 9 — removed when the source table is dropped.';
|
|
|
|
-- BEFORE-trigger so the write is blocked before any row image is
|
|
-- captured. AFTER would still raise but the surrounding tx would
|
|
-- have already taken row locks.
|
|
DROP TRIGGER IF EXISTS event_deadlines_readonly ON paliad.event_deadlines;
|
|
|
|
CREATE TRIGGER event_deadlines_readonly
|
|
BEFORE INSERT OR UPDATE OR DELETE ON paliad.event_deadlines
|
|
FOR EACH ROW
|
|
EXECUTE FUNCTION paliad.event_deadlines_readonly_trigger();
|
|
|
|
-- Defensive INSERT-row-level trigger covers the COPY path too; same
|
|
-- function, identical behaviour.
|
|
|
|
COMMENT ON TRIGGER event_deadlines_readonly ON paliad.event_deadlines IS
|
|
'Phase 3 Slice 3 read-only wrapper. Blocks every INSERT/UPDATE/DELETE '
|
|
'until Slice 9 drops the table. SELECT unaffected.';
|