server/docs/retninger/datalaget.md
vegard 8ca9832248 Legg til ops/ (vedlikeholdsjobber) og docs/retninger/ (arkitektoniske teser)
Ny mappe ops/ med repeterbare vedlikeholdsjobber:
- ryddejobb.md — full prosjektrevisjon
- doc-audit.md — docs vs kode
- drift-sjekk.md — prod vs lokal vs docs

Ny mappe docs/retninger/ med arkitektoniske teser:
- status_quo.md — hva Sidelinja er i dag
- rom_ikke_forum.md — opplevelse-først, to-lags-modell, administrativ opplevelse
- universell_input.md — tre primitiver (input, mottak, kommunikasjon), noder+edges
- maskinrommet.md — Rust-orkestrator, edge-drevet ressursorkestrering, CAS+pruning
- bruker_ikke_workspace.md — brukeren er sentrum, workspaces er samlings-noder
- datalaget.md — PG+Apache AGE, SpacetimeDB som sanntidslag, lagmodell

Oppdatert CLAUDE.md og proposals/README.md med referanser.

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

8 KiB

Datalaget — PG + AGE som enhetlig graf og arkiv

PostgreSQL er den eneste databasen. Apache AGE gir Cypher-semantikk for graftraverseringer. SpacetimeDB er sanntidslaget over samme data. Én database, to tilgangsmønstre, ingen eierskapskonflikt.

Observasjoner

Hele retningsarbeidet har bygget seg mot "alt er noder og edges." Tilgang er edges, visninger er spørringer, administrasjon er traversering. Spørsmålet er: hvilken teknologi støtter dette best?

Neo4j ble vurdert og forkastet

Neo4j er best-in-class for dype graftraverseringer, men for dette prosjektet gir den mer problemer enn den løser:

  • Tredje database. PG + SpacetimeDB + Neo4j = tre systemer å drifte, sikkerhetskopiere og overvåke. På én Hetzner VPS.
  • Mister PG-økosystemet. pgvector (semantisk søk), fulltekstsøk, JSONB, pg_cron, statistikk-aggregeringer — alt dette trenger vi uansett, og det lever i PG. Med Neo4j trenger vi PG i tillegg.
  • Minnehungrig. Neo4j anbefaler 8-16GB heap. På en delt VPS med PG, SpacetimeDB, Whisper og LiteLLM er det for mye.
  • Lisens. Community er AGPLv3. Enterprise-features (clustering, avansert sikkerhet) krever betalt lisens.

Apache AGE — Cypher i PG

Apache AGE er en PG-extension som legger til openCypher-støtte. Noder og edges lagres i PG-tabeller, men spørres med Cypher-semantikk.

Oppsider:

  • Én database. Ingen ny infrastruktur. Samme backup, connection pooling, tooling, monitoring.
  • SQL + Cypher i samme spørring. "Finn alle noder brukeren har tilgang til via team-traversering, JOINet med fulltekstsøk og pgvector." Det kan du ikke gjøre med en separat grafdatabase.
  • Null migrasjonskostnad. Eksisterende nodes/edges-tabeller kan eksponeres som graf. Legg til extension, ikke bytt database.
  • Økosystemet bevares. pgvector, fulltekstsøk, JSONB, pg_cron — alt fungerer side om side med Cypher-spørringer.
  • Produksjonsbruk. Azure og EDB tilbyr AGE som managed extension.

Nedsider:

  • Ikke native graf. Under panseret er det PG-tabeller. For svært dype traverseringer (10+ hopp over millioner av noder) er Neo4j raskere. Men de fleste spørringene våre er 1-5 hopp.
  • Yngre prosjekt. Mindre community, tynnere dokumentasjon enn Neo4j.
  • Quirks. Spørringer må være enten read-only eller write-only (WITH-clause for overgang). Noen pg_upgrade-begrensninger.

Beslutning

PostgreSQL + Apache AGE som enhetlig datalager for noder og edges.

De fleste spørringer i dette systemet er grunne:

  • "Vis noder med edge til denne brukeren" — 1 hopp
  • "Sjekk tilgang via team" — 2 hopp
  • "Finn alle kommunikasjonsnoder brukeren har tilgang til" — 2-3 hopp
  • "Traverser kunnskapsgrafen mellom to emner" — 3-5 hopp

AGE håndterer dette. Skulle det vise seg at dypere traverseringer blir en flaskehals i praksis, kan Neo4j evalueres da — men med én VPS og realistiske datamengder er det usannsynlig.

Lagmodell

┌─────────────────────────────────────┐
│  GUI (SvelteKit)                     │
│  Primitiver, visninger               │
└────────┬──────────────────┬─────────┘
         │ skriv            │ les (sanntid)
         │                  │ direkte WebSocket
