# 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 *nå*? 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](rom_ikke_forum.md): - "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