# Manuelle Testmatrix – automatisierte Wartelistenangebote

Im Projekt ist derzeit keine eigene PHPUnit-Testinfrastruktur konfiguriert. Die folgenden Fälle
sind deshalb nach Migration in einer Testumgebung manuell zu prüfen.

## Bewegungszentrum-Kursbuchungen

- Voller Kurs: neuer Eintrag erhält Status `waitlist`, aber kein Angebot.
- Storno einer aktiven Buchung: ältester passender Wartelisteneintrag erhält ein 24-Stunden-Angebot
  und genau eine Angebots-E-Mail.
- Getrennte Datums-/Zeitslots: ein Storno bietet ausschließlich im identischen Kontext weiter.
- Mehrere gleichzeitig abgelaufene Angebote eines Kontexts: alle verfallen; genau der nächste,
  bisher nicht angebotene FIFO-Eintrag erhält ein Angebot.
- Admin-Aktion „Platz anbieten" (grüner Haken in der Wartelisten-Übersicht): die gewählte Person
  erhält ein 24-Stunden-Angebot und die Platzangebot-E-Mail, unabhängig von der FIFO-Reihenfolge;
  die Zahlungsinfo geht erst nach der Annahme raus. Bei bereits laufendem Angebot wird die Frist
  erneuert (`state=renewed`).
- Admin-Aktion „Direkt umwandeln": Status springt auf `pending` und die Zahlungsinfo-Mail geht
  sofort raus, ohne Angebot und ohne Annahme-Link.
- Admin-Angebot ohne freien Platz: der Dialog warnt, das Angebot ist möglich, die Annahme wird
  aber mit `state=unavailable` abgelehnt.
- Claim vor Ablauf: Status wechselt atomar zu `pending`; Kapazität bleibt reserviert.
- Aufruf des Angebotslinks per GET: zeigt nur die Bestätigungsseite und verändert den Status
  nicht; erst der CSRF-geschützte POST nimmt den Platz an.
- Claim nach Ablauf oder nach Kapazitätsreduzierung: keine Überbuchung; Angebot wird verworfen.
- `--dry-run`: Anzahl stimmt, Status/Token/Zeitstempel und Messenger-Queue bleiben unverändert.

## Schwimmkurs-Terminbuchungen

- Storno eines aktiven Termins: ältester nicht benachrichtigter Eintrag erhält eine
  24-Stunden-Reservierung und genau eine Angebots-E-Mail.
- Mehrere abgelaufene Reservierungen desselben Termins: alle Tokens werden entfernt; höchstens
  ein nächster Eintrag wird angeboten.
- Claim vor Ablauf: Termin wird atomar angelegt und der Wartelisteneintrag entfernt.
- Claim bei ausgeschöpfter Kapazität: es entsteht kein zusätzlicher Termin.
- Nicht mehr verfügbarer oder archivierter Termin: Angebot verfällt ohne neues Angebot.
- `--dry-run`: Anzahl stimmt, Reservierungsfelder und Messenger-Queue bleiben unverändert.

## Betrieb

- `app:waitlist:e2e-test` durchläuft den kompletten Flow gegen die konfigurierte Datenbank
  (Testkurs ist inaktiv und wird ohne `--keep` wieder gelöscht). Optionen: `--system=bz|swim|both`,
  `--email`, `--keep`, `--skip-mail`, `--admin-offer` (BZ-Angebot per Admin-Aktion statt
  Automatisierung). Für Läufe ohne echten Versand `MAILER_DSN=null://null` setzen.
- Beide Commands ohne Treffer liefern Exit-Code `0` und Anzahl `0`.
- Ein provozierter Datenbankfehler liefert Exit-Code `1`.
- Zwei nahezu parallele Läufe erzeugen aufgrund der pessimistisch gesperrten Kurs-/Terminzeile
  kein doppeltes aktives Angebot.
