synops/docs/retninger/universell_input.md
vegard 0a467066ba Synops v2: arkitektur, retninger og dokumentasjon
Nystart basert på arkitektonisk innsikt fra Sidelinja v1.
Koden er ny, visjon og primitiver er validert gjennom tidligere arbeid.

Inneholder:
- Komplett arkitekturdokumentasjon (docs/arkitektur.md)
- 6 vedtatte retninger (docs/retninger/)
- Alle concepts, features, proposals og erfaringer fra v1
- Server-oppsett og drift (docs/setup/)
- LiteLLM-konfigurasjon (API-nøkler via env)
- Editor.svelte referanse fra v1

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 06:43:08 +01:00

14 KiB

Universell input og mottak

Én multimodal input-primitiv. Én personlig mottaksflate. Alt som fanges er samme type objekt. Hva det "er" bestemmes av edges, ikke av tabellen det ligger i. Hvordan det presenteres bestemmes av mottakeren.

Observasjoner

I dag har vi meldingsboksen som "universell primitiv" — men den er egentlig en lagringsprimitiv. Den samler chat, kanban-kort, kalenderoppføringer og notater i én tabell, men input er fortsatt forskjellig per kontekst: chat har ett tekstfelt, kanban har et skjema, kalender har en datovelger. Brukeren velger kontekst først, deretter gir de input.

Og vi har separate pipelines for ulike modaliteter: tekst går én vei, lyd (voice/transkripsjon) en annen, bilder en tredje. Hver med sin egen flyt.

Tesen

Én input-primitiv, to versjoner:

  • Sanntidsversjon — live i SpacetimeDB-laget. Brukes i rom, samarbeid, samtaler. Streamer input og viser resultater i sanntid.
  • Flat versjon — tradisjonelt mot PG. Brukes på bussen, alene, offline-aktig. Fanger input og lagrer asynkront.

Begge aksepterer 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
  • Nettoppslag — lim inn URL, den berikes automatisk
  • Kommunikasjon — samme primitiv for alene (dagbok), en-til-en (melding), gruppe (kanal)

Forskjellen mellom "jeg skriver dagbok", "jeg sender en melding" og "jeg lager et kanban-kort" er ikke hva brukeren gjør — det er hvilke edges som knyttes til resultatet.

Én tabell, edges definerer alt

All output fra input-primitiven lander som noder i kunnskapsgrafen. Én tabell. Ingen messages-tabell, ingen cards-tabell, ingen notes-tabell.

Hva en node "er" bestemmes utelukkende av edges:

  • Node + edge til kanal = chatmelding
  • Node + edge til board + status-edge = kanban-kort
  • Node + edge til dato = kalenderoppføring
  • Node + edge til kun bruker (privat) = dagboknotis
  • Node + edge til topic = faktoid i kunnskapsgrafen
  • Node uten edges = løs tanke, ennå uorganisert

Retyping er trivielt. Å gjøre en chatmelding om til et kanban-kort er å legge til en edge til et board og en status-edge. Fjerne fra chat er å fjerne kanal-edgen. Ingen datamigrering, ingen transformasjon av innhold. Bare edges.

Multitype er naturlig. En node kan være både et kanban-kort og en kalenderoppføring og en faktoid. Det er ikke en edge case — det er arkitekturen.

Implikasjoner

Meldingsboksen erstattes av noe dypere

Meldingsboksen var riktig intuisjon — men den er en lagringsprimitiv som prøver å forene ulike domenemodeller. Universell input + kunnskapsgrafen gjør det renere: det finnes bare noder og edges. "Meldingsboks" blir et view-konsept (hvordan noder vises i en kontekst), ikke et lagrings-konsept.

Input-metode og innholdstype er ortogonale

Du kan snakke inn et kanban-kort. Du kan tegne en kalenderoppføring. Du kan skrive en voice memo (tekst som transkriberes til lyd for en annen bruker). Input-primitiven bryr seg ikke om hva det blir — den fanger det som kommer inn.

Samme input, ulik routing

Lyd inn i input-primitiven kan routes helt forskjellig basert på edges:

  • Edge til et møterom → streames live til andre deltakere (sanntidslaget)
  • Edge til kun deg selv → transkriberes og lagres som personlig notat
  • Edge til en podcast-kanal → goes into produksjonspipeline
  • Edge til en person → sendes som lydmelding

Brukeren gjør det samme — snakker inn i input-feltet. Systemet router basert på kontekst og edges. Det er ingen "møte-app" eller "notat-app" eller "meldings-app" — det er én input med ulike destinasjoner.

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
  • Anna skriver tekst → node med tekst + TTS-versjon
  • Trond har lyd-preferanse → hører TTS-opplesning av Annas tekst

Senderen trenger ikke vite eller bry seg. Innholdet er det samme — presentasjonen er en mottaker-side preferanse. Modalitet er ikke en egenskap ved meldingen, men ved lesningen av den.

Én overflate å perfeksjonere

Brukerens mentale modell kollapser til én ting: input-feltet. All UX-investering konsentreres ett sted i stedet for å smøres tynt utover ti ulike grensesnitt. Én perfekt input-opplevelse — responsiv, multimodal, med god AI-støtte — i stedet for ti middelmådige spesialgrensesnitt.

