Commit graph

306 commits

Author SHA1 Message Date
9d405f90e3 Starter oppgave 15.2 2026-03-18 03:22:34 +00:00
831666012a Fullfører oppgave 15.1: Systemvarsler via STDB
Implementerer systemvarsler (system_announcement-noder) som vises som
banner/toast for alle aktive klienter i sanntid via SpacetimeDB.

Backend (maskinrommet):
- POST /intentions/create_announcement: oppretter varslingsnode med
  validering av announcement_type (info/warning/critical), datoer
  (scheduled_at, expires_at) og blocks_new_sessions. Visibility
  settes automatisk til 'open' for broadcast til alle klienter.
- POST /intentions/expire_announcement: fjerner varslingsnode med
  tilgangskontroll (kun eier kan slette).

Frontend:
- SystemAnnouncements.svelte: filtrerer nodeStore for aktive
  system_announcement-noder, skjuler utløpte (expires_at), viser
  nedtelling for planlagte hendelser (scheduled_at). Fargekoding:
  rød (critical), gul (warning), blå (info). Critical kan ikke
  dismisses. Oppdaterer nedtelling hvert sekund.
- Komponent lagt til i +layout.svelte for global synlighet.
- API-funksjoner (createAnnouncement, expireAnnouncement) i api.ts.

Ref: docs/concepts/adminpanelet.md § "Systemvarsler og vedlikeholdsmodus"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 03:21:18 +00:00
1c313f3857 Starter oppgave 15.1 2026-03-18 03:15:06 +00:00
1425a82cdd Fullfører oppgave 14.17: A/B-testing for presentasjonselementer
Implementerer automatisk A/B-testing for forside-varianter:

- PG-migrasjon 012: ab_events-tabell for impression/klikk-logging
  med hour_of_week (0-167) for tidspunkt-normalisering
- Variant-rotasjon: ab_select() velger tilfeldig blant testing-varianter
  ved forside-rendering, winner prioriteres, retired filtreres bort
- Impression-logging: asynkron fire-and-forget ved forside-serve
  (både cache-hit og -miss), lagres i ab_events
- Klikk-attribusjon: artikkelbesøk sjekker forside-cache for aktive
  AB-varianter og logger klikk. Eksplisitt tracking via
  GET /pub/{slug}/t/{article_id}?v={edge_id}
- Periodisk evaluator (300s intervall): z-test for proporsjoner
  (p < 0.05), minimum 100 impressions per variant, oppdaterer
  edge-metadata (ab_status, impressions, clicks, ctr)
- Redaktør-overstyring: POST /intentions/ab_override markerer
  valgt variant som winner, andre som retired (krever owner/admin)
- Auto-initialisering: maybe_start_ab_test() setter ab_status=testing
  automatisk når >1 variant av samme type opprettes

Alle 42 tester passerer inkludert 3 nye z-test-tester.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 03:13:39 +00:00
a10de64686 Starter oppgave 14.17 2026-03-18 02:56:45 +00:00
63630eb55a Fullfører oppgave 14.16: Presentasjonselementer som noder
Publisert tittel, ingress, OG-bilde og undertittel er nå egne noder
koblet til artikler via title/subtitle/summary/og_image-edges.
Rendering bruker presentasjonselementer med fallback til artikkelfelt.

Backend:
- Ny query: GET /query/presentation_elements?article_id=...
- render_article_to_cas henter presentasjonselementer via edges
- fetch_article + fetch_index_articles bruker pres.elementer
- Batch-henting for forsideartikler (én SQL-spørring)
- ArticleData utvides med subtitle + og_image
- Alle fire temaer viser subtitle og OG-bilde
- SEO og_image-tag fylles fra presentasjonselement

Frontend:
- PresentationEditor.svelte: opprett/rediger tittel, undertittel,
  ingress, OG-bilde med variantvelger (editorial/ai/social/rss)
- Integrert i PublishDialog via <details>-seksjon
- API-klient: fetchPresentationElements(), deleteNode()

