# Synops — Claude Code Prosjektguide ## Prosjektoversikt Synops er en plattform for redaksjonelt arbeid og podcast-produksjon. Self-hosted på Hetzner VPS med full datakontroll. Synops er plattformen. Sidelinja (podcastredaksjonen) er en tenant — en organisasjon som bruker Synops. Denne distinksjonen er bevisst: plattformkode og infrastruktur er skilt fra tenant-data og -innhold. ## Arbeidsflyt - **Standard arbeidsmodus:** Start i planleggingsmodus. Lag en grundig plan, få godkjenning, deretter implementer. Jobbene er ment å kunne kjøre lenge autonomt uten input underveis. - **Alt skjer på serveren.** Claude Code kjører direkte på produksjonsserveren (`/home/vegard/synops/`). Rust, Node.js og Docker er tilgjengelig. Bygging, testing og deploy skjer her. Vegard kobler til via SSH/tmux. - **Browser-testing:** Claude har ikke tilgang til browser. Visuell testing gjøres av Vegard. Claude verifiserer backend (kompilering, API, DB-state). - **Commit og push:** Bruk egen vurdering. Trygt og reverserbart. - **Deploy til produksjon:** Krever alltid eksplisitt godkjenning fra Vegard. - **Diskusjon:** Forklar og diskuter før arkitekturendringer. For implementering innenfor eksisterende spec — bare kjør. - **Defensiv skriving:** Skriv planer, arbeidsstatus og mellomresultater til disk underveis (f.eks. `docs/fikseliste.md` eller en dedikert fil i `docs/`). Kontekst kan forsvinne ved planmodus-reset eller krasj. Neste instans skal kunne lese seg opp fra filene og fortsette. ## Dokumentasjonstre CLAUDE.md er eneste startdokument. Alt annet ligger under `docs/`: - `docs/arkitektur.md` — Overordnet arkitektur, lagmodell, teknologivalg - `docs/retninger/` — Arkitektoniske teser og vedtatte retninger: - `README.md` — Oversikt og status - `status_quo.md` — Hva v1 var: ambisiøse primitiver, tradisjonell overflate - `rom_ikke_forum.md` — Opplevelse-først, to-lags-modell, administrativ opplevelse - `universell_input.md` — Tre primitiver (input, mottak, kommunikasjon), noder+edges - `maskinrommet.md` — Rust-orkestrator: fang, prosesser, lever - `bruker_ikke_workspace.md` — Noder er sentrum: brukere, team, innhold er noder. Tilgangsmatrise fra edges. - `datalaget.md` — PG(+AGE) som graf og arkiv, PG LISTEN/NOTIFY + WebSocket som sanntidslag - `arbeidsflaten.md` — Spatial canvas med verktøy-paneler, drag-and-drop, kompatibilitetsmatrise - `unix_filosofi.md` — Maskinrommet som orkestrator, arbeid i CLI-verktøy, Claude og maskinrommet deler verktøykasse - `docs/primitiver/` — Spesifikasjoner for kjerneprimitivene: - `nodes.md` — Node-skjema, node_kind, visibility, CAS-noder, eierskap - `edges.md` — Edge-skjema, typer, metadata, systemedges - `traits.md` — Trait-system: evner/funksjonalitet for samlingsnoder, katalog, pakker - (kommer: input, mottak, kommunikasjonsnode) - `docs/concepts/` — Brukeropplevelser/produktområder: - `studioet.md`, `møterommet.md`, `redaksjonen.md`, `podcastfabrikken.md`, `kunnskapsgrafen.md`, `valgomaten.md`, `den_asynkrone_gjesten.md`, `publisering.md`, `adminpanelet.md`, `arbeidstavlen.md`, `selvdokumenterende_system.md` - `docs/features/` — Tekniske byggeklosser: - Se individuelle filer for chat, kanban, kalender, meldingsboks, kunnskapsgraf, whiteboard, live transkripsjon, ressursforbruk, m.fl. - `lydstudio.md` — Lydredigering via FFmpeg, EDL, ikke-destruktiv prosessering - `artikkelverktoy.md` — Langform TipTap-editor, drag-and-drop mottak, source_material-edges - `universell_overfoering.md` — Drag-and-drop mellom verktøy-paneler, kompatibilitetsmatrise - `docs/fikseliste.md` — UI-bugs og forbedringer (levende jobbliste for grensesnitt) - `docs/proposals/` — Idébank med 32+ uimplementerte forslag (se README.md) - `docs/setup/` — Oppsett og drift: - `produksjon.md` — Steg-for-steg oppsett av Hetzner VPS fra scratch - `lokal.md` — Historisk: lokalt utviklingsmiljø (WSL2). Utdatert — all utvikling skjer nå på serveren. - `migration_safety.md` — Sjekkliste for PostgreSQL-migrasjoner (v1 workspace-RLS, trenger omskriving til node_access) - `docs/infra/` — Infrastruktur og drift: - `ai_gateway.md` — LiteLLM som sentralisert AI-ruter (BYOK + fallback) - `api_grensesnitt.md` — Kommunikasjonskart: SvelteKit er web-API, Rust er worker - `jobbkø.md` — PostgreSQL-basert køsystem for bakgrunnsjobber - `synkronisering.md` — Historisk: PG ↔ SpacetimeDB dataflyt (arkivdokument, SpacetimeDB fjernet mars 2026) - `claude_agent.md` — Claude som chat-deltaker: arkitektur, triggere, sikkerhet - `observerbarhet.md` — Strukturert logging, metrikk-endepunkt (/metrics), AI-kostnad - `docs/erfaringer/` — Lærdommer fra v1 (Svelte 5, Authentik). STDB-docs arkivert i `arkiv/` - `reference/` — Kode fra v1 med gjenbruksverdi (Editor.svelte) - `ops/` — Repeterbare vedlikeholdsjobber (ryddejobb, doc-audit, drift-sjekk) ## Aktører - **Vegard** — serveradmin, utvikler, bruker. Kobler til via SSH/tmux. - **Claude** — AI-agent, utvikler. Kjører direkte på serveren (`/home/vegard/synops/`). - Begge har sudo + docker-tilgang på serveren. ## Stack - **Orkestrator/Backend:** Rust (maskinrommet) — kjører native på hosten - **Frontend:** SvelteKit (TypeScript, PWA) - **Sanntid:** PG LISTEN/NOTIFY + WebSocket (portvokteren) - **Database/Graf:** PostgreSQL (+Apache AGE ved behov) - **Binærlagring:** CAS (content-addressable store) - **AI:** Claude Code (chat-agent), LiteLLM (AI Gateway), faster-whisper (STT) - **Infra:** Docker (tredjepart), systemd (egenutviklet), Caddy, Authentik (SSO) ## Driftsmodell: hybrid native + Docker Egenutviklet kode kjører **native på hosten** (systemd). Tredjepartstjenester kjører i **Docker**. Prinsipp: Docker for det vi ikke bygger selv, native for det vi har full kontroll over. ### Native (systemd) | Tjeneste | Beskrivelse | Deploy | |----------|-------------|--------| | **Caddy** | Reverse proxy + TLS | `sudo systemctl reload caddy` (config: `/srv/synops/config/caddy/Caddyfile`) | | **maskinrommet** | Rust API + jobbkø | `cargo build --release` → `sudo systemctl restart maskinrommet` | | **SvelteKit** | Frontend (når klar) | `npm run build` → systemd | Maskinrommet kjører native fordi det trenger tilgang til `claude` CLI og hele hosten. Env-filen genereres dynamisk av `scripts/maskinrommet-env.sh` med Docker container-IPs. ### Docker (docker-compose) | Tjeneste | Begrunnelse | |----------|-------------| | **PostgreSQL** | Versjonsstyring, enkel oppgradering | | **Authentik** | Kompleks stack (server + worker + Redis) | | **LiteLLM** | Ferdig image, sjelden oppdatering | | **faster-whisper** | Modellhåndtering, ferdig image | ### Kommunikasjon mellom lagene - Caddy (native) → Docker-tjenester: via localhost-porter (Authentik:9000, Forgejo:3000) - Caddy (native) → native tjenester: direkte localhost (maskinrommet:3100, SvelteKit:3200) - Maskinrommet (host) → Docker-tjenester: via container-IP (løses dynamisk i `maskinrommet-env.sh`) ## CLI-verktøy (`tools/`) Trenger du et verktøy — lag det. Gjør det generisk, robust og stabilt, så blir det tilgjengelig for maskinrommet (jobbkø) også. Claude og maskinrommet deler verktøykasse. - Navnekonvensjon: `synops-` (f.eks. `synops-transcribe`, `synops-render`) - Delt lib: `synops-common` crate (PG-tilkobling, CAS, node/edge-typer) - Dokumentert i `tools/README.md` - Ref: `docs/retninger/unix_filosofi.md`, `docs/infra/agent_api.md` ## Claude som chat-deltaker - **Agent-node:** `d3eebc99-9c0b-4ef8-bb6d-6bb9bd380a44` (node_kind: `agent`) - **Trigger:** Melding i kommunikasjonsnode der Claude er `member_of` → `agent_respond`-jobb → `claude -p` → svar tilbake i chatten - **Kill switch:** `UPDATE agent_identities SET is_active = false WHERE agent_key = 'claude-main'` - **Detaljer:** Se `docs/infra/claude_agent.md` ## Produksjonsserver - **IP:** 157.180.81.26 - **SSH:** `ssh vegard@157.180.81.26` - **Root-login:** Deaktivert - **Server-filer:** `/srv/synops/` (docker-compose.yml, .env, config/, data/) - **Domener (synops.no er primær):** - `synops.no` — Offentlig landingsside + /pub/* + /media/* (Caddy → statisk + maskinrommet) - `ws.synops.no` — Appen (SvelteKit + /api/* → maskinrommet). Krever login. - `auth.synops.no` — Authentik SSO - `api.synops.no` — Maskinrommet direkte (CLI, webhooks, eksternt) - `git.synops.no` — Forgejo (SSH port 222) - `vegard.info` — Personlig nettsted (statisk) - `sidelinja.org` — Redirect til synops.no - `workspace.synops.no` — Legacy redirect til ws.synops.no - `*.sidelinja.org` — Legacy aliaser (auth, api, git) ## Git - **Repos i Forgejo:** - `vegard/synops` — plattformkode og arkitektur: `ssh://git@git.synops.no:222/vegard/synops.git` - `sidelinja/sidelinja` — podcastinnhold: `ssh://git@git.synops.no:222/sidelinja/sidelinja.git` - **Git-identitet:** vegard / vnotnes@pm.me - **Forgejo-bruker:** vegard (admin) - **CLI:** Bruk `tea`, ikke `gh` (vi bruker Forgejo, ikke GitHub) ## Viktige regler - Aldri eksponere databaseporter mot internett - All AI-trafikk via maskinrommet, aldri direkte til leverandør-APIer - Tunge jobber (Whisper, LLM, TTS) blokkerer aldri brukerforespørsler - Sjekk alltid relevant doc i `docs/` før implementering - Dokumenter lærdommer i `docs/erfaringer/` ## Lagmodell ``` GUI (SvelteKit) — spatial canvas med verktøy-paneler │ skriv │ les (sanntid via WebSocket) ▼ ▲ Maskinrommet (Rust) ───┘ PG LISTEN/NOTIFY → WebSocket → GUI │ orkestrerer ▼ CLI-verktøy (tools/) ←── Claude bruker de samme │ ▼ Tjenester: PG+AGE, CAS, Whisper, LiteLLM, LiveKit ... ``` ## Kjerneprinsipper 1. **Alt er noder og edges.** Ingen separate tabeller for chat, kanban, kalender, notater. Visninger er spørringer mot grafen. 2. **Tre primitiver:** Input (fanger), Mottak (presenterer), Kommunikasjon (samler folk). Alt annet er visninger og edges. 3. **Maskinrommet orkestrerer, CLI-verktøy gjør jobben.** Maskinrommet eier auth, intentions, jobbkø og edge-logikk. All prosessering (transkribering, rendering, AI, lyd) skjer i CLI-verktøy som maskinrommet spawner. Claude bruker de samme verktøyene direkte. Ny funksjonalitet starter som CLI-verktøy, absorberes i orkestratoren, dokumenteres nøye. Ref: `docs/retninger/unix_filosofi.md`. 4. **Noder er sentrum.** Brukere, team, innhold — alt er noder. Du ser dine edges. Tilgang via materialisert tilgangsmatrise. 5. **Privat er default.** Input uten mottaker-edge er privat. Security by design, ikke konfigurasjon. 6. **PG er sannhetskilden.** All data lever i PostgreSQL. Sanntid via PG LISTEN/NOTIFY + WebSocket i portvokteren. 7. **Alt er paneler i en arbeidsflate.** Brukergrensesnittet er et spatial canvas der verktøy plasseres, sizes og arrangeres fritt. Hver feature er et panel i BlockShell. Interaksjon mellom paneler via drag-and-drop: - **Dra ut av kontekst → ny node.** Innhold som dras fra et verktøy til et annet skaper en ny node med `source_material`-edge tilbake. - **Dra verktøy inn i kontekst → transformer.** Et verktøy (AI, editor, studio) som mottar en node anvender sin funksjon på originalen. Ref: `docs/retninger/arbeidsflaten.md`, `docs/features/universell_overfoering.md`.