synops/migrations/018_pg_notify_triggers.sql
vegard 0ecb7104c0 WebSocket-lag i portvokteren: PG LISTEN/NOTIFY + WS-endepunkt (oppgave 22.1)
Implementerer Fase M1 av SpacetimeDB-migrasjonen:

- SQL-migrasjon 018: Triggers for notify_node_change, notify_edge_change
  og notify_access_change på nodes, edges og node_access-tabellene
- Ny ws.rs-modul i maskinrommet med:
  - PG LISTEN bakgrunnsoppgave som lytter på tre kanaler
  - Broadcast-kanal for å videresende events til alle WS-klienter
  - WebSocket-endepunkt (/ws) med JWT-autentisering
  - Initiell snapshot (initial_sync) ved tilkobling
  - Tilgangskontrollfiltrering per klient via node_access-matrisen
- Oppdatert AppState med WsBroadcast og /ws-rute

Frontend dual-tilkobling (STDB + nytt WS) kommer i neste commit.
2026-03-18 11:54:34 +00:00

110 lines
3 KiB
PL/PgSQL

-- 018_pg_notify_triggers.sql
-- PG LISTEN/NOTIFY triggers for sanntid: nodes, edges og node_access.
--
-- Portvokteren (maskinrommet) lytter på disse kanalene og videresender
-- endringer via WebSocket til tilkoblede klienter.
-- Ref: docs/retninger/datalaget.md (Fase M1)
BEGIN;
-- =============================================================================
-- notify_node_change: Sender NOTIFY ved INSERT, UPDATE eller DELETE på nodes.
-- Payload er JSON med operasjon, node-ID og node_kind.
-- =============================================================================
CREATE OR REPLACE FUNCTION notify_node_change()
RETURNS trigger AS $$
DECLARE
payload json;
target_row nodes%ROWTYPE;
BEGIN
IF TG_OP = 'DELETE' THEN
target_row := OLD;
ELSE
target_row := NEW;
END IF;
payload := json_build_object(
'op', TG_OP,
'id', target_row.id,
'kind', target_row.node_kind
);
PERFORM pg_notify('node_changed', payload::text);
RETURN target_row;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER nodes_notify
AFTER INSERT OR UPDATE OR DELETE ON nodes
FOR EACH ROW EXECUTE FUNCTION notify_node_change();
-- =============================================================================
-- notify_edge_change: Sender NOTIFY ved INSERT, UPDATE eller DELETE på edges.
-- Payload er JSON med operasjon, edge-ID, source, target og type.
-- =============================================================================
CREATE OR REPLACE FUNCTION notify_edge_change()
RETURNS trigger AS $$
DECLARE
payload json;
target_row edges%ROWTYPE;
BEGIN
IF TG_OP = 'DELETE' THEN
target_row := OLD;
ELSE
target_row := NEW;
END IF;
payload := json_build_object(
'op', TG_OP,
'id', target_row.id,
'source_id', target_row.source_id,
'target_id', target_row.target_id,
'edge_type', target_row.edge_type
);
PERFORM pg_notify('edge_changed', payload::text);
RETURN target_row;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER edges_notify
AFTER INSERT OR UPDATE OR DELETE ON edges
FOR EACH ROW EXECUTE FUNCTION notify_edge_change();
-- =============================================================================
-- notify_access_change: Sender NOTIFY ved endringer i node_access.
-- Brukes av portvokteren for å oppdatere klientenes tilgangsmatrise.
-- =============================================================================
CREATE OR REPLACE FUNCTION notify_access_change()
RETURNS trigger AS $$
DECLARE
payload json;
BEGIN
IF TG_OP = 'DELETE' THEN
payload := json_build_object(
'op', TG_OP,
'subject_id', OLD.subject_id,
'object_id', OLD.object_id
);
ELSE
payload := json_build_object(
'op', TG_OP,
'subject_id', NEW.subject_id,
'object_id', NEW.object_id,
'access', NEW.access
);
END IF;
PERFORM pg_notify('access_changed', payload::text);
RETURN COALESCE(NEW, OLD);
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER node_access_notify
AFTER INSERT OR UPDATE OR DELETE ON node_access
FOR EACH ROW EXECUTE FUNCTION notify_access_change();
COMMIT;