6 Backend
Ralf Warmuth edited this page 2026-01-10 23:58:44 +01:00

Backend-Dokumentation

Übersicht

Das PHP-Backend verwaltet Anmeldungen für die Zwergen-Börse. Es verwendet eine klare Architektur mit Models, Repositories und Services.

Für ein zusammenhängendes Gesamtbild (inkl. Build-/Laufzeit-Pfade):
Projekt-Landkarte (Code-getrieben)

Verzeichnisstruktur

zgb-backend/
├── Model/              # Domain-Models (Value Objects)
├── Repository/         # Datenzugriff
│   └── Schema/        # SQL-Dateien
├── Service/            # Business-Logik
└── web/               # Controller/Endpoints

Models

Registration

Immutable Value Object für Anmeldungen:

final class Registration
{
    public function __construct(
        public readonly string $salutation,
        public readonly string $firstName,
        public readonly string $lastName,
        public readonly string $street,
        public readonly string $postcode,
        public readonly string $city,
        public readonly string $email,
        public readonly string $phone,
        public readonly string $transfer,
        public readonly ?string $teamMember,
        public readonly int $number,
        public readonly string $createdAt
    ) {}
}

Felder:

  • salutation: Anrede (Herr, Frau, Divers)
  • firstName, lastName: Name
  • street, postcode, city: Adresse
  • email, phone: Kontakt
  • transfer: Übergabeart (Post, Abholung, Team)
  • teamMember: Name des Teammitglieds (optional)
  • number: Vergebene Anmeldenummer
  • createdAt: Zeitstempel

Config

Konfiguration für das System:

final class Config
{
    public function __construct(
        public readonly string $startDate,
        public readonly string $endDate,
        public readonly int $startNumber,
        public readonly int $maxNumber,
        public readonly string $operatorEmail,
        public readonly string $eventDate,
        public readonly string $adminPasswordHash = ''
    ) {}
}

Felder:

  • startDate: Startdatum Anmeldung (ISO-Format: Y-m-d)
  • endDate: Enddatum Anmeldung (ISO-Format: Y-m-d)
  • startNumber: Erste vergebene Nummer
  • maxNumber: Maximale Anzahl Anmeldungen
  • operatorEmail: E-Mail des Organisators
  • eventDate: Datum der Zwergenbörse (ISO-Format: Y-m-d)
  • adminPasswordHash: Gehashtes Admin-Passwort (optional)

Repositories

RegistrationRepository

Verwaltet Anmeldungen in der Datenbank.

Methoden:

  • saveRegistration(Registration $registration): Speichert Anmeldung
  • loadRegistration(int $id): Lädt Anmeldung nach ID
  • getAllRegistrations(): Alle Anmeldungen
  • clearAllRegistrations(): Löscht alle Anmeldungen
  • existsDuplicateRegistration(array $data): Prüft auf Duplikate

SQL-Schema: Repository/Schema/Registration/

ConfigRepository

Verwaltet System-Konfiguration als Key-Value-Paare.

Methoden:

  • loadConfig(): Lädt aktuelle Konfiguration als Config-Objekt
  • saveConfig(Config $config): Speichert Konfiguration (alle Werte)
  • getConfig(string $key): Lädt einzelnen Konfigurationswert
  • setConfig(string $key, string $value): Setzt einzelnen Konfigurationswert

SQL-Schema: Repository/Schema/Config/

Hinweis: Die Konfiguration wird als Key-Value-Paare in der Datenbank gespeichert. loadConfig() und saveConfig() arbeiten mit dem Config-Objekt, während getConfig() und setConfig() einzelne Werte verwalten.

Repository (Basis-Klasse)

Abstrakte Basis-Klasse für alle Repositories:

abstract class Repository
{
    public static function CreatePDO(string $dbPath): PDO
    // Erstellt PDO-Verbindung zur SQLite-Datenbank
    
