Commit graph

115 commits

Author SHA1 Message Date
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
08d2933788 Mottaksflaten v0: vis noder koblet til innlogget bruker (oppgave 3.4)
Henter brukerens node_id fra maskinrommets /me-endepunkt ved innlogging
(via Authentik access_token), cacher i JWT-sesjon. Mottaksflaten viser
alle noder brukeren har edges til (begge retninger), sortert nyeste først,
med tittel, utdrag, node_kind-merke og edge-type-merker.

Endringer:
- auth.ts: fetchNodeId() kaller maskinrommet /me ved sign-in
- app.d.ts: utvider JWT og Session med node_id/nodeId
- +page.svelte: erstatter dashboard med mottaksflate-visning
- .env.example: MASKINROMMET_URL for server-side API-kall

Krever at brukeren logger ut og inn igjen for å hente node_id.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 14:13:36 +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
6bc742cc8d Authentik OIDC login (oppgave 3.2)
Implementerer autentisering med Authentik via @auth/sveltekit:
- OIDC authorization code flow med PKCE og state-verifisering
- JWT-callback lagrer authentik_sub (SHA256-hash, ikke UUID) for
  konsistens med maskinrommets auth_identities-tabell
- Server hooks: alle ruter unntatt /signin og /auth/* krever sesjon
- Uautentiserte brukere redirectes til /signin (303)
- Innloggingsside med client-side signIn('authentik')
- Hovedside viser innlogget bruker med logg ut-knapp
- TypeScript-typer utvidet med JWT.authentik_sub

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-17 13:45:33 +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