Struktur, Doku und S0-Toolchain fuer das abdulive-Toolkit

Monorepo-Geruest fuer neun Streamer-Tools plus den Ingest-Daemon, der
unter sechs davon liegt. Enthaelt:

- docs/: Ueberblick, Architektur, Twitch-Integration, Datenmodell,
  Roadmap, Setup, Hebel-Analyse und den MVP-Plan "Clip-Knopf"
- docs/projects/: je eine Spezifikation pro Tool
- docs/decisions/: vier ADRs (TS-Monorepo, SQLite, EventSub/IRC, Docker)
- docker/: Image mit ffmpeg und whisper.cpp, abhaengigkeitsfreier
  Entrypoint mit check-env, fetch-model und calibrate
- config/layout.yaml: aus einem VOD-Screenshot eingemessener
  Facecam-Ausschnitt (440x330 oben links, Chat-Overlay ab x=1270)

Noch kein Anwendungscode - Scheibe S0 aus docs/07-mvp-plan.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013VTGjd92LsDDWF3frd9FTB
This commit is contained in:
ZeasyAlexandClaude Opus 5 committed 2026-09-09 08:56:09 +02:00
commit d09e2b945a
98 files changed
+3273

No files matched your search

+63
View File
@@ -0,0 +1,63 @@
# ADR-0004: Betrieb in Docker
**Status:** akzeptiert · **Datum:** 2026-09-09
## Kontext
Das Toolkit braucht ffmpeg, ein Whisper-Modell, Node und SQLite. Der Check der
Zielmaschine ergab: kein ffmpeg, kein pnpm, Python 3.14 (für das
`ctranslate2` — die Basis von faster-whisper — noch keine verlässlichen Wheels
liefert), keine NVIDIA-GPU. Das Toolkit soll auf Abdus Stream-PC laufen, also
auf einem Rechner, dessen Umgebung sich unabhängig vom Projekt ändert.
## Entscheidung
Alles läuft in Containern, orchestriert über `docker-compose`. Die einzige
Voraussetzung auf dem Stream-PC ist Docker Desktop und OBS.
## Begründung
- Die gesamte Toolchain (Node 22, ffmpeg mit libx264/libass, whisper.cpp, das
Sprachmodell) ist im Image festgeschrieben. Kein "läuft bei mir".
- Der Python-Konflikt entfällt vollständig, weil kein Python mehr gebraucht
wird (siehe [ADR-0001](ADR-0001-monorepo-typescript.md), aktualisiert).
- Updates sind ein `docker compose pull && up -d`, kein Nachinstallieren auf
einem Rechner, der gerade streamt.
## Konsequenzen — die vier Dinge, die man dabei falsch machen kann
**1. Die SQLite-Datei gehört nicht in einen Windows-Bind-Mount.**
Dateisperren über die 9p/virtiofs-Brücke zwischen Windows und WSL2 sind
unzuverlässig; SQLite im WAL-Modus reagiert darauf mit
`SQLITE_BUSY`/`database is locked` und im schlimmsten Fall mit Korruption.
Die Datenbank liegt deshalb in einem **benannten Docker-Volume**
(`abdulive-db`). Backups werden per Skript aus dem Volume nach Windows
kopiert, nicht durch direktes Mounten.
**2. Große Mediendateien nicht über den Bind-Mount verarbeiten.**
Das OBS-Replay-Verzeichnis wird nur lesend gemountet. Die Rohdatei wird
**einmal** in ein containerlokales Volume kopiert, dort verarbeitet, und nur
das fertige Ergebnis wird zurück nach `data/clips/` geschrieben. Direkt auf
dem Bind-Mount zu encodieren kostet ein Vielfaches der Zeit.
**3. OBS läuft auf dem Host, nicht im Container.**
Erreichbar über `host.docker.internal:4455`. In `docker-compose.yml` steht
`extra_hosts: ["host.docker.internal:host-gateway"]`, damit es auch außerhalb
von Docker Desktop funktioniert.
**4. Ein globaler Windows-Hotkey lässt sich aus einem Container nicht abfangen.**
Deshalb wird gar nicht erst versucht, einen eigenen Hotkey-Dienst zu bauen:
Der Hotkey wird **in OBS** auf "Wiedergabepuffer speichern" gelegt. OBS meldet
danach über obs-websocket das Ereignis `ReplayBufferSaved` mit dem Dateipfad —
das ist der Trigger. Kein Agent auf dem Host, kein zusätzlicher Autostart.
**Kosten, ehrlich benannt:** Docker Desktop startet eine WSL2-VM, die im
Leerlauf ein bis zwei GB RAM belegt und beim Encodieren CPU zieht, die dem
Stream fehlt. Gegenmaßnahmen: `.wslconfig` mit `memory=4GB` und
`processors=4`, ffmpeg mit `-preset veryfast` und niedriger Priorität, und
Rendering standardmäßig **nach** Streamende (`clipper.renderWhileLive: false`),
sofern die Kandidatenliste erst danach gebraucht wird.
**GPU:** Kein NVENC (keine NVIDIA-Karte), und Intel QSV ist aus WSL2 heraus
nicht verlässlich erreichbar. Es bleibt bei CPU-Encoding mit libx264. Für
Clips von 30–60 Sekunden ist das unkritisch.