Files
sufw-webseite-terminplanung/development-system/README.md
T
2026-08-28 17:30:28 +02:00

256 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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: <http://localhost:8080>
- Contao-Login: <http://localhost:8080/contao/login>
- Datenbankinspektor: <http://localhost:8081> (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.
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/`.
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 `public\perspektivwerk\*` rekursiv nach
`boogie:/html/perspektivwerk/`. 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/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 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: <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
`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=<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
<http://localhost:8080/booking-admin/>. 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 <http://localhost:8080/perspektivwerk/>. 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 `<link ...>` und `<script ...>` enthalten. Erscheinen stattdessen `&lt;link` oder `&lt;script`, wurde nicht das unmaskierte Feld **HTML-Code** verwendet und die Komponente kann nicht starten.
### Erforderliche Contao-Sicherheitseinstellung
Contao maskiert nicht freigegebene HTML-Tags auch im Inhaltselement **HTML**. Vor dem Einfügen der Komponente unter **System → Einstellungen → Sicherheit** die folgenden Einträge ergänzen:
- **Erlaubte HTML-Tags:** `script`, `link`
- **Erlaubte HTML-Attribute:** für `script` die Attribute `src`, `type`; für `link` die Attribute `href`, `rel`; für den Komponentenplatzhalter auf `div` entweder `data-*` oder mindestens `data-sufw-booking`, `data-project`.
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 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
Das Skript [scripts/Deploy-Perspektivwerk.ps1](scripts/Deploy-Perspektivwerk.ps1) überträgt ausschließlich den Inhalt von `public/perspektivwerk/` per SCP und korrigiert anschließend die Lesbarkeit auf dem Server per SSH. Dieser Ordner enthält auch `js/booking.js` und `js/booking.css`. Es lädt weder Contao noch die Datenbank oder andere Projektdateien hoch.
```powershell
.\scripts\Deploy-Perspektivwerk.ps1
```
Der Hostname `boogie` wird aus der lokalen SSH-Konfiguration verwendet. Der vollständige Inhalt wird per SCP-Aufruf nach `/home/boogie/html/perspektivwerk/` übertragen. Anschließend führt ein separater SSH-Aufruf `chmod -R a+rX /home/boogie/html/perspektivwerk` aus. Die Passphrase des SSH-Schlüssels wird daher in der Regel zweimal abgefragt.
Vor dem Upload gibt das Skript den vollständigen Zielpfad aus. Damit lässt sich direkt prüfen, ob `booking.js` unter `/home/boogie/html/perspektivwerk/js/booking.js` landet. Das große `X` in `a+rX` setzt das Ausführungsrecht nur auf Verzeichnissen und auf bereits ausführbaren Dateien; normale HTML-, CSS- und JavaScript-Dateien erhalten kein unnötiges Ausführungsbit.
## Versionierter Contao-Seitenzustand
Die Contao-Seiten, Artikel und Layouts liegen in MariaDB und werden deshalb zusätzlich als bereinigter SQL-Seed versioniert. Details zu Export, Import und den bewusst ausgeschlossenen Daten stehen in [database/README.md](database/README.md).
Die Seed-Integritätsprüfungen ausführen:
```powershell
Invoke-Pester .\tests\ContaoBaseline.Tests.ps1
```