# Universell input og mottak

**Status: Besluttet.**

> Én multimodal input-primitiv. Én personlig mottaksflate. Alt som
> fanges er en node. Hva det "er" bestemmes av edges. Hvordan det
> presenteres bestemmes av mottakeren.

## Input-primitiven

Én overflate som fanger alt:

- **Tekst** — skriving, Markdown, kodeblokker
- **Lyd** — voice memo, diktering → automatisk transkribert
- **Bilde** — foto, skjermbilde, tegning
- **AI-støtte** — spør AI, få forslag, la den transformere input
- **URL** — lim inn lenke, den berikes automatisk

Brukeren gjør det samme uansett kontekst — skriver, snakker eller
tegner i input-feltet. Forskjellen mellom "dagbok", "chatmelding"
og "kanban-kort" er ikke hva brukeren gjør — det er hvilke edges
som knyttes til resultatet.

### Én pipeline

All input går gjennom samme tekniske pipeline:
maskinrommet → SpacetimeDB (instant) → PG (asynk).

Konteksten bestemmer routing, ikke en teknisk modus:

- Du er i et møte → inputen streames live til andre deltakere
- Du er alene på bussen → inputen lander som privat node
- Du er i en podcast-kanal → inputen går inn i produksjonspipeline

Samme pipeline. Ulike edges.

### Input-metode og innholdstype er ortogonale

Du kan snakke inn et kanban-kort. Du kan tegne en kalenderoppføring.
Input-primitiven bryr seg ikke om hva det *blir* — den fanger det
som kommer inn. Alt etterpå er edges.

### Én overflate å perfeksjonere

All UX-investering konsentreres ett sted. Én perfekt input-opplevelse
— responsiv, multimodal, med god AI-støtte — i stedet for ti
middelmådige spesialgrensesnitt.

## Editoren

Input-komponenten er en TipTap-editor (ProseMirror-basert) som
konfigureres med ulike extensions basert på kontekst.

### Kontekst setter default, brukeren bestemmer

Konteksten (kommunikasjonsnoden du er i, visningen du bruker)
setter en *default* editor-konfigurasjon. Men brukeren kan alltid
overstyre — utvide til full editor eller forenkle. Ingen kunstig
grense mellom "chatmelding" og "artikkel."

Du *kan* skrive en gjennomformatert tekst i chatten. Men hvis en
chatmelding inspirerer en artikkel, drar du den til artikkelverktøyet
på arbeidsflaten. En ny innholdsnode opprettes med `source_material`-edge
til meldingen. Artikkelen skrives i et verktøy designet for langform —
chatinput er designet for samtale. Se [arbeidsflaten](arbeidsflaten.md).

Editoren husker brukerens valg per kontekst via preferanser på
brukernoden.

### Presets

| Kontekst | Default extensions | Eksempel |
|----------|-------------------|----------|
| Chat | Tekst, markdown, kodeblokker, lenker | Enkel melding |
| Artikkel/blogg | + overskrifter, bilder, embeds, blockquotes, tabeller | Publisert tekst |
| Show notes | + lister, tidskoder, lenker | Episodenotater |
| Kanban-kort | Tekst, sjekklister | Oppgavebeskrivelse |

Presets er bare default — brukeren kan utvide eller forenkle med
en knapp eller tastatursnarvei. Ikke en modebytte, bare at flere
verktøy blir tilgjengelig.

### Tekstlagring

Noden lagrer to representasjoner:

- `content TEXT` — ren tekst uten formatering, for fulltekstsøk
  og enkel visning
- `metadata.document JSONB` — strukturert TipTap/ProseMirror-
  dokument for rendering

```json
{
  "type": "doc",
  "content": [
    { "type": "paragraph", "content": [
      { "type": "text", "text": "Her er en intro." }
    ]},
    { "type": "image", "attrs": {
      "node_id": "uuid-av-cas-node", "alt": "Diagram"
    }},
    { "type": "paragraph", "content": [
      { "type": "text", "text": "Teksten fortsetter." }
    ]}
  ]
}
```

`content` genereres automatisk fra dokumentet ved lagring — bare
teksten, uten markup. Editoren produserer begge.

For enkle meldinger (ren tekst uten formatering) er
`metadata.document` null — `content` er alt som trengs.

### Bilder og media i tekst

Bilder i dokumentet refererer til CAS-noder via `node_id`.
CAS-noden er en egen node med `has_media`-edge til innholdsnoden.
Dokumentstrukturen bestemmer *hvor* bildet plasseres i teksten.

Tekst er *på* noden. Binærfiler er *andre* noder koblet med edges.
Ren separasjon: tekst er innhold, binærfiler er vedlegg som kan
plasseres inline.

## Edges definerer alt

Hva en node "er" bestemmes utelukkende av edges:

- Node + `belongs_to` → kanal = chatmelding
- Node + `belongs_to` → board + `status` = kanban-kort
- Node + `scheduled` → tidspunkt = kalenderoppføring
- Node uten edges til andre = privat notat
- Node + `mentions` → topic = faktoid i kunnskapsgrafen
- Node uten edges = løs tanke, ennå uorganisert

**Nye noder fra eksisterende.** Chatmelding → oppgave = ny
oppgavenode med `source_material`-edge til meldingen. Meldingen
forblir uendret. For lettvekts-triage (noden vises i kanban OG
chat): legg til `status`-edge direkte — ingen ny node nødvendig.

