Files
abdulive/docs/01-architecture.md
T
ZeasyAlexandClaude Opus 5.5 d00550aa37 Rueckbau: gestrichene Werkzeuge entfernt, Hub schreibt keinen Chat mehr mit
Raid-Scout, Auswertung, VOD-Kapitel, Community-Gedaechtnis, Punkteshop
und Recap samt Platzhaltern, Spezifikationen und Konfiguration. Der Hub
schickt am Chat zusaetzlich die Sendezeit mit, fuer die Uhrzeit im Pult.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 19:16:04 +01:00

123 lines
5.7 KiB
Markdown

# Architektur
## Bild
Stand vor dem Umzug in den Hub (ADR-0008). Raid-Scout, Auswertung,
VOD-Kapitel, Community-Gedaechtnis und Recap sind seit 2026-10-27 gestrichen.
```
Twitch OBS
┌──────────────────┐ ┌───────────┐
│ EventSub (WS) │ │ obs- │
│ IRC / Chat │ │ websocket │
│ Helix REST │ └─────┬─────┘
└────────┬─────────┘ │
│ │
┌────────▼────────────────────────▼────────┐
│ apps/ingest (Daemon) │
│ normalisiert alles zu Events │
└────────┬─────────────────────┬───────────┘
│ │
schreibt │ │ publiziert
▼ ▼
┌─────────────────┐ ┌──────────────────────┐
│ SQLite │ │ Event-Bus │
│ data/db/ │ │ (in-proc + WS 4790) │
└─────────────────┘ └──────────┬───────────┘
│
┌─────────┴─────────┐
▼ ▼
overlay-server clipper-Kette
(Pult, Sounds) ffmpeg, whisper
│ │
overlay-web data/clips
(Browser-Source)
```
## Prozesse
**Ein Prozess.** Oberflaeche, Ingest und die Werkzeugmodule laufen gemeinsam in
einem Container; schwere Arbeit (ffmpeg, whisper.cpp) laeuft als Kindprozess und
darf abstuerzen, ohne die Chat-Aufnahme mitzureissen. Begruendung und Grenzen:
[ADR-0006](decisions/ADR-0006-ein-dach.md).
| Port | Wofuer |
|------|--------|
| 4792 | Weboberflaeche: Einrichtung, OAuth-Rueckruf, Sichtung, Dashboard, `/health` |
| 4791 | Overlay-Server fuer die OBS-Browser-Quellen (ab M3) |
Beide nur auf `127.0.0.1` des Hosts veroeffentlicht.
Die Werkzeuge sind Module, keine eigenen Dienste:
| Modul | laeuft | Ausloeser |
|-------|--------|-----------|
| Ingest | dauernd | IRC, EventSub, Helix-Polling |
| Community, Loyalty | dauernd | Chat-Ereignisse |
| Clipper | bei Bedarf | `!clip`, OBS-Hotkey, spaeter Chat-Spitze |
| Broadcaster | bei Bedarf | `stream.online` |
| Recap, VOD-Kapitel | bei Bedarf | `stream.offline` |
| Raid-Scout | bei Bedarf | `!raidziel`, Oberflaeche |
## Event-Bus
Der Ingest normalisiert alles auf ein einheitliches Event-Format:
```ts
type StreamEvent = {
id: string; // ULID
ts: string; // ISO-8601, UTC
type: EventType; // 'chat.message' | 'stream.online' | ...
streamId: string | null;
userId: string | null;
payload: unknown; // typisiert pro EventType
};
```
Transport: ein `EventEmitter` im Prozess. Solange alles unter einem Dach laeuft
(ADR-0006), braucht es keinen Netzwerk-Bus. Die `events`-Tabelle ist trotzdem
die Wahrheit: sie wird immer geschrieben, und ein spaeter herausgeloester
Prozess kann seinen Rueckstand ueber `ts > lastSeen` aufholen.
Vollständige Event-Liste: siehe [`03-data-model.md`](03-data-model.md).
## Pakete
| Paket | Inhalt |
|-------|--------|
| `packages/shared` | Ereignistypen, ULID |
| `packages/core` | Config, Layout, Logger mit Maskierung, Retry, YAML-Leser |
| `packages/twitch` | Secret-Speicher, OAuth, Helix-Client, IRC-Client |
| `packages/db` | SQLite-Verbindung, Migrationen, Repositories |
Regel: Apps dürfen von Paketen abhängen, Pakete nie von Apps. Apps hängen nicht
voneinander ab — Kommunikation läuft über Bus und DB.
Importiert wird über die `imports`-Map der Wurzel-`package.json`
(`#core/config.ts`, `#db/repos.ts`). Das ist eine Node-Funktion, kein
Build-Werkzeug — es gibt keinen Bundler und keine Pfad-Aliasse im Compiler.
## Technologie
- **TypeScript auf Node 24**, ohne Build-Schritt und ohne
Laufzeitabhängigkeiten — Node führt die `.ts`-Dateien direkt aus. Siehe
[ADR-0001](decisions/ADR-0001-monorepo-typescript.md)
- **SQLite** über das eingebaute `node:sqlite` — siehe
[ADR-0002](decisions/ADR-0002-sqlite.md)
- **EventSub über WebSocket**, nicht Webhooks — siehe
[ADR-0003](decisions/ADR-0003-eventsub-websocket.md)
- **ffmpeg** (CLI) für Videoverarbeitung
- **whisper.cpp** (CLI) für Untertitel — kein Python, keine GPU
- **Serverseitiges HTML** ohne Framework für Einrichtung und Sichtungsseite;
für Dashboard und Overlays ab M3 ggf. Vite + Preact
- **Docker Compose** für den Betrieb — siehe [ADR-0004](decisions/ADR-0004-docker.md)
## Fehlerverhalten
- Jeder Netzwerkaufruf hat Retry mit exponentiellem Backoff (`packages/core/retry`).
- Der Ingest darf niemals wegen eines Konsumentenfehlers sterben. Konsumenten
laufen in eigenen Prozessen; ein Fehler dort schreibt in `logs/` und wird im
Dashboard als Warnung angezeigt.
- Wenn EventSub die Verbindung verliert: Reconnect mit Session-Resume, danach
Lücke über Helix-Polling schließen (`stream.online`-Status, Follower-Liste).