Commit graph

25 commits

Author SHA1 Message Date
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
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
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
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
b4c4bb8a0f Lydstudio: lydredigering via FFmpeg i nettleseren
Ikke-destruktiv redigering via EDL (Edit Decision List):
- Backend: audio.rs med FFmpeg-subprocess for klipp, normalisering,
  silence trim, fades, noise reduction, EQ, kompressor
- Frontend: /studio/[id] med wavesurfer.js RegionsPlugin,
  verktøypanel, sesjonslagring, og render-dialog
- Studio-trait for samlinger, versjonshistorikk via derived_from-edges
- API: audio_analyze (synkron), audio_process (jobbkø), audio_info

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 00:45:53 +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
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
7f5d23e0c6 Kunnskapsgraf: topic-noder, mentions-edges, visuell graf-visning (oppgave 9.4)
Backend:
- query_graph endpoint med rekursiv CTE-traversering (fokus + dybde)
- Filtrering på node_kind og edge_type, RLS-beskyttet
- Maks 200 noder, 1-3 hops dybde

Frontend:
- D3 force-directed graf på /graph med fargekodede noder
- Opprett topic-noder (node_kind='topic') direkte fra graf-visningen
- Opprett mentions-edges mellom vilkårlige noder
- Klikk for detaljer, dobbeltklikk for fokus, dra for å flytte
- Filter-legende for nodetyper og kanttyper
- Zoom, auto-fit, sidepanel med koblingsinfo
- Graf-knapp lagt til i mottaksflaten

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:01:57 +00:00
d8c0cceb89 Kanban-visning: board med drag-and-drop statusendring (oppgave 9.1)
Implementerer kanban som noder+edges uten separate tabeller:
- Board = collection-node med metadata.board og metadata.columns
- Kort = content-noder med belongs_to-edge til board
- Status via status-edge (kort→board) med metadata.value
- Posisjon via belongs_to-edge metadata.position

Backend:
- POST /intentions/update_edge — oppdater edge-type/metadata
- GET /query/board?board_id= — hent kort med status og posisjon

Frontend:
- /board/[id] route med kolonner, drag-and-drop, kortoppretting
- Sanntid via SpacetimeDB edge-subscriptions
- Board-oppretting og navigasjon fra mottak-siden

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 22:13:22 +00:00
d4715831bf Flytt Caddy fra Docker til native + fiks frontend-kjeden
- Caddy installert via apt, kjører som systemd-service
- Docker-tjenester eksponerer porter på localhost (Authentik:9000,
  Forgejo:3000, SpacetimeDB:9080)