Grunnlag for A/B-testing (oppgave 14.17): edge-metadata støtter
ab_status/impressions/clicks/ctr, best_of() prioriterer winner > testing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 02:55:23 +00:00
18642d5e79 Starter oppgave 14.16 2026-03-18 02:42:54 +00:00
bf67ad1b96 Fullfører oppgave 14.15: nav-lenker, docs, tasks.md
- Navigasjonslenker (Arkiv, Søk) i base.html header
- Dokumentasjon av implementerte sidetyper i publisering.md
- Markerer oppgave 14.15 som ferdig i tasks.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 02:41:34 +00:00
dda68594d7 Starter oppgave 14.15 2026-03-18 02:29:32 +00:00
cf38721459 Bulk re-rendering ved temaendring (oppgave 14.14): paginert batch-jobb via jobbkø
Når theme eller theme_config endres på en samling, trigges paginert
bulk re-rendering av alle artikler (100 om gangen). Artikler serveres
med gammelt tema til de er re-rendret — renderer_version identifiserer
hvilke som gjenstår. Duplikatsjekk mot eksisterende pending/running jobber.

- publishing.rs: trigger_bulk_rerender() med paginert SQL-query
- intentions.rs: theme/theme_config endring detekteres i update_node
- RENDERER_VERSION bumped til 2

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 02:28:07 +00:00
8155783fc4 Starter oppgave 14.14 2026-03-18 02:23:35 +00:00
6125302bcb Redaksjonell samtale (oppgave 14.13): kommunikasjonsnode knyttet til artikkel
Redaktør kan nå opprette en diskusjonstråd direkte fra den redaksjonelle
arbeidsflaten, knyttet til en innsendt artikkel og dens forfatter.

Backend:
- create_communication utvides med context_id som oppretter belongs_to-edge
  fra kommunikasjonsnoden til kontekstnoden (artikkelen)
- editorial_board-spørringen returnerer discussion_ids per kort (kommunikasjonsnoder
  med belongs_to til artikkelen)

Frontend:
- "Start samtale"-knapp på hvert redaksjonelt kort oppretter kommunikasjonsnode
  med redaktør som owner og forfatter som member, og navigerer til chatten
- Eksisterende samtaler vises som lenker på kortet

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 02:22:17 +00:00
7bdcdafa24 Starter oppgave 14.13 2026-03-18 02:15:18 +00:00
eea66744d8 Planlagt publisering (oppgave 14.12): periodisk scheduler i maskinrommet
Legger til en bakgrunns-scheduler som hvert 60. sekund sjekker for
belongs_to-edges med publish_at i fortiden der artikkelen ikke er rendret.
Ved treff: oppretter render_article-jobb (og render_index for berørte
samlinger) i jobbkøen. RSS-feeden oppdateres automatisk siden den
genereres dynamisk fra DB.

Detaljer:
- find_due_articles(): SQL-spørring med deduplisering mot eksisterende jobber
- run_publish_scheduler(): orkestrerer én runde med publisering
- start_publish_scheduler(): tokio::spawn med 60s poll-intervall
- Hooks inn i main.rs ved oppstart, parallelt med jobbkø og pruning

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 02:14:04 +00:00
1d2741a18a Starter oppgave 14.12 2026-03-18 02:10:20 +00:00
f1752e73f5 Redaktørens arbeidsflate (oppgave 14.11): Kanban-brett for innsendinger
Redaktøren ser alle artikler med submitted_to-edge til samlingen,
gruppert i fire kolonner etter status. Drag-and-drop mellom kolonner
endrer status via update_edge. Siste kolonne ("Planlagt") åpner en
dialog for å sette publish_at i edge-metadata — klar for oppgave 14.12
(planlagt publisering).

Backend: GET /query/editorial_board med forfatterinfo og edge-metadata.
Frontend: /editorial/[id] med sanntidsoppdateringer via SpacetimeDB.
Lenke fra PublishingTrait når require_approval er aktivt.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 02:09:03 +00:00
ffc0201103 Starter oppgave 14.11 2026-03-18 02:02:23 +00:00
f593b1e320 Redaksjonell innsending (oppgave 14.10): submitted_to-edge med rollevalidering
Maskinrommet håndhever nå publiseringsregler for samlinger med
require_approval: true i publishing-traiten:

- submitted_to-edge: kun roller i submission_roles (+ owner/admin) kan
  opprette. Metadata settes automatisk: status=pending, submitted_at=now.
