Auto-Cleanup unbestaetigter Buchungen
Pending-Buchungen werden nach 30 Min automatisch geloescht und sind in der Admin-GUI unsichtbar
Auto-Cleanup unbestaetigter Buchungen
Uebersicht
Wenn ein Kunde das Buchungsformular absendet, wird eine Buchung mit Status pending erstellt. Diese Buchung ist noch nicht bestaetiget - der Kunde muss zuerst den Bestaetigungslink in der E-Mail klicken (Double-Opt-In).
Bis zur Bestaetigung:
- Die Buchung ist unsichtbar in der Admin-Buchungsliste
- Die Buchung zaehlt nicht fuer die Kurskapazitaet (verfuegbare Plaetze)
- Nach 30 Minuten ohne Bestaetigung wird die Buchung automatisch geloescht
Warum?
| Problem | Loesung |
|---|---|
| Kunde schliesst Browser ohne zu bestaetigen | Buchung wird nach 30 Min aufgeraeumt |
| Spam-Buchungen (trotz Turnstile + Rate-Limiting) | Automatische Bereinigung |
| Admin sieht unbestaetigte Buchungen | Pending wird aus der Liste gefiltert |
| Falsche Kapazitaetsanzeige | Pending zaehlt nicht fuer Plaetze |
Buchungs-Ablauf
1. Kunde fuellt Formular aus
└─> Buchung wird mit Status "pending" erstellt
└─> Bestaetigungsmail wird gesendet
2. Warte auf Bestaetigung (max. 30 Minuten)
└─> Buchung ist UNSICHTBAR in der Admin-GUI
└─> Buchung zaehlt NICHT fuer Kapazitaet
3a. Kunde klickt Link innerhalb 30 Min
└─> Status wechselt zu "confirmed"
└─> Buchung erscheint in der Admin-GUI
└─> Buchung zaehlt fuer Kapazitaet
3b. Kunde klickt NICHT innerhalb 30 Min
└─> WP-Cron loescht die Buchung automatisch
└─> Audit-Log Eintrag wird erstellt
Technische Details
Klasse: Kurs_Booking_Buchung_Cleanup
Datei: includes/class-buchung-cleanup.php
| Konstante | Wert | Beschreibung |
|---|---|---|
CLEANUP_AFTER_MINUTES |
30 | Minuten bis zur Loeschung |
CRON_HOOK |
kurs_booking_cleanup_pending |
WP-Cron Hook-Name |
CRON_INTERVAL |
every_fifteen_minutes |
Cron laeuft alle 15 Min |
Methoden
| Methode | Beschreibung |
|---|---|
init() |
Registriert Cron-Schedule und Hook |
add_cron_interval() |
Custom 15-Minuten-Intervall |
run_cleanup() |
Hauptlogik: Sucht und loescht expired Buchungen |
deactivate() |
Entfernt Cron-Job bei Plugin-Deaktivierung |
Cleanup-Logik (run_cleanup)
- SQL-Query: Alle Buchungen mit
status = 'pending'undcreated_at < 30 Min - Pro Buchung:
- GoBD-Check: Hat die Buchung eine Rechnung? → Uebersprungen (Loeschstutz)
- Custom Table Eintrag loeschen (
Kurs_Booking_Database::delete_booking) - WordPress Post + Meta loeschen (
wp_delete_post) - Cache invalidieren (Repository + Kurs-Cache)
- Audit-Log Eintrag erstellen
- Debug-Log Zusammenfassung: "X geloescht, Y uebersprungen"
Admin-Filter: Pending ausblenden
Datei: includes/class-buchung.php - Methode hide_pending_from_admin_list()
Verwendet pre_get_posts Filter um Buchungen mit _buchung_status = 'pending' aus der Admin-Liste auszuschliessen.
Sicherheit
Mehrstufiger Spam-Schutz (bestehend)
| Schicht | Schutz | Datei |
|---|---|---|
| Layer 1 | Cloudflare Turnstile | class-ajax.php |
| Layer 2 | Honeypot-Felder | class-ajax.php |
| Layer 3 | Time-based Check (min. 3 Sek) | class-ajax.php |
| Layer 4 | Content-Filter (Spam-Keywords) | class-ajax.php |
| Layer 5 | Rate-Limiting (10/Stunde/IP) | class-ajax.php |
| Layer 6 | Auto-Cleanup nach 30 Min | class-buchung-cleanup.php |
GoBD-Compliance
Buchungen die bereits eine Rechnung haben (sevDesk Invoice ID, Anzahlungsrechnung, Restrechnung) werden niemals automatisch geloescht. Der GoBD-Loeschstutz (Kurs_Booking_GoBD::has_invoice()) wird vor jeder Loeschung geprueft.
Betroffene Dateien
| Datei | Aenderung |
|---|---|
includes/class-buchung-cleanup.php |
NEU - Cleanup-Klasse mit Cron |
includes/class-buchung.php |
hide_pending_from_admin_list() hinzugefuegt, Pending-Bubble entfernt |
kurs-booking.php |
init() + deactivate() Hooks fuer Cleanup |
Monitoring
Cron pruefen
# Ist der Cron-Job registriert?
wp cron event list | grep cleanup_pending
# Manuell ausloesen (zum Testen)
wp cron event run kurs_booking_cleanup_pending
Audit-Log
Jede automatisch geloeschte Buchung wird im Audit-Log protokolliert: - Aktion: delete - Objekt: buchung - Kontext: "Auto-Cleanup: Unbestaetigte Buchung nach 30 Min geloescht"