# Perspektivwerk Terminbuchung – lokales Entwicklungssystem Dieser Ordner enthält eine lokale Contao-4.13.58-Entwicklungsumgebung mit Apache, MariaDB und Bootstrap 5. Die Buchungskomponente verwendet browsernative DOM-APIs und keine jQuery-Abhängigkeit. ## Contao-Version und Sicherheitsstatus Die Abhängigkeiten sind auf `contao/manager-bundle` und `contao/core-bundle` in Version `4.13.58` festgelegt. `composer.lock` ist Teil des Repositorys und muss bei Änderungen mit eingecheckt werden. Contao 4.13.58 ist ausschließlich als lokale Kompatibilitätsumgebung vorgesehen. In `composer.json` ist die Advisory `PKSA-f8tt-pn3h-s2tw` gezielt dokumentiert und für Composer freigegeben, weil keine neuere 4.13-Version verfügbar ist. Ein `composer audit` meldet darüber hinaus historische Abhängigkeitswarnungen; diese Umgebung darf deshalb nicht unverändert produktiv eingesetzt werden. ## Start Voraussetzungen: Docker Desktop (Compose v2) und optional Node.js 20+ zum Ausführen der JavaScript-Regressionstests. ```powershell docker compose up --build ``` Beim ersten Start eines frischen Clones erzeugt Contao die benötigten Laufzeitverzeichnisse und Asset-Symlinks. Danach einmalig ausführen: ```powershell docker compose exec app vendor/bin/contao-setup --no-interaction --env=dev docker compose exec app chown -R www-data:www-data var public system files docker compose exec app vendor/bin/contao-console contao:migrate --no-interaction Neuen Admin-Account anlegen: ```powershell docker compose exec app vendor/bin/contao-console contao:user:create --admin ``` Danach den versionierten Seitenzustand importieren: ```powershell .\scripts\Import-ContaoBaseline.ps1 ``` - Website/CMS: - Contao-Login: - Datenbankinspektor: (Server `db`, Benutzer `perspektivwerk`, Passwort `perspektivwerk`, Datenbank `perspektivwerk`) Für die Frontend-Regressionstests: ```powershell npm install npm test ``` **Seite öffnen:** Frontend: http://localhost:8080/default Backend: http://localhost:8080/contao ## HTML Nachbau der Perpektivwerkseite http://localhost:8080/perspektivwerk/ Die genaue Contao-, PHP- und Template-Version der öffentlichen Seite ist nicht verlässlich aus dem ausgelieferten HTML ableitbar. Das Setup bildet daher die wahrscheinlichste Komponentenfamilie nach; es ist kein Dump der Produktivinstallation. IONOS/Hosting, Matomo-Konfiguration, Inhalte, Templates und Erweiterungen müssen bei Bedarf separat ergänzt werden. Der vollständige, statisch auslieferbare Perspektivwerk-DocumentRoot liegt in `public/perspektivwerk/`. Er enthält die Buchungs-API unter `booking/` und die Verwaltung unter `booking-admin/`. Die Vorschau verwendet relative API-URLs und funktioniert dadurch lokal unter `/perspektivwerk/` sowie auf dem Server direkt im DocumentRoot. Für einen einfachen Upload der vollständigen statischen Mockup-Seite auf den Testserver steht unter Windows dieses Skript bereit: ```bat scripts\Deploy-Perspektivwerk.bat ``` Es überträgt den vollständigen Ordner `public\perspektivwerk` und dessen benachbarte Konfigurationsdatei `public\booking-config.php` nach `boogie:html/perspektivwerk/`. Damit entsteht der Server-DocumentRoot unter `html/perspektivwerk/perspektivwerk/`; die Konfigurationsdatei liegt eine Ebene darüber und damit außerhalb des DocumentRoots. Anschließend setzt es per SSH lesbare Dateien und durchsuchbare Verzeichnisse. Vor dem ersten Upload `public\booking-config.php.example` nach `public\booking-config.php` kopieren und dort die Produktiv-`database_url` eintragen. Die echte Konfigurationsdatei ist von Git ausgeschlossen; sie wird bei fehlender oder leerer PHP-Umgebungsvariable `DATABASE_URL` verwendet. Die mit übertragene `.htaccess` verweigert den HTTP-Zugriff auf diese Datei. Voraussetzung ist ein konfigurierter OpenSSH-Zugang mit dem Host-Alias `boogie`. ## Datenbankgestützte Buchungsdemo Die Buchungsdemo lädt ihre Termine aus MariaDB und speichert eine Anmeldung über `public/perspektivwerk/booking/api.php`. Die API wird unabhängig von Contao direkt durch Apache ausgeliefert. In der statischen Vorschau liegt sie relativ unter `/perspektivwerk/booking/api.php`. 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 Anfrage zunächst als `pending_confirmation`. Sie erstellt einen zeitlich begrenzten Bestätigungslink, bestätigt danach atomar gegen die verfügbare Kapazität und erzeugt eine zweite Bestätigungsnachricht. Bestätigungs- und Erinnerungsnachrichten liegen standardmäßig im lokalen Mailausgang der Testverwaltung. Mit `BOOKING_MAIL_TRANSPORT=mail` versucht der Job den Versand über die PHP-Funktion `mail()`; SMTP-Konfiguration und echter Mailbetrieb gehören erst in die Produktiventscheidung. 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: { "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 `202 Accepted`; bei einem inzwischen ausgebuchten oder doppelt gebuchten Termin mit `409 Conflict`; fehlerhafte Pflichtangaben erhalten `422`. Der Link ruft `GET /booking/confirm.php?token=` auf. Erst dort wird die Teilnahme in den Status `confirmed` überführt. Nicht bestätigte Anfragen laufen nach 30 Minuten ab. ## Eigenständiges PHP-Backend Die Testverwaltung läuft unabhängig von Contao unter . Sie bietet für PW und PS: - Termin anlegen, bearbeiten sowie aktivieren/deaktivieren, - Übersicht und Entfernen von Teilnahmen, - lokaler Mailausgang mit kopierbarem Bestätigungslink, - Anzeige bestätigter Teilnahmen nach frei wählbarem Zeitraum, - abonnierbaren ICS-Feed je Projekt, - manuellen Lauf der Ablauf- und Erinnerungsjobs. Der Verwaltungsbereich hat absichtlich keine Benutzerverwaltung und darf nicht unverändert außerhalb der Testumgebung bereitgestellt werden. Er ist eine eigenständige PHP-Seite, keine Contao-Komponente. Die zeitgesteuerten Aufgaben können zusätzlich ohne Browser ausgeführt werden: ```powershell docker compose exec app php scripts/Run-BookingJobs.php ``` Für einen späteren Betrieb muss dieser Aufruf als geplanter Job erfolgen. Die ICS-Adresse zeigt die Testverwaltung an; sie enthält nur Terminmetadaten und keine Daten der Teilnehmenden. ## Zwei Einbindungswege Die Terminbuchungskomponente hat eine Vorschau auf einem Webseiten-Nachbau der Orginalseite: **Apache-Vorschau:** auf der statischen Perspektivwerk-Seite unter . Die Seite liegt in `public/perspektivwerk/`; ihre Referenzen auf die Komponente verwenden die relativen Pfade `js/booking.css` und `js/booking.js`. 2. **Contao:** als eigenständiges Inhaltselement vom Typ **HTML** auf einer Contao-Seite. Es enthält das kombinierte Snippet mit CSS, Komponentenplatzhalter und JavaScript. `public/` ist der Apache-Webroot der lokalen Entwicklungsumgebung. Daher ist kein Kopieren der Komponentenassets nach `files/terminbuchung/` erforderlich. ## Statische Buchungsvorschau in Contao einbinden 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: ```powershell npm run test ``` ### Einbinden in Contao Ein **neues** Inhaltselement vom Typ **HTML** anlegen. Im Feld **HTML-Code** den vollständigen Inhalt aus [integration/contao-html-element.html](integration/contao-html-element.html) einfügen und speichern. Nicht das Inhaltselement **Text** und keinen TinyMCE-Editor verwenden: Diese können `link`- und `script`-Tags als Text maskieren. Für die Produktionsschule wird `data-project="produktionsschule"` gesetzt. In der Seitenvorschau muss der HTML-Quelltext die Tags als `` und `