- belongs_to-edge til require_approval-samling: kun owner/admin.
- Status-endring på submitted_to: kun owner/admin av samlingen.

PublishingConfig utvidet med require_approval (default false) og
submission_roles (default ["member"]).

Nye hjelpefunksjoner: get_publishing_config, get_user_role_for_node,
user_is_owner_or_admin. EdgeRow utvidet med source_id/target_id.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 02:01:11 +00:00
a40a23447a Starter oppgave 14.10 2026-03-18 01:53:02 +00:00
66ebe58ff8 Custom domains (oppgave 14.9): DNS-validering, Caddy on-demand TLS, re-rendering
Tre hovedkomponenter:

1. custom_domain.rs — ny modul i maskinrommet:
   - GET /internal/verify-domain?domain= — Caddy on-demand TLS callback.
     Returnerer 200 hvis domenet er registrert i en publishing-trait, 404 ellers.
   - DNS-validering (validate_dns): sjekker at domenet peker til serverens IP
     via system DNS resolver. Kalles ved oppdatering av publishing-trait.
   - Domene-basert serving: /custom-domain/index, /custom-domain/{article_id},
     /custom-domain/feed.xml — Caddy rewriter custom domain-forespørsler hit,
     Host-header brukes til å finne samlingen.
   - Re-rendering: rerender_collection_articles() enqueuer render-jobber
     for alle artikler + forside når custom_domain endres.

