server/docs/concepts/den_asynkrone_gjesten.md
vegard a5985ef3f8 Dokumentasjon, erfaringslogg, migrasjoner og infra-oppdateringer
- Omorganiser docs/: konsepter, features, infra og proposals i egne mapper
- Ny docs/erfaringer/ med lærdommer fra chat-implementering (Svelte 5, SpacetimeDB, adapter-mønster)
- Oppdater ARCHITECTURE.md: Lag 1 status, ny §10 Erfaringslogg, SpacetimeDB i lokal dev
- Oppdater synkronisering.md med implementeringsstatus og designvalg
- Oppdater lokal.md med SpacetimeDB og AI Gateway
- Utvid PG-skjema med channels, messages, media_files, message_revisions
- Legg til seed_dev.sql, migration_safety.md, .env.example
- Nye feature-specs: chat, kanban, whiteboard, live_ai, lydmeldinger m.fl.
- Nye konsept-specs: studioet, møterommet, redaksjonen, den asynkrone gjesten m.fl.
- SpacetimeDB og AI Gateway i docker-compose.dev.yml
- collect-docs.sh inkluderer erfaringer/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 01:40:14 +01:00

4.5 KiB

Konsept: Den Asynkrone Gjesten

Filsti: docs/concepts/den_asynkrone_gjesten.md

1. Konsept

Mange interessante gjester har ikke tid til å stille i studio. Den Asynkrone Gjesten lar redaksjonen sende en unik lenke til en gjest som kan svare på spørsmål via tale — fra mobilen, når det passer dem. Svarene lander direkte i redaksjonens arbeidsflyt, transkriberes automatisk, og kan brukes i podcasten.

2. Brukeropplevelse

2.1 Redaksjonens side

  1. Redaksjonen oppretter en "Gjestesesjon" knyttet til et Tema.
  2. Legger inn spørsmål (tekst) som gjesten skal svare på.
  3. Systemet genererer en unik, tidsbegrenset URL.
  4. URL-en sendes til gjesten via e-post, SMS eller chat.
  5. Gjestens svar (lydmeldinger) dukker opp i Tema-chatten som voice_memo-meldinger, automatisk transkribert.
  6. Redaksjonen triagerer svarene — kan tagge, klippe inn i episode, eller bruke som research.

2.2 Gjestens side

  1. Gjesten åpner lenken i mobilnettleseren. Ingen app, ingen konto, ingen registrering.
  2. Ser en enkel, ren flate: podcast-logo, spørsmålene fra redaksjonen, og en opptaksknapp per spørsmål.
  3. Trykker record, snakker, trykker stopp. Kan lytte tilbake og ta om igjen.
  4. Ved innsending lastes lydfilene opp og gjesten ser en bekreftelse.
  5. Lenken utløper etter gitt tid eller antall besøk.

2.3 Minimal friksjon

  • Ingen Authentik-innlogging — tilgang via signert token
  • Ingen app — ren PWA/nettleser
  • Ingen redigering — gjesten snakker bare
  • Responsivt, mobil-first design

3. Komponenter

Feature Rolle
Lydmeldinger Opptakskomponent gjenbrukes (se docs/features/lydmeldinger.md)
Chat (channels) Svarene lander i en channel knyttet til Temaet
Live transkripsjon Whisper transkriberer via jobbkø (se docs/features/live_transkripsjon.md)
Podcastfabrikken Lydklipp kan trekkes inn som segment (se docs/concepts/podcastfabrikken.md)

4. Autentisering: Gjeste-tokens

4.1 Datamodell

guest_tokens (
    id           UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    workspace_id UUID NOT NULL REFERENCES workspaces(id) ON DELETE CASCADE,
    channel_id   UUID NOT NULL REFERENCES channels(id) ON DELETE CASCADE,
    guest_name   TEXT NOT NULL,               -- Visningsnavn ("Erna Solberg")
    questions    JSONB NOT NULL,              -- [{ "sort": 1, "text": "Hva tenker du om...?" }]
    token        TEXT UNIQUE NOT NULL,         -- Kryptografisk sikker, URL-safe token
    expires_at   TIMESTAMPTZ NOT NULL,
    max_recordings SMALLINT DEFAULT 10,       -- Maks antall opptak
    recordings_count SMALLINT DEFAULT 0,
    created_by   TEXT NOT NULL REFERENCES users(authentik_id),
    created_at   TIMESTAMPTZ NOT NULL DEFAULT now()
)

4.2 Sikkerhet

  • Token er kryptografisk tilfeldig (256-bit, URL-safe base64).
  • SvelteKit validerer token ved hvert request: sjekker expiry, recordings_count < max_recordings, og workspace-tilhørighet.
  • Gjestens meldinger merkes med author_id = NULL og metadata.guest_name + metadata.guest_token_id for sporbarhet.
  • Ingen tilgang til andre channels, workspaces eller funksjoner.
  • Tokenet kan revokeres manuelt av redaksjonen.

4.3 Flyt (teknisk)

Gjest åpner URL med token
  → SvelteKit validerer token
  → Viser spørsmål + opptaksknapp
  → Gjest tar opp svar
  → SvelteKit streamer lydfil til media/{workspace_slug}/voice/
  → Oppretter message (voice_memo) i channelen
  → Oppretter whisper_transcribe-jobb i jobbkøen
  → Inkrementerer recordings_count
  → Redaksjonen ser svaret i Tema-chatten

5. Dataklassifisering

Data Kategori Detaljer
Gjestens lydopptak Kritisk (backup) Unikt innhold
Guest tokens Flyktig (TTL) Utløper automatisk, slett expired tokens periodisk
Spørsmål (JSONB) Kritisk (PG) Redaksjonelt innhold

6. Instruks for Claude Code

  • guest_tokens-tabellen er ikke en node i grafen — den er ren tilgangsstyring.
  • Gjeste-UI er en egen SvelteKit-rute (/guest/[token]) med minimal layout (ingen navbar, ingen workspace-switcher).
  • Gjenbruk lydmeldinger-komponenten — ikke bygg en egen opptaksflyt.
  • Meldinger fra gjester har author_id = NULL. Frontend må håndtere dette gracefully (vis guest_name i stedet).
  • Tokenet skal aldri gi tilgang til å lese andre meldinger i channelen — gjesten kan kun skrive.
  • Alt er workspace-scopet. Token bærer workspace_id eksplisitt.