synops/docs/infra/api_grensesnitt.md
vegard 8e80102f6b Fullfør oppgave 22.2: Frontend-migrering fra SpacetimeDB til portvokteren
Frontend bruker nå kun portvokterens WebSocket for sanntidsdata.
SpacetimeDB-klienten er erstattet med en enkel WebSocket-klient
som kobler til /ws-endepunktet og oppdaterer reactive stores direkte.

Frontend-endringer:
- Nye lokale typer (types.ts) erstatter STDB module_bindings
- connection.svelte.ts: WebSocket til portvokteren med auto-reconnect
- stores.svelte.ts: Prosesserer WS-meldinger (initial_sync + events)
- MixerTrait: STDB-reducers erstattet med HTTP API-kall
- api.ts: Nye mixer-endepunkter (create, gain, mute, effect, role)
- +layout.svelte: Fjernet dual-tilkobling, kun portvokterens WS
- pg-ws.svelte.ts: Slettet (erstattet av connection.svelte.ts)

Dokumentasjon:
- datalaget.md: Fase M1+M2 markert som fullført
- api_grensesnitt.md: Oppdatert arkitekturdiagram, nye mixer-endepunkter
2026-03-18 12:26:33 +00:00

150 lines
8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.
SpacetimeDB er under utfasing — frontend bruker kun portvokterens WebSocket (Fase M2).
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- og STDB-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 STDB (instant),
spawn async PG-skriving, 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), oppretter rom i STDB, 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 STDB 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)
Erstatter SpacetimeDB-reducers for 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`).