133 lines
No EOL
12 KiB
Markdown
133 lines
No EOL
12 KiB
Markdown
# Sidelinja - Architecture Decision Record & System Overview
|
|
|
|
**Dette dokumentet definerer den overordnede arkitekturen, teknologistacken og datamodellen for Sidelinja-suiten. AI-agenter (som Claude Code) SKAL lese og forstå dette dokumentet før de foreslår endringer, skriver kode eller gjør arkitektoniske valg.**
|
|
|
|
## 1. Visjon og Konsept
|
|
Sidelinja er ikke bare en podcast-host; det er et **redaksjonelt operativsystem** og en **kunnskapsgraf**. Målet er å bygge en plattform som sømløst integrerer research, asynkron kommunikasjon (chat), sanntids innspilling (Lyd/Video) og automatisert publisering. Visjonen inkluderer også at plattformen skal fungere som en "live co-host" (virtuell assistent) under innspilling ved å boble opp relevant informasjon fra kunnskapsgrafen i sanntid. Systemet er bygget for full datakontroll, eierskap og minimal bruk av lukkede tredjepartstjenester.
|
|
|
|
## 2. Infrastruktur og DevOps
|
|
* **Produksjonsserver:** Hetzner VPS (Ubuntu, 8 vCPU, 16 GB RAM). Kapasiteten er tilstrekkelig for nåværende behov. Ved behov kan VPS-en dobles (16 vCPU, 32 GB). Mest CPU-krevende tjenester er faster-whisper og LiveKit under samtidig bruk — disse bør overvåkes først ved kapasitetsproblemer.
|
|
* **Orkestrering:** Docker / Docker Compose. Alle tjenester kjører i isolerte containere på et internt Docker-nettverk.
|
|
* **Reverse Proxy & Webserver:** **Caddy**. Håndterer all innkommende trafikk for flere domener, automatisk HTTPS (Let's Encrypt), og ruting til interne containere. Port 80/443 er de *eneste* portene som er eksponert mot internett.
|
|
* **Domener:**
|
|
- `sidelinja.org` — Hovedapplikasjon (SvelteKit, media, SpacetimeDB, LiveKit)
|
|
- `auth.sidelinja.org` — Authentik SSO (felles for alle domener)
|
|
- `git.sidelinja.org` — Forgejo
|
|
- `vegard.info` — Separat nettsted, deler SSO med Sidelinja
|
|
* **Kildekode og CI/CD:** **Forgejo** (Selv-hostet Git). All kode og konfigurasjon lever her.
|
|
* **Utvikling og Utrulling (Claude Code Workflow):** All prototyping og koding skjer lokalt i **WSL2 (Ubuntu)** på en lokal Windows 11-maskin. Når koden er testet og klar, pusher AI-agenten (Claude Code) til Forgejo. Deretter logger agenten seg på produksjonsserveren via SSH for å hente koden, trigge kompilering og starte tjenestene på nytt. Regelen "ikke programmere i produksjon" betyr utelukkende at redigering av kildekode og "prøving og feiling" hører hjemme lokalt, ikke live på serveren.
|
|
|
|
### 2.1 Serverstruktur og Backup-strategi (Produksjon)
|
|
All persistent data, konfigurasjon og kildekode monteres via Docker Bind Mounts til en fast struktur på vertssystemet, typisk `/srv/sidelinja/`. Dette muliggjør granulert backup.
|
|
|
|
/srv/sidelinja/
|
|
├── docker-compose.yml # Orkestrering
|
|
├── .env # Miljøvariabler (IKKE i Git)
|
|
├── config/ # Konfigurasjonsfiler (Caddy, Authentik, etc.)
|
|
├── data/ # Databaser (Postgres, SpacetimeDB, Forgejo) -> KRITISK BACKUP
|
|
├── media/ # Lydfiler (podcast, råopptak) -> KRITISK BACKUP
|
|
└── logs/ # Caddy access-logger, app-logger -> SEPARAT/LANGTIDS BACKUP
|
|
|
|
*Målrettet backup:* Mappen `logs/` ekskluderes fra den daglige snapshot-backupen for å spare plass, men rulleres og arkiveres separat for fremtidig dataanalyse.
|
|
|
|
### 2.2 Lokalt Utviklingsmiljø (Dev Replika)
|
|
For å sikre smidig lokal utvikling i WSL2, bygger vi en nøyaktig replika av produksjonsmiljøet, men optimalisert for utviklingshastighet (Hot Reloading). **Komplett steg-for-steg oppsett finnes i `docs/setup/lokal.md`, produksjonsoppsett i `docs/setup/produksjon.md`.**
|
|
|
|
* **Docker Compose Dev:** Vi bruker en egen `docker-compose.dev.yml` som spinner opp lokale instanser av databasene (PostgreSQL, SpacetimeDB) og LiveKit. Volumene for disse er lokale og flyktige/seedede.
|
|
* **SvelteKit HMR:** SvelteKit-klienten kjøres *utenfor* Docker under aktiv utvikling (ved bruk av `npm run dev` i WSL2). Dette sikrer at Hot Module Replacement (HMR) fungerer lynraskt når kode endres.
|
|
* **Lokal Ruting:** En lokal Caddy-instans ruter trafikk fra `localhost` til SvelteKit, SpacetimeDB og LiveKit, med self-signed sertifikater (`local_certs`) for sikker kontekst (WebRTC).
|
|
* **Forgejo:** Kjører *ikke* lokalt. Push direkte til produksjons-Forgejo fra WSL2.
|
|
|
|
## 3. Teknologistack
|
|
Vi følger et "Best tool for the job"-prinsipp, med en sterk preferanse for minnesikkerhet, ytelse og rene grensesnitt.
|
|
|
|
* **Backend/Automasjon:** **Rust**. Brukes som bakgrunnsworkers (jobbkø), logg-parsing og SpacetimeDB-moduler. Rust er *ikke* en API-server — SvelteKit server-side håndterer all HTTP-kommunikasjon og PG-tilgang direkte (se `docs/features/api_grensesnitt.md`).
|
|
* **Frontend / UI:** **SvelteKit** (med TypeScript). Bygges som en PWA. Valgt for ytelse og enkel integrasjon med WebRTC og vanilla JS-biblioteker.
|
|
* **Sanntids Lyd/Video:** **LiveKit** (Selv-hostet). Håndterer WebRTC, fler-bruker videochat og opptak i det virtuelle "studioet".
|
|
* **AI / Prosessering:** `faster-whisper` (lokal transkripsjon) og OpenRouter (Claude-modeller for tekstanalyse).
|
|
* **SSO / Autentisering:** **Authentik** (Selv-hostet). Sentralisert rollestyring.
|
|
|
|
## 4. Den To-delte Databasestrategien
|
|
1. **PostgreSQL (Historikk & Kunnskapsgraf):** Én sentralisert instans i Docker for brukerkontoer, Git-metadata, aggregert statistikk og Kunnskapsgrafen (Artikler, Faktoider).
|
|
2. **SpacetimeDB (Sanntid & Arbeidsflyt):** In-memory database for live chat, status på episoder, og live-oppdateringer i studio. Klienten (Svelte) lytter direkte på SpacetimeDB. Strategisk avhengighet, men all persistent data synkes til PostgreSQL — ved eventuelt bortfall kan sanntidslaget erstattes uten tap av data.
|
|
3. **Synkronisering:** Event-drevet med ~5 sek forsinkelse. SpacetimeDB er autoritativ for sanntidsdata (chat, kanban), PostgreSQL for persistent data (kunnskapsgraf, metadata). Detaljer i `docs/features/synkronisering.md`.
|
|
|
|
## 5. Datamodell: Kunnskapsgrafen
|
|
Systemet er bygget rundt **Temaer** og **Aktører**, ikke episoder. Dette bygger et asynkront research-arkiv. Alle entiteter arver UUID fra en felles `nodes`-supertabell som gir ekte FK-integritet i grafmodellen (detaljer i `docs/features/kunnskapsgraf_og_relasjoner.md`).
|
|
* **Tema (Saker):** Levende konsepter ("Skolepolitikk").
|
|
* **Aktør (Entity):** Personer eller organisasjoner ("Jonas Gahr Støre").
|
|
* **Faktoide (Factoid):** En atomisk bit med informasjon koblet til Aktører/Temaer ("Søkte jobb i AP i 2011").
|
|
* **Episode:** Et tidsbegrenset prosjekt ("Episode 42") som samler et utvalg av aktuelle *Temaer*.
|
|
* **Segment:** En tidsavgrenset del av en episode med egen transkripsjon, koblet til Temaer/Aktører i grafen. Muliggjør presise oppslag ("hva sa vi om X i Episode 42?").
|
|
* **Research-klipp:** Råtekst renset av AI, koblet til Temaer/Aktører.
|
|
|
|
**Transkripsjoner:** Git (Forgejo) er kilde til sannhet (redigerbar, sporbar). PostgreSQL er søkeindeks (full-text, koblet til grafen). Endringer i Git reimporteres automatisk via Forgejo webhook.
|
|
|
|
## 6. Podcast Hosting og Distribusjon
|
|
* **Lagring:** MP3-filer lagres flatt i `/srv/sidelinja/media/`. Ingen lydfiler i databaser.
|
|
* **Servering:** Caddy serverer media-mappen. MÅ ha `Accept-Ranges: bytes` aktivert for podcast-streaming.
|
|
* **RSS-Feed:** Genereres av SvelteKit og leveres statisk eller dynamisk med aggressiv caching.
|
|
|
|
## 7. Planlagte Funksjoner (Feature Ideas)
|
|
Dette er hovedkonseptene plattformen skal støtte. **Merk: Detaljerte tekniske spesifikasjoner, flytskjemaer og datastrukturer for hver av disse ligger i mappen `docs/features/`.**
|
|
|
|
* **Live AI-Assistent i Studio:** Sanntidstranskripsjon via mikrofonene som lytter etter nøkkelord (Named Entity Recognition). Gjør asynkrone oppslag i PostgreSQL og dytter relevante "Faktoider" live til Svelte-grensesnittet via SpacetimeDB mens programlederne snakker.
|
|
* **AI Research-Klipper ("Ctrl+A workflow"):** Et verktøy der redaksjonen limer inn rotete nyhetsartikler. AI-en (OpenRouter) renser, oppsummerer, og trekker ut Aktører og Faktoider som lagres i Kunnskapsgrafen.
|
|
* **Produktivitetssuiten:** En Svelte/SpacetimeDB-basert flate for Kanban-styring av episoder, trådet chat knyttet til Temaer, og kollaborative show notes.
|
|
* **Valgomat:** En publikumsrettet, avansert og interaktiv valgomat drevet av SpacetimeDB for umiddelbar respons og vekting av svar.
|
|
* **Podcast-Statistikk (Privacy First):** Batch-prosessering i Rust som tygger Caddy JSON-logger, dedupliserer lyttere, fjerner bots og lagrer ferdig statistikk i PostgreSQL.
|
|
* **Podcastfabrikken:** System for automatisk og manuell publisering (Whisper transkripsjon, metadata via OpenRouter) og versjonshåndtering/cache-busting ved oppdatering av eksisterende episoder.
|
|
|
|
## 8. Bygge-rekkefølge (Avhengighetskart)
|
|
|
|
```
|
|
Lag 1 — Fundament (ingen avhengigheter):
|
|
├── PostgreSQL-skjema (nodes, graph_edges, job_queue)
|
|
├── SpacetimeDB grunnoppsett
|
|
└── SvelteKit skjelett med Authentik-integrasjon
|
|
|
|
Lag 2 — Kjernekomponenter (krever Lag 1):
|
|
├── Jobbkø-worker (Rust)
|
|
├── Kunnskapsgraf CRUD (SvelteKit server-side)
|
|
└── Produktivitetssuiten: Chat + Kanban (SpacetimeDB ↔ PG synk)
|
|
|
|
Lag 3 — Features (krever Lag 2):
|
|
├── AI Research-Klipper (kunnskapsgraf + jobbkø)
|
|
├── Podcastfabrikken (jobbkø + episoder/segmenter)
|
|
└── Podcast-Statistikk (jobbkø + episoder)
|
|
|
|
Lag 4 — Avansert (krever Lag 3):
|
|
├── Live AI-Assistent (fylt kunnskapsgraf + LiveKit + Whisper)
|
|
└── Valgomat (selvstendig, lav prioritet)
|
|
```
|
|
|
|
## 9. Observabilitet
|
|
|
|
### 9.1 Helse
|
|
Alle Docker-containere skal ha `healthcheck` definert i `docker-compose.yml`:
|
|
- PostgreSQL: `pg_isready`
|
|
- SpacetimeDB: TCP-sjekk mot intern port
|
|
- Caddy: `curl -f http://localhost/health`
|
|
- SvelteKit: `curl -f http://localhost:3000/health`
|
|
- Rust Workers: Heartbeat-rad i `job_queue` (en `worker_heartbeat`-jobb som re-enqueuer seg selv hvert minutt — fravær betyr død worker)
|
|
|
|
### 9.2 Logging
|
|
- **Format:** Strukturert JSON fra alle komponenter (Rust, SvelteKit, Caddy)
|
|
- **Plassering:** `/srv/sidelinja/logs/` med undermapper per tjeneste
|
|
- **Rotasjon:** Standard Linux logrotate, daglig rotasjon, 30 dagers retensjon
|
|
- Caddy podcast-logger behandles separat av statistikk-workeren (se `docs/features/podcast_statistikk.md`)
|
|
|
|
### 9.3 Jobbkø-overvåking
|
|
- Admin-visning i SvelteKit som viser `job_queue`-status (pending, running, error-count)
|
|
- Feilede jobber (`status = 'error'`) poster automatisk en varslingsmelding til et dedikert system-tema i Produktivitetssuiten (intern chat), slik at redaksjonen ser det i sin daglige arbeidsflate
|
|
|
|
### 9.4 Ingen eksterne tjenester
|
|
All overvåking og varsling skjer internt i Sidelinja-suiten. Ingen avhengighet til Discord, Slack eller andre tredjepartstjenester.
|
|
|
|
## 10. AI Agent Guidelines (Instrukser for Claude Code)
|
|
* **Start her:** Når du settes til å bygge en ny komponent, sikre alltid at det lokale utviklingsmiljøet (`docker-compose.dev.yml`) kjører først.
|
|
* **Dokumentasjonsstandard:** Når du skal implementere en ny funksjon (feature), sjekk ALLTID om det finnes et dokument i `docs/features/<feature-navn>.md` først. Oppdater disse dokumentene hvis arkitekturen for funksjonen endres.
|
|
* **Ingen "gh" CLI:** Vi bruker Forgejo. For Pull Requests/Issues, bruk `tea` CLI.
|
|
* **Deployment:** Kod og test lokalt i WSL. Push til Forgejo, logg inn via SSH for å pulle kode og restarte containere/tjenester (`docker compose up -d`).
|
|
* **Asynkron AI:** Tyngre jobber (Whisper, OpenRouter) skal aldri blokkere web-forespørsler. Alle bakgrunnsjobber kjøres via den felles PostgreSQL-baserte jobbkøen (se `docs/features/jobbkø.md`).
|
|
* **Sikkerhet:** Forsøk aldri å eksponere databaseporter ut mot internett i Docker Compose-filer (hverken lokalt eller i prod). Port 80/443 (Caddy) er de eneste inngangsportene. |