# Support-Wissen

Antworten auf Fragen von Anwendern, geprüft am Code. Der Antwort-Agent liest diese Datei zuerst
und sucht im Code nur, was hier fehlt oder als geändert gilt. Keine Namen, keine Mailadressen.

## Fit wie ein Fisch: Wann bekommt die Warteliste frei gewordene Plätze (Stornieren, Sammelanmeldung, Kapazität erhöhen)?
Stichworte: Buchungstool, Warteliste, Nachrücken, Stornieren, Teilnehmer löschen, Sammelanmeldung, Kapazität, Platzangebot, 24 Stunden, Reservieren
- Teilnehmer im Admin stornieren: Stornomail an die Eltern, danach sofort `offerNextForCourse` -> genau ein Angebot an den ältesten passenden Wartelisteneintrag (gleiche Altersgruppe, Bad/Uhrzeit im Wunsch, FIFO nach createdAt). Mail geht sofort raus (kein async Messenger für Mails).
- Angebot gilt 24 Stunden (`FischWaitlistService::OFFER_LIFETIME_HOURS`), ein offenes Angebot zählt als belegt.
- Abgelaufene Angebote reicht der Job `app:fisch:waitlist-expire` weiter; docs/CRONJOBS.md empfiehlt */5, die echte Crontab steht auf dem Server.
- Kein passender Eintrag: Platz bleibt frei, bei offener Anmeldephase öffentlich buchbar.
- Archivieren (Teilnehmer oder Sammelanmeldung) setzt nur archivedAt, kein Angebot an die Warteliste. Zum Nachrücken also "Stornieren" nutzen.
- Sammelanmeldung stornieren: ungenutzte Links werden gelöscht, angemeldete Kinder bleiben; `offerNextForCourse` nur EINMAL -> nur ein Platz wird angeboten, Rest bleibt frei. Tipp: restliche Plätze in der Warteliste per "Platzangebot" oder "Übernehmen" vergeben.
- Kapazität erhöhen (`FischCourseController::updateCapacity`): setzt nur maxCapacity, kein Wartelistenangebot, keine Schonfrist. Bei offener Anmeldephase sofort öffentlich buchbar.
- Platz für eine bestimmte Person sichern: direkt nach dem Erhöhen eine Sammelanmeldung über einen Platz anlegen (reserviert sofort) oder Person auf der Warteliste per "Übernehmen" eintragen.

Grundlage (Stand 2026-10-04): `src/Service/Fisch/FischWaitlistService.php` · `src/Service/Fisch/FischRegistrationService.php` · `src/Service/Fisch/FischBulkRegistrationService.php` · `src/Controller/Admin/Fisch/FischCourseController.php` · `src/Controller/Admin/Fisch/FischWaitlistController.php` · `src/Service/Fisch/FischCapacityService.php` · `docs/CRONJOBS.md`
<!-- stand: 2026-10-04 | dateien: src/Service/Fisch/FischWaitlistService.php#560f6442c8, src/Service/Fisch/FischRegistrationService.php#4ae4918901, src/Service/Fisch/FischBulkRegistrationService.php#3240772190, src/Controller/Admin/Fisch/FischCourseController.php#9296413f1d, src/Controller/Admin/Fisch/FischWaitlistController.php#5c813545f9, src/Service/Fisch/FischCapacityService.php#1cbc35dcd4, docs/CRONJOBS.md#1815743bb8 -->

## Welche geplanten Hintergrund-Jobs (Cron) gibt es im Projekt und wann laufen sie?
Stichworte: Cron, Crontab, Scheduler, Warteliste, Fisch, Messenger, Console, alle 5 Minuten, CRONJOBS
- Kein Symfony Scheduler; periodische Aufgaben über Server-crontab (`docs/CRONJOBS.md`), Pfad-Beispiel `/var/www/ksbdueren`.
- Empfohlen alle 5 Min (`*/5 * * * *`): `app:expire-course-waitlist-offers`, `app:expire-appointment-waitlist-offers`, `app:fisch:waitlist-expire`, `app:fisch:expire-pending`.
- BZ/Schwimm: abgelaufene 24-h-Wartelistenangebote weiterreichen; Fisch zusätzlich 72-h-unbestätigte Anmeldungen stornieren.
- Asynchrone Termin-Mails: dauerhafter Messenger-Worker, nicht Cron (`START_MESSENGER_WORKER.md`).
- Ältere/weitere Cron-Beispiele in `cron_jobs.txt` und Einzeldoks (Outlook, Zahlungen, Logs); maßgeblich für Warteliste/Fisch ist `docs/CRONJOBS.md`; produktive Crontab nur auf dem Server.

Grundlage (Stand 2026-10-04): `docs/CRONJOBS.md` · `cron_jobs.txt` · `src/Command/ExpireCourseWaitlistOffersCommand.php` · `src/Command/ExpireAppointmentWaitlistOffersCommand.php` · `src/Command/Fisch/FischWaitlistExpireCommand.php` · `src/Command/Fisch/FischExpirePendingRegistrationsCommand.php`
<!-- stand: 2026-10-04 | dateien: docs/CRONJOBS.md#1815743bb8, cron_jobs.txt#92799de14a, src/Command/ExpireCourseWaitlistOffersCommand.php#dc92b1d8e7, src/Command/ExpireAppointmentWaitlistOffersCommand.php#cb2b02e2b8, src/Command/Fisch/FischWaitlistExpireCommand.php#ce8bdc05fa, src/Command/Fisch/FischExpirePendingRegistrationsCommand.php#44ee878596 -->

