Befunde aus dem Sicherheits-Review des vorherigen Commits: - Gerät eine Buchung in "Prüfung nötig" (Rückbuchung, Doppelzahlung ...), wird der Stripe-Plan beendet und offene Rechnungen storniert. Nach Bestätigung legt der Worker einen neuen Plan für die offenen Raten an. Vorher zog Stripe auch bei Buchungen in Prüfung weiter ein. - Vor dem Anlegen wird bei Stripe nach einem laufenden Plan der Buchung gesucht; der Idempotenzschlüssel enthält Generation und Start. Verhindert einen zweiten Plan nach verlorener ID und die Rückgabe des alten, beendeten Plans nach einer Prüfung. - Start bei bereits verstrichener Fälligkeit deterministisch am nächsten 9-Uhr-Termin, letzte Rate bleibt am Stichtag. - Rückbuchungs-Event meldet die betroffene Buchung zurück. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
5.1 KiB
Tests und Abnahme
Stand 27.09.2026. Alle aufgeführten Läufe sind lokal ausgeführt und bestanden.
Automatisierte Tests
pnpm test umfasst 72 Tests in 6 Dateien. Sie laufen gegen eine echte, frisch gestartete PostgreSQL-18-Instanz, damit Zeilensperren und Trigger mitgetestet werden.
| Geschäftsrisiko | Datei |
|---|---|
| Alle vier Gesamtpreise, 28 % statt 30 % | tests/pricing.test.ts |
| Alle zwölf Ratenbeträge exakt, einschließlich 1.237,50 € | tests/payment-plan.test.ts |
| Zeitgrenzen 01.11.2026 und 01.01.2027 in Europe/Berlin, Sommerzeit | tests/pricing.test.ts, booking.integration.test.ts |
| Ungültige, inaktive, abgelaufene, noch nicht gültige, fremd gebundene und ausgeschöpfte Gutscheine | booking.integration.test.ts |
| Gleichzeitige Einlösung eines begrenzten Codes (7 parallel, 2 erlaubt) und Gesamtkontingent | booking.integration.test.ts |
| Gleichzeitige Buchungen bei knapper Kapazität (8 parallel, 2 Plätze) | booking.integration.test.ts |
| Abgelaufene Reservierungen, verzögerte Zahlung (SEPA), verspätete Zahlung mit und ohne freien Platz, verlorener Webhook | payments.integration.test.ts |
| Doppelte und ungeordnete Stripe-Events, Livemodus-Event im Testbetrieb, Signaturprüfung | payments.integration.test.ts |
| Zahlungserfolg, Abbruch, Fehler, Teilzahlung, Authentifizierung, Erstattung | payments.integration.test.ts, admin.integration.test.ts |
| Sperre aller Live-Checkout-Zugänge ohne Freigabe, Vorschauphase | sales-gate.test.ts, booking.integration.test.ts |
| Keine weitere Abbuchung nach der letzten Rate oder nach Stornierung, Zahlungsmethode getrennt | payments.integration.test.ts, admin.integration.test.ts |
| Unveränderlicher Preis-Snapshot (DB-Trigger), Idempotenz bei Doppelklick | booking.integration.test.ts |
End-to-End und Sicht
pnpm test:e2e umfasst 9 Tests auf den Profilen Smartphone (Pixel 7), Tablet (820 × 1180) und Desktop (1440 × 900):
- axe-Prüfung WCAG 2.1 AA ohne Verstöße
- kein horizontales Scrollen
- keine öffentliche Platzzahl
- Buchungsdialog: Pflichtfelder, Gutschein, Ratenplan 3 × 660 €, Erklärungen, Fokus beim Öffnen und Schließen per Escape
- Admin-Weiterleitung, Export mit gefälschtem Cookie ergibt 401, Statusseite mit
noindex
Bildschirmfotos aller drei Größen wurden visuell geprüft.
Letzter Lauf 01.10.2026 nach Einbau von Team, Villa-Bildern und bestätigtem Termin: 81/81 Unit- und Integrationstests, 9/9 E2E-Tests, Produktionsbuild grün. Team und Unterkunft wurden zusätzlich per Bildschirmfoto auf Smartphone (390 px) und Desktop (1440 px) geprüft. Mit Termin 08.05.2027 fällt die letzte Rate auf den 08.04.2027.
Hinweis: Läuft der Testserver nicht unter der Adresse aus APP_URL, lehnt der Same-Origin-Schutz die Preisabfrage ab (403). Dann hängt der Buchungsdialog bei „Preise werden geladen …“. Server deshalb mit passender APP_URL starten, z. B. APP_URL=http://localhost:3005 PORT=3005 pnpm start und E2E_BASE_URL=http://localhost:3005 pnpm test:e2e.
Manuell über HTTP geprüft
- Admin-Ablauf:
- Öffentliche Registrierung wird mit 400 abgelehnt, ein falsches Passwort mit 401.
- Ohne 2FA leitet
/adminzur Einrichtung um, der Export antwortet 401. - Nach der TOTP-Aktivierung sind Dashboard und CSV mit 200 erreichbar.
- CSRF: Anfragen ohne JSON bekommen 415, fremde Origins 403.
- Preismanipulation: Ein mitgeschicktes
totalCentswird ignoriert. - Sicherheitsheader (CSP mit Nonce, HSTS, X-Frame-Options) sind gesetzt.
- Der Standalone-Build läuft mit Datenbank. Worker-Lauf und
admin:createfunktionieren, eine doppelte Anlage wird abgewiesen. - Build, Typprüfung und ESLint laufen ohne Fehler, Kustomize rendert 17 Ressourcen.
Lauf 06.10.2026 nach Umstellung der Folgeraten auf Stripe Billing (inkl. Anhalten bei Prüfung und Schutz vor doppeltem Plan): 88/88 Unit- und Integrationstests, Typprüfung und ESLint ohne Fehler. Zusätzlich StripeGateway gegen die echte Stripe-Test-API mit Testuhr geprüft: Zeitplan mit zwei Folgeraten erzeugt genau zwei bezahlte Rechnungen (je 700 €, Metadaten bookingId/kind, PaymentIntent mit Charge) und endet danach (completed); abgelehnte Karte ergibt offene Rechnung mit geplantem Wiederholungsversuch und Zahlungslink; Storno setzt den Zeitplan auf canceled und die offene Rechnung auf void, auch wiederholt und vor dem Start.
Nicht ausgeführt / Einschränkungen
- Echte Stripe-Testbuchung gegen die Stripe-API: Ein Stripe-Testschlüssel lag nicht vor. Die Stripe-Logik ist gegen eine Attrappe mit Stripe-Semantik getestet (Idempotenz, Session-Zustände, Rechnungen des Ratenplans), die Webhook-Signatur mit der echten Stripe-Bibliothek. Mit Schlüssel: Anleitung in der README (
stripe listen, Testkarten). - Docker-Image und Cluster: Auf dem Entwicklungsrechner gibt es kein Docker und keinen Cluster-Zugang. Das Dockerfile ist nicht gebaut und nicht im Cluster ausgerollt. Geprüft sind der Standalone-Build und das Rendern der Manifeste.
- SMTP-Versand: nur über den Datei-Testausgang geprüft.
- Referenzseite: nur über eine Textzusammenfassung ausgewertet (siehe ARCHITEKTUR.md).