Dette er en radikal forenkling av utviklingsoverflaten. I stedet for å bygge og vedlikeholde chat-input, kanban-skjema, kalender-dialog, notat-editor, voice-recorder, dagbok-felt — bygger vi ett grensesnitt og investerer alt i å gjøre det feilfritt. Alt etterpå er edges.

Visninger er spørringer mot grafen

Chat-visningen = "vis noder med edge til denne kanalen, sortert på tid." Kanban-visningen = "vis noder med edge til dette boardet, gruppert på status." Kalender-visningen = "vis noder med dato-edge, plassert på tidslinje." Dagbok-visningen = "vis private noder for denne brukeren, sortert på tid."

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

To versjoner passer to-lags-modellen

Sanntidsversjonen lever i SpacetimeDB-laget: input streames, resultater er live, andre ser hva du gjør. Flat versjonen lever i det tradisjonelle laget: input sendes, lagres i PG, ferdig. Begge produserer identiske noder i grafen.

Synlighet er bare en edge

Privat = edge kun til deg. Delt = edge til en gruppe/kanal. Publisert = edge til en offentlig kontekst. Å "dele" noe er å legge til en edge. Å "gjøre privat" er å fjerne den. Innholdet endres aldri.

Universelt mottak — den andre primitiven

Input-primitiven er halvparten. Den andre halvdelen er mottak: hvordan du konsumerer det andre produserer. Der input er "én overflate som fanger alt", er mottak "én overflate som presenterer alt tilpasset deg."

Dimensjoner ved mottak

Format. Lyd, tekst, visuelt — mottaker bestemmer (allerede beskrevet over). Men det gjelder alt, ikke bare meldinger: en AI-oppsummering kan leses eller høres. Et whiteboard-snapshot kan vises som bilde eller som tekstlig beskrivelse.

Filtrering. Hva ser du? Alt fra alle er støy. Mottaksflaten filtrerer basert på dine edges: hvilke kanaler du følger, hvilke personer du samarbeider med, hvilke topics du er interessert i. Du kuraterer ikke manuelt — du justerer edges, og mottaksflaten oppdateres.

Prioritering. Hva er viktig ? En AI-assistert redaksjonell flate som løfter frem det som trenger oppmerksomhet: ubesvarte meldinger, oppgaver med frist, noder som er endret siden sist, tråder med aktivitet. Ikke en notifikasjonsliste — en vektet visning av det som er relevant.

Tempo. Sanntid eller asynkront. I sanntidslaget: ting streamer inn mens de skjer — en kollega snakker, du hører/leser live. I det tradisjonelle laget: du får en digest, en oppsummering, et overblikk over hva som har skjedd siden sist. Samme noder, ulikt tempo.

Kilde. Direkte fra en person, eller via en node. Et møte som genererer innsikter. En AI-jobb som er ferdig. En tråd som har blitt aktiv igjen. En podcast-episode som er klar for review. Kilden trenger ikke være et menneske — det kan være en prosess, en hendelse, en tilstandsendring i grafen.

Mottaksflaten som speilbilde av input

Input Mottak
Én overflate for all input Én overflate for alt mottak
Sender bestemmer ikke format Mottaker bestemmer format
Modalitet er ortogonal Presentasjon er ortogonal
Kontekst gir edges Preferanser gir filtrering
Sanntid + flat versjon Sanntid (stream) + asynkron (digest)

Mange-til-én og mange-via-mange

Mottaksflaten håndterer naturlig:

  • Én-til-én — Trond sender deg en melding
  • Mange-til-én — fem personer i en kanal, du ser alt
  • Via node — et møte genererer et referat, du mottar det
  • Via kjede — en chatmelding → blir oppgave → oppgaven fullføres → du får oppdatering. Hele kjeden er edges, og du ser resultatet i din mottaksflate uten å ha fulgt hvert steg.

Mottaksflaten er også en visning av grafen

Akkurat som chat-visningen er "noder med kanal-edge sortert på tid", er mottaksflaten "noder med edge til meg, vektet på relevans og tid." Det er ikke en egen mekanisme — det er enda en spørring mot samme graf, bare med deg som sentrum.

Kommunikasjonsnoden — den tredje primitiven

Input fanger. Mottak presenterer. Men det mangler noe: stedet der folk møtes. En kommunikasjonsnode er en node i grafen som samler deltakere, definerer tilgangsregler, og fungerer som kontekst for input og mottak.

Én node, mange former

En kommunikasjonsnode er konseptuelt identisk uansett skala:

Variant Deltakere Input-tilgang Mottak-tilgang
Én-til-én samtale 2 Begge Begge
Gruppechat N Alle medlemmer Alle medlemmer
Redaksjonsmøte N Alle medlemmer Alle medlemmer
Allmøte 1 + N Lederen snakker Alle lytter, noen kan rekke opp hånden
Podcastinnspilling 2-4 + N Vertene snakker Alle lytter, markører for produsent
Livesending 1-4 + ∞ Vertene Streamet til nettside/app, lyd eller video
Asynkron gjest 1 + 1 Gjest gir input innen frist Redaksjonen mottar

