Implementert fullstendig epost-mottak pipeline: - Parser raw RFC 5322 epost fra stdin via mailparse - Sjekk 1: Envelope-sender matches auth_identities.email (case-insensitive) - Sjekk 2: Body starter med konfigurerbar aktiveringsfrase (default: "Kjære vaktmester") - Begge sjekker må bestå — ellers forkastes eposten stille (exit 0, ingen bounce) - Ved match: oppretter content-node med visibility=hidden, created_by=bruker - Metadata lagrer source=email, from, to, subject for sporbarhet - UTF-8 håndtering: prøver raw bytes som UTF-8 først, faller tilbake til mailparse charset - Aktiveringsfrase konfigurerbar via --phrase eller SYNOPS_MAIL_PHRASE env
438 lines
43 KiB
Markdown
438 lines
43 KiB
Markdown
# Synops — Implementeringsoppgaver
|
||
|
||
Sekvensiell liste. Hver oppgave gjøres i én Claude Code-sesjon.
|
||
Runner-scriptet plukker første ugjorte oppgave som ikke er blokkert.
|
||
|
||
## Statuser
|
||
|
||
- `- [ ]` — Klar til å gjøres
|
||
- `- [~]` — Pågår. En agent jobber på denne. Andre agenter hopper over.
|
||
- `- [x]` — Ferdig
|
||
- `- [?]` — Åpent spørsmål, trenger avklaring fra Vegard.
|
||
- `- [!]` — Blokkert av teknisk problem.
|
||
|
||
`[~]`, `[?]` og `[!]` blokkerer alle oppgaver som avhenger av denne.
|
||
Detaljer skrives som innrykket tekst med `>` prefix under oppgaven.
|
||
Runner-scriptet legger automatisk til `> Påbegynt: <timestamp>` for `[~]`.
|
||
|
||
Hvis en `[~]`-oppgave har stått i >60 min uten commit, anta at
|
||
sesjonen krasjet. Kjør `run-next-task.sh --unstale` for å frigjøre.
|
||
|
||
## Avhengigheter
|
||
|
||
Oppgaver innen en fase er sekvensielle (1.1 før 1.2, osv).
|
||
Faser avhenger av hverandre slik:
|
||
|
||
```
|
||
Fase 1 (infra) → Fase 2 (maskinrommet) → Fase 3 (frontend)
|
||
↘ Fase 4 (tilgang)
|
||
Fase 3 + 4 → Fase 5 (kommunikasjon)
|
||
Fase 2 → Fase 6 (CAS) → Fase 7 (lyd)
|
||
Fase 5 → Fase 8 (aliaser)
|
||
Fase 3 → Fase 9 (visninger)
|
||
Fase 2 → Fase 10 (AI)
|
||
Fase 5 + 6 + 7 → Fase 11 (produksjon)
|
||
Fase 3 + 4 → Fase 13 (traits)
|
||
Fase 6 + 13 → Fase 14 (publisering)
|
||
Fase 3 + 10 → Fase 15 (adminpanel)
|
||
Fase 11 + 13 → Fase 16 (lydmixer)
|
||
Fase 17 (lydstudio-utbedring) — ingen avhengigheter, kan kjøres parallelt
|
||
Fase 10 + 13 → Fase 18 (AI-verktøy)
|
||
Fase 3 + 13 → Fase 19 (arbeidsflaten — spatial canvas)
|
||
Fase 19 → Fase 20 (universell overføring + panelrework)
|
||
Fase 2 → Fase 21 (CLI-verktøy — unix-filosofi)
|
||
Alt → Fase 12 (herding)
|
||
Fase 12 → Fase 22 (SpacetimeDB-migrering — fullført)
|
||
Fase 22 → Fase 23 (validering — alle faser)
|
||
Fase 23 → Fase 24 (orkestrering)
|
||
Fase 24 → Fase 25 (web clipper)
|
||
Fase 25 → Fase 26 (epost)
|
||
Fase 25 → Fase 27 (tankekart) — uavhengig av epost
|
||
Fase 25 → Fase 28 (manglende CLI + AI-ruting) — uavhengig av epost
|
||
Fase 25 → Fase 29 (universell input) — uavhengig av epost
|
||
Fase 25 → Fase 30 (podcast-hosting) — uavhengig av epost
|
||
```
|
||
|
||
Hvis en oppgave er `[?]` eller `[!]`, hoppes den over — og alle
|
||
oppgaver som avhenger av den (innen fasen + avhengige faser).
|
||
Uavhengige faser kan fortsatt plukkes.
|
||
|
||
---
|
||
|
||
## Fase 1: Infrastruktur-fundament
|
||
|
||
- [x] 1.1 PostgreSQL schema: opprett database `synops`, enums (`visibility`, `access_level`), tabeller (`nodes`, `edges`, `node_access`, `auth_identities`) med indekser. Kjør på server via SSH. Ref: `docs/primitiver/nodes.md`, `docs/primitiver/edges.md`, `docs/retninger/bruker_ikke_workspace.md`.
|
||
- [x] 1.2 Seed-data: opprett Vegards brukernode (`node_kind='person'`, `title='Vegard'`) og `auth_identities`-rad. Opprett Sidelinja samlings-node og `owner`-edge fra Vegard.
|
||
- [x] 1.3 SpacetimeDB modul: opprett Rust-modul med `nodes` og `edges`-tabeller som speiler PG-skjema. Grunnleggende reducers for CRUD. Deploy til server. Ref: `docs/retninger/datalaget.md`, `docs/erfaringer/spacetimedb_integrasjon.md`.
|
||
- [x] 1.4 Caddy-config: reverse proxy for maskinrommet (api.sidelinja.org), SpacetimeDB, og SvelteKit. Auto-TLS. Ref: `docs/setup/produksjon.md`.
|
||
- [x] 1.5 Authentik: opprett OIDC-provider og applikasjon for Synops. Konfigurer redirect URIs. Ref: `docs/erfaringer/authentik_oppsett.md`.
|
||
|
||
## Fase 2: Maskinrommet — skjelett
|
||
|
||
- [x] 2.1 Rust-prosjekt: opprett `maskinrommet/` med axum, tokio, sqlx (PG), serde. Dockerfile. Kompilerer og starter. Ref: `docs/retninger/maskinrommet.md`.
|
||
- [x] 2.2 Auth-middleware: valider Authentik JWT-tokens, slå opp `auth_identities` → node_id. Returner 401 for ugyldige tokens.
|
||
- [x] 2.3 SpacetimeDB-klient i maskinrommet: koble til STDB, skriv noder og edges via reducers.
|
||
- [x] 2.4 Skrivestien: `POST /intentions/create_node` — valider, skriv STDB (instant), spawn async PG-skriving. Returner node_id umiddelbart.
|
||
- [x] 2.5 Flere intensjoner: `create_edge`, `update_node`, `delete_node`. Validering av tilgang (created_by eller owner/admin-edge).
|
||
- [x] 2.6 Docker Compose: legg maskinrommet inn i server-stacken. Intern nettverkstilgang til PG og STDB.
|
||
|
||
## Fase 3: Frontend — skjelett
|
||
|
||
- [x] 3.1 SvelteKit-prosjekt: opprett `frontend/` med TypeScript, TailwindCSS. PWA-manifest. Lokal dev med HMR.
|
||
- [x] 3.2 Authentik login: OIDC-flow (authorization code + PKCE). Session-håndtering. Redirect til login ved 401.
|
||
- [x] 3.3 STDB WebSocket-klient: abonner på noder og edges. Reaktiv Svelte-store som oppdateres ved endringer.
|
||
- [x] 3.4 Mottaksflaten v0: vis noder med edge til innlogget bruker, sortert på `created_at`. Enkel liste med tittel og utdrag.
|
||
- [x] 3.5 TipTap-editor: enkel preset (tekst, markdown, lenker). Send `create_node`-intensjon til maskinrommet ved submit.
|
||
- [x] 3.6 Sanntidstest: åpne to faner, skriv i én, se noden dukke opp i den andre via STDB.
|
||
|
||
## Fase 4: Tilgangskontroll
|
||
|
||
- [x] 4.1 `recompute_access` i maskinrommet: ved edge-endring, oppdater `node_access`-matrisen. Håndter direkte edges (owner, admin, member, reader).
|
||
- [x] 4.2 Team-transitivitet: member_of-edge til team → arv tilgang fra teamets edges.
|
||
- [x] 4.3 Visibility-filtrering: STDB-spørringer respekterer visibility-enum. Frontend ser bare noder brukeren har tilgang til.
|
||
- [x] 4.4 RLS-policies på PG: `node_access`-basert filtrering for tunge spørringer.
|
||
|
||
## Fase 5: Kommunikasjonsnoder
|
||
|
||
- [x] 5.1 Opprett kommunikasjonsnode: intensjon `create_communication` → node med `node_kind='communication'`, deltaker-edges, metadata (started_at).
|
||
- [x] 5.2 Kontekst-arv: input i kommunikasjonsnode → automatisk `belongs_to`-edge.
|
||
- [x] 5.3 Chat-visning i frontend: noder med `belongs_to`-edge til kommunikasjonsnode, sortert på tid, sanntid via STDB.
|
||
- [x] 5.4 Én-til-én chat: opprett kommunikasjonsnode med to deltakere. Full loop: skriv melding → vis i sanntid hos begge.
|
||
|
||
## Fase 6: CAS og mediefiler
|
||
|
||
- [x] 6.1 CAS-lagring: filsystem med content-addressable hashing (SHA-256). Katalogstruktur med hash-prefix. Deduplisering.
|
||
- [x] 6.2 Upload-endepunkt: `POST /intentions/upload_media` → hash fil, lagre i CAS, opprett media-node med `has_media`-edge.
|
||
- [x] 6.3 Serving: `GET /cas/{hash}` → stream fil fra disk. Caddy kan serve direkte for ytelse.
|
||
- [x] 6.4 Bilder i TipTap: drag-and-drop/paste → upload → CAS-node → inline i `metadata.document` via `node_id`.
|
||
|
||
## Fase 7: Lyd-pipeline
|
||
|
||
- [x] 7.1 faster-whisper oppsett: Docker-container, GPU hvis tilgjengelig, norsk modell. Ref: `docs/erfaringer/`.
|
||
- [x] 7.2 Transkripsjons-pipeline: lydfil i CAS → maskinrommet trigger Whisper → resultat i `content`-feltet.
|
||
- [x] 7.3 Voice memo i frontend: opptak-knapp i input-komponenten → upload → CAS → transkripsjon.
|
||
- [x] 7.4 Lyd-avspilling: spiller av original lyd fra CAS-node. Waveform-visning.
|
||
- [x] 7.5 Segmenttabell-migrasjon: opprett `transcription_segments`-tabell i PG. Oppdater `transcribe.rs` til SRT-format → parse → skriv segmenter. Miljøvariabler: `WHISPER_MODEL` (default "medium"), `WHISPER_INITIAL_PROMPT`. Ref: `docs/concepts/podcastfabrikken.md` § 3.
|
||
- [x] 7.6 Transkripsjonsvisning i frontend: segmenter med tidsstempler, avspillingsknapp per segment (hopper til riktig sted i lydfilen), redigerbare tekstfelt (setter `edited = true`). Universell komponent for podcast, møter, voice memos.
|
||
- [x] 7.7 Re-transkripsjonsflyt: ved ny transkripsjon, vis side-om-side med forrige versjon. Highlight manuelt redigerte segmenter fra forrige versjon. Bruker velger per segment.
|
||
- [x] 7.8 SRT-eksport: generer nedlastbar SRT-fil fra `transcription_segments`-tabellen.
|
||
|
||
## Fase 8: Aliaser
|
||
|
||
- [x] 8.1 Alias-noder: opprett alias-node med `alias`-edge (system=true) fra hovednoden. Usynlig for traversering.
|
||
- [x] 8.2 Kontekstbasert identitet: maskinrommet setter `created_by` til alias-node når brukeren opererer i kontekst der aliaset er vert/deltaker.
|
||
|
||
## Fase 9: Flere visninger
|
||
|
||
- [x] 9.1 Kanban-visning: noder med board-edge, gruppert på status-edge. Drag-and-drop for statusendring.
|
||
- [x] 9.2 Kalender-visning: noder med `scheduled`-edge, på tidslinje.
|
||
- [x] 9.3 Dagbok-visning: private noder (ingen delte edges), sortert på tid.
|
||
- [x] 9.4 Kunnskapsgraf: topic-noder, `mentions`-edges. Visuell graf-visning.
|
||
|
||
## Fase 10: AI og beriking
|
||
|
||
- [x] 10.1 LiteLLM oppsett: Docker-container, API-nøkler, modell-routing. Ref: `docs/infra/ai_gateway.md`.
|
||
- [x] 10.2 AI-foreslåtte edges: maskinrommet sender innhold til LLM → foreslår mentions, topics.
|
||
- [x] 10.3 Oppsummering: kommunikasjonsnode → AI-generert sammendrag som ny node.
|
||
- [x] 10.4 TTS: tekst → lyd via ElevenLabs. Mottaker-preferanse i metadata.
|
||
|
||
## Fase 11: Produksjons-pipeline
|
||
|
||
- [x] 11.1 LiveKit oppsett: Docker-container for WebRTC. Ref: `docs/setup/produksjon.md`.
|
||
- [x] 11.2 Sanntidslyd: kommunikasjonsnode med live-status → LiveKit-rom for deltakere.
|
||
- [x] 11.3 Pruning-logikk: TTL per modalitet, signaler som forlenger levetid, disk-nødventil.
|
||
- [x] 11.4 Podcast-RSS: samlings-node med publiserings-edges → generert RSS-feed.
|
||
|
||
## Fase 13: Trait-system
|
||
|
||
- [x] 13.1 Trait-metadata på samlingsnoder: maskinrommet validerer `metadata.traits`-objektet ved `create_node` og `update_node` for samlingsnoder. Avvis ukjente trait-navn. Ref: `docs/primitiver/traits.md`.
|
||
- [x] 13.2 Trait-aware frontend: samlingssider leser `traits` fra metadata og rendrer kun aktive komponenter. Dynamisk komponent-lasting basert på trait-liste.
|
||
- [x] 13.3 Pakkevelger: UI for å opprette ny samling med forhåndsdefinert pakke (nettmagasin, podcaststudio, redaksjon osv.) eller manuelt valg av traits.
|
||
- [x] 13.4 Trait-administrasjon: admin-UI for å legge til/fjerne traits på eksisterende samlinger med konfigurasjon per trait.
|
||
|
||
## Fase 14: Publisering
|
||
|
||
- [x] 14.1 Tera-templates: innebygde temaer (avis, magasin, blogg, tidsskrift) med Tera i Rust. Artikkelmal + forside-mal per tema. CSS-variabler for theme_config-overstyring. Ref: `docs/concepts/publisering.md` § "Temaer".
|
||
- [x] 14.2 HTML-rendering av enkeltartikler: maskinrommet rendrer `metadata.document` til HTML via Tera, lagrer i CAS. Noden får `metadata.rendered.html_hash` + `renderer_version`. SEO-metadata (OG-tags, canonical, JSON-LD).
|
||
- [x] 14.3 Forside-rendering: maskinrommet spør PG for hero/featured/strøm (tre indekserte spørringer), appliserer tema-template, rendrer til CAS (statisk modus) eller serverer med in-memory cache (dynamisk modus). `index_mode` og `index_cache_ttl` i trait-konfig.
|
||
- [x] 14.4 Caddy-ruting for synops.no/pub: Caddy reverse-proxyer til maskinrommet som gjør slug→hash-oppslag og streamer CAS-fil. `Cache-Control: immutable` for artikler. Kategori/arkiv/søk serveres dynamisk av maskinrommet med kortere cache-TTL.
|
||
- [x] 14.5 Slot-håndtering i maskinrommet: `slot` og `slot_order` i `belongs_to`-edge metadata. Ved ny hero → gammel hero flyttes til strøm. Ved featured over `featured_max` → FIFO tilbake til strøm. `pinned`-flagg forhindrer automatisk fjerning.
|
||
- [x] 14.6 Forside-admin i frontend: visuell editor for hero/featured/strøm. Drag-and-drop mellom plasser. Pin-knapp. Forhåndsvisning. Oppdaterer edge-metadata via maskinrommet.
|
||
- [x] 14.7 Publiseringsflyt i frontend (personlig): publiseringsknapp på noder i samlinger med `publishing`-trait der `require_approval: false`. Forhåndsvisning, slug-editor, bekreftelse. Avpublisering ved fjerning av edge.
|
||
- [x] 14.8 RSS/Atom-feed: samling med `rss`-trait genererer feed automatisk ved publisering/avpublisering. `synops.no/pub/{slug}/feed.xml`. Maks `rss_max_items` (default 50).
|
||
- [x] 14.9 Custom domains: bruker registrerer domene i `publishing`-trait. Maskinrommet validerer DNS, Caddy on-demand TLS med validerings-callback. Re-rendring med riktig canonical URL.
|
||
- [x] 14.10 Redaksjonell innsending: `submitted_to`-edge med status-metadata (`pending`, `in_review`, `revision_requested`, `rejected`, `approved`). Maskinrommet validerer at kun roller i `submission_roles` kan opprette `submitted_to`, og kun owner/admin kan endre status eller opprette `belongs_to`. Ref: `docs/concepts/publisering.md` § "Innsending".
|
||
- [x] 14.11 Redaktørens arbeidsflate: frontend-visning av noder med `submitted_to`-edge til samling, gruppert på status. Kanban-stil drag-and-drop for statusendring. Siste kolonne ("Planlagt") setter `publish_at` i edge-metadata.
|
||
- [x] 14.12 Planlagt publisering: maskinrommet sjekker periodisk (cron/intervall) for `belongs_to`-edges med `publish_at` i fortiden som ikke er rendret. Ved treff: render HTML → CAS → oppdater RSS.
|
||
- [x] 14.13 Redaksjonell samtale: ved innsending kan redaktør opprette kommunikasjonsnode knyttet til artikkel + forfatter for diskusjon/feedback utover kort notat i edge-metadata.
|
||
- [x] 14.14 Bulk re-rendering: batch-jobb via jobbkø ved temaendring. Paginert (100 artikler om gangen), oppdaterer `renderer_version`. Artikler serveres med gammelt tema til re-rendret.
|
||
- [x] 14.15 Dynamiske sider: kategori-sider (filtrert på tag-edges), arkiv (kronologisk med månedsgruppering), søk (PG fulltekst). Alle paginerte, cachet i maskinrommet. Om-side som statisk CAS-node.
|
||
- [x] 14.16 Presentasjonselementer som noder: publisert tittel, ingress, OG-bilde, undertittel er egne noder med `title`/`summary`/`og_image`-edges til artikkelen. Frontend for å opprette/redigere varianter. Ref: `docs/concepts/publisering.md` § "Presentasjonselementer".
|
||
- [x] 14.17 A/B-testing: maskinrommet roterer varianter ved forside-rendering, logger impressions/klikk per variant, normaliserer CTR mot tidspunkt-baseline. Etter statistisk signifikans markeres vinner. Redaktør kan overstyre. Edge-metadata: `ab_status`, `impressions`, `clicks`, `ctr`.
|
||
|
||
## Fase 15: Adminpanel
|
||
|
||
- [x] 15.1 Systemvarsler: varslingsnode (`node_kind='system_announcement'`) med type (info/warning/critical), nedtelling og utløp. Frontend viser banner/toast for alle aktive klienter via STDB. Ref: `docs/concepts/adminpanelet.md`.
|
||
- [x] 15.2 Graceful shutdown: admin setter vedlikeholdstidspunkt → nedtelling i frontend → nye LiveKit-rom blokkeres → jobbkø stopper → vent på aktive jobber → restart. Vis aktive sesjoner før bekreftelse.
|
||
- [x] 15.3 Jobbkø-oversikt: admin-UI for aktive, ventende og feilede jobber. Filtrer på type/samling/status. Manuell retry og avbryt.
|
||
- [x] 15.4 AI Gateway-konfigurasjon: admin-UI for modelloversikt, API-nøkler (kryptert), ruting-regler per jobbtype, fallback-kjeder, forbruksoversikt per samling. Ref: `docs/infra/ai_gateway.md`.
|
||
- [x] 15.5 Ressursstyring: prioritetsregler mellom jobbtyper, ressursgrenser per worker, ressurs-governor for automatisk nedprioritering under aktive LiveKit-sesjoner, disk-status med varsling.
|
||
- [x] 15.6 Serverhelse-dashboard: tjeneste-status (PG, STDB, Caddy, Authentik, LiteLLM, Whisper, LiveKit), metrikker (CPU, minne, disk), backup-status, logg-tilgang.
|
||
- [x] 15.7 Ressursforbruk-logging: `resource_usage_log`-tabell i PG. Maskinrommet logger AI-tokens (inn/ut, modellnivå), Whisper-tid (sek), TTS-tegn, CAS-lagring (bytes), LiveKit-tid (deltaker-min). Båndbredde via Caddy-logg-parsing. Ref: `docs/features/ressursforbruk.md`.
|
||
- [x] 15.8 Forbruksoversikt i admin: aggregert visning per samling, per ressurstype, per tidsperiode. Drill-down til jobbtype og modellnivå.
|
||
- [x] 15.9 Brukersynlig forbruk: hver bruker ser eget forbruk i profil/innstillinger. Per-node forbruk synlig i node-detaljer for eiere.
|
||
|
||
## Fase 16: Lydmixer
|
||
|
||
Ref: `docs/features/lydmixer.md`
|
||
|
||
- [x] 16.1 LiveKit-klient i frontend: installer `livekit-client`, koble til rom, vis deltakerliste. Deaktiver LiveKit sin auto-attach av `<audio>`-elementer — lyd rutes gjennom Web Audio API i stedet.
|
||
- [x] 16.2 Web Audio mixer-graf: opprett `AudioContext`, `MediaStreamSourceNode` per remote track → per-kanal `GainNode` → master `GainNode` → `destination`. `AnalyserNode` per kanal for VU-meter.
|
||
- [x] 16.3 Mixer-UI (MixerTrait-komponent): kanalstripe per deltaker med volumslider (0–150%), nød-mute-knapp (stor, rød), VU-meter (canvas/CSS), navnelabel. Master-fader og master-mute. Responsivt design (mobil: kompakt fader-modus).
|
||
- [x] 16.4 Delt mixer-kontroll via SpacetimeDB: `MixerChannel`-tabell + reducers (`set_gain`, `set_mute`, `toggle_effect`). Frontend abonnerer og oppdaterer Web Audio-graf ved endring fra andre deltakere. Visuell feedback (sliders beveger seg i sanntid). Tilgangskontroll: eier/admin kan sette deltaker til viewer-modus.
|
||
- [x] 16.5 Sound pads: pad-grid UI (4×2), forhåndslast lydfiler fra CAS til `AudioBuffer`. Avspilling ved trykk (`AudioBufferSourceNode`). Pad-konfig i `metadata.mixer.pads` (label, farge, cas_hash). Synkronisert avspilling via LiveKit Data Message.
|
||
- [x] 16.6 EQ-effektkjede: fat bottom (`BiquadFilterNode` lowshelf ~200Hz), sparkle (`BiquadFilterNode` highshelf ~10kHz), exciter (`WaveShaperNode` + highshelf). Per-kanal toggles, synkronisert via STDB. Presets (podcast-stemme, radio-stemme).
|
||
- [x] 16.7 Stemmeeffekter: robotstemme (ring-modulasjon: `OscillatorNode` → `GainNode.gain`), monsterstemme (egenutviklet `AudioWorkletProcessor` med phase vocoder for pitch shift). Effektvelger-UI per kanal. Parameterjustering (pitch-faktor, oscillator-frekvens).
|
||
|
||
## Fase 17: Lydstudio-utbedring
|
||
|
||
Ref: Kodegjennomgang av `b4c4bb8` (Lydstudio: lydredigering via FFmpeg).
|
||
|
||
- [x] 17.1 Responsivt studio-layout: `/studio/[id]` sidebar stacker under waveform på mobil. Verktøypanel som modal/sheet på små skjermer. Ref: feedback om at alt UI skal være responsivt uten unntak.
|
||
- [x] 17.2 FFmpeg-parametervalidering: valider at alle numeriske verdier (threshold, gain, ratio, frekvenser) er innenfor sikre grenser i `audio.rs` før de interpoleres i filterstrenger. Avvis ugyldige verdier med feilmelding.
|
||
- [x] 17.3 Fade/silence-logikk: fiks negativ fade-out start (clamp til 0), og adaptiv silence-margin (margin skal ikke overstige halve regionens varighet). Gi feilmelding ved ugyldige fade-varigheter.
|
||
- [x] 17.4 Frontend input-begrensninger: legg til `min`/`max` på alle tallfelter i OperationPanel (silenceThreshold, fadeMs, normTarget, compRatio). Hindre ugyldig input.
|
||
- [x] 17.5 Job-polling opprydding: rydd opp interval/timeout ved navigering bort fra studio-siden. Vis feilmelding etter N mislykkede polling-forsøk. Wrap metadata JSON.parse i try/catch.
|
||
- [x] 17.6 Temp-fil opprydding: legg til periodisk jobb i maskinrommet som sletter gamle temp-filer i CAS tmp-katalog. Bruk `/tmp` eller sett TTL.
|
||
- [x] 17.7 FFmpeg feilmeldinger til bruker: propager stderr fra FFmpeg-feil til frontend via strukturert feilrespons. Vis i RenderDialog.
|
||
|
||
## Fase 18: AI-verktøy (arbeidsflate)
|
||
|
||
Ref: `docs/features/ai_verktoy.md`, `docs/retninger/arbeidsflaten.md`
|
||
|
||
- [x] 18.1 AI-preset node-type: `node_kind: 'ai_preset'` med metadata (prompt, model_profile, category, icon, color). Maskinrommet validerer ved opprettelse. Seed standardprompter (rens tekst, korrektør, oppsummering, oversett, skriv om, trekk ut fakta, forenkle, endre tone).
|
||
- [x] 18.2 AI-prosessering endepunkt: `POST /intentions/ai_process` med source_node_id, ai_preset_id, direction (node_to_tool / tool_to_node). Maskinrommet henter kilde-content og preset-prompt, mapper modellprofil → LiteLLM-alias, sender til AI Gateway. Logg forbruk i ai_usage_log.
|
||
- [x] 18.3 Direction-logikk: `tool_to_node` → lagre original som revisjon, oppdater node content. `node_to_tool` → opprett ny node med AI-output, opprett `derived_from`-edge til kilde + `processed_by`-edge til AI-preset.
|
||
- [x] 18.4 AI-verktøy panel (frontend): Svelte-komponent for arbeidsflaten. Prompt-velger med standardprompter, fritekst-felt for egendefinert prompt, modell-indikator (readonly). Drag-and-drop mottak for tekstnoder.
|
||
- [x] 18.5 Drag-and-drop integrasjon: node → verktøy (ny node), verktøy → node (in-place revisjon). Drop-sone feedback med verktøyets farge. Inkompatibilitet for lyd/bilde-noder med forklaring.
|
||
- [x] 18.6 Egendefinerte presets: brukere kan opprette egne AI-preset-noder med custom prompt. Dele via edges til samling/team. Modellprofil satt av admin.
|
||
|
||
## Fase 19: Arbeidsflaten — Spatial Canvas
|
||
|
||
Ref: `docs/retninger/arbeidsflaten.md`, `docs/features/canvas_primitiv.md`
|
||
|
||
- [x] 19.1 Canvas-primitiv Svelte-komponent: pan/zoom kamera med CSS transforms, viewport culling, pointer events (mus + touch), snap-to-grid (valgfritt), fullskjermsmodus. Ref: `docs/features/canvas_primitiv.md`.
|
||
- [x] 19.2 BlockShell wrapper-komponent: header med tittel + fullskjerm/resize/lukk-knapper, drag-handles for repositionering, resize-handles, drop-sone rendering (highlight ved drag-over). Responsivt (min-size, max-size).
|
||
- [x] 19.3 Arbeidsflaten layout: skriv om `/collection/[id]` fra vertikal stack til Canvas + BlockShell. Last brukerens lagrede arrangement eller bruk defaults fra samlingens traits. Persist arrangement i bruker-edge metadata. Desktop: spatial canvas, mobil: stacked/tabs. Ref: `docs/retninger/arbeidsflaten.md` § "Tre lag".
|
||
- [x] 19.4 Kontekst-header: header tilhører flaten, viser gjeldende node som nedtrekksmeny/kontekst-velger. Mest brukte noder øverst (frekvens/recency), søkbart. Verktøymeny for å instansiere nye paneler. Ref: `docs/retninger/arbeidsflaten.md` § "Kontekst-header".
|
||
- [x] 19.5 Snarveier: paneler kan minimeres til kompakt ikon/fane. Dobbeltklikk → minimer/gjenopprett. Bevarer posisjon og størrelse. Ref: `docs/retninger/arbeidsflaten.md` § "Snarveier".
|
||
- [x] 19.6 Personlig flate: brukerens standard arbeidsflate (node_kind: 'workspace'). Vises når ikke koblet til en annen node. Persistent layout.
|
||
|
||
## Fase 20: Universell overføring + panelrework
|
||
|
||
Ref: `docs/features/universell_overfoering.md`, `docs/retninger/arbeidsflaten.md` § "Kompatibilitetsmatrise"
|
||
|
||
- [x] 20.1 message_placements tabell: PG-migrasjon + SpacetimeDB-modul med `place_message`, `remove_placement`, `move_on_canvas` reducers. Synk STDB→PG. Ref: `docs/features/universell_overfoering.md` § 2.
|
||
- [x] 20.2 source_material edge-type: legg til i edge-skjema + maskinrommet-validering. Støtt kontekst-metadata (quoted, summarized, referenced) og excerpt-felt. Ref: `docs/retninger/arbeidsflaten.md` § "source_material-edge".
|
||
- [x] 20.3 BlockReceiver interface: implementer `canReceive()`, `receive()`, `renderDropZone()` i alle trait-komponenter (Chat, Kanban, Kalender, Editor, Studio). Kompatibilitetsmatrise bestemmer godkjente drops. Ref: `docs/features/universell_overfoering.md` § 4–5.
|
||
- [x] 20.4 Transfer service: `innholdstransfer`-modus (ny node + source_material edge) og `lettvekts-triage` (eksisterende node + ny edge/placement). Bestem modus fra verktøy-par. Shift-modifier for override. Ref: `docs/features/universell_overfoering.md` § 1, 3.
|
||
- [x] 20.5 Panelrework — Chat: gjør ChatTrait til fullverdig BlockShell-panel med BlockReceiver, fullskjerm-toggle, og responsivt design innenfor begrenset container.
|
||
- [x] 20.6 Panelrework — Kanban: gjør KanbanTrait til BlockShell-panel med drag-and-drop aksept fra andre paneler, fullskjerm, responsivt.
|
||
- [x] 20.7 Panelrework — Kalender: gjør CalendarTrait til BlockShell-panel med drop-aksept for scheduling, fullskjerm, responsivt.
|
||
- [x] 20.8 Panelrework — Editor/Artikkelverktøy: gjør artikkelverktøy til BlockShell-panel med source_material mottak fra andre paneler. Ref: `docs/features/artikkelverktoy.md`.
|
||
- [x] 20.9 Panelrework — Studio: gjør StudioTrait til BlockShell-panel med drop-aksept for lydfiler, fullskjerm, responsivt.
|
||
|
||
## Fase 21: CLI-verktøy — Unix-filosofi
|
||
|
||
Ref: `docs/retninger/unix_filosofi.md`. Bryt ut prosessering fra maskinrommet til
|
||
standalone CLI-verktøy i `tools/`. Maskinrommet kaller dem fra jobbkøen, Claude
|
||
kaller dem direkte. Samme verktøy, to brukere.
|
||
|
||
### Prosessering (erstatter jobbkø-handlere)
|
||
|
||
- [x] 21.1 `synops-transcribe`: Whisper-transkribering. Input: `--cas-hash <hash> --model <model> [--initial-prompt <tekst>]`. Output: JSON med segmenter. Skriver segmenter til PG, oppdaterer node metadata. Erstatter `transcribe.rs`.
|
||
- [x] 21.2 `synops-audio`: FFmpeg-prosessering. Input: `--cas-hash <hash> --edl <json>`. Output: ny CAS-hash. Erstatter `audio.rs`. Inkluder parametervalidering (fase 17.2–17.3).
|
||
- [x] 21.3 `synops-render`: Tera HTML-rendering. Input: `--node-id <uuid> --theme <tema>`. Output: CAS-hash for rendret HTML. Erstatter `publishing.rs`.
|
||
- [x] 21.4 `synops-rss`: RSS/Atom-generering. Input: `--collection-id <uuid>`. Output: XML til stdout. Erstatter `rss.rs`.
|
||
- [x] 21.5 `synops-tts`: Tekst-til-tale. Input: `--text <tekst> --voice <stemme>`. Output: CAS-hash for lydfil. Erstatter `tts.rs`.
|
||
- [x] 21.6 `synops-summarize`: AI-oppsummering. Input: `--communication-id <uuid>`. Output: sammendrag som tekst. Erstatter `summarize.rs`.
|
||
- [x] 21.7 `synops-suggest-edges`: AI-foreslåtte edges. Input: `--node-id <uuid>`. Output: JSON med forslag (target, edge_type, confidence). Erstatter `ai_edges.rs`.
|
||
- [x] 21.8 `synops-respond`: Claude chat-svar. Input: `--communication-id <uuid> --message-id <uuid>`. Output: svartekst. Erstatter `agent.rs` sin prosessering (auth/ratelimit forblir i maskinrommet).
|
||
- [x] 21.9 `synops-prune`: Opprydding av gamle noder. Input: `--dry-run` for forhåndsvisning. Erstatter `pruning.rs`.
|
||
|
||
### Oppslag (Claude-verktøy)
|
||
|
||
- [x] 21.10 `synops-context`: Hent kontekst for en samtale. Input: `--communication-id <uuid>`. Output: markdown med spec, deltakere, historikk, relaterte noder.
|
||
- [x] 21.11 `synops-search`: Fulltekstsøk i grafen. Input: `<query> [--kind <node_kind>] [--limit N]`. Output: matchende noder med utdrag.
|
||
- [x] 21.12 `synops-tasks`: Parse tasks.md og vis status. Input: `[--phase N] [--status todo|done|blocked]`. Output: formatert oppgaveliste.
|
||
- [x] 21.13 `synops-feature-status`: Sjekk feature-status. Input: `<feature_key>`. Output: spec-sammendrag, oppgavestatus, nylige commits, ubesvart feedback.
|
||
- [x] 21.14 `synops-node`: Hent/vis en node med edges. Input: `<uuid> [--depth N] [--format json|md]`. Output: node-data med edges.
|
||
|
||
### Infrastruktur
|
||
|
||
- [x] 21.15 Jobbkø-dispatcher: endre maskinrommets jobbkø-handlere til å spawne CLI-verktøy (`Command::new("synops-X")`) i stedet for inline-kode. Stdout → jobbresultat, stderr → feillogg, exitkode → status.
|
||
- [x] 21.16 Felles lib: `synops-common` crate med PG-tilkobling, CAS-helpers, og node/edge-typer. Deles mellom alle CLI-verktøy for å unngå duplisering.
|
||
|
||
## Fase 12: Herding
|
||
|
||
- [x] 12.1 Observerbarhet: strukturert logging, metrikker (request latency, queue depth, AI cost).
|
||
- [x] 12.2 Backup: PG-dump rutine.
|
||
- [x] 12.3 Feilhåndtering: retry med backoff i skrivestien, dead letter queue for feilede PG-skrivinger.
|
||
- [x] 12.4 Ytelse: profiler PG-spørringer, optimaliser node_access-oppdatering.
|
||
|
||
## Fase 22: SpacetimeDB-migrering — PG LISTEN/NOTIFY
|
||
|
||
Ref: `docs/retninger/datalaget.md` (revidert mars 2026). Faser ut SpacetimeDB
|
||
til fordel for PG LISTEN/NOTIFY + WebSocket i portvokteren. Én datakilde,
|
||
ingen synk-kompleksitet.
|
||
|
||
- [x] 22.1 WebSocket-lag i portvokteren: implementer PG LISTEN/NOTIFY-lytter og WebSocket-endepunkt. Legg til PG-triggers (`notify_node_change`, `notify_edge_change`) for nodes og edges. Frontend kobler til begge (STDB + nytt WS) i parallell for verifisering.
|
||
- [x] 22.2 Frontend-migrering: erstatt SpacetimeDB-klient med vanlig WebSocket til portvokteren. Erstatt STDB-stores med reaktive stores som lytter på WebSocket. Verifiser all sanntidsfunksjonalitet (chat, kanban, kalender, mixer, canvas).
|
||
- [x] 22.3 Fjern STDB-skrivestien: portvokteren slutter å skrive til SpacetimeDB. All skriving går kun til PG. NOTIFY-triggere er eneste push-mekanisme. Verifiser at ingenting avhenger av STDB-data.
|
||
- [x] 22.4 Fjern SpacetimeDB: stopp Docker-container, fjern STDB-modul, fjern STDB-klient fra portvokteren og frontend, fjern synkroniseringskode, oppdater docs og CLAUDE.md.
|
||
- [x] 22.5 Opprydding: arkiver STDB-relaterte erfaringsdocs, oppdater alle docs-referanser, fjern Docker-konfig for SpacetimeDB, fjern SpacetimeDB-loven fra feedback-memories.
|
||
|
||
## Fase 23: Validering — test og kvalitetssikring per fase
|
||
|
||
Hver oppgave spinner opp en ny sesjon med frisk kontekst som gjennomgår
|
||
implementeringen fra den angitte fasen. Sesjonen tester, leser kode,
|
||
verifiserer mot spec, og sjekker at ting faktisk fungerer. Ved funn:
|
||
fiks direkte hvis det er småting, eller opprett nye work_items (tasks)
|
||
med spesifikasjon for det som trenger en dedikert sesjon.
|
||
|
||
- [x] 23.1 Valider fase 1–2 (infra + maskinrommet): PG-skjema, indekser, auth-middleware, intensjoner, STDB-klient (nå erstattet av WS). Verifiser at skjema matcher docs, at auth fungerer, at skrivestien er konsistent.
|
||
- [x] 23.2 Valider fase 3–4 (frontend + tilgang): SvelteKit-oppsett, OIDC-flow, sanntid, mottaksflate, TipTap-editor, node_access-matrise, team-transitivitet, visibility-filtrering.
|
||
- [x] 23.3 Valider fase 5–8 (kommunikasjon + CAS + lyd + aliaser): chat-loop, kontekst-arv, CAS-hashing/deduplisering, Whisper-pipeline, segmenttabell, SRT-eksport, alias-identitet.
|
||
- [x] 23.4 Valider fase 9–10 (visninger + AI): kanban drag-and-drop, kalender, dagbok, kunnskapsgraf, LiteLLM-ruting, AI-foreslåtte edges, oppsummering, TTS.
|
||
- [x] 23.5 Valider fase 11 (produksjon): LiveKit-oppsett, sanntidslyd, pruning-logikk, podcast-RSS.
|
||
- [x] 23.6 Valider fase 13–14 (traits + publisering): trait-validering, pakkevelger, Tera-templates, HTML-rendering, forside, slot-håndtering, redaksjonell flyt, planlagt publisering, A/B-testing.
|
||
- [x] 23.7 Valider fase 15–16 (admin + lydmixer): systemvarsler, graceful shutdown, jobbkø-oversikt, ressursstyring, serverhelse, Web Audio mixer, delt kontroll, sound pads, EQ, stemmeeffekter.
|
||
- [x] 23.8 Valider fase 17–18 (lydstudio-utbedring + AI-verktøy): responsivt layout, FFmpeg-validering, fade/silence, AI-presets, direction-logikk, drag-and-drop integrasjon.
|
||
- [x] 23.9 Valider fase 19–20 (arbeidsflaten + universell overføring): canvas pan/zoom, BlockShell, layout-persistering, snarveier, transfer service, alle panelreworks (chat, kanban, kalender, editor, studio).
|
||
- [x] 23.10 Valider fase 21 (CLI-verktøy): kjør hvert synops-*-verktøy, verifiser --help, --payload-json, output-format, feilhåndtering, synops-common integrasjon.
|
||
- [x] 23.11 Valider fase 22 (STDB-migrering): WebSocket-sanntid fungerer, PG LISTEN/NOTIFY-triggere, ingen STDB-rester i aktiv kode/konfig.
|
||
|
||
## Fase 24: Orkestrering — trigger-drevne automatiseringer
|
||
|
||
Ref: `docs/concepts/orkestrering.md`. Orkestreringsnoder (`node_kind: 'orchestration'`)
|
||
med fritekst-instruksjoner som boten utfører via function calling. Strukturerte triggere,
|
||
automatisk eskalering av intelligens ved feil, kompilering av velprøvde mønstre.
|
||
|
||
- [x] 24.1 Orchestration node-type: legg til `orchestration` i maskinrommets node-validering. Metadata-skjema: `trigger` (event + conditions), `executor`, `intelligence`, `effort`, `compiled`, `pipeline`. Valider trigger-events mot kjent liste.
|
||
- [x] 24.2 Trigger-evaluering i portvokteren: ved node/edge-events, sjekk om noen `orchestration`-noder matcher triggeren. Effektiv lookup (indeksert på `metadata.trigger.event`). Ingen LLM-kall for trigger-matching.
|
||
- [x] 24.3 Script-kompilator: parser menneskelig scriptspråk ("transkriber lydfilen (stor modell)") og kompilerer til tekniske CLI-kall. Matcher verb mot `cli_tool`-noders `aliases`, argumenter mot `args_hints`, variabler fra trigger-kontekst. Rust-stil kompileringsfeil med forslag.
|
||
- [x] 24.4 cli_tool alias-metadata: utvid alle `cli_tool`-noder med `aliases` (norske verb) og `args_hints` (menneskelige argumenter → CLI-flagg). Seed for alle eksisterende verktøy.
|
||
- [x] 24.5 Script-executor: vaktmesteren parser kompilert script og eksekverer steg sekvensielt via generisk dispatch. VED_FEIL-håndtering. Logger i `orchestration_log`.
|
||
- [x] 24.6 Orchestration UI: editor med tre visninger (Enkel/Teknisk/Kompilert) som tabber. Sanntids kompileringsfeil. Trigger-velger, "Test kjøring"-knapp, kjørehistorikk. Ref: `docs/concepts/orkestrering.md`.
|
||
- [x] 24.7 AI-assistert oppretting: `synops-ai` med auto-generert systemprompt (fra cli_tool-noder) foreslår script fra fritekst-beskrivelse. Vaktmesteren validerer. Eventually-modus: lagre som work_item for Claude Code.
|
||
- [x] 24.8 Kaskade: `triggers`-edge mellom orkestreringer. Output fra én trigger neste. Syklusdeteksjon for å unngå uendelige loops.
|
||
- [x] 24.9 Seed-orkestreringer: opprett standard-orkestreringer for podcast-pipeline, publiseringsflyt, og AI-beriking basert på eksisterende hardkodet logikk i vaktmesteren. Skrives i menneskelig scriptspråk.
|
||
|
||
## Fase 25: Web Clipper — `synops-clip`
|
||
|
||
Ref: `docs/proposals/web_clipper.md`. CLI-verktøy som henter URL, parser med
|
||
Readability, og oppretter innholdsnode med AI-beriking. Brukes av @bot i chat
|
||
("les denne artikkelen"), orkestreringer, og fremtidig browser-extension.
|
||
|
||
- [x] 25.1 `synops-clip` CLI: hent URL, parse med Readability (mozilla/readability via JS eller Rust-port), returner ren tekst + metadata (tittel, forfatter, dato, ingress). Fallback til headless browser (Playwright) for JS-rendrede sider. Detekter betalingsmur (kort/avkuttet innhold, "logg inn for å lese", kjente paywall-mønstre) — returner `"paywall": true` og tilgjengelig innhold (ingress/utdrag). Output: JSON med `title`, `author`, `date`, `content`, `url`, `paywall`.
|
||
- [x] 25.2 Node-opprettelse: `synops-clip --write` oppretter `content`-node med artikkelinnhold, `metadata.source_url`, og `tagged`-edge "clipped". AI-oppsummering via LiteLLM. `mentions`-edges til gjenkjente entiteter i kunnskapsgrafen.
|
||
- [x] 25.3 @bot-integrasjon: bruker limer inn URL i chat → boten gjenkjenner URL, kaller `synops-clip`, presenterer oppsummering i chatten, oppretter node i bakgrunnen. Ved paywall: "Denne artikkelen er bak betalingsmur. Jeg fikk med tittel og ingress — lim inn innholdet om du vil dele resten."
|
||
- [x] 25.4 Orkestrering-støtte: `synops-clip` tilgjengelig som verktøy i orkestreringer. F.eks. "Clip alle URL-er som deles i #Redaksjonen og oppsummer dem".
|
||
|
||
## Fase 26: Epost — send og motta via synops.no
|
||
|
||
Vaktmesteren kan sende epost (msmtp) og motta epost (Postfix → synops-mail).
|
||
Brukernavn@domene ruter til brukerens innboks. Alle domener (synops.no,
|
||
sidelinja.org, vegard.info) ruter til samme bruker basert på username.
|
||
|
||
- [x] 26.1 Username i auth_identities: legg til `username`-kolonne, populer fra Authentik `preferred_username` ved login. Unik constraint. Oppdater auth-callback i SvelteKit til å lagre username.
|
||
- [x] 26.2 msmtp oppsett: konfigurer utgående epost via SMTP-relay. Avsender: `vaktmester@synops.no`. Tilgjengelig som `synops-mail --send --to <epost> --subject <emne>` CLI-verktøy.
|
||
- [x] 26.3 MX-records: sett opp MX for synops.no, sidelinja.org, vegard.info som peker til serveren.
|
||
- [x] 26.4 Postfix minimal: installer Postfix som lokal MTA kun for mottak. Ingen relay, ingen kø for utgående. Pipe innkommende epost til `synops-mail --receive`.
|
||
- [x] 26.5 `synops-mail --receive`: Rust CLI som leser raw epost fra stdin. Sjekk 1: avsender-epost matcher `auth_identities.email`? Sjekk 2: innhold starter med "Kjære vaktmester" (eller konfigurerbar frase)? Begge må matche. Opprett `content`-node i brukerens innboks med epostinnholdet. Alt annet → /dev/null, ingen bounce.
|
||
- [ ] 26.6 Domene-alias: `vegard@synops.no`, `vegard@sidelinja.org`, `vegard@vegard.info` ruter alle til samme bruker via username-oppslag i PG. Domenet er irrelevant.
|
||
- [ ] 26.7 Utgående varsler: vaktmesteren kan sende epost-varsler til brukere (ny oppgave tildelt, innsendt artikkel godkjent, etc.) via `synops-mail --send`. Konfigurerbart per bruker i metadata.preferences.
|
||
|
||
## Fase 27: Tankekart — radial grafvisning
|
||
|
||
Ref: `docs/features/tankekart.md`. Tankekart-panel som viser noder og edges
|
||
i radial layout med en rotnode i sentrum. Ingen ny backend — ren frontend-
|
||
visning av eksisterende grafdata.
|
||
|
||
- [x] 27.1 MindMap Svelte-komponent: radial/tree-layout av noder rundt en rotnode. Hent relaterte noder (1-2 hopp) via WebSocket. d3-hierarchy eller trigonometri for layout. Pan/zoom via canvas-primitiv. Klikk node = ny rot, dobbeltklikk = åpne i editor.
|
||
- [x] 27.2 BlockShell-panel: MindMap som BlockShell-panel i arbeidsflaten med fullskjerm, resize, drag-handle. Rotnode fra kontekst-header. Responsivt.
|
||
- [x] 27.3 MindMap-trait: `mindmap`-trait for samlingsnoder. Vises i trait-velger ved opprettelse. Konfigurasjon: default dybde (1-3 hopp), layout-stil (radial/tree).
|
||
|
||
## Fase 28: Manglende CLI-verktøy + AI-rutingskontroll
|
||
|
||
Verktøy som mangler i verktøykassen, pluss admin-styring av hvilken
|
||
modell som brukes til hva.
|
||
|
||
### synops-ai: lettvekts LLM-kall
|
||
|
||
- [x] 28.1 `synops-ai` CLI: direkte LLM-kall via LiteLLM. Input: `--prompt <tekst> [--model <alias>] [--system <systemprompt>]`. Output: tekst til stdout. Ingen fillesing, ingen verktøy, bare prompt inn/ut. Bruker `ai_job_routing`-tabellen for å bestemme modell hvis `--model` ikke er satt. Logger i `ai_usage_log`.
|
||
- [x] 28.2 AI-rutingskontroll i admin: utvid admin-UI (fase 15.4) med konfigurasjon av hvilken modell som brukes per kontekst. Tabellen `ai_job_routing` mapper `(job_type, context)` → `model_alias`. Kontekster: `orchestration_script`, `orchestration_dream`, `bot_chat`, `bot_triage`, `summarize`, `suggest_edges`, `classify`. Admin kan endre uten redeploy.
|
||
- [x] 28.3 Kostnadstak per bruker/samling: `ai_budget`-felt i metadata for brukere og samlinger. `synops-ai` sjekker budsjett mot `ai_usage_log` aggregat før kall. Ved overskridelse: returner feilmelding, opprett work_item.
|
||
|
||
### Øvrige manglende verktøy
|
||
|
||
- [x] 28.4 `synops-notify`: send varsel via epost (synops-mail), WebSocket-push, eller begge. Input: `--to <node_id> --message <tekst> [--channel email|ws|both]`. Brukes av orkestreringer og vaktmesteren.
|
||
- [x] 28.5 `synops-validate`: sjekk at en node matcher forventet skjema for sin node_kind. Input: `--node-id <uuid>`. Output: liste av avvik. Brukes av valideringsfasen og som pre-commit sjekk.
|
||
- [x] 28.6 `synops-backup`: PG-dump + CAS-filiste + metadata-snapshot. Input: `[--full | --incremental]`. Output: backup-sti. Erstatter cron-scriptet fra 12.2.
|
||
- [x] 28.7 `synops-health`: sjekk status for alle tjenester (PG, Caddy, vaktmesteren, LiteLLM, Whisper, LiveKit). Output: JSON med status per tjeneste. Brukes av admin-dashboard og overvåking.
|
||
|
||
## Fase 29: Universell input — alle modaliteter blir noder
|
||
|
||
Ref: `docs/features/universell_input.md`. Utvid input-primitiven til å dekke
|
||
alle relevante modaliteter. Alt ender som noder. Modaliteten er transport,
|
||
noden er det som lever videre.
|
||
|
||
### Skjermklipp
|
||
- [x] 29.1 Skjermklipp-input: paste screenshot fra clipboard i chat/editor → upload til CAS → media-node. Frontend detekterer bilde-paste (ClipboardEvent). Valgfri AI-beskrivelse via synops-ai ("beskriv dette bildet"). Metadata: `{ "source": "screenshot", "description": "..." }`.
|
||
|
||
### RSS/Feed-abonnement
|
||
- [x] 29.2 `synops-feed` CLI: abonner på RSS/Atom-feed. Input: `--url <feed-url> --collection-id <uuid> [--interval 30m]`. Poller feed, oppretter `content`-node for nye entries med `metadata.source_url` og `tagged`-edge "feed". AI-oppsummering valgfritt. Paywall-deteksjon gjenbrukt fra synops-clip.
|
||
- [x] 29.3 Feed-orkestrering: standard-orkestrering "Overvåk RSS-feed" som bruker synops-feed. Konfigurerbar per samling. Nye artikler havner i innboks eller direkte i en kanal.
|
||
|
||
### Webhook (universell ekstern input)
|
||
- [x] 29.4 Webhook-endepunkt i vaktmesteren: `POST /api/webhook/<token>` → opprett node fra JSON-body. Hvert webhook har et unikt token (UUID) knyttet til en `webhook`-node med `belongs_to`-edge til målsamling. Validerer token, oppretter `content`-node med payload i metadata.
|
||
- [x] 29.5 Webhook-admin: UI for å opprette/administrere webhooks. Vis token, mål-samling, siste hendelser, aktivitet-logg. Regenerer token. Deaktiver/slett.
|
||
- [x] 29.6 Webhook-templates: forhåndsdefinerte mappinger for kjente tjenester (GitHub → commits/issues, Slack → meldinger, CI/CD → build-status). Template mapper JSON-felt til node title/content/metadata.
|
||
|
||
### Video
|
||
- [x] 29.7 Video-opptak i frontend: webcam/skjermopptak via MediaRecorder API → upload til CAS → media-node. Start/stopp-knapp i input-komponenten. Maks varighet konfigurerbar.
|
||
- [x] 29.8 Video-prosessering: `synops-video` CLI for transcode (H.264), thumbnail-generering, og varighet-uttrekk. Input: `--cas-hash <hash>`. Output: ny CAS-hash (trancodet) + thumbnail CAS-hash.
|
||
|
||
### Geolokasjon
|
||
- [x] 29.9 Lokasjon-input: "Del posisjon"-knapp i input-komponenten → Geolocation API → node med `metadata.location: { "lat": 59.91, "lon": 10.75 }`. Kart-visning i node-detaljer (Leaflet/OpenStreetMap). Valgfritt: reverse geocoding via Nominatim for adresse.
|
||
|
||
### Håndskrift/tegning
|
||
- [x] 29.10 Tegne-input: enkel canvas-basert tegneflate i input-komponenten. Eksporter som PNG → CAS → media-node. Ikke whiteboard (det er et eget verktøy) — dette er "rask skisse som input", som en post-it.
|
||
|
||
### Kalender-import
|
||
- [x] 29.11 ICS-import: `synops-calendar` CLI som parser ICS-fil og oppretter noder med `scheduled`-edges. Input: `--file <ics> --collection-id <uuid>`. Duplikatdeteksjon via UID. Oppdatering ved re-import.
|
||
- [x] 29.12 CalDAV-abonnement: abonner på ekstern CalDAV-kalender (Google, Outlook). Poller periodisk, synkroniserer endringer. Som RSS-feed men for kalenderhendelser.
|
||
|
||
## Fase 30: Podcast-hosting — komplett, uten ekstern avhengighet
|
||
|
||
Ref: `docs/features/podcast_hosting.md`. Bygg komplett podcast-hosting i Synops.
|
||
Ingen castopod, ingen ekstern tjeneste. Import fra eksisterende podcast med
|
||
prøveimport-flyt.
|
||
|
||
### RSS og metadata
|
||
- [x] 30.1 iTunes/Podcasting 2.0 RSS-tags: utvid synops-rss med `<itunes:*>` og `<podcast:*>` namespace. Tags fra samlingens podcast-trait metadata (author, category, explicit, language). Podcast:transcript og podcast:chapters fra eksisterende edges.
|
||
- [x] 30.2 Podcast-trait metadata: utvid podcast-trait med iTunes-felt (itunes_category, itunes_author, explicit, language, redirect_feed). Admin-UI for å redigere.
|
||
|
||
### Statistikk
|
||
- [x] 30.3 `synops-stats` CLI: parse Caddy access-logger for /media/*-requests. Aggreger nedlastinger per episode per dag. IAB-regler: filtrer bots (user-agent), unik IP per 24t. Output: JSON med episode_id, date, downloads, unique_listeners. `--write` lagrer i PG.
|
||
- [x] 30.4 Statistikk-dashboard: vis nedlastinger per episode, trend over tid, topp-episoder, klienter (Apple/Spotify/andre), geografi. Integrert i admin-panelet.
|
||
|
||
### Embed-spiller
|
||
- [x] 30.5 Podcast-spiller komponent: Svelte-komponent med artwork, tittel, play/pause, progress, waveform, kapittelmerkering. Responsiv. Serveres som iframe-embed: `synops.no/pub/<slug>/<episode>/player`.
|
||
|
||
### Import
|
||
- [x] 30.6 `synops-import-podcast` CLI: importer eksisterende podcast fra RSS-feed. Parse metadata, last ned lydfiler/artwork/transkripsjoner til CAS, opprett noder med edges. Duplikatdeteksjon via `<guid>`. `--dry-run` for forhåndsvisning. Idempotent: kjør flere ganger, bare nye episoder importeres.
|
||
- [x] 30.7 Prøveimport-flyt i frontend: "Importer podcast"-wizard i admin. Steg 1: lim inn RSS-URL, vis forhåndsvisning av episoder. Steg 2: importer (kan ta tid for mange episoder). Steg 3: sjekk resultat, sammenlign feeds. Steg 4: re-importer nye episoder når klar. Steg 5: aktiver 301-redirect på gammel host.
|
||
|
||
### Eksport og redirect
|
||
- [x] 30.8 Feed-redirect: `redirect_feed`-felt i podcast-trait. Når satt: Caddy returnerer 301 for feed-URL. Brukeren kan alltid flytte bort. Admin-UI med én-klikks aktivering og advarsel.
|