**Multitype er naturlig.** En node kan ha flere roller samtidig
— både kanban-kort og kalenderoppføring og faktoid. Det er for
noder som genuint tjener flere formål, ikke for å "gro" en
chatboble til en artikkel. Artikkelen er en *ny* node med
`source_material`-edge. Se [arbeidsflaten](arbeidsflaten.md).

### Edge-tildeling

Når du "bare sier noe" — hvem bestemmer edges?

1. **Kontekst gir det meste.** Du er i en samtale → `belongs_to`-
   edge til samtalen. Du er alene → privat. Dekker 80%.
2. **Eksplisitt handling.** Du drar en node til kanban-brettet
   (legg til board-edge) eller til artikkelverktøyet (ny node med
   `source_material`-edge). Du tagger noe. Du setter en dato.
   Se [arbeidsflaten](arbeidsflaten.md) for kompatibilitetsmatrise.
3. **AI-foreslått.** Systemet foreslår `mentions`-edge når du
   nevner en person. Foreslår kanban når noe ligner en oppgave.

Detaljer for AI-foreslåtte edges avklares ved implementering.

## Mottak-primitiven

Der input er "én overflate som fanger alt", er mottak "én overflate
som presenterer alt tilpasset *deg*."

### Mottaker bestemmer format

All lyd transkriberes. All tekst kan leses opp (TTS). Noden har
alltid begge representasjoner. Mottaker setter sin preferanse:

- Trond snakker inn en tanke → node med lyd + transkripsjon
- Peter har tekst-preferanse → ser transkripsjonen
- Vegard har lyd-preferanse → hører originallyd

Modalitet er ikke en egenskap ved meldingen, men ved *lesningen*.

### Dimensjoner ved mottak

**Format.** Lyd, tekst, visuelt — mottaker bestemmer.

**Filtrering.** Mottaksflaten filtrerer basert på dine edges:
kanaler du følger, personer du samarbeider med, topics du er
interessert i.

**Prioritering.** AI-assistert vekting: ubesvarte meldinger,
oppgaver med frist, noder endret siden sist. Ikke en
notifikasjonsliste — en vektet visning av det som er relevant.

**Tempo.** Sanntid (ting streamer inn) eller asynkront (digest,
oppsummering).

### Mottaksflaten er en visning av grafen

"Noder med edge til *meg*, vektet på relevans og tid." Ikke en
egen mekanisme — en spørring mot grafen med deg som sentrum.

## Kommunikasjonsnoden — den tredje primitiven

Input fanger. Mottak presenterer. Kommunikasjonsnoden er *stedet*
der folk møtes — en node som samler deltakere, definerer
tilgangsregler, og fungerer som kontekst.

### Én node, mange former

| Variant | Deltakere | Input | Mottak |
|---------|-----------|-------|--------|
| Én-til-én | 2 | Begge | Begge |
| Gruppechat | N | Alle | Alle |
| Møte | N | Alle | Alle |
| Allmøte | 1 + N | Leder | Alle lytter |
| Podcastinnspilling | 2-4 + N | Verter | Alle lytter |
| Livesending | 1-4 + ∞ | Verter | Streamet |
| Asynkron gjest | 1 + 1 | Gjest | Redaksjonen |

Forskjellen er edge-konfigurasjoner, ikke ulike systemer:
- `owner`-edge — kontrollerer noden
- `member`-edge — kan gi input og motta
- `reader`-edge — kan kun motta

### Kontekst arves automatisk

Input i en kommunikasjonsnode arver kontekst-edges. Sier du noe
i et møte → noden får `belongs_to`-edge til møtet automatisk.

### Livssyklus

- **Live** — deltakere til stede, input streames
- **Asynkron** — deltakere gir input i eget tempo
- **Avsluttet** — arkivert, alt som ble sagt er noder med edges
- **Gjenåpnet** — reaktivert ("vi tar opp tråden fra forrige møte")

### Skalering er edge-endring

Samtale → møte = flere deltaker-edges.
Møte → livesending = offentlige mottak-edges.
Livesending → podcast = publiserings-edges på arkivert innhold.

## Tekniske forutsetninger

### STT (tale → tekst): løst
Faster-whisper kjører lokalt, god norsk kvalitet.

### TTS (tekst → tale): løsbart
Start med ElevenLabs bak AI Gateway, bytt til lokal modell når
kvaliteten holder. Backend-swap bak gatewayen — brukeren merker
ingenting.

## Visninger er spørringer

Chat = noder med kanal-edge, sortert på tid.
Kanban = noder med board-edge, gruppert på status.
Kalender = noder med dato-edge, på tidslinje.
Dagbok = private noder, sortert på tid.
Mottaksflate = noder med edge til deg, vektet.

Alle leser fra samme graf. Ingen har "sin egen" data.

## Forhold til andre retninger

- [Noder er sentrum](bruker_ikke_workspace.md) — visibility,
  tilgangsmatrise, aliaser
- [Datalaget](datalaget.md) — SpacetimeDB holder hele grafen,
  PG persisterer asynkront
- [Maskinrommet](maskinrommet.md) — validering, routing, CAS,
  tunge jobber (Whisper, TTS, AI)
- [Rom, ikke forum](rom_ikke_forum.md) — kommunikasjonsnoden
  er den konkrete realiseringen av "rommet"