┌────────▼────────┐  ┌─────▼─────────┐
│  Maskinrommet    │  │  SpacetimeDB  │──┐
│  (Rust)          │  │  (STDB)       │  │
│  Orkestrering    │  └───────────────┘  │
└──┬─────┬─────┬──┘                      │
   │     │     │         sync ↕          │
   ▼     ▼     ▼                         │
┌─────┐┌─────┐┌─────┐┌─────────────┐   │
│ PG  ││STDB ││ CAS ││ Whisper,    │   │
│+AGE ││(skr)││     ││ LiteLLM,   │   │
│     ││     ││     ││ LiveKit ... │   │
└─────┘└─────┘└─────┘└─────────────┘   │

Skriv vs les — to stier med god grunn

Skriv: GUI → Maskinrommet (Rust) → tjenester (PG, STDB, CAS, ...)

All orkestrering, edge-logikk, ressursallokering og validering går gjennom Rust. Maskinrommet bestemmer hva som skjer: hva som skrives til PG, hva som speiles til SpacetimeDB, hva som lagres i CAS, hvilke tjenester som trigges.

Les (sanntid): SpacetimeDB → GUI (direkte WebSocket)

SpacetimeDB sitt klient-SDK kobler seg direkte via WebSocket, definerer SQL-subscriptions, og synkroniserer automatisk med lokal cache — uten network round-trips for lesing (~10μs per transaksjon). Å proxy dette gjennom Rust ville lagt til et hopp, serialisering og kontekstbytte — en dårligere reimplementering av noe STDB gjør optimalt. Den direkte lese-stien er en bevisst arkitekturbeslutning, ikke et hull i lagmodellen.

Les (tradisjonelt): GUI → Maskinrommet (Rust) → PG

Søk, historikk, statistikk, arkiv — alt som ikke er sanntid går gjennom Rust og PG. AGE-spørringer for graftraversering, pgvector for semantisk søk, SQL for aggregeringer.

PG er arkivet og grafen

Alle noder og edges lever i PG. AGE gir Cypher-spørringer for traversering. Standard SQL for alt annet (aggregeringer, fulltekstsøk, JOINs mot pgvector). Én database, to spørrespråk som utfyller hverandre.

SpacetimeDB er sanntidslaget

Aktive noder og edges speilet til SpacetimeDB for live-oppdateringer. Ting som er "nå" lever i SpacetimeDB. Ting som er "ferdig" lever kun i PG. Ingen eierskapskonflikt — SpacetimeDB er en live-visning av en delmengde av PG-grafen.

CAS er binærlageret

Lyd, bilde, video lagres content-addressable utenfor PG. Noder i PG peker på CAS-hasher. Pruning-regler basert på edges, aksesslog og modalitet (se maskinrommet).

Migreringsstrategi

Fase 1: AGE på eksisterende PG

Installer Apache AGE extension. Eksponer eksisterende nodes/edges- tabeller som graf. Ingen endring for resten av systemet — bare en ny måte å spørre på.

Fase 2: Konsolider til node+edge-modellen

Migrer meldingsboks, kanban, kalender etc. til den universelle node+edge-modellen gradvis. Gamle tabeller kan leve som views over grafen i overgangsperioden.

Fase 3: Parallell prototype

Det gamle systemet kjører uforstyrret. En ny frontend-prototype bygges ved siden av som bruker AGE-grafen direkte. Live sync fra gammelt til nytt via enveis oppdateringer. Testbrukere leker i det nye, produksjon er trygt i det gamle.

Fase 4: Cutover

Når det nye er godt nok, flyttes trafikk over. Det gamle systemet kan kjøre som read-only fallback en periode.

Spenninger og åpne spørsmål

  • AGE-modenhet. Prosjektet er aktivt og støttet av Azure/EDB, men community er mindre enn Neo4j. Risikoen er håndterbar fordi dataene alltid er PG-tabeller — AGE er bare et spørrelag.
  • SpacetimeDB-synk. Hvordan synkes noder/edges mellom PG (AGE) og SpacetimeDB effektivt? Trenger en sync-mekanisme som forstår "aktiv delmengde."
  • Skjemadesign. Én node-tabell med alle typer innhold — hva er felles kolonner vs edge-metadata vs JSONB-payload? Trenger gjennomtenkt skjema som balanserer fleksibilitet og spørrbarhet.

Forhold til andre retninger

  • Universell input og mottak — noder og edges er den underliggende datamodellen for alle tre primitiver
  • Maskinrommet — CAS og pruning lever her, AGE brukes for edge-drevet ressursorkestrering
  • Bruker, ikke workspace — tilgang via graf-traversering (AGE) i stedet for workspace-membership-tabeller
  • Rom, ikke forum — to-lags-modellen: SpacetimeDB for nåtid, PG+AGE for arkiv og graf