Forskjellen er ikke ulike systemer — det er ulike edge-konfigurasjoner på samme nodetype:

  • Eier-edge — hvem kontrollerer noden (kan invitere, endre regler, avslutte)
  • Input-edge — hvem kan gi input (snakke, skrive, tegne, dele skjerm)
  • Mottak-edge — hvem kan motta (lytte, lese, se stream)
  • Rolle-edge — spesialroller (moderator, produsent, gjest)

Kommunikasjonsnoden er en kontekst for de andre primitivene

Når du gir input i en kommunikasjonsnode, arver inputen kontekst-edges automatisk. Sier du noe i et møte → noden du skaper får edge til møtet. Du trenger ikke tenke på det — konteksten følger med.

Mottak i en kommunikasjonsnode er det samme som universelt mottak, bare scoped til den noden: du ser/hører det andre deltakere gir som input, presentert etter dine preferanser.

Livssyklus

En kommunikasjonsnode kan være:

  • Live — aktiv i sanntidslaget. Deltakere er til stede, input streames.
  • Asynkron — aktiv i det tradisjonelle laget. Deltakere gir input i eget tempo (chat, asynkron gjest).
  • Avsluttet — arkivert i PG. Alt som ble sagt/delt er noder med edges til kommunikasjonsnoden. Kan søkes, gjenfinnes, refereres.
  • Gjenåpnet — løftet tilbake til sanntidslaget. "Vi tar opp tråden fra forrige møte" er bokstavelig talt å reaktivere en node.

Skalering er en edge-endring, ikke en migrasjonsoperasjon

En samtale mellom to blir et møte ved å legge til flere deltaker-edges. Et møte blir en livesending ved å legge til offentlige mottak-edges. En livesending blir en podcast ved å legge til publiserings-edges på arkivert innhold. Ingen migrering, ingen konvertering — bare edges.

Tekniske forutsetninger

STT (tale → tekst): løst

Faster-whisper kjører lokalt, god norsk kvalitet. Allerede i stacken.

TTS (tekst → tale): løsbart

Norsk TTS lokalt er ikke godt nok ennå (Piper er "usable" men dårlig rytme, XTTS-v2 støtter ikke norsk). Kommersielt er det løst:

  • ElevenLabs — beste kvalitet, eksplisitt norsk med regionale aksenter
  • Azure Neural TTS — god kvalitet, ~$15/M tegn
  • Google Cloud TTS — god kvalitet, WaveNet/Neural2

Strategi: start med kommersiell API (ElevenLabs) bak AI Gateway, bytt til lokal modell (Chatterbox Multilingual el.l.) når kvaliteten er god nok. Brukeren merker ingenting — det er en backend-swap bak gatewayen. Samme mønster som Whisper: tung jobb → jobbkø → worker → resultat som node-metadata.

Følg med på: Chatterbox Multilingual (Resemble AI) — annonsert norsk støtte, 350M params, lovende for lokal kjøring.

Spenninger og åpne spørsmål

  • Ytelse. Én tabell med alt i — skalerer det? PG med riktige indekser og partisjonering håndterer mye, men det er en reell designbeslutning.
  • Skjema. Noder trenger noe felles skjema (innhold, created_at, author). Men ulike modaliteter har ulike metadata (transkripsjon, bildestørrelse, varighet). Hva er felles og hva er edge-metadata?
  • AI-klassifisering. Når brukeren bare "sier noe" — hvem bestemmer hvilke edges som knyttes? Manuelt? AI-foreslått? Kontekstbasert (sa det i en kanal → kanal-edge)? Sannsynligvis en blanding, men det krever gjennomtenkt UX.
  • Migrering. Meldingsboksen har allerede innhold. Kan vi migrere til node+edge-modellen gradvis, eller er det et brudd?
  • Kompleksitet for utviklere. "Alt er noder og edges" er konseptuelt rent, men å bygge en kanban-visning som spørrer en graf er mer komplekst enn å lese fra en cards-tabell. Er abstraksjonen verdt kompleksiteten?

Tre primitiver, én graf

Primitiv Hva den gjør Brukerens opplevelse
Input Fanger alt — tekst, lyd, bilde, AI Én overflate å snakke/skrive/tegne i
Mottak Presenterer alt tilpasset deg Én personlig flate med det som er relevant
Kommunikasjon Samler folk med tilgangsregler Et sted å være — samtale, møte, sending

Alt er noder og edges i samme graf. Input skaper noder. Mottak spør grafen med deg som sentrum. Kommunikasjonsnoder gir kontekst og tilgangsregler. Visninger (chat, kanban, kalender, dagbok, stream) er bare spørringer med ulike filtre.

Forhold til andre retninger

Denne retningen konkretiserer rom, ikke forum:

  • "Formløs input, struktur etterpå" → universell input + edges
  • "To lag" → sanntidsversjon + flat versjon
  • "Privat/delt som lag" → synlighet som edge
  • "Siloer forsvinner" → alt er noder, visninger er spørringer
  • "Rommet som primitiv" → kommunikasjonsnoden