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

+71
View File
@@ -0,0 +1,71 @@
# 8 — Punktesystem mit Bedeutung (`apps/loyalty`)
**Wirkrichtung:** Bindung. Läuft als Modul im `overlay-server`.
## Warum nicht Channel Points?
Twitch-Channel-Points funktionieren, haben aber zwei Grenzen: Man kann die
Vergabelogik nicht anpassen (keine Boni für Verhalten, das man belohnen will),
und Einlösungen sind an das Twitch-UI gebunden. Eigene Punkte laufen daneben.
**Beides parallel betreiben.** Channel Points bleiben für simple Sachen,
eigene Punkte für alles, was Logik braucht. `channel.channel_points_custom_reward_redemption.add`
wird ohnehin schon ingested, also können beide Systeme dieselben Aktionen
auslösen.
## Vergabe
| Anlass | Punkte |
|---|---|
| pro 10 Minuten Anwesenheit | 10 |
| ...davon aktiv im Chat | +5 |
| erste Nachricht des Streams | 25 |
| Anwesenheit in Streamminute 1–10 | +50 (belohnt pünktliches Erscheinen) |
| Follow | 200 (einmalig) |
| Sub / Resub | 500 |
| Raid rein | 300 an den Raider |
| Clip, der übernommen wird | 250 an den Auslöser |
Anwesenheit kommt aus `user_streams.minutes` (Helix-Chatter-Liste alle 5 min),
nicht aus dem Chat allein — sonst bekommen stille Zuschauer nie etwas.
## Shop
Der Punkt der Sache ist, dass Einlösungen **wirklich etwas tun**:
| Artikel | Kosten | Aktion | Freigabe |
|---|---|---|---|
| Streamtitel für 10 min | 5.000 | `PATCH /helix/channels`, Timer setzt zurück | ja |
| Emote-Regen 30 s | 800 | Overlay-Effekt | nein |
| Sound aus dem Board | 300 | Overlay + Audio | nein |
| Challenge für Abdu | 3.000 | Karte im Overlay, Abdu bestätigt | ja |
| Nächstes Spiel bestimmen | 10.000 | Eintrag in die Warteschlange | ja |
| Facecam-Filter 60 s | 1.500 | obs-websocket Filter an | nein |
`requires_approval` ist bei allem gesetzt, was den Stream nach außen verändert
(Titel!) oder Abdu zu etwas verpflichtet. Titeländerung zusätzlich abgesichert:
Wortfilter, Längenbegrenzung, automatische Rückkehr zum Originaltitel per
Timer, und der Originaltitel wird vorher in `stream_segments` gesichert.
## Rückerstattung
Wenn eine Aktion fehlschlägt (OBS nicht erreichbar, Helix-Fehler, Abdu lehnt
ab), werden die Punkte automatisch zurückgebucht und der User im Chat
informiert. `redemptions.status = 'refunded'`.
## Bilanz-Integrität
Punkte werden nie direkt auf `users.points` geschrieben, sondern als Zeilen in
einer `points_ledger`-Tabelle geführt; `users.points` ist ein
Materialized-Summenfeld, das über einen Trigger aktualisiert wird. So ist jede
Punktzahl nachvollziehbar und ein Fehler in der Vergabelogik reparierbar, ohne
dass jemandem grundlos Punkte fehlen.
## Abnahmekriterien
- Ein Zuschauer, der 30 min anwesend ist und dreimal schreibt, hat exakt die
erwartete Punktzahl.
- Titel-Einlösung ändert den Titel und setzt ihn nach 10 min zurück, auch wenn
der Server dazwischen neu startet (Timer wird persistiert).
- Fehlgeschlagene Einlösung bucht zurück.
- `points_ledger`-Summe stimmt mit `users.points` überein.