synops/docs/retninger/datalaget.md
vegard aee6adc425 Fjern STDB-skrivestien: all skriving går kun til PG (oppgave 22.3)
SpacetimeDB var brukt som «instant feedback»-lag mellom portvokteren
og frontend. Nå som PG NOTIFY-triggere og WebSocket er på plass
(oppgave 22.1–22.2), er STDB-skrivestien overflødig.

Endringer:
- intentions.rs: Alle CRUD-operasjoner (create/update/delete node/edge)
  skriver nå synkront til PG i stedet for STDB-først + async PG-jobbkø.
  PG NOTIFY-triggere gir umiddelbar sanntidsoppdatering til klienter.
  Tilgangsgivende edges (owner/admin/member_of/reader) bruker transaksjon
  med recompute_access direkte i handleren.
- maintenance.rs: Fjernet StdbClient fra alle funksjoner. Varsler
  opprettes/oppdateres/slettes direkte i PG.
- agent.rs, audio.rs, tts.rs, ai_process.rs: Fjernet STDB-synk etter
  CLI-verktøy-kjøring. PG NOTIFY dekker sanntidsvisning.
- pg_writes.rs: Fjernet sync_node_access_to_stdb. access_changed
  NOTIFY-trigger håndterer dette.
- workspace.rs: Synkrone PG-skrivinger med recompute_access.
- summarize.rs, ai_edges.rs: Fjernet StdbClient fra signaturer.
- jobs.rs: Fjernet StdbClient fra dispatch og start_worker.
- main.rs: Fjernet STDB-initialisering, warmup, stdb_monitor.
  StdbClient fjernet fra AppState. stdb.rs beholdt som død kode
  (fjernes i oppgave 22.4).
- health.rs: Fjernet STDB-helsesjekk fra dashboard.
- Slettet warmup.rs og stdb_monitor.rs (PG→STDB-synk ikke lenger
  relevant).
- docs/retninger/datalaget.md: Markert fase M3 som fullført.
2026-03-18 13:11:33 +00:00

5.7 KiB

Datalaget

Status: Besluttet. Revidert mars 2026 — SpacetimeDB fases ut.

PostgreSQL er eneste datakilde. Sanntid via PG LISTEN/NOTIFY og WebSocket i portvokteren. CAS lagrer binærdata. Apache AGE legges til ved behov for Cypher-traverseringer. SpacetimeDB fases ut — se migrasjonsplan.

Lagmodell

GUI (SvelteKit)
  │ skriv                    │ les (sanntid, WebSocket)
  ▼                          ▼
Portvokteren (Rust)         Portvokteren ──WebSocket──→ GUI
  │ validering                 ▲
  └──→ PostgreSQL ──NOTIFY──→──┘

Skrivestien

GUI → portvokteren → validering → PG. Frontend oppdateres via WebSocket-push utløst av PG NOTIFY.

Lesestien (sanntid)

PG → portvokteren → WebSocket → GUI. Portvokteren holder en in-memory cache av aktive subscriptions og pusher relevante endringer til tilkoblede klienter.

Lesestien (tunge spørringer)

GUI → portvokteren → PG. Fulltekstsøk, pgvector, statistikk, AGE-traverseringer.

PostgreSQL — eneste datakilde

Én sannhetskilde. Ingen synk, ingen konsistensproblemer:

  • Sanntid: LISTEN/NOTIFY → portvokteren → WebSocket
  • Fulltekstsøk: tsvectornodes.content og nodes.title
  • Semantisk søk: pgvector for embedding-basert likhet
  • Graftraversering: rekursive CTEs, Apache AGE ved behov
  • Statistikk: aggregeringer, tidsserier
  • Tilgangsmatrise: node_access beregnet fra edges

Apache AGE — ved behov

De fleste spørringer er grunne (1-3 hopp) og håndteres av CTEs. AGE legges til som PG-extension når Cypher-semantikk faktisk trengs:

  1. Nå: PG med nodes/edges-tabeller og CTEs
  2. Når CTEs blir smertefulle: Legg til AGE
  3. Usannsynlig: Evaluer Neo4j hvis AGE ikke holder

AGE er en extension, ikke en migrering.

CAS — binærlagring

