Merge wt-erinnerung: Erinnerungs-Plugin (Konflikte aufgelöst)

This commit is contained in:
Flo Hartmann
2026-08-21 20:37:20 +00:00
11 changed files with 1552 additions and 25 deletions

View File

@@ -4,7 +4,8 @@
modularer Plugin-Architektur. Lauffähiger Kern mit Plugin-System,
Authentifizierung/Rollen und Migrationen; vollständig implementiert sind
bisher **Audit-Log**, **Benachrichtigung**, **Neuheiten (BGG-Sync)**,
**Dedup-Prüfung**, **Planungsliste** und **Archiv (12-Monats-Autopilot)**.
**Dedup-Prüfung**, **Planungsliste**, **Archiv (12-Monats-Autopilot)** und
**Erinnerungen**.
## Stack
@@ -56,6 +57,8 @@ Beim ersten Start wird automatisch ein Admin-Konto angelegt:
| `SPIELE_DEDUP_BGG_AKTIV` | `1` | BGG-Zusatzdaten für die Dedup-Prüfung an (`1`) oder aus (`0`): Alternate-Names und Erweiterungs-Relationen |
| `SPIELE_ARCHIV_JOB_AKTIV` | `1` | Täglicher Archivierungs-Job an (`1`) oder aus (`0`) |
| `SPIELE_ARCHIV_JOB_UHRZEIT` | `03:00` | Tageszeit des täglichen Archiv-Laufs im Format `HH:MM` |
| `SPIELE_ERINNERUNG_JOB_AKTIV` | `1` | Täglicher Erinnerungs-Check an (`1`) oder aus (`0`) |
| `SPIELE_ERINNERUNG_JOB_UHRZEIT` | `08:00` | Uhrzeit (HH:MM) des täglichen Erinnerungs-Checks |
## Tests
@@ -83,6 +86,13 @@ Zeitzonen-Unterschieden), Job-Lauf mit Audit-Einträgen, Wiederherstellen
inkl. BGG-Konflikt und Ersatz-Rezensent, Rollen sowie Suche/Filter in der
Admin-Ansicht.
Das Plugin **erinnerung** ist abgedeckt mit: Ausgaben-CRUD (nur Admin, mit
Audit), Erinnerungslogik mit eingefrorener Uhr (freezegun) — 4-Wochen-Grenze
(28 Tage exakt), kein Versand vor der Frist und nach dem Redaktionsschluss,
Empfängerregeln (offene oder fehlende Planung, Rollen-Filter), Doppelschutz
pro Ausgabe+Benutzer, manuelle Prüfung, Scheduler-Lifecycle/Uhrzeit-Konfiguration
— wiederum plus ein Integrationstest mit den echten Plugins.
## Architektur
```
@@ -102,7 +112,8 @@ plugins/ ein Ordner pro Funktion, ladbar über den Plugin-Load
├── dedup/ VOLL IMPLEMENTIERT: check_titel-API, Heuristik, Protokoll
├── planung/ VOLL IMPLEMENTIERT: Planungsliste, Verschiebung, Dialoge
├── archiv/ VOLL IMPLEMENTIERT: 12-Monats-Autopilot, Job, UI
├── erinnerung/ export/ (Stubs, ladbar)
├── erinnerung/ VOLL IMPLEMENTIERT: Ausgaben, 4-Wochen-Erinnerung, Tages-Job
├── export/ (Stub, ladbar)
└── … je __init__.py + templates/<name>/
```
@@ -430,6 +441,57 @@ vereinigte Liste angezeigt (neueste Archivierung zuerst):
nicht wiederhergestellt; existiert der zugeordnete Rezensent nicht mehr,
übernimmt der wiederherstellende Admin die Zuordnung (gemeldet und
auditiert). Rezensenten und Redakteure erhalten 403.
## Plugin „erinnerung“ (implementiert)
Redaktionsschluss pro Ausgabe mit automatischer 4-Wochen-Erinnerung an alle
Rezensenten — mehrere Ausgaben laufen parallel.
### Datentabellen
Eigene Migration `0001_ausgaben_und_protokoll`, zwei Tabellen
(SQLite ↔ Postgres portabel):
| Tabelle | Spalten | Zweck |
|---------|---------|-------|
| `erinnerung_ausgabe` | `name` (z. B. „3/2025“), `redaktionsschluss` (Datum), Zeitstempel | Eine Magazin-Ausgabe; Anlegen/Bearbeiten/Löschen nur für Rolle **Admin** |
| `erinnerung_protokoll` | `ausgabe_id`, `user_id`, `kanaele`, `erstellt_am` | Jede versendete Erinnerung; **eindeutig** über (Ausgabe, Benutzer) → keine Doppelerinnerung |
### Erinnerungslogik
- **Fenster:** 28 Tage (4 Wochen) vor dem Redaktionsschluss bis zum
Redaktionsschluss selbst (jeweils inklusive). Davor und danach wird nicht
erinnert.
- **Empfänger:** alle aktiven Rezensenten, die noch offene Planungseinträge
haben (Status ≠ „abgeschlossen“, also „offen“ oder „in Bearbeitung“) oder
gar keine Einträge. Wer alles abgeschlossen hat, wird nicht erinnert;
Admins und Redakteure nie.
- **Versand:** über `send_notification` des benachrichtigung-Plugins
(Kategorie `erinnerung`) — die Kanäle richten sich nach der Präferenz des
Benutzers. Ohne Partner-Plugin wird kein Protokoll geschrieben, damit der
nächste Lauf es erneut versucht.
- **Doppelschutz:** pro (Ausgabe, Benutzer) wird genau einmal erinnert; der
Versand steht in `erinnerung_protokoll`. Auch ein späteres Bearbeiten des
Redaktionsschlusses löst keine zweite Erinnerung aus.
- **Audit:** jede Erinnerung als `System`/`benachrichtigt` (Objekttyp
`erinnerung`), jede Ausgaben-Änderung als `erstellt`/`geaendert`/
`geloescht` (Objekttyp `ausgabe`).
### Geplanter Job & manuelle Prüfung
APScheduler prüft **täglich** (Standard 08:00 Uhr, konfigurierbar über
`SPIELE_ERINNERUNG_JOB_UHRZEIT`, abschaltbar über
`SPIELE_ERINNERUNG_JOB_AKTIV=0`). Unter **Erinnerungen → „Jetzt prüfen und
erinnern“** führt ein Admin denselben Check sofort aus; das Ergebnis
erscheint als Banner. Die Uhr liegt zentral in `dienst.heute()` — Tests
frieren sie mit freezegun ein.
### UI
Unter **Erinnerungen** (`/erinnerung`) sehen alle angemeldeten Benutzer die
Ausgaben mit Redaktionsschluss und Restzeit-Badge. Admins verwalten zusätzlich
die Ausgaben (anlegen/bearbeiten/löschen), starten den Sofort-Check und
sehen den **Erinnerungsstatus**: wer wurde für welche Ausgabe wann über
welche Kanäle erinnert.
## Deployment (später)
@@ -449,8 +511,8 @@ geschrieben.
| 4 | Plugin `neuheiten` (BGG-Sync, APScheduler, Filter) | ✅ fertig |
| 5 | Plugin `dedup` (Verlags-Konflikt, deutsche Version, Vorgänger-/Planungs-Check) | ✅ fertig |
| 6 | Plugin `planung` (Verschiebung, händischer Eintrag + Prüfungen + Benachrichtigung) | ✅ fertig |
| 7 | Plugin `archiv` (12-Monats-Autopilot, Wiederherstellen, täglicher Job) | ✅ fertig (171 Tests grün) |
| 8 | Plugin `erinnerung` (Redaktionsschluss pro Ausgabe, 4-Wochen-Erinnerung) | ⏳ offen |
| 7 | Plugin `archiv` (12-Monats-Autopilot, Wiederherstellen, täglicher Job) | ✅ fertig |
| 8 | Plugin `erinnerung` (Redaktionsschluss pro Ausgabe, 4-Wochen-Erinnerung, Tages-Job) | ✅ fertig |
| 9 | Plugin `export` (CSV + PDF via WeasyPrint) | ⏳ offen |
| 10 | Integrationstests über alle Plugins | ⏳ offen |
| 11 | Deployment auf swen.henry.insight-it.de (Compose + Traefik, Live-Check) | ⏳ offen |
@@ -460,6 +522,5 @@ Legende: ✅ fertig · 🔄 in Arbeit · ⏳ offen · ⚠️ fertig mit offenen
## Offene Punkte (nicht Teil von Phase 1)
- CSRF-Schutz für Formulare (aktuell SameSite=Lax-Cookie als Basisschutz)
- Hintergrund-Jobs (APScheduler) für Erinnerungen
- WeasyPrint für PDF-Export (Systemabhängigkeiten im Container)
- Tailwind via CDN nur für Dev; für Produktion lokal gehostete Assets