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.
5.7 KiB
Datalaget
Status: Besluttet. Revidert mars 2026 — SpacetimeDB fases ut.
PostgreSQL er eneste datakilde. Sanntid via PG
LISTEN/NOTIFYog 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:
tsvectorpånodes.contentognodes.title - Semantisk søk: pgvector for embedding-basert likhet
- Graftraversering: rekursive CTEs, Apache AGE ved behov
- Statistikk: aggregeringer, tidsserier
- Tilgangsmatrise:
node_accessberegnet 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:
- Nå: PG med nodes/edges-tabeller og CTEs
- Når CTEs blir smertefulle: Legg til AGE
- 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
- Noder er sentrum — tilgangsmatrise beregnet fra edge-grafen, brukes for WebSocket-filtrering
- Universell input og mottak — noder og edges er datamodellen for alle tre primitiver
- Maskinrommet / Portvokteren — CAS-pruning, edge-drevet ressursorkestrering, validering før skriving, WebSocket-endepunkt for sanntid