# Synkronisering: SpacetimeDB ↔ PostgreSQL > **UTGÅTT (mars 2026).** SpacetimeDB er fjernet fra prosjektet. > Sanntid leveres nå via PG LISTEN/NOTIFY + WebSocket i portvokteren. > Se `docs/infra/api_grensesnitt.md` for gjeldende arkitektur. > Dokumentet beholdes som historisk referanse. ## Konsept SpacetimeDB holder hele grafen (alle noder og edges) i minne. PostgreSQL er persistent backup og arkiv. Skriving går til begge. Lesing går fra SpacetimeDB. ``` GUI (SvelteKit) │ skriv │ les (sanntid) ▼ ▼ Maskinrommet (Rust) SpacetimeDB ──→ GUI │ ▲ ├──→ PostgreSQL (persistent) │ └──→ SpacetimeDB ───────────┘ ``` ## Hvorfor hele grafen i SpacetimeDB Node- og edge-skjemaet er minimalt: åtte kolonner på nodes, åtte på edges. For en liten brukerbase er hele grafen triviell å holde i minne. Dette forenkler alt: - Ingen sync-logikk for å bestemme hva som er "aktivt" - Ingen henting fra PG når noen åpner noe gammelt - Frontend har alltid alt tilgjengelig via WebSocket - Én lesekilde — ingen tvetydighet Når dette *blir* problematisk (hundretusenvis av noder, minnepress), innføres eviction basert på aksessmønstre. Men det er en optimaliseringsbeslutning, ikke en arkitekturbeslutning. Modellen endres ikke. ## Skrivestien Maskinrommet validerer, så skriver i to steg: 1. **Validering** — tilgangssjekk, unique-constraints, forretningsregler 2. **SpacetimeDB først** — frontend oppdateres umiddelbart (~10μs) 3. **PG asynkront** — persistent backup i bakgrunnen Frontend er allerede oppdatert mens PG-skrivingen skjer. Brukeren merker ingenting. Hvis PG-skrivingen feiler: maskinrommet logger og prøver igjen. SpacetimeDB har dataen — den er bare ikke persistert ennå. Ingen datatap så lenge SpacetimeDB kjører. ## Lesestien Frontend leser **kun fra SpacetimeDB** via WebSocket-subscriptions. Ingen PG-kall fra frontend for data som vises i sanntid. Unntak: tunge spørringer som ikke passer sanntidslaget — statistikk, fulltekstsøk, pgvector-søk, AGE-traverseringer. Disse går GUI → Maskinrommet → PG. ## Oppvarming (PG → SpacetimeDB) Ved oppstart av SpacetimeDB laster maskinrommet hele grafen fra PG: 1. Alle noder 2. Alle edges 3. `node_access`-matrisen Rekkefølge: noder først (edges refererer til noder). CAS-noder lastes uten binærinnhold (bare metadata). ## Feilhåndtering | Scenario | Konsekvens | Håndtering | |----------|-----------|------------| | SpacetimeDB krasjer | Sanntid forsvinner, upersistert data kan tapes | Restart + oppvarming fra PG. Tap begrenset til skrivinger som ikke rakk PG. | | PG nede | Persistering stopper | SpacetimeDB serverer lesing og mottar skrivinger. PG-backlog tas igjen ved recovery. | | Maskinrommet krasjer | Ingen skriving | Frontend ser siste state. Restart plukker opp. | ## SpacetimeDB som utbyttbar SpacetimeDB er en sanntidscache, ikke en avhengighet. Hvis den fjernes fra stacken: - **Sanntid:** PG `LISTEN/NOTIFY` → SvelteKit SSE - **Skriving:** Maskinrommet → PG direkte - **Lesing:** Maskinrommet → PG → GUI Denne fallbacken trenger ikke implementeres, men arkitekturen skal aldri gjøre den umulig. ## Tilgangsmatrise i SpacetimeDB `node_access`-matrisen lastes inn i SpacetimeDB ved oppvarming. Når maskinrommet oppdaterer matrisen i PG (ved edge-endring), oppdaterer den også SpacetimeDB. SpacetimeDB-modulen bruker matrisen for å filtrere subscriptions — klienter ser kun noder de har tilgang til. ## Konflikthåndtering SpacetimeDB er single-threaded per modul — reducer-funksjoner serialiseres automatisk. Ingen klassiske race conditions. Samtidig redigering (to brukere endrer samme node): maskinrommet serialiserer via SpacetimeDB. Last-write-wins. SpacetimeDB kringkaster resultatet til alle klienter. PG oppdateres asynkront med det endelige resultatet.