synops/docs/infra/synkronisering.md
vegard 00bf5d27ce Arkitekturbeslutninger: noder er sentrum, edges definerer alt
Grunnleggende arkitekturbeslutninger tatt og dokumentert:

- Alt er noder (brukere, team, innhold, mediefiler, samlings-noder)
- Edges definerer hva en node er (freeform typer, metadata i JSONB)
- Materialisert tilgangsmatrise (node_access) erstatter workspace-RLS
- Visibility (hidden/discoverable/readable/open) på noder
- Aliaser via usynlige system-edges
- Maskinrommet eier all skriving (SpacetimeDB først, PG asynk)
- SpacetimeDB holder hele grafen, PG er persistent backup
- Node- og edge-skjema spesifisert (docs/primitiver/)

Fjernet workspace-konseptet fra hele dokumentasjonen (~40 filer).
Fem retninger besluttet, én åpen (rom, ikke forum).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 10:29:54 +01:00

3.6 KiB

Synkronisering: SpacetimeDB ↔ PostgreSQL

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.