server/docs/features/chat.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

139 lines
8.3 KiB
Markdown

# Feature: Chat (Channels & Meldinger)
**Filsti:** `docs/features/chat.md`
## 1. Konsept
En universell, sanntids meldingskomponent bygget på SpacetimeDB. Chat er ikke bundet til én kontekst — den kan knyttes til enhver node i Kunnskapsgrafen via **channels**. Ulike konsepter bruker chat med ulik konfigurasjon, men all infrastruktur er delt.
## 2. Channels-modellen
En **channel** er en meldingsstrøm knyttet til en vilkårlig node (parent) i grafen. Channelen er selv en node (`node_type = 'channel'`), noe som betyr at den deltar i grafen og arver workspace-isolasjon.
```
┌─────────────┐ parent_id ┌─────────────┐
│ Channel │ ──────────────────► │ Vilkårlig │
│ (node) │ │ node │
└──────┬──────┘ └─────────────┘
│ channel_id
┌─────────────┐
│ Meldinger │
│ (nodes) │
└─────────────┘
```
En node kan ha **flere channels**. Eksempler:
- Et Tema har "Diskusjon" (default) + "Research-dump"
- En Episode har "Redaksjonelt" (intern kommentartråd)
- Et Møte har "Scratchpad" (flyktig, TTL)
- En Aktør har "Notater" (valgfri)
### 2.1 Channel-konfigurasjon
Hver channel har en `config` (JSONB) som styrer hvilke capabilities den støtter:
```json
{
"threads": true, // reply-to-tråder
"mentions": true, // #/@ parsing + automatiske graph_edges
"attachments": true, // filopplasting
"research_clips": true, // research_clip meldingstype (AI-prosessert)
"ttl_days": null // null = permanent, tall = auto-slett etter N dager
}
```
### 2.2 Standard channel-presets per konsept
| Konsept | Channel-navn | Config |
|---|---|---|
| **Redaksjonen** (Tema) | "Diskusjon" | `threads: true, mentions: true, attachments: true, research_clips: true, ttl_days: null` |
| **Redaksjonen** (Tema) | "Research" (valgfri) | `threads: false, mentions: true, attachments: true, research_clips: true, ttl_days: null` |
| **Møterommet** | "Scratchpad" | `threads: false, mentions: false, attachments: false, research_clips: false, ttl_days: 90` |
| **Studioet** | "Studio-chat" | `threads: false, mentions: false, attachments: false, research_clips: false, ttl_days: 30` |
| **Episode** | "Redaksjonelt" | `threads: true, mentions: true, attachments: true, research_clips: false, ttl_days: null` |
Presets er kun defaults — en workspace-admin kan justere config per channel.
### 2.3 Automatisk opprettelse
Når en node opprettes som forventes å ha chat (Tema, Episode, Møte), oppretter systemet automatisk en default-channel. Dette skjer i SvelteKit server-side som en del av node-opprettelsestransaksjonen.
## 3. Meldinger
### 3.1 Datamodell (PostgreSQL)
Meldinger er noder i Kunnskapsgrafen (`node_type = 'melding'`):
```sql
messages (
id UUID PK nodes(id),
channel_id UUID NOT NULL channels(id),
reply_to UUID messages(id), -- tråder (hvis config.threads = true)
author_id TEXT NOT NULL users,
message_type message_type, -- 'text', 'research_clip', 'factoid', 'system'
body TEXT NOT NULL,
metadata JSONB, -- ekstra data (research-klipp AI-resultat, etc.)
edited_at TIMESTAMPTZ,
created_at TIMESTAMPTZ
)
```
### 3.2 SpacetimeDB (sanntid)
SpacetimeDB holder aktive channels' meldinger i minnet. Nye meldinger sendes via SpacetimeDB og kringkastes til alle tilkoblede klienter i samme workspace og channel. Synkes til PostgreSQL med ~5 sek forsinkelse (se `docs/infra/synkronisering.md`).
## 4. Mentions & Autocomplete
Kun aktive når `config.mentions = true`.
* **Trigger-tegn:** `#` (Temaer/Aktører fra Kunnskapsgrafen), `@` (brukere/redaksjonsmedlemmer), `/` (kommandoer).
* **Filtrering:** Svelte-klienten filtrerer den lokale SpacetimeDB-cachen umiddelbart. Skriver man `#Ha...` vises en klikkbar liste ("Hans Petter Sjøli", "Høyre").
* **Grafkobling:** Ved `#`-mention opprettes automatisk `MENTIONS`-edges i `graph_edges` mellom meldingen og den nevnte noden.
* **Mobil-optimalisert:** Autocomplete-listen er tappbar og tilpasset mindre skjermer.
## 5. Tråder
Kun aktive når `config.threads = true`. Meldinger kan ha en `reply_to`-referanse. Frontend viser tråder som innrykk eller ekspanderbare grupper.
## 6. Vedlegg
Kun aktive når `config.attachments = true`. Meldinger kan ha vedlegg via `message_attachments``media_files`. Whiteboard-eksport kan knyttes som vedlegg.
## 7. Versjonshistorikk
Alle meldinger støtter redigering med full historikk via `message_revisions`. Original tekst bevares alltid.
## 8. Tale-til-tekst (Voice-to-text)
Mobilvennlig diktering for situasjoner der tastatur er upraktisk. Brukeren trykker en mikrofon-knapp, snakker, og får teksten tilbake som en vanlig melding klar til redigering og sending.
### 8.1 Flyt
1. Bruker trykker og holder (eller toggler) mikrofon-knappen i chat-feltet.
2. Nettleseren fanger lyd via `MediaRecorder` API (WebM/Opus).
3. Lydklippet sendes til Whisper (`POST /v1/audio/transcriptions`, `response_format=text`, `language=no`) via SvelteKit server-side.
4. Transkripsjonen settes inn i meldingsfeltet — brukeren kan redigere før sending.
5. Ingen lagring av lydfilen — den kastes etter transkripsjon.
### 8.2 Avgrensning
* Dette er **ikke** en lydmelding-feature (à la WhatsApp). Lyden er et transportmiddel for tekst. Kun teksten lagres.
* Whisper-kallet er kort (<30 sek tale) og kan rutes direkte til Whisper-serveren uten jobbkø.
* Bruk `small`-modellen for lav latens. Navnenøyaktighet er mindre viktig for korte chatmeldinger.
## 9. TTL (automatisk opprydding)
Channels med `config.ttl_days` satt til et tall får sine meldinger automatisk slettet av en nattlig jobbkø-jobb. Brukes for flyktige kontekster (scratchpads, studio-chat).
## 10. Implementeringsstatus
### Ferdig (mars 2025)
- **ChatBlock.svelte:** Refaktorert til adapter-mønster via `createChat()` factory
- **PG-adapter (`pg.svelte.ts`):** Polling hvert 3. sek, full-fetch (ingen akkumulering). Fungerer som selvstendig fallback.
- **SpacetimeDB hybrid-adapter (`spacetime.svelte.ts`):** Henter historikk fra PG via REST + lytter SpacetimeDB WebSocket for sanntidspush. Dedupliserer mot PG-data. Faller tilbake til PG REST ved sending hvis SpacetimeDB er nede.
- **Factory (`create.svelte.ts`):** Velger adapter basert `VITE_SPACETIMEDB_URL`. SSR-safe med `browser`-guard.
- **Shared types (`types.ts`):** `Message` og `ChatConnection` interface brukt av begge adaptere.
- **SpacetimeDB Rust-modul (`spacetimedb/src/lib.rs`):** `ChatMessage`-tabell, `SyncOutbox`, `send_message`-reducer. Publisert som `sidelinja-realtime`.
- **TypeScript-bindings:** Generert fra SpacetimeDB-modulen, camelCase-properties.
- **Autoscroll:** `$effect` som scroller ned ved nye meldinger.
- **Datogruppering:** Visuell datoseparator ("I dag", "I går", dato).
### Gjenstår
- **Sync-worker (SpacetimeDB PG):** Rust-worker som poller `sync_outbox` og persisterer til PostgreSQL. Se `docs/infra/synkronisering.md` §5.1.
- **Tråder, mentions, vedlegg, TTL** avventer Kunnskapsgraf CRUD (Lag 2).
- **Autentisering:** `author_name`/`author_id` settes ikke automatisk ennå (avventer Authentik-integrasjon).
## 11. Instruks for Claude Code
* **Opprettelsesrekkefølge:** Opprett `nodes`-rad `channels`-rad (for meldinger) `nodes`-rad `messages`-rad. Alt i én transaksjon med riktig `workspace_id`.
* **Channel-opprettelse:** Når en Tema, Episode eller Møte opprettes, opprett alltid en default-channel i samme transaksjon.
* **Mentions-parsing:** Skjer i SvelteKit server-side ved mottak av meldingen. Parse `#`- og `@`-tags, valider mot noder i workspace-et, og opprett `graph_edges`.
* **Config-respekt:** Frontend-komponenten lese `channel.config` og slå av/ UI-elementer (tråd-knapp, vedlegg-knapp, mention-autocomplete) basert config.
* **SpacetimeDB er autoritativ** for aktive meldinger, PG for historikk.
* **Alt er workspace-scopet.** Channels arver workspace via `nodes.workspace_id`.