## Wie funktioniert der öffentliche Termin-Check-in?
Stichworte: appointments, check-in, bookingToken, scan, PUBLIC_ACCESS, security.yaml, verified
- `/appointments` ist in `security.yaml` mit `PUBLIC_ACCESS`; Admin-Routen dort haben zusätzlich `IsGranted`.
- Check-in (`appointment_check_in`) und Vorschau (`appointment_check_in_info`) erwarten den `bookingToken` aus der Appointment-Entity (nicht die numerische ID).
- Gültig für Check-in: Status `verified`, aktuelle Zeit zwischen `startTime` und `endTime`, noch nicht `checkedIn`.
- QR-Scanner-Template: `templates/appointment/scan.html.twig` — Token aus URL-Segment oder reinem QR-Text.

Grundlage (Stand 2026-10-07): `config/packages/security.yaml` · `src/Controller/AppointmentController.php` · `templates/appointment/scan.html.twig` · `src/Entity/Appointment.php`
<!-- stand: 2026-10-07 | dateien: config/packages/security.yaml#2683ba59ef, src/Controller/AppointmentController.php#3cbb3efefe, templates/appointment/scan.html.twig#8fcfc77a67, src/Entity/Appointment.php#ccc2258c03 -->

## Wie sind öffentliche Abmeldung und Termin-Warteliste abgesichert?
Stichworte: security.yaml, PUBLIC_ACCESS, cancellation, my-bookings, waiting-list, leave, email, appointments, scan, check-in
- Öffentliche Abmeldung: Pfade `^/cancellation` und `^/my-bookings` müssen in `access_control` vor der Fallback-Regel `^/` → `ROLE_USER` stehen.
- Termin-Warteliste verlassen: `POST /appointments/waiting-list/leave/{id}` unter `^/appointments` öffentlich; Absicherung über passende `email` im JSON-Body.
- Check-in/Scanner-Routen hängen am Controller-Präfix `#[Route('/appointments')]` – Unterrouten nicht nochmals mit `/appointments/…` prefixen.
- QR-Validierung: `GET /qr-scanner/validate/{token}` erfordert Login (`ROLE_USER`); keine Buchungs-Tokens in Fehler-JSONs zurückgeben.

Grundlage (Stand 2026-10-07): `config/packages/security.yaml` · `src/Controller/PublicCancellationController.php` · `src/Controller/WaitingListController.php` · `src/Controller/AppointmentController.php` · `src/Controller/QrScannerController.php`
<!-- stand: 2026-10-07 | dateien: config/packages/security.yaml#186f83e5c7, src/Controller/PublicCancellationController.php#39bddb0b08, src/Controller/WaitingListController.php#383d0bdcd9, src/Controller/AppointmentController.php#e52ed3ecf6, src/Controller/QrScannerController.php#192eec0ac7 -->

## Wie ist der Termin-Check-in und die Scan-URL im AppointmentController geroutet?
Stichworte: appointments, scan, check-in, bookingToken, Route-Prefix, verified, PUBLIC_ACCESS
- Klassen-`#[Route('/appointments')]`; Unterroute `/scan` → `/appointments/scan` (kein doppeltes `/appointments/appointments/…`).
- `POST /appointments/check-in/{token}` und `GET /appointments/check-in-info/{token}` per `bookingToken`, nicht Appointment-ID.
- Check-in nur bei Status `verified`, Zeitfenster start–end, noch nicht eingecheckt.

Grundlage (Stand 2026-10-08): `src/Controller/AppointmentController.php` · `config/packages/security.yaml`
<!-- stand: 2026-10-08 | dateien: src/Controller/AppointmentController.php#e52ed3ecf6, config/packages/security.yaml#186f83e5c7 -->

## Wie funktionieren Fisch-Elternbriefe und die Übersetzungslinks in den Mails?
Stichworte: Elternbrief, Deutsch, Flaggen, Webseite, elterninfo, PDF, DeepL, Kampagnen-Token
- Die E-Mail enthält nur den deutschen Text (mit Platzhaltern); keine fremdsprachigen Absätze in der Mail.
- Optional am Ende: kurzer Hinweis „Übersetzung auf der Webseite:“ und Flaggen-Links (SVG von FISCH_PUBLIC_URL) zu `/booking/fisch/elterninfo/{token}?lang=…`.
- Fremdsprachige Texte pflegt der Admin unter „Übersetzungen für die Webseite“ (DeepL); sie erscheinen nur auf der öffentlichen Seite, nicht in der E-Mail.
- PDF-Anhänge global oder pro Schwimmbad; Versand wie zuvor über `FischMailService::dispatch`.

Grundlage (Stand 2026-10-13): `src/Service/Fisch/FischParentMailService.php` · `templates/admin/fisch/parent_mail/index.html.twig` · `templates/fisch_booking/parent_info.html.twig`
<!-- stand: 2026-10-13 | dateien: src/Service/Fisch/FischParentMailService.php#319b8e92af, templates/admin/fisch/parent_mail/index.html.twig#74b120d09a, templates/fisch_booking/parent_info.html.twig#d53999f8a8 -->
