Files
sufw-webseite-terminplanung/development-system/README.md
T

13 KiB
Raw Blame History

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.

docker compose up --build

Beim ersten Start eines frischen Clones erzeugt Contao die benötigten Laufzeitverzeichnisse und Asset-Symlinks. Danach einmalig ausführen:

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:

.\scripts\Import-ContaoBaseline.ps1

Für die Frontend-Regressionstests:

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:

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:

.\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):

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:

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/perspektivwerk/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:

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:

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 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 in der statischen Vorschau aus /perspektivwerk/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:

Copy-Item public\perspektivwerk\booking\booking.js public\perspektivwerk\js\booking.js -Force
Copy-Item public\perspektivwerk\booking\booking.css public\perspektivwerk\js\booking.css -Force

Der vorhandene SCP-Upload überträgt den vollständigen statischen Perspektivwerk-DocumentRoot einschließlich Buchungsdemo. Vor dem externen Einsatz müssen die Migrationen eingespielt und booking-config.php mit einer sicheren Datenbank-URL befüllt sein.

Statische Perspektivwerk-Seite übertragen

Das Skript scripts/Deploy-Perspektivwerk.bat überträgt den Ordner public/perspektivwerk/ als vollständigen DocumentRoot per SCP und korrigiert anschließend die Lesbarkeit auf dem Server per SSH. Es lädt weder Contao noch Datenbank-Migrationen hoch.

scripts\Deploy-Perspektivwerk.bat

Der Hostname boogie wird aus der lokalen SSH-Konfiguration verwendet. Der Ordner landet unter /home/boogie/html/perspektivwerk/perspektivwerk/; die Konfiguration liegt daneben unter /home/boogie/html/perspektivwerk/booking-config.php. 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 muss die ignorierte booking-config.php befüllt sein. 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.

Die Seed-Integritätsprüfungen ausführen:

Invoke-Pester .\tests\ContaoBaseline.Tests.ps1