# ARBEITSPAKETE – KSB Düren / Bewegungszentrum

Feature- und Modul-Übersicht. Details in den jeweiligen Root-`.md`-Dateien und `AGENTS.md`.

| AP | Modul | Status | Doku / Hinweise |
|----|--------|--------|-----------------|
| AP-1 | Schwimmkurs-Terminbuchung | produktiv | `APPOINTMENTS_*`, automatisierte Wartelistenangebote |
| AP-2 | Bewegungszentrum-Kursbuchung | produktiv | `KURSE_NEUE_FELDER_DOKUMENTATION.md`, automatisierte Wartelistenangebote |
| AP-3 | Event Center / Bewegung am Ehrentag | produktiv | Pakete/Dauern/max. Kinder je Paket im Admin; 3,5h und bis-6-Jahre-3h für neue Buchungen inaktiv (Migration `Version20261103183000`, Deploy offen) |
| AP-4 | Kursleiter-Portal | produktiv | `/instructor/dashboard`, vergangene Termine |
| AP-5 | Outlook / Kalender-Sync | produktiv | `MICROSOFT_OUTLOOK_*`, `CALENDAR_*`, Token-Refresh |
| AP-6 | E-Mail (IMAP + Templates) | produktiv | `EMAIL_*`, getrennte Template-Admin-Seiten |
| AP-7 | Container / SwimMonitor (Bayrol/Dulcopool) | produktiv | `config/apache/`, `WATER_DATA_COMPARISON.md` |
| AP-8 | Inspektionssystem | produktiv | `INSPECTION_SYSTEM.md` |
| AP-9 | SSL / Apache-Proxy Subdomains | produktiv | `SSL_CERTBOT_ERNEUERUNG.md` |
| AP-10 | Agenten-Doku & TODO-Workflow | **neu 2026-07-16** | `AGENTS.md`, `docs/TODO.md`, `.cursor/rules/` |
| AP-12 | SwimMonitor-Oberfläche 2.0 | **auf main seit 2026-11-03, Server-Deploy offen** | `docs/SWIMMONITOR-STYLE.md` |

## Wartelisten-Automatisierung (2026-07-20)

**Status: abgeschlossen, Deployment ausstehend.**

- Einheitliche 24-Stunden-Platzangebote für BZ-Kursbuchungen und Schwimmkurs-Termine.
- FIFO-Weitergabe unter pessimistischer Sperre; BZ-Kontexte berücksichtigen Datum,
  Zeitslot und Mehrfachtermine.
- Getrennte Ablauf-Commands mit nebenwirkungsfreiem `--dry-run`, vorgesehen alle fünf Minuten.
- Claim-Prüfungen verhindern Überbuchungen; Stornierungen stoßen die passende Weitergabe an.
- Datenbankschema: `migrations/Version20260720160000.php`.
- Betrieb: `docs/CRONJOBS.md`; Abnahme: `docs/WARTELISTEN_TESTMATRIX.md`.

| AP-11 | Fit wie ein Fisch Buchung | **Phase 5 live — 2026-09-10** | `docs/FIT_WIE_EIN_FISCH.md`, Migration `Version20260910150000` |

## Hub & KSB-Fixes (2026-08-22)

**Status: umgesetzt (Deploy ausstehend).**

- Öffentlicher Einstieg `/buchung` mit vier getrennten Cards (Schwimmcontainer, BZ, Fit wie ein Fisch, KSB).
- Kursbuchungs-Fallback: Zahlungsinfo nur mit Kurszuordnung; neutrale System-Mail sichtbar in der Template-UI.
- BZ-/Schwimm-Warteliste: Umwandlung mit E-Mail wie Automatisierung; Detail-Modal; Zahlung erst nach Umwandlung.

## Fit wie ein Fisch — Phase 5: Mails, Sammelanmeldung, Warteliste (2026-09-10)

**Status: umgesetzt (Absenderadresse, Standorttexte und Cron noch offen — siehe `docs/TODO.md`).**
Auftrag vom 2026-09-10. Alles bleibt im `Fisch`-Namensraum — keine gemeinsamen Entities mit
Schwimmcontainer, Bewegungszentrum oder Event Center, auch wenn Muster (Warteliste, Platzangebot,
Template-Platzhalter) von dort übernommen werden.

### Umfang

1. **E-Mail-Vorlagen** `/admin/fisch/email-templates` — echte Verwaltung wie in den anderen
   Systemen, mit eigener Entity `FischEmailTemplate` (Tabelle `fisch_email_template`) statt der
   gemeinsamen `EmailTemplate`. Absender pro Vorlage hinterlegbar; solange die eigenen
   Zugangsdaten fehlen, wird die vorhandene Absenderadresse genutzt und im Admin ein
   Hinweis angezeigt.