Lyd, bilde, video lagres content-addressable på disk. CAS-noder i grafen bærer metadata (cas_hash, mime, size_bytes). Selve biten lever utenfor PG.

Pruning-regler basert på modalitet, edges og aksessmønstre. Se maskinrommet.

Sanntid via PG LISTEN/NOTIFY

PG har innebygd pub/sub. Portvokteren lytter og videresender:

PG: NOTIFY node_changed, '{"id":"abc","kind":"content"}'
  → Portvokteren mottar
  → Sjekker tilgangsmatrise: hvem skal se denne endringen?
  → Pusher til relevante WebSocket-tilkoblinger
  → Frontend oppdaterer reaktivt

Trigger i PG

CREATE OR REPLACE FUNCTION notify_node_change()
RETURNS trigger AS $$
BEGIN
  PERFORM pg_notify('node_changed',
    json_build_object(
      'op', TG_OP,
      'id', NEW.id,
      'kind', NEW.node_kind
    )::text
  );
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER nodes_notify
  AFTER INSERT OR UPDATE ON nodes
  FOR EACH ROW EXECUTE FUNCTION notify_node_change();

Tilsvarende for edges.

WebSocket i portvokteren

Portvokteren holder:

  • Map av tilkoblede klienter → brukerens node_id
  • Map av node_id → synlige noder (fra node_access)
  • Ved NOTIFY: filtrer på tilgang, push til relevante klienter

Enklere enn STDB-synk: én retning (PG → klient), ingen reducer-logikk, ingen konsistensproblemer.

Hvorfor SpacetimeDB fases ut

SpacetimeDB var et godt eksperiment. Det løste sanntid elegant i prototype-fasen. Men for produksjon på én server:

  • Synk-kompleksitet. PG ↔ STDB synk er en egen feilkategori. Erfaringsdocs (adapter_moenster.md, spacetimedb_integrasjon.md) dokumenterer smerten.
  • Dobbelt vedlikehold. STDB-modul med reducers må holdes i synk med PG-skjema. Endring i nodes-tabellen → to steder.
  • Ekstra SPOF. Enda en tjeneste å overvåke, restarte, debugge.
  • Unødvendig for skalaen. PG LISTEN/NOTIFY + WebSocket gir ~5ms latency. STDB ga ~0.01ms. Forskjellen er umerkelig for brukere.
  • CLI-verktøy forenkles. Bare PG-tilkobling, ingen STDB-klient.

Migrasjonsplan: STDB → PG LISTEN/NOTIFY

Fase M1: WebSocket-lag i portvokteren

Implementert LISTEN/NOTIFY-lytter og WebSocket-endepunkt i portvokteren. PG-triggers for nodes, edges og access. Frontend koblet til begge (STDB + nytt WS) i parallell.

Fase M2: Frontend-migrering

Frontend bruker nå kun portvokterens WebSocket. SpacetimeDB-klient fjernet. Reactive stores oppdateres direkte fra WS-meldinger. Berikede events: portvokteren henter full raddata fra PG etter NOTIFY (ikke bare ID) slik at stores kan oppdateres uten ekstra API-kall. Mixer-kanaler migrert fra STDB til PG-tabell med tilhørende NOTIFY-trigger og HTTP API-endepunkter.

Fase M3: Fjern skrivestien til STDB

Portvokteren skriver kun til PG. STDB-skrivestien er fjernet. Alle intensjoner (create/update/delete node/edge) skriver synkront til PG. NOTIFY-triggere er eneste push-mekanisme. Warmup (PG→STDB) og STDB-monitor er fjernet. StdbClient er fjernet fra AppState. Job-handlere (agent, audio, tts, ai_process) synker ikke lenger til STDB — PG NOTIFY dekker sanntid.

Fase M4: Fjern STDB

  • Stopp SpacetimeDB Docker-container
  • Fjern STDB-modul (spacetimedb/)
  • Fjern STDB-klient fra portvokteren
  • Fjern STDB-avhengigheter fra frontend
  • Fjern synkroniserings-kode
  • Oppdater docs (synkronisering.md → arkiver)
  • Oppdater CLAUDE.md

Fase M5: Opprydding

  • Slett erfaringsdocs som kun gjelder STDB
  • Oppdater alle docs-referanser til STDB
  • Fjern Docker-konfig for SpacetimeDB

Forhold til andre retninger