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
150 lines
8 KiB
Markdown
150 lines
8 KiB
Markdown
# 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.1–22.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.0–1.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`).
|