Innarbeid ekstern review: RLS-siloer, AGE-pragmatisme, compute-separasjon

- bruker_ikke_workspace: RLS-advarsel tatt på alvor — samlings-noder er
  harde sikkerhetsiloer under panseret, edge-basert tilgang er UX-lag
  innenfor siloene
- datalaget: AGE moderert fra "beslutning" til "planlagt utvidelse" —
  start med CTEs, legg til AGE når det faktisk trengs
- maskinrommet: compute-separasjon dokumentert — tunge workers kan
  flyttes til egen node, maskinrommet ruter transparent

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
vegard 2026-03-17 05:04:09 +01:00
parent 6ec430141b
commit c5de6086ca
3 changed files with 63 additions and 8 deletions

View file

@ -102,20 +102,47 @@ Ingen "slett bruker fra workspace." Fjern deltaker-edges. Brukerens
private noder som hadde edge til samlings-noden beholder den edgen private noder som hadde edge til samlings-noden beholder den edgen
(det er brukerens innhold), men de mister tilgang til andres noder. (det er brukerens innhold), men de mister tilgang til andres noder.
## RLS og sikkerhet: samlings-noder som harde siloer
Viktig arkitekturbeslutning: **"bruker, ikke workspace" er en
UX-modell, ikke en sikkerhetsmodell.**
Ren edge-basert tilgangskontroll — der hver lesing traverserer grafen
for å sjekke om brukeren har en sti til noden — ville kvelt
databasen når grafen vokser. I dag har PG bunnsolid RLS med
`workspace_id = current_setting(...)` — instant og vanntett.
Løsningen er å skille UX fra sikkerhet:
- **UX-laget:** Brukeren ser sine edges. Ingen "velg workspace."
Filtrering etter samlings-node er frivillig.
- **Sikkerhetslaget:** Under panseret har hver node fortsatt en
`workspace_id` (eller samlings-node-id) som RLS sjekker. Det er
den harde sikkerhetsgensen — billig, velprøvd, instant.
- **Finere tilgang innenfor siloen:** Edge-basert tilgang (eier,
admin, deltaker, leser) sjekkes *innenfor* en silo, ikke som
erstatning for den.
Samlings-noder er altså ikke bare frivillig organisering — de er
sikkerhetsiloer i databasen. Brukeren merker det ikke, men PG
trenger det.
## Spenninger og åpne spørsmål ## Spenninger og åpne spørsmål
- **Overblikk.** Uten workspaces som organisatorisk enhet — hvordan - **Overblikk.** Uten workspaces som organisatorisk enhet — hvordan
unngår du at alt flyter sammen? Samlings-noder er svaret, men de unngår du at alt flyter sammen? Samlings-noder er svaret, men de
må være intuitive å opprette og bruke uten å bli "workspaces med må være intuitive å opprette og bruke uten å bli "workspaces med
ny navn." ny navn."
- **Tilgangskontroll i praksis.** Edge-basert tilgang er fleksibelt, - **Kryssgående noder og siloer.** Hvis noder har `workspace_id` for
men kan det bli uoversiktlig? "Hvem har tilgang til hva" må være RLS, kan en node da tilhøre to samlings-noder? Kanskje via en
lett å besvare. Kanskje samlings-noden gir en naturlig audit-visning. "primær silo" for RLS + sekundære edges for visning. Trenger
gjennomtenkt design.
- **Arv og konflikter.** En node med edge til to samlings-noder med - **Arv og konflikter.** En node med edge til to samlings-noder med
ulike pruning-profiler — hva vinner? Trenger klare regler som er ulike pruning-profiler — hva vinner? Trenger klare regler som er
intuitive for brukeren. intuitive for brukeren.
- **Migrering.** Eksisterende workspace-modell har innhold. Kan - **Migrering.** Eksisterende workspace-modell har innhold. Kan
workspaces bli samlings-noder gradvis? workspaces bli samlings-noder gradvis? RLS-modellen gjør dette
enklere — workspace_id kan bli samlings-node-id uten endring i
sikkerhetslogikk.
## Forhold til andre retninger ## Forhold til andre retninger

View file

@ -52,7 +52,8 @@ og edges lagres i PG-tabeller, men spørres med Cypher-semantikk.
## Beslutning ## Beslutning
**PostgreSQL + Apache AGE** som enhetlig datalager for noder og edges. **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: De fleste spørringer i dette systemet er grunne:
- "Vis noder med edge til denne brukeren" — 1 hopp - "Vis noder med edge til denne brukeren" — 1 hopp
@ -60,9 +61,15 @@ De fleste spørringer i dette systemet er grunne:
- "Finn alle kommunikasjonsnoder brukeren har tilgang til" — 2-3 hopp - "Finn alle kommunikasjonsnoder brukeren har tilgang til" — 2-3 hopp
- "Traverser kunnskapsgrafen mellom to emner" — 3-5 hopp - "Traverser kunnskapsgrafen mellom to emner" — 3-5 hopp
AGE håndterer dette. Skulle det vise seg at dypere traverseringer PG med rekursive CTEs håndterer 1-3 hopp utmerket. AGE legges til
blir en flaskehals *i praksis*, kan Neo4j evalueres da — men med når graftraversering faktisk blir en målbar flaskehals — ikke før.
én VPS og realistiske datamengder er det usannsynlig. 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 ## Lagmodell

View file

@ -255,6 +255,27 @@ Rekkefølge: definer traits → migrer eksisterende worker-jobber inn →
legg til nye tjenester etter hvert. Fast punkt fra dag én, full legg til nye tjenester etter hvert. Fast punkt fra dag én, full
dekning over tid. dekning over tid.
## Compute-separasjon
Maskinrommet orkestrerer — men tunge jobber trenger ikke kjøre på
samme maskin. Hetzner CPX42 (8 vCPU, 16 GB RAM) skal håndtere state
(PG, SpacetimeDB) og sanntid (Caddy, LiveKit, SvelteKit). Whisper
(CPU-intensiv, spesielt large-v3) og lokal LLM (kildevern-modus)
vil konkurrere om ressurser under live innspilling.
Maskinrommets abstraksjon gjør dette løsbart:
- **Nå:** Alt på én VPS. Jobbkøen prioriterer sanntid over batch.
Whisper kjøres med lavere concurrency under live-sesjoner.
- **Senere:** Trekk ut tunge workers til en separat node (billig
ARM/Ampere-instans) som poller jobbkøen over internt nettverk.
Maskinrommet ruter transparent — primitivene merker ingenting.
- **Kildevern-modus:** Lokal LLM (Llama/Gemma) krever GPU eller
dedikert compute. Urealistisk på delt VPS. Egen node for dette.
Poenget: maskinrommet er designet for å rute arbeid, ikke for å
*utføre* alt selv. Compute-separasjon er en konfigurasjon, ikke en
arkitekturendring.
## Spenninger og åpne spørsmål ## Spenninger og åpne spørsmål
- **Synkron vs asynkron.** "Fang" og "lever" kan være instant, men - **Synkron vs asynkron.** "Fang" og "lever" kan være instant, men