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>
175 lines
8 KiB
Markdown
175 lines
8 KiB
Markdown
# 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](universell_input.md) — noder og edges
|
|
er den underliggende datamodellen for alle tre primitiver
|
|
- [Maskinrommet](maskinrommet.md) — CAS og pruning lever her, AGE
|
|
brukes for edge-drevet ressursorkestrering
|
|
- [Bruker, ikke workspace](bruker_ikke_workspace.md) — tilgang via
|
|
graf-traversering (AGE) i stedet for workspace-membership-tabeller
|
|
- [Rom, ikke forum](rom_ikke_forum.md) — to-lags-modellen:
|
|
SpacetimeDB for nåtid, PG+AGE for arkiv og graf
|