feat(t-paliad-184): mig 086 — event_deadlines read-only trigger
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.
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
-- t-paliad-184 down — reverts the read-only wrapper from
|
||||
-- 086_event_deadlines_readonly.up.sql. Order: trigger → function.
|
||||
|
||||
DROP TRIGGER IF EXISTS event_deadlines_readonly ON paliad.event_deadlines;
|
||||
DROP FUNCTION IF EXISTS paliad.event_deadlines_readonly_trigger();
|
||||
58
internal/db/migrations/086_event_deadlines_readonly.up.sql
Normal file
58
internal/db/migrations/086_event_deadlines_readonly.up.sql
Normal file
@@ -0,0 +1,58 @@
|
||||
-- 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.';
|
||||
Reference in New Issue
Block a user