Commit graph

531 commits

Author SHA1 Message Date
10d3249a6a Starter oppgave 30.6 2026-03-18 23:55:39 +00:00
4c1c470ed7 Embed podcast-spiller: /pub/{slug}/{episode}/player (oppgave 30.5)
Ny maskinrommet-handler som serverer en selvstående HTML-side med
podcast-spiller, designet for iframe-embedding på eksterne nettsider.

Spilleren inkluderer:
- Artwork (episode-spesifikk med fallback til samlingens)
- Tittel og podcast-navn
- Play/pause med loading-spinner
- WaveSurfer.js waveform-visualisering (CDN)
- Tidsvisning (nåværende/total)
- Kapittelmerkering (visuelt på waveform + klikkbar liste)
- Responsiv design (mobil-vennlig ned til 360px)
- Iframe-vennlige headers (X-Frame-Options, CSP frame-ancestors)

Rute: GET /pub/{slug}/{episode_id}/player
Registrert før {article_id} catch-all i rutehierarkiet.
2026-03-18 23:53:21 +00:00
4b53adefa9 Starter oppgave 30.5 2026-03-18 23:45:32 +00:00
3e57adce46 Podcast-statistikk dashboard i admin-panelet (oppgave 30.4)
Nytt dashboard under /admin/podcast-stats som viser:
- Nøkkeltall: totale nedlastinger, unike lyttere, antall episoder
- Daglig trend med horisontale bar charts
- Topp-episoder rangert etter nedlastinger
- Klientfordeling (Apple Podcasts, Spotify, etc.) med stacked bar

Backend: GET /admin/podcast/stats spør podcast_download_stats-tabellen
(fylt av synops-stats CLI fra oppgave 30.3) og aggregerer per episode,
per dag, og per klient via jsonb_each_text.

