- 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>
4.5 KiB
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
- Redaksjonen oppretter en "Gjestesesjon" knyttet til et Tema.
- Legger inn spørsmål (tekst) som gjesten skal svare på.
- Systemet genererer en unik, tidsbegrenset URL.
- URL-en sendes til gjesten via e-post, SMS eller chat.
- Gjestens svar (lydmeldinger) dukker opp i Tema-chatten som
voice_memo-meldinger, automatisk transkribert. - Redaksjonen triagerer svarene — kan tagge, klippe inn i episode, eller bruke som research.
2.2 Gjestens side
- Gjesten åpner lenken i mobilnettleseren. Ingen app, ingen konto, ingen registrering.
- Ser en enkel, ren flate: podcast-logo, spørsmålene fra redaksjonen, og en opptaksknapp per spørsmål.
- Trykker record, snakker, trykker stopp. Kan lytte tilbake og ta om igjen.
- Ved innsending lastes lydfilene opp og gjesten ser en bekreftelse.
- 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 = NULLogmetadata.guest_name+metadata.guest_token_idfor 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 (visguest_namei 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.