feat: DB backend and API implemementation

This commit is contained in:
Robert Wartenberg committed 2026-08-28 10:13:55 +02:00
1 parent 39b891cd63
commit a78e84515a
14 files changed
+955 -652

No files matched your search

+97 -2
View File
@@ -60,6 +60,83 @@ Die genaue Contao-, PHP- und Template-Version der öffentlichen Seite ist nicht
Die Terminlogik liegt in `public/booking/booking.js` als browsernatives ES-Modul. Für die statische Perspektivwerk-Vorschau liegen identische Kopien unter `public/perspektivwerk/js/`.
## Datenbankgestützte Buchungsdemo
Die Buchungsdemo lädt ihre Termine aus MariaDB und speichert eine Anmeldung
über `public/booking/api.php`. Die API wird unabhängig von Contao direkt durch
Apache ausgeliefert, verwendet aber dieselbe `DATABASE_URL` wie Contao. Dadurch
funktioniert sie aus der Vorschau `/perspektivwerk/` und aus dem Contao-
HTML-Element gleichermaßen.
Vor dem ersten Aufruf müssen die externen Migrationen eingespielt werden:
```powershell
.\scripts\Invoke-BookingMigrations.ps1
```
`database/migrations/001_booking_schema.sql` ist produktionsgeeignet
versioniert und idempotent. Sie enthält Tabellen für Termine und Anmeldungen
sowie klar erkennbare Demo-Termine. Die API prüft Kapazitäten innerhalb einer
Transaktion und sperrt den Termin dabei mit `SELECT … FOR UPDATE`; parallele
Anmeldungen können dadurch die Kapazität nicht überschreiten.
Die Demo speichert eine gültige Anmeldung direkt als `confirmed`. Sie hat
bewusst noch **keinen** Mailversand, kein Double-Opt-in, keine Erinnerungen,
keinen ICS-Feed und keine Verwaltungsoberfläche. Die Anzeige benennt diesen
Umstand ausdrücklich. Ein Produktiveinsatz erfordert außerdem die in den
SOLL-Dokumenten genannten Entscheidungen zu Art. 13 DSGVO, Löschfristen,
Mailbetrieb, Rollen/Berechtigungen und Missbrauchsschutz.
Der Browser erhält ein CSRF-Token per gleicher Sitzung; die API validiert alle
Pflichtdaten serverseitig und begrenzt Anmeldungen pro Sitzung. Dies ist eine
Demonstration der Schutzrichtung, ersetzt aber keine gesonderte
Sicherheitsanalyse für den Produktivbetrieb.
### API verwenden
Die API ist unter `/booking/api.php` erreichbar und akzeptiert ausschließlich
gleichartige Same-Origin-Anfragen. Sie liefert JSON und verwendet keine
Zugangsdaten im Browser.
Termine eines Monats laden (`to` ist der erste Tag des Folgemonats):
```text
GET /booking/api.php?project=perspektivwerk&from=2026-09-01&to=2026-10-01
```
`project` ist entweder `perspektivwerk` oder `produktionsschule`. Der Zeitraum
darf höchstens 93 Tage umfassen. Die Antwort enthält ein `csrfToken` und eine
Liste `events`. Ein Event enthält unter anderem `id`, `title`, `startsAt`,
`endsAt`, `capacity`, `availableCapacity`, `status` (`available` oder `full`),
`format` (`vor_ort` oder `telefonisch`) und `introductionRequired`.
Eine Anmeldung wird per `POST` angelegt. Dazu muss dieselbe Browser-Sitzung wie
beim `GET` verwendet und das erhaltene Token im Header
`X-SUFW-Booking-CSRF` übertragen werden:
```http
POST /booking/api.php
Content-Type: application/json
X-SUFW-Booking-CSRF: <csrfToken-aus-dem-GET>
{
"project": "perspektivwerk",
"eventId": "6c7f216b-2704-4c81-b17a-000000000001",
"name": "Max Mustermann",
"email": "max@example.org",
"phone": "+49 351 123456",
"privacyAccepted": true,
"introductionAttended": false,
"introductionDate": ""
}
```
Für ein PS-`Probearbeiten` mit `introductionRequired: true` müssen
`introductionAttended` den Wert `true` und `introductionDate` ein gültiges
Datum im Format `YYYY-MM-DD` enthalten. Bei Erfolg antwortet die Demo mit
`201 Created`; bei einem inzwischen ausgebuchten oder doppelt gebuchten Termin
mit `409 Conflict`; fehlerhafte Pflichtangaben erhalten `422`.
## Zwei Einbindungswege
Die Terminbuchungskomponente hat eine Vorschau auf einem Webseiten-Nachbau der Orginalseite:
@@ -71,7 +148,10 @@ Die Terminbuchungskomponente hat eine Vorschau auf einem Webseiten-Nachbau der O
## Statische Buchungsvorschau in Contao einbinden
Die erste Komponente ist absichtlich datenbankfrei. Sie zeigt Test-Slots, rendert einen Monatskalender und unterscheidet freie von belegten Terminen. Ein Klick auf einen freien Slot öffnet eine modale Eingabemaske für Name, E-Mail, Telefon, Alter, Nachricht, Ansprechperson bei AfA/Jobcenter sowie die DSGVO-Einwilligung. Die Eingaben werden derzeit ausschließlich im Browser validiert und weder gespeichert noch versendet.
Die Komponente lädt Termin- und Kapazitätsdaten über die beschriebene API. Ein
Klick auf einen freien Termin öffnet eine modale Eingabemaske für Name,
E-Mail-Adresse, Telefonnummer und die DSGVO-Kenntnisnahme; für Probearbeiten
kommen Einführungsveranstaltung und Datum hinzu.
Die Komponente benötigt keinen TypeScript-Compiler und keinen Build-Schritt. Regressionstests ausführen:
@@ -93,7 +173,22 @@ Contao maskiert nicht freigegebene HTML-Tags auch im Inhaltselement **HTML**. Vo
Danach den Contao-Cache über **Systemwartung** leeren und das Inhaltselement erneut speichern. Keine globale Freigabe mit `*` verwenden. Wer ein HTML-Inhaltselement bearbeiten darf, kann mit dem freigegebenen `script`-Tag JavaScript auf der Website ausführen; diese Bearbeitungsrechte müssen daher auf vertrauenswürdige Backend-Nutzer beschränkt bleiben.
Die Beispieltermine stehen in `public/booking/booking.js`; `public/perspektivwerk/js/booking.js` ist die für den statischen Upload bestimmte Kopie. Ein Test stellt sicher, dass beide Dateien gleich bleiben. Der spätere serverseitige Endpunkt muss sie ersetzen; Datenbankzugänge oder SQL gehören niemals in das HTML oder das Browser-JavaScript.
Die Termin- und Kapazitätsdaten kommen aus `/booking/api.php`; Datenbankzugänge
oder SQL gehören niemals in das HTML oder das Browser-JavaScript.
`public/perspektivwerk/js/booking.js` und die zugehörige CSS-Datei sind die für
den statischen Upload bestimmte Kopie. Ein Test stellt sicher, dass beide
Asset-Paare gleich bleiben. Nach Änderungen können sie lokal synchronisiert
werden mit:
```powershell
Copy-Item public\booking\booking.js public\perspektivwerk\js\booking.js -Force
Copy-Item public\booking\booking.css public\perspektivwerk\js\booking.css -Force
```
Der vorhandene SCP-Upload überträgt weiterhin nur die statische
Perspektivwerk-Seite. Für einen externen Einsatz der Buchungsdemo müssen
zusätzlich `/booking/api.php`, die Migrationen und die sichere
`DATABASE_URL`-Konfiguration auf dem Zielserver bereitgestellt werden.
## Statische Perspektivwerk-Seite übertragen