Filtrering på tidsperiode (7/30/90/365 dager) og enkelt-episode.
2026-03-18 23:42:23 +00:00
e394035a5e Starter oppgave 30.4 2026-03-18 23:35:33 +00:00
86d7002815 synops-stats CLI: podcast-nedlastingsstatistikk fra Caddy-logger (oppgave 30.3)
Nytt CLI-verktøy som parser Caddy JSON access-logger for /media/cas/*
requests og aggregerer nedlastinger per episode per dag.

IAB-compliance:
- Filtrerer 40+ kjente bot user-agents (Googlebot, scrapers, crawlers)
- Unik IP per episode per 24t-vindu (dag-basert deduplisering)

Output: JSON med episode_id, cas_hash, date, downloads, unique_listeners,
og klient-fordeling (Apple Podcasts, Spotify, Overcast, etc.)

--write oppretter podcast_download_stats-tabell i PG med UPSERT
(cas_hash + date som unik nøkkel). Beriker med episode-info fra
has_media-edges når tilgjengelig.
2026-03-18 23:30:45 +00:00
43db2c5d00 Starter oppgave 30.3 2026-03-18 23:24:22 +00:00
6aeb8aa783 Podcast-trait admin-UI og utvidet RSS-metadata (oppgave 30.2)
Dedikert admin-UI for podcast-trait med riktige skjemafelt:
- iTunes Author, Category (med underkategori-dropdown), Language
- Explicit-avkrysning, Redirect Feed URL
- Erstatter generisk nøkkel/verdi-editor for podcast-traitet

RSS-utvidelser:
- itunes:category støtter nå nested subcategory-element
- itunes:new-feed-url for feed-migrasjon via redirect_feed
- Oppdatert både maskinrommet og synops-rss CLI-verktøy
2026-03-18 23:21:15 +00:00
84396dc805 Starter oppgave 30.2 2026-03-18 23:15:30 +00:00
d7f08d439d iTunes/Podcasting 2.0 RSS-tags: komplett implementering (oppgave 30.1)
Utvider synops-rss og maskinrommet/src/rss.rs med iTunes og Podcasting 2.0
namespace for podcast-samlinger.

Channel-level tags:
- itunes:author, itunes:category, itunes:explicit fra podcast-trait metadata
- itunes:image fra samlingens og_image-edge (CAS-hash)
- itunes:type (episodic)
- podcast:locked

Item-level tags:
- itunes:title, itunes:duration (fra media-metadata duration_secs)
- itunes:explicit (arver fra kanal), itunes:image (episode og_image)
- podcast:transcript (SRT-URL hvis transcription_segments finnes)
- podcast:chapters (JSON-URL hvis chapter-edges finnes)

DB-spørringene er utvidet til å hente transkripsjons-eksistens,
varighet, episode-bilde og kapitler i effektive batch-spørringer.

Merk: Transcript/chapters-URL-ene genereres i feeden men krever
offentlige endepunkt for å serveres (fremtidig oppgave).
2026-03-18 23:12:34 +00:00
1b459948b9 Starter oppgave 30.1 2026-03-18 23:05:30 +00:00
5b3367e7e5 CalDAV-abonnement: periodisk polling av eksterne kalendere (oppgave 29.12)
Utvider synops-calendar CLI med --url for å hente ICS fra eksterne URLer
(Google Calendar, Outlook, etc). Ny calendar_poller i maskinrommet poller
samlingers calendar_subscriptions[] med konfigurerbart intervall, etter
samme mønster som feed_poller for RSS-feeds.

Endringer:
- synops-calendar: ny --url parameter + reqwest for HTTP-henting
- calendar_poller.rs: bakgrunnsloop som finner forfalne abonnementer
- calendar_poll jobbtype i dispatcher med CLI-dispatch til synops-calendar
- API: configure_calendar_subscription + remove_calendar_subscription
- Migrasjon 031: indeks + prioritetsregel for calendar_poll-jobber
2026-03-18 23:04:29 +00:00
55e45e32e0 Starter oppgave 29.12 2026-03-18 22:55:29 +00:00
a77a6ea12f ICS-import: synops-calendar CLI for kalenderimport (oppgave 29.11)
Nytt CLI-verktøy som parser ICS-filer (RFC 5545) og oppretter
content-noder med scheduled-edges i Synops. Duplikatdeteksjon
via ICS UID i node-metadata — re-import oppdaterer eksisterende
noder i stedet for å lage duplikater.

Støtter --file/--collection-id og --payload-json for jobbkø.
Oppretter belongs_to + scheduled edges per hendelse.
2026-03-18 22:51:16 +00:00
59e34878cc Starter oppgave 29.11 2026-03-18 22:45:29 +00:00
4d03ab7271 Tegne-input: enkel canvas-basert skisseflate i chat-input (oppgave 29.10)
Ny DrawingInput-komponent som lar brukeren tegne en rask skisse direkte
fra chat-inputen. Åpner fullskjerm-canvas med fargevelger, penseltykkelse,
angre og tøm. Eksporterer som PNG → CAS → media-node med metadata
source=drawing. Følger samme mønster som VoiceRecorder/VideoRecorder.

Ikke whiteboard — dette er "post-it-skisse som input".
2026-03-18 22:43:19 +00:00
3b7dd3cb68 Starter oppgave 29.10 2026-03-18 22:40:33 +00:00
6729a35435 Lokasjon-input: del posisjon i chat med kartvisning (oppgave 29.9)
Ny «Del posisjon»-knapp i ChatInput ved siden av tale/video-knappene.
Bruker Geolocation API for å hente brukerens posisjon, oppretter en
content-node med metadata.location { lat, lon, address }.

Reverse geocoding via Nominatim (best-effort) gir adresse i metadata.
Kartvisning i chat via Leaflet/OpenStreetMap viser posisjonen inline.

Komponenter:
- LocationShare.svelte: knapp + geolocation + geocoding + node-opprettelse
- LocationMap.svelte: Leaflet-kart med markør og adresse-popup
- Leaflet lastes via CDN (unpkg) i app.html
2026-03-18 22:36:08 +00:00
87170e8059 Starter oppgave 29.9 2026-03-18 22:30:30 +00:00
3b6bab5092 synops-video: CLI for video-transcode, thumbnail og varighet (oppgave 29.8)
Nytt CLI-verktøy som prosesserer video fra CAS:
- Transcode til H.264/AAC MP4 med faststart (web-optimert)
- Thumbnail-generering (JPEG, 480px bred)
- Varighet-uttrekk via ffprobe

Input: --cas-hash eller --payload-json (jobbkø-modus)
Output: JSON med transcoded_hash, thumbnail_hash, duration_ms
Med --write: oppdaterer medienodens metadata i PG

Følger samme mønster som synops-audio: CAS inn/ut, --write for
DB-persistering, --payload-json for dispatch fra maskinrommet.
2026-03-18 22:25:42 +00:00
10a4dd8059 Starter oppgave 29.8 2026-03-18 22:20:27 +00:00
fd40d51466 Video-opptak i frontend: webcam/skjermopptak via MediaRecorder API (oppgave 29.7)
VideoRecorder-komponent med to moduser:
- Kamera: getUserMedia med video+lyd, 720p
- Skjerm: getDisplayMedia med valgfri lyd, 1080p

Funksjoner:
- Modus-velger (kamera/skjerm) før opptak starter
- Live forhåndsvisning under opptak
- Konfigurerbar maks varighet (default 5 min), advarsel siste 30 sek
- Automatisk stopp ved maks varighet
- Upload til CAS → media-node med metadata (source, record_type, duration)
- Integrert i ChatInput ved siden av VoiceRecorder
2026-03-18 22:19:30 +00:00
532bd4b3ec Starter oppgave 29.7 2026-03-18 22:15:30 +00:00
a3dfa3b254 Webhook-templates: forhåndsdefinerte mappinger for kjente tjenester (oppgave 29.6)
Legger til et template-system for webhooks som vet hvordan kjente
tjenester strukturerer sine JSON-payloads, og mapper dem til
meningsfulle node title/content/metadata.

Templates:
- github-push: Commits med repo, branch, pusher, formaterte meldinger
- github-issues: Issue-hendelser med nummer, labels, state
- github-pull-request: PR-hendelser med branch-info, merge-status
- slack-message: Slack Event API-meldinger med kanal og bruker
- ci-build: Generisk CI/CD (GitHub Actions, GitLab CI, Jenkins)

Backend:
- webhook_templates.rs: Template-definisjoner og apply-logikk
- webhook.rs: Bruker template fra webhook-nodens metadata.template_id
- webhook_admin.rs: GET /admin/webhooks/templates, POST set_template,
  template_id i create og list

Frontend:
- Template-velger i opprett-skjema og på hver webhook-kort
- Kan bytte template på eksisterende webhooks

6 unit-tester for alle templates. Verifisert med curl mot live endpoint.
2026-03-18 22:10:33 +00:00
af014fc883 Starter oppgave 29.6 2026-03-18 22:00:26 +00:00
097ef02aea Webhook-admin: UI for å opprette/administrere webhooks (oppgave 29.5)
Backend (maskinrommet):
- GET /admin/webhooks — liste alle webhooks med aktivitetsinfo
- GET /admin/webhooks/events?webhook_id=... — siste hendelser
- POST /admin/webhooks/create — opprett webhook for samling
- POST /admin/webhooks/regenerate_token — nytt token
- POST /admin/webhooks/delete — slett webhook

Frontend:
- /admin/webhooks side med full CRUD
- Vis token, mål-samling, hendelsesteller, siste aktivitet
- Kopier token/URL til utklippstavle
- Utfellbar hendelseslogg per webhook med payload-visning
- Regenerer token med bekreftelse
- Slett med bekreftelse
- Nav-lenke fra admin-hub
2026-03-18 21:55:24 +00:00
96746fa2f0 Starter oppgave 29.5 2026-03-18 21:45:26 +00:00
8c77b60561 Webhook-endepunkt: POST /api/webhook/<token> → content-node (oppgave 29.4)
Nytt offentlig endepunkt som mottar vilkårlig JSON og oppretter en
content-node i målsamlingen. Webhook-noder har et unikt token i
metadata som brukes til autentisering i stedet for JWT.

Flyten: token-oppslag → finn belongs_to-edge til samling →
opprett content-node med payload i metadata → belongs_to-edge →
tilgangspropagering fra samling.

Trekker ut title/content fra payload automatisk når feltene finnes.
2026-03-18 21:41:22 +00:00
30dc76db8a Starter oppgave 29.4 2026-03-18 21:35:33 +00:00
7fbdc3f5dc Feed-orkestrering: periodisk RSS/Atom-polling per samling (oppgave 29.3)
Ny standard-orkestrering "Overvåk RSS-feed" som bruker synops-feed CLI.
Samlinger konfigurerer feed-abonnementer via metadata.feed_subscriptions[],
med konfigurerbar URL, intervall og mål (inbox/channel).

Komponenter:
- Migration 030: synops-feed cli_tool-seed, orchestration-seed, indeks, prioritetsregel
- feed_poller.rs: Bakgrunnstask som hvert 60s finner forfalne abonnementer
  og enqueuer feed_poll-jobber. Dedupliserer mot kjørende jobber.
- feed_poll job handler: Spawner synops-feed CLI, oppdaterer last_polled_at
- API: configure_feed_subscription + remove_feed_subscription endepunkter

Verifisert: NRK toppsaker.rss → 100 noder opprettet, last_polled_at oppdatert.
2026-03-18 21:32:00 +00:00
f2b3ea454f Starter oppgave 29.3 2026-03-18 21:20:40 +00:00
8d327423f3 synops-feed: RSS/Atom-feed abonnement med deduplisering (oppgave 29.2)
Nytt CLI-verktøy som henter og parser RSS/Atom-feeds (via feed-rs),
oppretter content-noder for nye entries med:
- metadata.source_url, feed_entry_id, original_author, published_at
- tagged-edge "feed" (selv-edge)
- belongs_to-edge til angitt samling
- Paywall-deteksjon gjenbrukt fra synops-clip

Dedupliserer på source_url — kjøring nummer to oppretter ingen duplikater.
Designet for å kjøres periodisk av maskinrommet/jobbkø (én gang per poll).
--interval lagres som metadata for orkestreringsoppsettet.

Støtter --payload-json for jobbkø-dispatch.
2026-03-18 21:16:36 +00:00
32a8568823 Starter oppgave 29.2 2026-03-18 21:10:40 +00:00
1d8ebf259b Skjermklipp-input: paste screenshot i chat → CAS → media-node (oppgave 29.1)
Frontend:
- ChatInput: paste-handler detekterer bilder fra clipboard (ClipboardEvent),
  laster opp til CAS via uploadMedia med metadata_extra { source: "screenshot" }
- Chat-side: viser bildenoder inline med AI-beskrivelse når tilgjengelig
- api.ts: uploadMedia støtter nå metadata_extra for ekstra node-metadata

Backend (maskinrommet):
- upload_media: nytt metadata_extra multipart-felt som merges inn i
  media-nodens metadata (f.eks. source, description)
- describe_image: ny jobbtype — enqueuues automatisk for screenshot-uploads,
  kaller synops-ai med --image for AI-beskrivelse av bildet
- Beskrivelsen lagres tilbake i media-nodens metadata.description

synops-ai:
- Nytt --image flag for multimodal LLM-kall (vision) via LiteLLM
- Sender bilde som base64 data-URL i OpenAI-kompatibelt format
- Brukes av describe_image-jobben for bildbeskrivelse
2026-03-18 21:07:00 +00:00
09ed49d7d7 Starter oppgave 29.1 2026-03-18 20:55:34 +00:00
d3ecb5b279 synops-health: sjekk status for alle tjenester i stacken (oppgave 28.7)
CLI-verktøy som sjekker PG, Caddy, Maskinrommet, LiteLLM, Whisper,
LiveKit og Authentik parallelt. Output: JSON med status per tjeneste
+ samlet helsetilstand (healthy/degraded). Exit-kode 0 = alt oppe.

Gjenbruker samme mønster som maskinrommet/src/health.rs men som
frittstående verktøy — kan brukes av admin-dashboard, overvåking,
og direkte fra CLI.
2026-03-18 20:54:27 +00:00
8f12b08c25 Starter oppgave 28.7 2026-03-18 20:50:26 +00:00
f1e6355037 synops-backup: PG-dump + CAS-filiste + metadata-snapshot (oppgave 28.6)
Nytt Rust CLI-verktøy som erstatter scripts/backup-pg.sh:
- pg_dump -Fc via docker exec (konsistent snapshot)
- CAS-manifest: liste over alle filer med hash og størrelse
- Metadata-snapshot (JSON) med tidsstempel, modus, statistikk
- --full / --incremental / --payload-json for jobbkø
- Rotasjon av gamle dumper (30 dager, kun ved --full)

Output: strukturert JSON med backup-sti og detaljer.
2026-03-18 20:45:02 +00:00
0f7fdb75e0 Starter oppgave 28.6 2026-03-18 20:40:25 +00:00
053990d222 synops-validate: sjekk at en node matcher forventet skjema for sin node_kind (oppgave 28.5)
Nytt CLI-verktøy som henter en node fra PG og validerer:
- Basisfelter: visibility, created_by, metadata-type, kjent node_kind
- node_kind-spesifikk metadata: collection (traits), ai_preset,
  orchestration, media, communication
- Relasjonelle sjekker: person→auth_identities, agent→agent_identities

Samler alle avvik (feiler ikke på første treff). Output i markdown
eller JSON (--format). Exit-koder: 0=OK, 1=avvik, 2=feil.

Valideringsreglene speiler maskinrommet/src/intentions.rs slik at
skrivestien og valideringsverktøyet håndhever samme skjema.
2026-03-18 20:37:23 +00:00
fa7b8f500d Starter oppgave 28.5 2026-03-18 20:30:25 +00:00
bdb4a697f5 synops-notify: send varsel via epost, WebSocket-push, eller begge (oppgave 28.4)
Nytt CLI-verktøy som sender varsler til brukere via to kanaler:
- Email: Slår opp epost fra auth_identities, kaller synops-mail
- WebSocket: Oppretter notification-node i PG med node_access for mottaker,
  PG NOTIFY-trigger leverer via portvokteren til brukerens WS-tilkobling

Støtter --channel email|ws|both (default: ws) og --payload-json for jobbkø-dispatch.
Validerer at mottaker er person/agent. JSON-output til stdout.
2026-03-18 20:27:04 +00:00
e0afec848b Starter oppgave 28.4 2026-03-18 20:20:27 +00:00
2fa5d7ef2f AI-kostnadstak per bruker/samling: budsjettsjekk før AI-kall (oppgave 28.3)
Samlings- og brukernoder kan nå ha ai_budget i metadata:
  { "ai_budget": { "monthly_limit_usd": 50.0 } }

Før hvert AI-kall aggregeres inneværende måneds forbruk fra
ai_usage_log og sammenlignes med grensen. Ved overskridelse:
- AI-kallet blokkeres med feilmelding
- En work_item-node opprettes med tag "budget_exceeded"
- Work_item knyttes til samlingen via belongs_to-edge

Endringer:
- migrations/029: requested_by-kolonne i ai_usage_log + indekser
- synops-ai: --collection-id/--user-id flagg, budsjettsjekk i prompt
- maskinrommet/ai_budget.rs: delt budsjettsjekk-modul
- maskinrommet/ai_process.rs: budsjettsjekk før AI gateway-kall
- docs/infra/ai_gateway.md: oppdatert § 6.3 fra "fase 2" til implementert
2026-03-18 20:19:52 +00:00
c0f05ab5e9 Starter oppgave 28.3 2026-03-18 20:10:30 +00:00
a06b79478a AI-rutingskontroll i admin: 13 kontekster konfigurerbare uten redeploy (oppgave 28.2)
Utvider /admin/ai med full kontroll over hvilken modellalias som brukes
per AI-kontekst. Admin kan bytte modell for orkestrering, bot-chat,
oppsummering, edge-forslag, klassifisering osv. uten å restarte
maskinrommet.

Endringer:
- Migration 028: seeder 7 nye kontekster i ai_job_routing
  (orchestration_script/dream, bot_chat/triage, summarize, suggest_edges, classify)
- Backend: resolve_routing_or_default() i ai_admin.rs — felles oppslag
  mot ai_job_routing med fallback til sidelinja/rutine
- Dispatchers (ai_edges, summarize) bruker nå routing-tabellen i stedet
  for hardkodede env-variabler — endringer trer i kraft umiddelbart
- Frontend: Ruting-tab omskrevet med kategoriserte kontekster
  (Orkestrering, Bot & chat, Analyse, Prosessering), beskrivelser per
  kontekst, og støtte for egendefinerte regler
- Docs: ai_gateway.md §3.4 oppdatert med alle 13 kontekster
2026-03-18 20:06:50 +00:00
1c59604b07 Starter oppgave 28.2 2026-03-18 19:55:35 +00:00
8436f75d87 synops-ai prompt: direkte LLM-kall via LiteLLM (oppgave 28.1)
Legger til `synops-ai prompt`-subkommando for enkel prompt-inn/tekst-ut
bruk av LLM via LiteLLM gateway. Eksisterende script-generering
flyttes til `synops-ai script`-subkommando.

Prompt-modus:
- --prompt (påkrevd): bruker-prompt
- --model (valgfri): modellalias, slås opp fra ai_job_routing hvis utelatt
- --system (valgfri): systemprompt
- --job-type: for modelloppslag og logging (default: simple_prompt)
- --temperature: LLM-temperatur (default: 0.7)
- Logger tokenbruk i ai_usage_log

Seed: simple_prompt → sidelinja/rutine i ai_job_routing.
2026-03-18 19:51:44 +00:00
b89f307fa2 Starter oppgave 28.1 2026-03-18 19:45:28 +00:00
8f7d2d7fe8 MindMap-trait for samlingsnoder (oppgave 27.3)
Gjør mindmap til et offisielt trait som kan velges ved opprettelse
av samlingsnoder. Frontend-komponenten (27.1) og BlockShell-panelet
(27.2) var allerede på plass — dette kobler traiten inn i backend-
validering og pakke-definisjoner.

Endringer:
- Lagt til "mindmap" i VALID_TRAITS (intentions.rs)
- Validering av konfig: default_depth 1-3, layout radial/tree
- Inkludert mindmap i Podcaststudio- og Wiki-pakker (traits.ts)
- Oppdatert trait-katalog i docs/primitiver/traits.md
2026-03-18 19:44:30 +00:00