    protected function getSQL(string $fname): string
    // Lädt SQL-Datei aus Schema-Verzeichnis
}

Services

AuthService

Authentifizierung und Rate-Limiting.

Methoden:

  • isAdmin(): Prüft Admin-Status
  • requireAdmin(): Erzwingt Admin-Login
  • login(): Setzt Admin-Session
  • logout(): Beendet Session
  • checkRateLimit(): Prüft Rate-Limit
  • failRateLimit(): Erhöht Fehlversuche
  • resetRateLimit(): Setzt Rate-Limit zurück

Rate-Limiting:

  • Max. 5 Fehlversuche
  • Block: 10 Minuten

CSRFService

CSRF-Token-Verwaltung.

Methoden:

  • getToken(): Generiert/erhält Token
  • checkToken(?string $token): Validiert Token
  • rotateToken(): Rotiert Token

Implementierung:

  • Token in Session gespeichert
  • 32 Bytes zufällige Hex-String
  • Prüfung bei allen POST-Requests

MailService

E-Mail-Versand mit Templates.

Methoden:

  • sendUserMail(Registration $registration, Config $config): Bestätigung an User
  • sendOrganizerMail(Registration $registration, Config $config): Benachrichtigung an Organisator

Templates:

  • MailTemplates/user_mail.txt: User-Bestätigung
  • MailTemplates/organizer_mail.txt: Organisator-Benachrichtigung

