# Traits — Evner og funksjonalitet for noder **Status:** Vedtatt ## Konsept En **trait** er en navngitt evne som beriker en samlingsnode med spesifikk funksjonalitet. Traits bestemmer hva en samling *kan gjøre* — hvilke UI-komponenter som vises i frontend og hvilken backend-oppførsel maskinrommet aktiverer. Traits er mekanismen som gjør at én og samme node-/edge-arkitektur kan fungere som nettmagasin, podcaststudio, diskusjonsklubb, wiki, eller en kombinasjon av flere. ## Designprinsipper 1. **Komposisjon, ikke typer.** En samling er ikke "et magasin" — den har traits som *gjør den til* et magasin. Legg til eller fjern traits når som helst uten migrasjon. 2. **Traits i metadata, ikke edges.** Traits er egenskaper ved samlingen, ikke relasjoner mellom entiteter. Edges er for relasjoner (innhold → samling). Metadata er for konfigurasjon (hva samlingen kan gjøre). 3. **Lukket katalog, åpen konfigurasjon.** Trait-navn er et kjent sett vi eier koden for. Konfigurasjonen innenfor hver trait er fleksibel JSONB. 4. **Uavhengige traits.** Hver trait fungerer alene. Verdien oppstår i sammensetningen — og det er brukeren som setter sammen, ikke utvikleren. 5. **To effekter per trait.** Hver trait aktiverer: - **Frontend:** UI-komponenter, visninger, interaksjoner - **Backend:** Maskinrommet-oppførsel, validering, jobb-triggering ## Metadata-struktur Traits lever i samlingsnodenes `metadata.traits`-objekt: ```jsonc { "node_kind": "collection", "title": "Sidelinja Magasin", "metadata": { "traits": { "publishing": { "slug": "sidelinja", "custom_domain": "magasin.sidelinja.org", "theme": "editorial", "open_graph_defaults": { "image": "cas://sha256-abc123" } }, "editor": { "preset": "longform", "allow_collaborators": true }, "rss": { "format": "atom", "title": "Sidelinja Magasin", "max_items": 50 }, "comments": { "moderation": "pre-approve", "anonymous": false } } } } ``` Fravær av en trait betyr at funksjonaliteten er deaktivert. Ingen boolean `enabled`-flagg — traiten finnes eller finnes ikke. ## Trait-katalog ### Innhold & redigering | Trait | Frontend | Backend | |---|---|---| | `editor` | TipTap med presets (longform, note, chat, code) | Validering av dokumentstruktur | | `versioning` | Revisjonshistorikk, diff, rollback-knapp | Snapshot ved signifikante endringer | | `collaboration` | Samtidig redigering, markører, inline-kommentarer | OT/CRDT via STDB | | `translation` | Språkvelger, side-ved-side-visning | AI-oversettelse via jobbkø | | `templates` | Mal-velger ved ny node | Mal-noder i samlingen | ### Publisering & distribusjon | Trait | Frontend | Backend | |---|---|---| | `publishing` | Publiseringsknapp, forhåndsvisning, URL-visning, SEO-editor | HTML-rendering til CAS, Caddy-ruting, OG-tags | | `rss` | Feed-URL synlig i UI | Feed-generering ved publisering | | `newsletter` | Abonnentliste, utsendingsknapp, forhåndsvisning | E-postutsending ved publisering | | `custom_domain` | Domene-innstilling i admin | Caddy on-demand TLS, DNS-validering | | `analytics` | Besøksstatistikk-dashbord | Logg-parsing, IAB-filtrering | | `embed` | Kopier embed-kode-knapp | Generer iframe-snippet med riktige dimensjoner | | `api` | API-dokumentasjon, nøkkelhåndtering | Offentlig JSON-endepunkt for samlingens innhold | ### Lyd & video | Trait | Frontend | Backend | |---|---|---| | `podcast` | Episodeliste, lydavspiller, RSS-lenke | RSS med enclosures, metadata-håndtering | | `recording` | LiveKit-studio, opptak-kontroller | LiveKit-rom, lydkonsolidering | | `transcription` | Transkripsjonsvisning, redigerbar SRT | Whisper-pipeline via jobbkø | | `tts` | "Les opp"-knapp, lydversjon av artikler | Tekst-til-tale via jobbkø | | `clips` | Klipp-editor, segment-markering | Segmentering, CAS-lagring av klipp | | `playlist` | Ordnet avspillingsliste, drag-and-drop rekkefølge | Sekvensiell avspilling | | `mixer` | Lydmixer: volumslidere, mute, VU-meter, sound pads, stemme-/EQ-effekter | Pad-konfig i metadata (se `docs/features/lydmixer.md`) | | `studio` | Lydstudio-panel: lydfilliste med metadata, drag-ut, drop-aksept for lyd, lenke til fullverdig editor | Validering av lydformat, FFmpeg-pipeline via jobbkø (se `docs/features/lydstudio.md`) | ### Kommunikasjon | Trait | Frontend | Backend | |---|---|---| | `chat` | Sanntidsmeldinger, tråder, reaksjoner | STDB-synk, TTL-håndtering | | `forum` | Trådet diskusjon, sortering (nyeste/populære/ubesvarte) | Tråd-indeksering | | `comments` | Kommentarfelt under publisert innhold | Moderasjonskø, evt. anonym input | | `guest_input` | Gjeste-lenke-generering, svar-oversikt | Token-generering, CAS-upload, rate limiting | | `announcements` | Enveis-feed, kun eiere/admins poster | Skrivetilgangsvalidering | | `polls` | Avstemnings-UI, resultatvisning | Stemmetelling, duplikatdeteksjon | | `qa` | Spørsmål/svar-format, oppstemming, "godkjent svar" | Sortering, markering | ### Organisering | Trait | Frontend | Backend | |---|---|---| | `kanban` | Board med kolonner, drag-and-drop | Statusoverganger, posisjonsberegning | | `calendar` | Kalendervisning (måned/uke/dag) | Scheduling-edges, ICS-eksport | | `timeline` | Kronologisk visning | Tidsbasert sortering og filtrering | | `table` | Strukturert tabellvisning, filtrerbare kolonner | Metadata-indeksering | | `gallery` | Rutenett av bilde-/medianoder | Thumbnail-generering | | `bookmarks` | Kuratert lenkesamling med forhåndsvisning | URL-enrichment via maskinrommet | | `tags` | Tagging, filtrering, tag-sky | Tag-indeksering | ### Kunnskap | Trait | Frontend | Backend | |---|---|---| | `knowledge_graph` | Visuell graf, auto-tagging | NER, embedding-generering | | `wiki` | Slug-baserte sider, kryssreferanser, "finnes ikke ennå"-lenker | Slug-unikhet, backlink-indeks | | `glossary` | Begrepsliste, hover-definisjoner i annet innhold | Begrep-matching i tekst | | `faq` | Spørsmål/svar-par med søk | Søkeindeksering | | `bibliography` | Kildehenvisninger, siteringsformat, referanseliste | Sitats-parsing, DOI-oppslag | ### Automatisering & AI | Trait | Frontend | Backend | |---|---|---| | `auto_tag` | Foreslåtte tags ved ny node, godkjenn/avvis | AI-tagging via jobbkø | | `auto_summarize` | AI-sammendrag synlig, redigerbart | Sammendrag-generering ved publisering/møteslutt | | `digest` | Periodisk oppsummering i UI | AI-sammendrag av aktivitet på intervall | | `bridge` | "Også funnet i..."-forslag | pgvector-embedding, krysskontekst-søk | | `moderation` | Moderasjonskø, flagging | AI-assistert innholdsvurdering | | `ai_tool` | AI-verktøy-panel med prompt-velger, drag-and-drop tekstbehandling | Modellprofil-mapping, AI Gateway, ai_usage_log (se `docs/features/ai_verktoy.md`) | ### Tilgang & fellesskap | Trait | Frontend | Backend | |---|---|---| | `membership` | Søknads-/innmeldingsknapp | Søknadskø, godkjenningsflyt | | `roles` | Rolletildeling i admin | Egendefinerte roller utover owner/admin/member/reader | | `invites` | Invitasjonslenker med kopiering | Token-generering, utløp, maks bruk | | `paywall` | Betalingsflyt, tilgangskontroll | Stripe/Vipps-integrasjon | | `directory` | Medlemsoversikt med profiler | Profilindeksering | ### Ekstern integrasjon | Trait | Frontend | Backend | |---|---|---| | `webhook` | Webhook-konfigurasjon i admin | HTTP-varsling ved hendelser | | `import` | Import-veiviser (WordPress, Markdown, RSS) | Parsing, node-opprettelse, mediaimport | | `export` | Eksport-knapp (Markdown, EPUB, PDF) | Format-konvertering, CAS-pakking | | `ical_sync` | Kalender-URL, synk-status | Toveis ICS-synk | ## Pakker Pakker er forhåndsdefinerte kombinasjoner av traits med fornuftige defaults. En pakke er *ikke* en type eller en låst konfigurasjon — den er et startpunkt. Brukeren kan legge til eller fjerne traits etterpå. | Pakke | Traits | |---|---| | **Nettmagasin** | editor(longform), publishing, rss, comments, analytics, custom_domain, newsletter | | **Podcaststudio** | podcast, recording, transcription, mixer, editor(shownotes), rss, analytics, clips, knowledge_graph | | **Nyhetsbrev** | editor(longform), newsletter, analytics, versioning | | **Wiki** | wiki, editor(longform), collaboration, versioning, knowledge_graph, glossary | | **Diskusjonsklubb** | forum, chat, polls, membership, roles, directory | | **Kursplattform** | editor(longform), playlist, qa, membership, paywall, templates | | **Møteplass** | recording, mixer, chat, kanban, calendar, auto_summarize, guest_input | | **Fotoblogg** | gallery, publishing, comments, custom_domain, rss | | **Prosjektstyring** | kanban, calendar, chat, table, tags, roles | | **Åpen forskning** | editor(longform), versioning, bibliography, publishing, comments, collaboration, api | | **Community radio** | recording, mixer, podcast, chat, polls, membership, clips, playlist | | **Bokmerke-vegg** | bookmarks, tags, publishing, rss, comments | | **Redaksjon** | chat, kanban, calendar, editor(longform), knowledge_graph, guest_input | ## Implementeringsstrategi Traits implementeres én og én, ikke alle samtidig. Prioritering følger brukerbehovene til Sidelinja som første tenant. En trait krever: 1. **Spesifikasjon** — hva traiten gjør, metadata-skjema, UI-mockup 2. **Backend** — maskinrommet-kode som reagerer på traitens tilstedeværelse 3. **Frontend** — Svelte-komponent(er) som rendres når traiten er aktiv 4. **Dokumentasjon** — oppdater denne filen og evt. `docs/features/` Rekkefølge for første bolk (Sidelinja-behov): `editor` → `chat` → `publishing` → `rss` → `podcast` → `recording` → `transcription` → `knowledge_graph` → `kanban` → `calendar`