Legger til observerbarhetslaget i maskinrommet: - Strukturert JSON-logging via LOG_FORMAT=json (maskinlesbart for log-aggregering). Default er human-readable for utvikling. - Ny metrics-modul med in-memory request latency tracking per rute (count, avg, min, max, p50/p95/p99 fra siste 1000 forespørsler). - Custom axum-middleware erstatter tower_http::TraceLayer — logger method, path, status og duration_ms per request, og mater metrikk-samleren. - GET /metrics-endepunkt som returnerer: - request_latency: per-rute statistikk - queue_depth: pending/running/error/retry fra job_queue - ai_cost: aggregert fra ai_usage_log (siste time/24h/30d) - Default loggnivå endret fra debug til info for mindre støy.
200 lines
11 KiB
Markdown
200 lines
11 KiB
Markdown
# 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.
|
|
|
|
## 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, SpacetimeDB 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/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` — PostgreSQL ↔ SpacetimeDB dataflyt og eierskapsmodell
|
|
- `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 (adapter-mønster, Svelte 5, SpacetimeDB, Authentik)
|
|
- `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:** SpacetimeDB
|
|
- **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 |
|
|
| **SpacetimeDB** | Eksperimentelt, offisielt image |
|
|
| **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, SpacetimeDB:9080)
|
|
- 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-<verb>` (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:**
|
|
- `sidelinja.org` — Tenant-app (Sidelinja podcastredaksjonen)
|
|
- `auth.sidelinja.org` — Authentik SSO
|
|
- `git.sidelinja.org` — Forgejo (SSH port 222)
|
|
- `vegard.info` — Separat nettsted
|
|
- `synops.no` — Plattformdomene (placeholder, klar for subdomener)
|
|
|
|
## Git
|
|
- **Repos i Forgejo:**
|
|
- `vegard/synops` — plattformkode og arkitektur: `ssh://git@git.sidelinja.org:222/vegard/synops.git`
|
|
- `sidelinja/sidelinja` — podcastinnhold: `ssh://git@git.sidelinja.org: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, direkte WebSocket)
|
|
▼ ▼
|
|
Maskinrommet (Rust) SpacetimeDB ──→ GUI
|
|
│ orkestrerer
|
|
▼
|
|
CLI-verktøy (tools/) ←── Claude bruker de samme
|
|
│
|
|
▼
|
|
Tjenester: PG+AGE, SpacetimeDB, 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 arkivet, SpacetimeDB er nåtid.** Ingen eierskapskonflikt.
|
|
To lag, to roller.
|
|
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`.
|