2. **Standort-Zusatzinfos** — `FischPool` erhält Adresse, Anfahrt, Parkplatz-Hinweis, Maps-Link
   und Hinweistext. Die Angaben stehen als Platzhalter in den Vorlagen zur Verfügung und gehen
   je Schwimmbad automatisch mit der Mail raus.
3. **Buchungsflow** — Anmeldung erzeugt eine offene Anmeldung mit Validierungslink
   (`pending` + Token), erst der Klick bestätigt sie (`confirmed`) und löst die
   Bestätigungsmail aus. Offene Anmeldungen belegen den Platz mit, damit nichts doppelt
   vergeben wird; ein Command gibt abgelaufene Reservierungen wieder frei.
4. **Warteliste** — Detailansicht zur Buchung wie in den anderen Systemen, automatisches
   Platzangebot mit Frist (Angebots-Token) beim Freiwerden eines Platzes und weiterhin
   händisches Nachrücken.
5. **Listen** — Kontaktdaten (Telefon, Adresse, Erziehungsberechtigte) in den Kurs- und
   Teilnehmeransichten sichtbar, CSV-Export auch in der Teilnehmerliste eines Kurses.
6. **Formularbuilder** — konfigurierbare Felder für drei Formulare: Einzelanmeldung,
   Schule (Sammelanmeldung) und Eltern (Anmeldung über den Schul-Link). Definition als
   Feldliste pro Formulartyp; Kernfelder (Name, Geburtsdatum) bleiben gesetzt, weil die
   Altersgruppen-Logik daran hängt.
7. **Sammelanmeldung** — Link an die Schule, die den Slot komplett bucht; daraus entstehen
   kurze Eltern-Links, mit denen die Kinder endgültig angemeldet werden. Reservierte Plätze
   sind ab der Buchung der Schule blockiert.

### Festlegungen

- **Eigene Vorlagen-Entity** statt `EmailTemplate`, damit die Allowlist-Logik der anderen
  Systeme unberührt bleibt (Wartbarkeit, ausdrücklicher Wunsch).
- **Offene Anmeldungen blockieren Plätze** (Frist 72 Stunden), sonst ließe sich der Kurs
  während der Validierung überbuchen.
- **Feldkonfiguration als JSON** je Formulartyp; Zusatzfelder landen als JSON an der Anmeldung,
  damit kein Schemawechsel pro neuem Feld nötig ist.
- **Eltern-Links kurz codiert** (Base32, 10 Zeichen) unter `/booking/fisch/e/{code}`.

### Abnahme

- Container + Twig lint ok; Migration `Version20260910150000` angewandt.
- `app:fisch:e2e-test` (mit `MAILER_DSN=null://null`): Anmeldung→Verify, Wartelisten-Angebot nach
  Storno→Claim, Sammelanmeldung Schule→Elternlink — alle drei Pfade grün. Anmeldephase wird nur
  für den Lauf geöffnet und danach wiederhergestellt.
- Ablaufjobs: `app:fisch:waitlist-expire`, `app:fisch:expire-pending` (siehe `docs/CRONJOBS.md`).

| AP-12 | Signage-Steuerung (Mini-PC `signage01`) | **umgesetzt 2026-10-26, Deploy ausstehend** | `docs/SYMFONY-INTEGRATION-SIGNAGE-DPOHL.md` Abschnitt 9, Migrationen `Version20261026170000`, `Version20261026220000` |

## Signage-Steuerung (2026-10-26)

**Status: umgesetzt und lokal geprüft, Server-Inbetriebnahme offen (siehe `docs/TODO.md`).**

- Verwaltung unter `/signage`: Geräte, Videos (Chunk-Upload, ffprobe-Prüfung), Playlists,
  Kalender mit 7-Tage-Vorschau und Konfliktprüfung (400 Tage), Veröffentlichen, Sofortwiedergabe,
  Protokoll. Rollen `ROLE_SIGNAGE_VIEWER` / `_EDITOR` / `_ADMIN`, Superadmin hat alle.
- Geräte-API `/signage/api/v1/player/*` (enroll, desired-state, releases, media, heartbeat,
  command-results): eigene zustandslose Firewall, Bearer-Token (nur Hash in der DB),
  IP-Allowlist `SIGNAGE_PLAYER_ALLOWED_IPS`, Fehler als `application/problem+json`.
- Manifest im Player-Format; Zeitplan 1:1 aus `signage_player/schedule.py` portiert
  (`SignageSchedule`, Sommerzeit wie `fold=0`).
- Abnahme lokal: 66 API-/Verwaltungsprüfungen auf Wegwerf-SQLite, 160 Vergleiche PHP gegen
  Python-Player ohne Abweichung, erzeugtes Manifest von `Release.model_validate_json` akzeptiert,
  Migration nur als `--dry-run`.
