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
72 lines
2.9 KiB
Markdown
72 lines
2.9 KiB
Markdown
# 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.
|