Rydder opp siste «v2»-referanser i docs (status_quo, migration_safety, personlig_workspace, spacetimedb_integrasjon). Legger til editor-seksjon i universell_input.md (TipTap, presets, tekstlagring) og oppdaterer nodes.md med content/metadata.document-modellen. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
260 lines
8.6 KiB
Markdown
260 lines
8.6 KiB
Markdown
# 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 med overskrifter, bilder
|
|
og blockquotes i chatten. Om du vil publisere den etterpå er det
|
|
bare å legge til en publiserings-edge. Innholdet er det samme.
|
|
|
|
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
|
|
|
|
**Retyping er trivielt.** Chatmelding → kanban-kort = legg til
|
|
board-edge og status-edge. Ingen datamigrering, bare edges.
|
|
|
|
**Multitype er naturlig.** En node kan være *både* kanban-kort
|
|
*og* kalenderoppføring *og* faktoid. Det er ikke en edge case —
|
|
det er arkitekturen.
|
|
|
|
### 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.
|
|
Du tagger noe. Du setter en dato.
|
|
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"
|