- Ergänzung 2026-10-26:
  - Planungskalender mit Drag & Drop (Playlist oder Einzelvideo, verschieben, Ende ziehen,
    Rückfrage bei Serien).
  - „Text-Videos“: Vorlagen mit Hintergrundvideo; der Server rendert per ffmpeg ein MP4 in die
    Mediathek. Migration `Version20261026220000`, Command `signage:text-video:render`.
  - Hoch-/Querformat:
    - Drehung je Ausgabe (`normal|left|right|inverted`) als `outputs[].rotation` im Manifest;
      bei `normal` fehlt das Feld.
    - Drehung von Handyvideos wird erkannt.
    - Hinweise in Mediathek und Kalender.
    - Text-Videos lassen sich als Hochformat 1080×1920 oder Querformat 1920×1080 erzeugen,
      zugeschnitten oder mit unscharfem Rand.
  - Deploy ausstehend.

## TV-Wand (2026-11-02)

**Status: lokal umgesetzt, nicht committet und nicht deployt.**

- `/live-dashboard/tv` zeigt je Container das 3D-Modell, dreht es und springt dann weiter, zum Schluss To-dos und Termine. Regen, Wind und Sonne liegen nur hier auf der Bühne, abhängig vom Standortwetter; nach Sonnenuntergang bleibt die Sonne aus.
- Messkarten und Schilder am Modell tragen den Sollzustand. Die Leiste zeigt den Stand der letzten Aktualisierung. Leistung erscheint mit Einheit, sobald eine Messreihe existiert.
- Diagramme aus Influx, keine Grafana-Rahmen. Design und Messreihen-Präfix eines neuen Containers über die Zusatzfelder `sceneDesign` und `influxPrefix`.
- LTE-Empfang als vier Balken neben dem Online-Status, auch in der Container-Übersicht und in der Detailansicht. Der Mobi-Router veröffentlicht RSRP/RSSI jede Minute auf `rtrmobi/lte`. Ohne Wert bleiben die Balken leer.

## Anlagenansicht (2026-11-01)

**Status: auf `/container/{id}` umgesetzt, lokal in einer Vorschau geprüft, nicht committet und nicht deployt.**

- 3D-Modell, Mobi-Folie und Fenster aus `schwimmcontainer/demo` liegen unter `public/container-ansicht/`.
- Die Seite zeigt Stammdaten, Live-Werte (Temperatur, Chlor, Redox, pH, Grenzen, Standort) am passenden Bereich.
- Energie: letzter Influx-Wert, dessen Messung `power`, `strom`, `leistung`, `watt`, `energie` oder `kwh` enthält.
  Narwali 2 hat zusätzlich das Grafana-Panel Leistung/Strom. Ohne Messung steht „kein Messwert“.

## SwimMonitor-Oberfläche 2.0 (2026-10-31)

**Status: umgesetzt, auf `main` (`c6fab7f`). Auf dem Server noch `./scripts/deploy.sh` (siehe `docs/TODO.md`).**

- Gemeinsames Layout `templates/swimmonitor/base.html.twig` mit Navigation nach Bereichen, Hell/Dunkel/Auto,
  lokale Schriften (IBM Plex) und lokale Bibliotheken (Bootstrap, Font Awesome, Leaflet, FullCalendar, Chart.js).
- Umgebaut: `/api-data`, `/container/{id}`, `/admin/user` (Liste, Anlegen, Bearbeiten), `/admin/settings`, `/changelog`,
  `/admin/todo`, `/admin/inspection-templates`, `/admin/lilian-labs` (Übersicht, Konfiguration, Messwerte),
  `/admin/water-comparison` (Diagramme, Details), `/calendar` (alle Container und je Container),
  `/admin/appointment-types`, `/signage` mit allen Unterseiten, `/appointments/privacy`, `/appointments/imprint`.
- Regeln: kein Inline-CSS, kein Inline-JavaScript, kein CDN; Verhalten über `data-*` und Dateien unter `public/js/`.
  Damit ist für diese Seiten `script-src 'self'; style-src 'self'` möglich (noch nicht gesetzt).
- Alle anderen Seiten sind unverändert und weiter erreichbar, aber nicht mehr im Menü.
- Changelog-Inhalt in `config/swimmonitor/changelog.yaml`, Release 2.0.0.
- Prüfung: alle betroffenen Seiten gerendert und das ausgelieferte HTML auf `style=`, `on…=`, Inline-`<script>`/`<style>`
  und externe Quellen geprüft (ohne Befund), Hell/Dunkel per Screenshot, 390 px ohne Überlauf, `lint:twig`/`lint:yaml`.
  Datenverändernde Aktionen (Speichern, Löschen, Verschieben) wurden bewusst nicht ausgeführt.

**Legende:** *produktiv* = im Einsatz; größere offene Punkte immer in `docs/TODO.md` pflegen.
