# 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** som enhetlig datalager for noder og edges. **Apache AGE** som planlagt utvidelse — ikke forpliktet fra dag én. 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 PG med rekursive CTEs håndterer 1-3 hopp utmerket. AGE legges til når graftraversering faktisk blir en målbar flaskehals — ikke før. AGE er en extension, ikke en migrering, så den kan boltes på uten å endre eksisterende kode. Pragmatisk rekkefølge: 1. **Nå:** PG med nodes/edges-tabeller og CTEs 2. **Når CTEs blir smertefulle:** Legg til AGE for Cypher-spørringer 3. **Usannsynlig:** Evaluer Neo4j hvis AGE ikke holder ## 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