Ny mappe ops/ med repeterbare vedlikeholdsjobber: - ryddejobb.md — full prosjektrevisjon - doc-audit.md — docs vs kode - drift-sjekk.md — prod vs lokal vs docs Ny mappe docs/retninger/ med arkitektoniske teser: - status_quo.md — hva Sidelinja er i dag - rom_ikke_forum.md — opplevelse-først, to-lags-modell, administrativ opplevelse - universell_input.md — tre primitiver (input, mottak, kommunikasjon), noder+edges - maskinrommet.md — Rust-orkestrator, edge-drevet ressursorkestrering, CAS+pruning - bruker_ikke_workspace.md — brukeren er sentrum, workspaces er samlings-noder - datalaget.md — PG+Apache AGE, SpacetimeDB som sanntidslag, lagmodell Oppdatert CLAUDE.md og proposals/README.md med referanser. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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 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:
- "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