synops/docs/infra/api_grensesnitt.md
vegard b5aa5bb243 Fjern SpacetimeDB komplett (oppgave 22.4)
SpacetimeDB er nå helt fjernet fra Synops. Sanntid håndteres av
PG LISTEN/NOTIFY + WebSocket i portvokteren (maskinrommet).

Kode fjernet:
- spacetimedb/ Rust-modul og spacetime.json
- maskinrommet/src/stdb.rs (HTTP-klient for STDB-reducers)
- frontend module_bindings/ (23 auto-genererte filer)
- spacetimedb npm-avhengighet fra package.json
- scripts/test-sanntid.sh (testet STDB-flyt)

Infrastruktur:
- Docker-container stoppet og fjernet fra docker-compose.yml
- Caddy: fjernet /spacetime/* reverse proxy
- maskinrommet-env.sh: fjernet STDB_IP og SPACETIMEDB_*-variabler
- .env.example: fjernet SpacetimeDB-seksjoner

Dokumentasjon oppdatert:
- CLAUDE.md: stack, lagmodell, kjerneprinsipper, driftsmodell
- docs/arkitektur.md: skrivestien, lesestien, datalag, teknologivalg
- docs/retninger/datalaget.md: migrasjonshistorikk, status "fjernet"
- 37 andre docs oppdatert (features, concepts, infra, ops, retninger)
- Alle kode-kommentarer med STDB-referanser oppdatert

Verifisert: maskinrommet bygger og starter OK, frontend bygger OK,
helsesjekk returnerer 200. Caddy reloadet.
2026-03-18 13:39:09 +00:00

7.9 KiB
Raw Blame History

Infrastruktur: API-grensesnitt og Tjenesteansvar

1. Konsept

Frontend sender intensjoner til maskinrommet (Rust/axum HTTP API). Maskinrommet eier alle skrivinger: det validerer, skriver til PG, og orkestrerer konsekvenser.

Sanntid: PG LISTEN/NOTIFY → maskinrommet → WebSocket /ws → frontend. Frontend bruker portvokterens WebSocket for sanntid. Tunge spørringer (søk, statistikk, graftraversering) går via maskinrommet → PG.

2. Kommunikasjonskart

┌─────────────────────────────────────────────────────────────┐
│  Brukerens nettleser (SvelteKit klient)                     │
└──────────┬──────────────────────┬───────────────────────────┘
           │                      │
           │ HTTP (intensjoner)   │ WebSocket (sanntid)
           ▼                      ▼
┌──────────────────────────────────────┐
│  Maskinrommet / Portvokteren (Rust)  │
│  axum HTTP API + WebSocket           │
│                                      │
│  Ansvar:                             │
│  - Validere intensjoner              │
│  - Skrive til PG                     │
│  - Orkestrere bakgrunnsjobber        │
│  - Tunge spørringer                  │
│  - Sanntid via PG LISTEN → WS       │
└──┬─────────────┬─────────────────────┘
   │             │
   ▼             ▼
┌─────┐  ┌─────────────┐
│ PG  │  │ Whisper,    │
│     │  │ LiteLLM,   │
│     │  │ LiveKit ... │
└─────┘  └─────────────┘

3. Ansvarsfordeling

Komponent Rolle Snakker med
SvelteKit (klient) UI, brukerinteraksjon Maskinrommet (HTTP + WS)
Maskinrommet (Rust) Intensjons-API, orkestrering, sanntid, tunge spørringer PG, CAS, Whisper, LiteLLM
PostgreSQL Eneste datakilde, sanntid via LISTEN/NOTIFY Maskinrommet (SQL)

4. Viktige avklaringer

  • Maskinrommet er HTTP API + WebSocket-server (axum). Frontend sender intensjoner via HTTP, mottar sanntid via WebSocket.
  • Maskinrommet eier alle skrivinger. Frontend skriver aldri direkte til PG.
  • SvelteKit er et rent frontend-prosjekt. Ingen server-side PG-tilgang.
  • Bakgrunnsjobber (Whisper, LLM, TTS) orkestreres av maskinrommet, aldri direkte fra frontend.

5. Implementerte endepunkter

Offentlige

  • GET /health — Helsesjekk. Verifiserer PG-tilkobling.

WebSocket (sanntid, oppgave 22.122.2)

  • GET /ws?token=<JWT> — WebSocket-oppgradering for sanntidsstrøm. Token sendes som query-parameter (nettlesere støtter ikke custom headers ved WS upgrade).
    • Ved tilkobling: sender initial_sync med alle noder, edges, access og mixer_channels brukeren kan se.
    • Deretter: strømmer berikede events (node_changed, edge_changed, access_changed, mixer_channel_changed), filtrert på brukerens tilgangsmatrise (node_access).
    • Berikede events: INSERT/UPDATE-events inneholder full raddata fra PG (ikke bare ID), slik at frontend kan oppdatere stores direkte uten ekstra API-kall.
    • Kilder: PG LISTEN/NOTIFY-triggere på nodes, edges, node_access og mixer_channels.
    • Ved lag (klient sakker etter): sender full resync (ny initial_sync).

Autentiserte (krever Authorization: Bearer <JWT>)

  • GET /me — Returnerer autentisert brukers node_id og authentik_sub.
  • POST /intentions/create_node — Opprett node. Skriv til PG, returner node_id umiddelbart.
    • Body (JSON): { node_kind?, title?, content?, visibility?, metadata? }
    • Defaults: node_kind="content", visibility="hidden", andre felter tomme
    • Respons: { node_id: "<uuid>" }
  • POST /intentions/create_edge — Opprett edge mellom to noder. Validerer at begge nodene eksisterer og at edge_type ikke er tom.
    • Body (JSON): { source_id, target_id, edge_type, metadata?, system? }
    • Defaults: metadata={}, system=false
    • Respons: { edge_id: "<uuid>" }
  • POST /intentions/update_node — Oppdater eksisterende node (partial update). Krever tilgang: created_by eller owner/admin-edge.
    • Body (JSON): { node_id, node_kind?, title?, content?, visibility?, metadata? }
    • Kun oppgitte felter endres, resten beholdes
    • Respons: { node_id: "<uuid>" }
  • POST /intentions/delete_node — Slett node og tilhørende edges. Krever tilgang: created_by eller owner/admin-edge.
    • Body (JSON): { node_id }
    • Respons: { deleted: true }
  • POST /intentions/update_edge — Oppdater eksisterende edge (partial update). Krever tilgang: created_by eller owner/admin-edge til source-noden.
    • Body (JSON): { edge_id, edge_type?, metadata? }
    • Kun oppgitte felter endres, resten beholdes
    • Respons: { edge_id: "<uuid>" }
  • POST /intentions/delete_edge — Slett en edge. Brukes bl.a. for avpublisering. Krever tilgang: created_by eller owner/admin-edge til source-noden. Ved fjerning av belongs_to-edge til publiseringssamling invalideres forside-cache.
    • Body (JSON): { edge_id }
    • Respons: { deleted: true }
  • POST /intentions/set_slot — Sett slot-metadata (hero/featured/strøm) på belongs_to-edge i publiseringssamling. Håndterer hero-erstatning og featured-overflow.
    • Body (JSON): { edge_id, slot, slot_order?, pinned? }
    • Respons: { edge_id, displaced[] }

LiveKit / Sanntidslyd (oppgave 11.2)

  • POST /intentions/join_communication — Koble til sanntidslyd i en kommunikasjonsnode. Validerer deltaker-tilgang (owner/member_of/host_of-edge eller via alias). Genererer LiveKit access token (JWT), oppdaterer node-metadata.
    • Body (JSON): { communication_id, role? } (role: "publisher" | "subscriber", default "publisher")
    • Respons: { livekit_room_name, livekit_token, livekit_url, identity, participants[] }
    • Frontend bruker livekit_token + livekit_url til å koble livekit-client SDK.
  • POST /intentions/leave_communication — Forlat sanntidsrom. Fjerner deltaker fra live-rom.
    • Body (JSON): { communication_id }
    • Respons: { status: "left" }
  • POST /intentions/close_communication — Steng sanntidsrom (krever owner/admin). Fjerner alle deltakere, setter live_status=ended i metadata.
    • Body (JSON): { communication_id }
    • Respons: { status: "closed" }

Mixer-kanaler (oppgave 22.2)

Delt mixer-tilstand i LiveKit-rom. Skriver til PG mixer_channels-tabell; NOTIFY-trigger propagerer til WS.

  • POST /intentions/create_mixer_channel — Opprett mixer-kanal for deltaker i rom.
    • Body: { room_id, target_user_id }
  • POST /intentions/set_gain — Sett gain (0.01.5) for en kanal.
    • Body: { room_id, target_user_id, gain }
  • POST /intentions/set_mute — Mute/unmute en kanal.
    • Body: { room_id, target_user_id, is_muted }
  • POST /intentions/toggle_effect — Toggle en lydeffekt.
    • Body: { room_id, target_user_id, effect_name }
  • POST /intentions/set_mixer_role — Sett rolle (editor/viewer) for deltaker.
    • Body: { room_id, target_user_id, role }

6. Instruks for Claude Code

  • Maskinrommet (maskinrommet/) er Rust-prosjektet med axum, tokio, sqlx.
  • Intensjoner fra frontend → POST /intentions/* endepunkter i maskinrommet.
  • Tunge spørringer fra frontend → GET /query/* endepunkter i maskinrommet.
  • Frontend (SvelteKit) har ingen direkte databasetilgang.
  • Bakgrunnsjobber trigges av maskinrommet, ikke via en separat jobbkø-tabell.

Historisk merknad: Tidligere beskrev dette dokumentet en arkitektur der SvelteKit var web-API og Rust kun var workers. Denne ble erstattet av maskinrommet-arkitekturen (se docs/retninger/maskinrommet.md).