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.
172 lines
5.7 KiB
Markdown
172 lines
5.7 KiB
Markdown
# 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:** `tsvector` på `nodes.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](maskinrommet.md).
|
|
|
|
## 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
|
|
|
|
```sql
|
|
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](bruker_ikke_workspace.md) — tilgangsmatrise
|
|
beregnet fra edge-grafen, brukes for WebSocket-filtrering
|
|
- [Universell input og mottak](universell_input.md) — noder og edges
|
|
er datamodellen for alle tre primitiver
|
|
- [Maskinrommet / Portvokteren](maskinrommet.md) — CAS-pruning,
|
|
edge-drevet ressursorkestrering, validering før skriving,
|
|
WebSocket-endepunkt for sanntid
|