2. Caddy on-demand TLS (Caddyfile):
   - Catch-all :443-blokk med on_demand ask-callback til maskinrommet.
   - Rewrite-regler: / → /custom-domain/index, /feed.xml → /custom-domain/feed.xml,
     /* → /custom-domain/{uri}. Host-header bevares for domene-oppslag.

3. intentions.rs — utvidet update_node:
   - DNS-validering ved setting av custom_domain i publishing-trait.
   - Detekterer endring i custom_domain og trigger re-rendering av
     alle artikler (canonical URL endres).

Eksisterende kode (publishing.rs, rss.rs) bruker allerede custom_domain
for base_url/canonical_url — ingen endringer nødvendig der.

Ref: docs/concepts/publisering.md § "Custom domain-mekanisme"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 01:51:35 +00:00
8c7c0bfff9 Starter oppgave 14.9 2026-03-18 01:43:30 +00:00
265adea0b3 RSS/Atom-feed (oppgave 14.8): feed-discovery + betinget RSS-lenke
Feeden i rss.rs var allerede implementert med full RSS 2.0 og Atom 1.0
støtte, inkl. podcast-enclosures. Det som manglet var integrasjon med
publiseringstemplates:

- base.html: <link rel="alternate"> for feed auto-discovery (kun når
  samlingen har rss-trait)
- base.html: RSS-lenke i nav vises kun for samlinger med rss-trait
- publishing.rs: has_rss propageres fra CollectionRow gjennom alle
  render-funksjoner til Tera-kontekst
- CAS-rendering (render_article_to_cas, render_index_to_cas) sjekker
  også rss-trait for korrekt template-kontekst

Verifisert: kompilerer, alle 36 tester passerer, feed.xml returnerer
gyldig RSS/Atom, 404 for ukjente slugs, discovery-link i HTML.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 01:42:16 +00:00
20b07131da Starter oppgave 14.8 2026-03-18 01:34:57 +00:00
27d0d8db94 Publiseringsflyt i frontend (oppgave 14.7)
Personlig publiseringsflyt for samlinger med publishing-trait der
require_approval: false. Bruker kan publisere artikler fra mottak
til samlingen, og avpublisere ved å fjerne belongs_to-edge.

Backend:
- Nytt delete_edge-endepunkt i maskinrommet med tilgangskontroll
  og automatisk forside-cache-invalidering ved avpublisering

Frontend:
- PublishDialog: forhåndsvisning, slug-editor, tema-info, bekreftelse
- EditorTrait: publiser/avpubliser-knapper på innholdsnoder i
  publiseringssamlinger, velger for upubliserte artikler
- deleteEdge i API-klienten

Docs:
- Oppdatert api_grensesnitt.md med delete_edge, update_edge, set_slot

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 01:33:37 +00:00
7eeee34c74 Legg til fase 19 (spatial canvas) og 20 (universell overføring + panelrework)
Arkitekturskiftet fra "vertikalt stablede traits" til "spatial canvas
med verktøy-paneler" krever:

Fase 19 — Arbeidsflaten:
- Canvas-primitiv (pan/zoom/viewport)
- BlockShell wrapper for alle paneler
- Collection-side rewrite til spatial layout
- Kontekst-header med node-velger
- Snarveier og personlig flate

Fase 20 — Universell overføring:
- message_placements tabell + STDB
- source_material edge-type
- BlockReceiver interface i alle traits
- Transfer service (innholdstransfer + triage)
- Panelrework for Chat, Kanban, Kalender, Editor, Studio

Ref: docs/retninger/arbeidsflaten.md, docs/features/universell_overfoering.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 01:28:24 +00:00
ee5a971af5 Starter oppgave 14.7 2026-03-18 01:25:43 +00:00
8a4df2c237 Forside-admin i frontend (oppgave 14.6)
Visuell editor for redaksjonell forside-styring. Rute:
/collection/[id]/forside med tre soner (hero, featured, strøm).

- HTML5 drag-and-drop mellom hero/featured/strøm-plasser
- Pin-knapp per artikkel (forhindrer automatisk fjerning)
- Hurtigknapper for å flytte artikler mellom slots
- Forhåndsvisning via iframe av publisert forside
- Bruker POST /intentions/set_slot API fra maskinrommet
- Sanntidsdata fra SpacetimeDB (belongs_to-edges med slot-metadata)
- PublishingTrait viser nå «Rediger forside»-knapp og publisert-lenke

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 01:24:25 +00:00
822bcb41d1 Starter oppgave 14.6 2026-03-18 01:17:39 +00:00
141cac9292 Slot-håndtering i maskinrommet (oppgave 14.5)
Ny intention `POST /intentions/set_slot` for redaksjonell
kontroll over forside-slots i publiseringssamlinger.

Håndhever:
- Maks 1 hero: gammel ikke-pinned hero flyttes til strøm
- featured_max: eldste ikke-pinned featured FIFO til strøm
- pinned-flagg beskytter mot automatisk fjerning
- Krever owner/admin-tilgang til samlingen
- Trigger forside-rerendering etter slot-endring

Returnerer liste over displaced edges slik at frontend
kan vise hva som ble flyttet.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 01:16:21 +00:00
6e6e4912c1 Starter oppgave 14.5 2026-03-18 01:10:48 +00:00
82b43a55e9 Caddy-ruting for synops.no/pub → maskinrommet (oppgave 14.4)
synops.no/pub/* proxyes nå til maskinrommet (port 3100) som eier
slug→hash-mappingen og setter Cache-Control-headere:
- Artikler fra CAS: immutable (1 år)
- Dynamisk forside: max-age=index_cache_ttl (default 300s)
- Kategori/arkiv/søk (14.15): kortere TTL når endepunktene kommer

Bruker `handle` (ikke `handle_path`) slik at /pub-prefixet
beholdes — maskinrommets ruter forventer /pub/{slug}/...

Verifisert: Caddy validerer OK, 404 for ukjent slug passerer
korrekt gjennom proxyen med `via: 1.1 Caddy`-header.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 01:09:34 +00:00
72f8bae2fa Starter oppgave 14.4 2026-03-18 01:05:51 +00:00
f537f3dcf3 Forside-rendering med to moduser: statisk CAS og dynamisk in-memory cache (oppgave 14.3)
serve_index støtter nå index_mode fra publishing-trait:
- "static": render_index-jobb rendrer forsiden til CAS ved publisering,
  samlingens metadata.rendered_index.index_hash peker til CAS-fil,
  serveres med Cache-Control: immutable
- "dynamic" (default): in-memory cache med konfigurerbar TTL
  (index_cache_ttl, default 300s), invalidert ved belongs_to-endringer

Tre separate indekserte PG-spørringer erstatter den gamle
alt-i-ett-spørringen — filtrerer på slot i edge-metadata
(hero/featured/strøm) med LIMIT, bruker GIN-indeks.

Trigger-logikk utvidet: belongs_to-edge-opprettelse legger
render_index-jobb i kø (statisk) eller invaliderer cache (dynamisk).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 01:04:31 +00:00
51f49fea22 Legg til fase 17: lydstudio-utbedring (7 oppgaver)
Kodegjennomgang av lydstudio-implementasjonen avdekket:
- Responsivt design mangler (mobil-layout)
- FFmpeg-parametervalidering bør strammes
- Fade/silence-logikkfeil (negativ start, margin-underflow)
- Frontend input-begrensninger mangler
- Job-polling lekker ved navigering
- Temp-filer ryddes ikke ved krasj
- FFmpeg-feilmeldinger når ikke bruker

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:55:20 +00:00
2ac0ba5fcb Starter oppgave 14.3 2026-03-18 00:54:18 +00:00
e050612dec HTML-rendering av enkeltartikler til CAS med SEO-metadata (oppgave 14.2)
Implementerer rendering-pipeline: metadata.document (TipTap JSON) → HTML
via Tera-templates → CAS-lagring → metadata.rendered oppdateres.

Nye moduler:
- tiptap.rs: Konverterer TipTap/ProseMirror JSON til HTML. Støtter
  paragraph, heading, blockquote, lister, code_block, image, hr,
  og marks (bold, italic, strike, code, link, underline).
  XSS-sikker med HTML-escaping.

- render_article jobb i jobbkøen: Henter node + samling, konverterer
  document → HTML, rendrer med Tera + tema, lagrer i CAS, oppdaterer
  nodens metadata.rendered med html_hash og renderer_version.

Endringer:
- publishing.rs: SeoData-struct med OG-tags, canonical URL, JSON-LD.
  render_article_to_cas() for full pipeline. serve_article() serverer
  fra CAS (immutable cache) hvis pre-rendret, fallback til on-the-fly.
  RENDERER_VERSION=1 for fremtidig bulk re-rendering.

- intentions.rs: Trigger render_article-jobb automatisk når belongs_to
  edge opprettes til samling med publishing-trait.

- Alle 4 artikkel-templates: SEO-block med meta description, OG-tags
  (type, title, description, url, site_name, image, published_time),
  canonical URL, RSS-link, og JSON-LD structured data.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:52:58 +00:00
5d14acf921 Starter oppgave 14.2 2026-03-18 00:43:12 +00:00
4b9f520eab Tera-templates: innebygde temaer for publisering (oppgave 14.1)
Implementerer publiseringsmotoren med fire innebygde temaer:
- Avis: multi-kolonne, informasjonstung, hero+sidebar+rutenett
- Magasin: store bilder, luft, editorial, cards-layout
- Blogg: enkel, én kolonne, kronologisk liste
- Tidsskrift: akademisk, tekstdrevet, nummerert innholdsfortegnelse

Hvert tema har artikkelmal + forside-mal som Tera-templates (Jinja2-like).
CSS-variabler for theme_config-overstyring fra publishing-traiten —
fungerer meningsfullt med bare "theme": "magasin" (null konfigurasjon).

Teknisk:
- publishing.rs: Tera engine, render-funksjoner, DB-spørringer, HTTP-handlers
- Templates innebygd via include_str! (kompilert inn i binæren)
- Ruter: GET /pub/{slug} (forside), /pub/{slug}/{id} (artikkel),
  /pub/{slug}/preview/{theme} (forhåndsvisning med testdata)
- 6 enhetstester for CSS-variabler, rendering og tema-fallback

Ref: docs/concepts/publisering.md § "Temaer"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:41:54 +00:00
260d3d030c Starter oppgave 14.1 2026-03-18 00:33:54 +00:00
51eb089f0c Trait-administrasjon: admin-UI for å administrere traits på samlinger (oppgave 13.4)
Legger til et admin-panel på samlingssiden der man kan legge til/fjerne
traits fra katalogen og konfigurere per-trait-innstillinger. Endringene
sendes via updateNode til maskinrommet som validerer mot VALID_TRAITS.

- Ny updateNode-funksjon i api.ts
- Delt trait-katalog i lib/traits.ts (brukes av collection/new og TraitAdmin)
- TraitAdmin.svelte: toggle traits, rediger config-nøkler, lagre
- Integrasjon i collection/[id] med Traits-knapp i header

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:32:31 +00:00
b05b4f6e58 Starter oppgave 13.4 2026-03-18 00:27:29 +00:00
427eae9641 Pakkevelger: UI for ny samling med pakker eller manuelt trait-valg (oppgave 13.3)
Ny side /collection/new med:
- 13 forhåndsdefinerte pakker (nettmagasin, podcaststudio, redaksjon osv.)
  som kort-grid med ikon, beskrivelse og trait-liste
- Manuelt trait-valg med hele trait-katalogen kategorisert i 9 grupper
- Oppsummering med valgte traits og opprett-knapp
- Navigerer til /collection/[id] etter opprettelse

Knapp «Ny samling» lagt til i mottak-headeren.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:26:17 +00:00
7079759c24 Starter oppgave 13.3 2026-03-18 00:21:52 +00:00
263f63bec8 Trait-aware frontend: samlingssider med dynamiske trait-paneler (oppgave 13.2)
Samlingsnoder med `metadata.traits` rendres nå som egne sider på
/collection/[id]. Hvert trait-navn mappes til en dedikert Svelte-komponent
som viser relevant UI. Traits uten egen komponent vises med et generisk panel.

Komponenter for 9 traits: editor, chat, kanban, podcast, publishing,
rss, calendar, recording, transcription. Mottak-siden viser traits som
pills og lenker til samlingssiden.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:20:35 +00:00
a404751fe4 Starter oppgave 13.2 2026-03-18 00:15:34 +00:00
37cd133e1d Trait-validering for samlingsnoder (oppgave 13.1)
Maskinrommet validerer nå metadata.traits ved create_node og update_node
for collection-noder. Ukjente trait-navn avvises med 400 Bad Request.

Lukket katalog med 48 gyldige traits fra docs/primitiver/traits.md.
Konfigurasjon per trait er fri JSONB — kun nøkkelnavnene valideres.
Noder som ikke er collections valideres ikke (traits ignoreres).

Inkluderer 6 unit-tester for valideringsfunksjonen.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:14:21 +00:00
a21da84122 Starter oppgave 13.1 2026-03-18 00:10:25 +00:00
e5c7791dfc Podcast-RSS: samlings-node med publiserings-edges → generert RSS-feed (oppgave 11.4)
Nytt endepunkt GET /pub/{slug}/feed.xml som genererer RSS 2.0 eller
Atom 1.0 feed for samlinger med rss-trait. Feeden er offentlig (ingen auth).

- Slår opp samling via publishing.slug i metadata.traits
- Henter belongs_to-edges (publiserte noder), sortert på publish_at
- Podcast-samlinger (med podcast-trait) inkluderer <enclosure>-tags
  med CAS-URL, MIME-type og filstørrelse fra has_media-edges
- Støtter RSS 2.0 (default) og Atom 1.0 via rss.format config
- iTunes-namespace for podcast-feeds
- Stabile GUID-er basert på node UUID
- 5 min cache (Cache-Control: public, max-age=300)

Manuell XML-generering uten ekstra avhengigheter — enklere enn å
introdusere en RSS-crate for dette omfanget.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:09:10 +00:00
da988234dd Starter oppgave 11.4 2026-03-18 00:03:43 +00:00
6d916d9860 Pruning-logikk: TTL per modalitet, signaler, disk-nødventil (oppgave 11.3)
Implementerer automatisk opprydding av CAS-filer basert på dokumentert
spec i docs/retninger/maskinrommet.md:

- TTL per modalitet: lyd 30d, bilde 30d, video 14d, tekst aldri
- Signaler som forlenger levetid: publishing-edge, siste tilgang
  (last_accessed_at), utranskribert lyd beholdes
- Tre-trinns disk-nødventil:
  - >85%: slett generert innhold (TTS osv, kan regenereres)
  - >90%: aggressiv pruning med kraftig redusert TTL
  - >95%: kritisk — alt uten publishing-edge slettes
- Periodisk bakgrunnsloop: hvert 6. time, oftere ved høy disk
- Tilgangslogging: serving oppdaterer last_accessed_at (fire-and-forget)
- Pruning-hendelser logges til resource_usage_log

Ny modul: maskinrommet/src/pruning.rs
Ny migrasjon: 010_pruning.sql (last_accessed_at kolonne + indeks)
CasStore utvidet med delete(), disk_usage_bytes(), disk_usage_percent()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:02:27 +00:00