Template-Syntax:

  • {{variable}}: Platzhalter
  • {{#if teamMember}}...{{/if}}: Bedingte Blöcke

Für den asynchronen Versand (Queue, Rate-Limit, Cron):
Mail-Queue

SessionService

Zentrales, sicheres Session-Setup.

Methoden:

  • start(): Startet Session mit sicheren Default-Flags

Features:

  • Automatische Cookie-Flag-Konfiguration (HttpOnly, Secure, SameSite)
  • Strict Mode aktiviert
  • Nur Cookie-basierte Sessions
  • CLI-kompatibel (keine Cookies im CLI-Modus)

Verwendung:

SessionService::start();
// Danach kann $_SESSION verwendet werden

RateLimitService

File-basiertes Rate-Limiting für spezifische Aktionen.

Methoden:

  • allowWithCooldown(string $filePath, string $actionKey, int $cooldownSeconds): Prüft, ob Aktion erlaubt ist

Features:

  • File-basiertes Locking (flock)
  • Action-spezifische Cooldowns
  • Fail-open bei Dateisystem-Problemen

Verwendung:

if (!RateLimitService::allowWithCooldown($rateLimitFile, 'admin_password_reset', 600)) {
    // Aktion noch in Cooldown (10 Minuten)
}

Einsatz:

  • Passwort-Reset-Limiting (10 Minuten Cooldown)
  • Weitere Rate-Limits nach Bedarf

LogService

Strukturiertes Logging für Fehler und Events.

Methoden:

  • error(string $message, array $context = [], ?\Throwable $exception = null): Loggt Fehler
  • warning(string $message, array $context = []): Loggt Warnung
  • info(string $message, array $context = []): Loggt Info
  • debug(string $message, array $context = []): Loggt Debug-Info

Features:

  • Strukturiertes JSON-Logging
  • Kontext-Informationen
  • Exception-Stack-Traces
  • Log-Level (ERROR, WARNING, INFO, DEBUG)

Verwendung:

LogService::error('Fehler beim Speichern', [
    'file' => __FILE__,
    'line' => __LINE__,
    'registration_number' => $number
], $exception);

MailQueueWorker

Asynchroner E-Mail-Versand mit Queue-System.

Methoden:

  • run(string $dbPath, string $logPath): Startet Worker (CLI-only)

Features:

  • Token-Bucket Rate-Limiting
  • Retry-Mechanismus mit Backoff
  • Lock/Lease-System für Concurrency
  • Automatische Cleanup von "waisen" Jobs

Siehe auch: Mail-Queue

Web-Endpoints

Öffentliche Endpoints

/anmeldung/ (static/anmeldung/index.phppublic/anmeldung/index.php)

Zeigt Anmeldeformular:

  • Prüft Anmeldezeitraum
  • Findet freie Nummer
  • Zeigt Formular oder Fehlermeldung

/registration/ (static/registration/index.phppublic/registration/index.php)

Verarbeitet Formular-Submission:

  • Validierung
  • Duplikat-Prüfung
  • Speicherung
  • E-Mail-Versand
  • Weiterleitung

Hinweis: Die konkreten Build-/Laufzeit-Pfade und der vollständige Flow sind in der Projekt-Landkarte (Code-getrieben) dokumentiert.

Admin-Endpoints

/backend/web/admin_login.php

Login-Seite:

  • Passwort-Eingabe
  • Rate-Limiting
  • Session-Management

/backend/web/admin.php

Haupt-Admin-Seite:

  • Konfiguration bearbeiten
  • Export-Funktion
  • Logout
  • Passwort ändern
  • Anmeldungen löschen

Zugriffsschutz: Nur für eingeloggte Admins

/backend/web/admin_password.php

Passwort ändern:

  • Altes Passwort prüfen
  • Neues Passwort setzen
  • Hash in Datenbank speichern

/backend/web/admin_logout.php

Logout:

  • Session beenden
  • Weiterleitung zu Login

/backend/web/export_registrations.php

CSV-Export:

  • Alle Anmeldungen als CSV
  • Download-Datei

/backend/web/clear_registrations.php

Anmeldungen löschen:

  • Nur außerhalb Anmeldezeitraum
  • Unwiderruflich

/backend/web/counter.php

Zählt Anmeldungen:

  • Aktuelle Anzahl
  • JSON-Response

Datenbank-Schema

Quelle der Wahrheit

Das Schema wird automatisch initialisiert und liegt als SQL-Dateien unter:

  • zgb-backend/Repository/Schema/Registration/*
  • zgb-backend/Repository/Schema/Config/*
  • zgb-backend/Repository/Schema/MailQueue/*

Eine lesbare Zusammenfassung ist in Datenbank.
Für “Warum ist das so?” siehe Entscheidungen & Historie.

Für Performance-Aspekte (SQLite, Caches, Indizes, etc.):
Performance & Optimierungen

Sicherheit

Implementierte Maßnahmen

  1. CSRF-Schutz: Token bei allen POST-Requests
  2. SQL-Injection-Schutz: Prepared Statements
  3. Rate-Limiting: Schutz vor Brute-Force
  4. Session-Sicherheit: Regenerierung nach Login
  5. Input-Validierung: Server-seitig
  6. HTTP-Security-Headers: X-Frame-Options, CSP, etc.

Best Practices

  • Passwörter: Bcrypt-Hashing (über password_hash())
  • Sessions: Sichere Cookie-Flags
  • Fehlerbehandlung: Keine sensiblen Daten in Fehlermeldungen
  • Logging: Admin-Aktionen protokollieren

Erweiterungen

Neue Funktion hinzufügen

  1. Model erstellen (falls nötig):

    // zgb-backend/Model/NewModel.php
    
  2. Repository erstellen:

    // zgb-backend/Repository/NewRepository.php
    // SQL in Repository/Schema/NewModel/
    
  3. Service erstellen (falls nötig):

    // zgb-backend/Service/NewService.php
    
  4. Controller erstellen:

    // zgb-backend/web/new_endpoint.php
    

Validierung erweitern

Validierung erfolgt in den Controllern. Beispiel:

if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    exit('Ungültige E-Mail-Adresse');
}

E-Mail-Templates anpassen

Templates in Service/MailTemplates/ bearbeiten:

  • Platzhalter: {{variable}}
  • Bedingte Blöcke: {{#if condition}}...{{/if}}