- Caddy-blokk fjernet fra docker-compose.yml
- iptables-hack fjernet (ingen Docker→host-proxy lenger)
- Caddy proxyer /api/* til maskinrommet (unngår CORS)
- SpacetimeDB URL fikset (trailing slash for korrekt URL-resolving)
- Arvet tilgang i nodeVisibility (belongs_to → foreldrenode)
- Signin-side bruker <a> i stedet for client-side signIn()
- /claude redirect-rute for testing
- @auth/core oppgradert 0.34.3→0.41.1

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 21:26:06 +00:00
35701aeb2a Fullfør oppgave 7.8: SRT-eksport fra transkripsjons-segmenter
Nytt GET /query/segments/srt-endepunkt som genererer nedlastbar SRT-fil
fra transcription_segments-tabellen. Bruker RLS-verifisert tilgang.
Frontend har nedlastingsknapp i TranscriptionView med autentisert fetch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 18:47:50 +01:00
b4ee80a97b Fullfør oppgave 7.7: Re-transkripsjonsflyt med side-om-side-sammenligning
Ny funksjonalitet for å kjøre re-transkripsjon på eksisterende media-noder
og sammenligne gammel vs ny versjon per segment. Manuelt redigerte segmenter
fra forrige versjon blir uthevet, og brukeren velger per segment hvilken
versjon som skal beholdes.

Backend (Rust):
- POST /intentions/retranscribe — trigger ny Whisper-jobb for media-node
- GET /query/transcription_versions — list alle versjoner for en node
- GET /query/segments_version — hent segmenter for spesifikk versjon
- POST /intentions/resolve_retranscription — anvend per-segment-valg

Frontend (Svelte):
- RetranscriptionCompare.svelte — side-om-side visning med per-segment-valg
- TranscriptionView: re-transkriber-knapp, auto-detect nye versjoner, polling
- API-klient: nye funksjoner for alle re-transkripsjonsendepunkter

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 18:41:09 +01:00
0967e43af8 Implementer transkripsjonsvisning med segmenter (oppgave 7.6)
Backend:
- GET /query/segments?node_id=... — henter nyeste segmenter for en media-node
  med RLS-basert tilgangssjekk via nodes-tabellen
- POST /intentions/update_segment — redigerer segmenttekst, setter edited=true

Frontend:
- TranscriptionView.svelte: universell komponent for segment-visning med
  tidsstempler, avspillingsknapp per segment, og redigerbare tekstfelt
- AudioPlayer: integrert med TranscriptionView når segmenter finnes,
  faller tilbake til flat tekst ellers
- Mottak og chat-sider oppdatert med nodeId/accessToken for segment-lasting
- Fikser duration_ms → sekunder-konvertering i metadata-oppslag

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 18:29:43 +01:00
63d4bbd41b Fullfør oppgave 7.4: Lyd-avspilling med waveform-visning
Legger til AudioPlayer-komponent som spiller av lyd fra CAS-noder
med waveform-visualisering via wavesurfer.js. Komponenten viser
play/pause, tidslinje, og kan ekspandere transkripsjonen.

Chat-visningen inkluderer nå media-noder (has_media-edges) sammen
med tekstmeldinger, sortert kronologisk. Talenotater vises med
mikrofon-ikon, waveform og transkripsjon.

Mottak-siden viser også AudioPlayer for media-noder med lyd.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 18:07:29 +01:00
ebbec982b3 Fullfør oppgave 7.3: Voice memo — opptak-knapp i frontend
Legger til VoiceRecorder-komponent som bruker MediaRecorder API for
lydopptak i nettleseren. Opptaket lastes opp til CAS via eksisterende
uploadMedia-endepunkt, som automatisk trigger Whisper-transkripsjon.

Komponenten er integrert i:
- ChatInput: mikrofon-knapp mellom tekstfelt og send-knapp
- NodeEditor: mikrofon-knapp i verktøylinjen

Flyten: opptak → webm/opus blob → upload → CAS → whisper_transcribe-jobb.
Ingen backend-endringer nødvendig — hele transkripsjons-pipelinen fra
oppgave 7.2 gjenbrukes uendret.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 17:51:40 +01:00
dee9d5bf3a Fullfør oppgave 6.4: Bilder i TipTap via drag-and-drop/paste
Brukeren kan nå dra eller lime inn bilder i TipTap-editoren.
Bildet lastes opp til CAS via upload_media-endepunktet, og settes
inn som <img> med CAS-URL i metadata.document (HTML).

Endringer:
- Ny uploadMedia() og casUrl() i api.ts for multipart upload
- @tiptap/extension-image med CasImage-utvidelse (data-node-id attr)
- handleDrop/handlePaste i editor intercepter bildefiler
- Upload-status vises i editoren mens bilder lastes opp
- accessToken sendes ned til NodeEditor fra +page.svelte

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 17:07:17 +01:00
5d2581710f Fullfør oppgave 5.4: én-til-én chat med deltaker-velger
Implementerer full 1:1 chat-loop:
- NewChatDialog: velg person å starte samtale med
- Fikser API-felt (participant_ids → participants) for korrekt
  kommunikasjon med maskinrommets create_communication-endepunkt
- Opprett kommunikasjonsnode med to deltakere (owner + member_of)
- Dedupliserer: finner eksisterende samtale før ny opprettes
- Chat-header viser den andre deltakerens navn i 1:1-samtaler
- Testbruker-node opprettet på server for verifisering

Full loop verifisert via STDB: node + edges + melding + belongs_to
fungerer, WebSocket-subscribers ser endringer i sanntid.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 16:25:44 +01:00
2af06111bb Fullfør oppgave 5.3: chat-visning med sanntid via STDB
Chat-visning i frontend som viser noder med belongs_to-edge til en
kommunikasjonsnode, sortert på tid, med sanntidsoppdatering via
SpacetimeDB.

Nye filer:
- frontend/src/routes/chat/[id]/+page.svelte — Chat-side som viser
  meldinger (noder med belongs_to-edge), deltakere, auto-scroll,
  og avsender-info. Bruker edgeStore.byTarget() for reaktive
  oppdateringer når nye meldinger kommer via STDB.
- frontend/src/lib/components/ChatInput.svelte — Enkel meldings-input
  med Enter-for-send, auto-resize textarea.

Endringer:
- frontend/src/lib/api.ts — Lagt til createCommunication()-funksjon
  for å opprette kommunikasjonsnoder fra frontend.
- frontend/src/routes/+page.svelte — Kommunikasjonsnoder i mottaket
  er nå klikkbare lenker til chat-visningen. "Ny samtale"-knapp.
- tasks.md — Oppgave 5.3 markert som ferdig.

Arkitektur: Chat-visningen bruker context_id-parameteren i
create_node-intensjonen (implementert i 5.2) for automatisk
belongs_to-edge. Meldinger hentes reaktivt fra STDB-stores —
ingen polling, ingen ekstra API-kall.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 16:15:15 +01:00
b55705d12c Kontekst-arv: automatisk belongs_to-edge ved input i kommunikasjonsnode
Legger til context_id-parameter på create_node-intensjonen. Når context_id
er satt (og peker på en kommunikasjonsnode), opprettes automatisk en
belongs_to-edge fra den nye noden til kontekstnoden. Dette er kjernen i
kontekst-arv: si noe i et møte → noden tilhører møtet automatisk.

Backend: Validerer at context_id eksisterer og er communication-node,
oppretter belongs_to-edge i STDB+PG etter node-opprettelse.
Frontend: Oppdaterer API-typer med context_id og belongs_to_edge_id.

Ref: docs/retninger/universell_input.md (kontekst arves automatisk)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 15:57:25 +01:00
023b598436 Frontend: visibility-filtrering med nodeAccessStore
Visibility-filtrering (oppgave 4.3, del 2/2):
- Regenerert STDB TypeScript-bindinger med node_access-tabell
- nodeAccessStore: reaktiv Svelte 5 store for tilgangsmatrisen
- nodeVisibility()-funksjon: returnerer 'full'/'discoverable'/'hidden'
  basert på created_by, node_access, og visibility-enum
- Mottaksflaten filtrerer noder: hidden-noder skjules,
  discoverable viser kun tittel, readable/open vises fullt
- Abonnerer på node_access-tabell via STDB WebSocket
- Debug-info viser antall access-rader

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 15:15:22 +01:00
83cc04937c Fullfør oppgave 3.6: Sanntidstest verifisert
Backend-verifisering av sanntidsflyt (STDB CRUD) bestått:
- Node opprettelse, oppdatering, sletting via STDB HTTP API
- Edge opprettelse med kaskadesletting
- Data synkronisert korrekt mellom PG og STDB

Frontend klar for browser-test (to faner):
- Arkitekturen støtter sanntid: STDB WebSocket → onInsert → stores → $derived
- Lagt til console.log i stores for å spore sanntidshendelser
- Alle builds (svelte-check, vite build, cargo check) grønne

Testskript: scripts/test-sanntid.sh (8 backend-tester)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 14:40:18 +01:00
0756e17069 Fullfør oppgave 3.5: TipTap-editor med create_node + owner-edge
Legger til owner-edge etter node-opprettelse slik at noden dukker opp
i brukerens mottak. Gjør API-klienten konfigurerbar via VITE_API_URL
for fremtidig produksjonsbruk. Legger til createEdge i API-klienten.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 14:26:59 +01:00
daaafd34ab TipTap-editor med create_node-intensjon (oppgave 3.5)
Legger til en TipTap-basert rik tekst-editor i mottaksflaten som sender
create_node-intensjoner til maskinrommet ved submit.

- TipTap med StarterKit (tekst, markdown), Link-extension og Placeholder
- NodeEditor.svelte: tittel + innhold, Ctrl+Enter for submit
- API-klient (lib/api.ts) som kaller maskinrommet via /api proxy
- Authentik access_token eksponert i session for API-kall
- Vite proxy rewrite fikset (/api → maskinrommet root)
- HTML-innhold lagres i metadata.document, ren tekst i content

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 14:24:25 +01:00
a91d358263 STDB WebSocket-klient med reaktive Svelte-stores (oppgave 3.3)
Frontend kobler til SpacetimeDB via WebSocket og abonnerer på
node- og edge-tabellene. Data eksponeres som reaktive Svelte 5-stores
(runes) som oppdateres automatisk ved insert/update/delete.

Implementering:
- spacetimedb SDK (npm) + genererte TypeScript-bindings
- connection.svelte.ts: tilkoblingsmanager med reaktiv state
- stores.svelte.ts: nodeStore og edgeStore med sekundærindekser
  (bySource, byTarget, byKind, byType osv.)
- Layout initialiserer tilkobling ved autentisering
- Hjemmesiden viser tilkoblingsstatus og antall noder/edges
- .env.example med VITE_SPACETIMEDB_URL og VITE_SPACETIMEDB_MODULE

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 13:55:37 +01:00
d43365d5ea SvelteKit frontend-skjelett (oppgave 3.1)
Oppretter frontend/ med SvelteKit, TypeScript, TailwindCSS v4 og
adapter-node. PWA-manifest med SVG-ikon. Vite proxy til
api.sidelinja.org for lokal utvikling med HMR.

Oppdaterer docs/setup/lokal.md med riktige stier (frontend/ og
maskinrommet/ i stedet for web/ og rust/).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 13:37:41 +01:00