No results
Table of Contents
- Projekt-Landkarte (Code-getrieben)
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.
Projekt-Landkarte (Code-getrieben)
Diese Seite ist eine kurze mentale Landkarte des Projekts, basierend auf dem aktuellen Quellcode.
Was ist das System?
- Frontend: statische HTML-Seiten, generiert aus
content/(Markdown/HTML) via Node-Build. - Backend: PHP + SQLite für Anmeldung + Admin.
- Deployment-Artifact:
public/(wird gebaut und deployed).
Build & Laufzeit-Pfade (wichtig für das Verständnis)
Der Build (scripts/build.mjs) erzeugt/füllt public/:
- Content-Seiten:
content/*.md|*.html→public/<slug>/index.html - Assets:
static/assets/*→public/assets/*(CSS/JS/Images) - PHP Public Endpoints:
static/<dir>/*.php→public/<dir>/*.php- z.B.
static/anmeldung/index.php→public/anmeldung/index.php - z.B.
static/registration/index.php→public/registration/index.php - z.B.
static/api/event-date.php→public/api/event-date.php
- z.B.
- Backend-Code:
zgb-backend/*→public/backend/* - Datenverzeichnis:
zgb-data/(falls vorhanden) →public/data/- falls keine Quelle vorhanden:
public/data/wird angelegt (DB entsteht beim ersten Zugriff) - Build stellt außerdem eine sperrende
public/data/.htaccesssicher (Schutz vor HTTP-Zugriff).
- falls keine Quelle vorhanden:
Merksatz: Alles, was der Webserver serviert, kommt aus public/.
Haupt-User-Flow: Anmeldung
1) Formular anzeigen: /anmeldung/
Datei: public/anmeldung/index.php (aus static/anmeldung/index.php)
- Lädt Config aus SQLite (über
ConfigRepository). - Prüft Anmeldezeitraum (
startDate/endDate); außerhalb wird das Formular nicht angezeigt (ggf. Countdown bis Start). - Ermittelt eine freie Nummer im Bereich (
startNumberbisstartNumber+maxNumber-1) nur zur Anzeige. - Setzt serverseitig einen Form-Timer in der Session (
form_start_time) für Timeout beim POST. - CSRF: erzeugt Token mit kurzer TTL (
CSRFService::getTokenWithTTL(180)).
2) Formular abschicken: /registration/ (POST)
Datei: public/registration/index.php (aus static/registration/index.php)
- Validiert Eingaben + prüft:
- CSRF (TTL 180s)
- Form-Timeout (serverseitig, 180s seit Formularanzeige)
- Duplikat (gleiche Kerndaten) → Redirect
?duplicate=1
- Speichert Anmeldung in SQLite mit atomarer Nummernvergabe:
- Nummer wird erst beim POST vergeben
- innerhalb einer SQLite Write-Transaktion (
BEGIN IMMEDIATE) → parallel sicher - bei voller Kapazität → Redirect
?full=1
- Danach Mail:
- Standard: Mail-Queue (Jobs in DB) wenn
mailQueueEnabled=1 - Optional: Direktversand (wenn Queue deaktiviert)
- Standard: Mail-Queue (Jobs in DB) wenn
- Erfolgs-Redirect (PRG):
/anmeldung/?success=1
“Event-Datum” im Header (Countdown)
- JS:
public/assets/script.jsversucht Event-Datum zu finden:- auf PHP-Seiten über Meta-Tag
meta[name="event-date"] - auf statischen HTML-Seiten via API:
GET /api/event-date.phpliefert{"eventDate": "YYYY-MM-DD"}.
- auf PHP-Seiten über Meta-Tag
- API-Endpoint:
public/api/event-date.php- Browser-Cache: 30s
- Server-Cache: file-basiert 60s (
public/data/.event-date-cache.json)
Admin-Flow
Login: /backend/web/admin_login.php
- Session-basiert (Flag
is_admin) - Passwort-Hash liegt in Config (
adminPasswordHash) - Rate-Limit (session-basiert): 5 Fehlversuche → 10 Minuten Block
- “Passwort vergessen?”:
- erzeugt neues Passwort (random)
- speichert neuen Hash in Config
- sendet Mail an
operatorEmail - zusätzliches Cooldown file-basiert (z.B. 10 Minuten)
Admin-Konfiguration: /backend/web/admin.php
Tabs:
- Konfiguration:
startDate,endDate,startNumber,maxNumber,operatorEmail,eventDate - Admin & Export: CSV-Download, Logout, Passwort ändern, Link zum Löschen
- Mail-Queue: Queue aktiv, max mails/h, Test-Redirect, Status + “failed retry”
Live-Status:
admin_queue_status.phpliefert JSON (pending/sending/failed + registrationsTotal)admin.phppollt das JSON alle 10s (Fetch, no-store).
CSV-Export:
POST /backend/web/export_registrations.php(mit CSRF) → CSV-Download aller Registrierungen
Löschen:
GET/POST /backend/web/clear_registrations.php(CSRF-geschützt, Bestätigung)- UI deaktiviert Löschlink in
admin.phpwährend Anmeldezeitraum (zusätzlicher Schutz ist sinnvoll, Server-seitig kann man das bei Bedarf ebenfalls erzwingen).
Mail-Queue (asynchroner Versand)
Datenmodell
- Tabelle
mail_queue(SQLite) mit Statuspending|sending|failed - Idempotenz: Unique-Index
(registration_number, mail_type)verhindert doppelte Jobs pro Anmeldung+Mailtyp. - Jobs werden nach Erfolg gelöscht (“Option A”).
Worker (Cron)
- Entry:
public/backend/cron/send_mail_queue.php(CLI-only) - Worker:
MailQueueWorker::run()- Token-Bucket Rate-Limit (Config-Key
mailMaxPerHour, Default 40, Range 1–60) - Claiming/Locking via DB (
locked_until) - Backoff bei Fehlern, nach vielen Versuchen “parkt” er Jobs bis Admin-Retry.
- Token-Bucket Rate-Limit (Config-Key
Test-Modus:
- Key
mailRedirectToSchumbi=1leitet User-Mails (nicht Orga) auf@schumbi.deum,- aber nur außerhalb des echten Anmeldezeitraums (serverseitig erzwungen).
Config-Keys (SQLite config Key/Value)
Kern:
startDate(YYYY-MM-DD)endDate(YYYY-MM-DD)startNumber(int als string)maxNumber(int als string)operatorEmaileventDate(YYYY-MM-DD)adminPasswordHash
Mail-Queue:
mailQueueEnabled(1/0)mailMaxPerHour(1..60)mailRedirectToSchumbi(1/0)- intern für Token-Bucket:
mailTokensmailLastRefill
Sicherheit (Kurzliste)
- Session-Härtung:
SessionServicesetzt Cookie-Flags (HttpOnly, SameSite=Lax, Secure bei HTTPS). - CSRF:
CSRFService(Standard-Token + TTL-Token für Registrierung). - Admin Rate-Limit: session-basiert in
AuthService. - Reset-Cooldown: file-basiert in
RateLimitService. - DB-Schutz:
public/data/.htaccesswird beim Build erzeugt/validiert.
“Wo schaue ich zuerst hin?” (Debug-Map)
- Build/Output:
scripts/build.mjs - Anmelde-UI:
static/anmeldung/index.php - POST-Verarbeitung:
static/registration/index.php - DB/Repositories:
zgb-backend/Repository/*+zgb-backend/Repository/Schema/* - Admin:
zgb-backend/web/admin*.php - Mail-Queue:
zgb-backend/Service/MailQueueWorker.php+zgb-backend/Repository/MailQueueRepository.php - Frontend JS:
static/assets/script.js(Header-Countdown, Menu, Formular-Countdown)
Einstieg
Architektur
- Architektur-Übersicht
- Frontend-Build
- Backend
- Datenbank
- Mail-Queue
- Performance & Optimierungen
- Entscheidungen & Historie
Betrieb
Projektarbeit
- Code:
ssh://forgejo@home.schumbi.de/ralf/zgb_www.git - Wiki:
ssh://forgejo@home.schumbi.de/ralf/zgb_www.wiki.git