- PlayerPosition Enum (7 Handball-Positionen) mit Label/ShortLabel - Spielerstatistik pro Spiel (Tore, Würfe, TW-Paraden, Bemerkung) - Position-Dropdown in Spieler-Editor und Event-Stats-Formular - Statistik-Seite: TW zuerst, Trennlinie, Feldspieler, Position-Badges - Spielfeld-SVG mit Ampel-Performance (grün/gelb/rot) - Anklickbare Spieler im Spielfeld öffnen Detail-Modal - Fahrgemeinschaften (Anbieten, Zuordnen, Zurückziehen) - Übersetzungen in allen 6 Sprachen (de, en, pl, ru, ar, tr) - .gitignore für Laravel hinzugefügt - Demo-Daten mit Positionen und Statistiken Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
8.1 KiB
8.1 KiB
WebApp_Install — Handball Team Manager
Projekt-Typ
Laravel 12 WebApp zur Verwaltung von Handball-Teams, Spielern, Eltern, Terminen und Dateien. PHP 8.2+, SQLite/MySQL, Blade + Alpine.js + Tailwind CSS, Quill.js WYSIWYG-Editor. Deployment: Shared Hosting (all-inkl.com, FTP only, kein SSH).
Architektur
Verzeichnisstruktur
app/Models/— Eloquent Models (User, Player, Team, Event, Setting, etc.)app/Http/Controllers/Admin/— Admin-Bereich (UserController, SettingsController, etc.)app/Http/Controllers/Auth/— Login, Register, ForgotPassword, ResetPasswordapp/Http/Middleware/— InstallerMiddleware, SetLocaleMiddleware, SecurityHeadersMiddleware, ActiveUserMiddleware, DsgvoConsentMiddleware, StaffMiddleware, AdminOnlyMiddlewareapp/Services/— HtmlSanitizerService (HTMLPurifier), GeocodingService, SupportApiServiceapp/Enums/— UserRole, EventType, EventStatus, ParticipantStatus, CateringStatusapp/Notifications/— ResetPasswordNotification (Custom, mit Setting-Template)resources/views/— Blade-Templates (layouts: admin, guest, app, installer)lang/{de,en,pl,ru,ar,tr}/— 6 Sprachen: Deutsch, Englisch, Polnisch, Russisch, Arabisch, Tuerkischdatabase/migrations/— Nummeriert mit Prefix 0001-0035database/seeders/— AdminSeeder, DemoSeeder, FaqSeeder
Wichtige Patterns
- Settings: Key-Value Store in
settingsTabelle.Setting::get($key)mit 1-Stunden-Cache,Setting::set($key, $value)mit Cache-Invalidierung - Locale-Settings: Rechtliche Texte und E-Mail-Templates sind locale-suffixed:
impressum_html_de,datenschutz_html_en,password_reset_email_pletc. - Passwort-Hashing: User-Model nutzt Laravel Cast
'password' => 'hashed'— KEIN manuelles Hash::make beim Setzen via$user->password = $pwnoetig - HTML-Output: Alle
{!! !!}-Ausgaben von User-Content muessen durchHtmlSanitizerService::sanitize()gehen - Rollen: Admin, Coach, ParentRep, User (Enum
UserRole) - Soft-Deletes: User und Player (7 Tage Wiederherstellung)
- Activity-Log:
ActivityLog::log()/ActivityLog::logWithChanges()fuer Audit-Trail - User-Model: Nutzt
NotifiableTrait (erforderlich fuer Passwort-Reset-Notifications) - .env-Manipulation:
updateEnvValues()Helper in InstallerController und SettingsController
Multi-Language
- 6 Sprachen: de, en, pl, ru, ar, tr
- Translation-Dateien:
lang/{locale}/admin.php,auth_ui.php,passwords.php,ui.php,events.php,profile.php,validation.php - Locale wird per SetLocaleMiddleware aus
$user->localeoder Session gesetzt - RTL-Support fuer Arabisch (ar)
- Alle Uebersetzungsschluessel muessen in ALLEN 6 Sprachen hinzugefuegt werden
Installer (5-Step Wizard)
- Systemcheck (PHP-Version, Extensions, Berechtigungen)
- Datenbank (SQLite/MySQL Konfiguration)
- Einstellungen (App-Name, Admin-Account)
- E-Mail (SMTP-Konfiguration mit Verbindungstest, oder Log-Modus zum Ueberspringen)
- Abschluss (Finalize, Demo-Daten, Lizenz)
InstallerMiddlewareprueftstorage/installedDatei- Setup-Token-Schutz: Token in
storage/setup-token, SHA256 im Laravel-Log - SMTP-Test nutzt
Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport - PW-Reset-Standardtexte fuer 6 Sprachen in
getDefaultPasswordResetTexts() - Session-basierte Datenpersistenz zwischen Schritten
Password Reset Flow
- User klickt "Passwort vergessen?" auf Login-Seite
- ForgotPasswordController sendet Reset-Link via Laravel Password Broker
- ResetPasswordNotification laedt Custom-Template aus
Setting::get('password_reset_email_{locale}') - Platzhalter:
{name},{link},{app_name} - Fallback auf Standard-Laravel-Template mit Translation-Keys (
passwords.reset_*)
Admin Settings Tabs
- Allgemein: App-Name, Slogan, Favicon, Saison
- E-Mail: SMTP-Konfiguration mit Verbindungstest (schreibt in .env,
Artisan::call('config:clear')) - Rechtliches: Impressum + Datenschutz + PW-Reset-E-Mail pro Sprache (Quill-Editor mit Flaggen-Selector)
- Event-Standards: Min-Werte fuer Spieler, Catering, Zeitnehmer pro Event-Typ
- Dateikategorien: CRUD fuer File-Categories
- Sichtbarkeit: Feature-Toggles
- Lizenz: License-Key-Validierung via SupportApiService
- Wartung: Demo-Daten loeschen, Factory-Reset
Lazy Quill-Initialisierung (Rechtliches-Tab)
- Quill-Editoren werden erst bei Klick auf die Sprach-Flagge erstellt (
initLocaleEditors(locale)) - Verhindert Datenverlust: Nicht-initialisierte Locales behalten ihre Server-Werte in Hidden-Inputs
$watch('legalLocale')+$nextTick()fuer verzoegerte ErstellungsyncEditors()synchronisiert nur tatsaechlich initialisierte Editoren
Route-Struktur (Middleware)
- Installer:
throttle:10,1, ohne SetLocaleMiddleware/ActiveUserMiddleware - Oeffentlich: Login, Register, Legal-Pages, Locale-Switch
- User-Bereich:
authMiddleware - Admin-Bereich:
auth+admin+prefix('admin')- Staff-Routes (Admin + Coach):
staffMiddleware - Admin-Only-Routes:
admin-onlyMiddleware (Settings, Locations, Support)
- Staff-Routes (Admin + Coach):
Security
Middleware-Stack
- CSP und Permissions-Policy via SecurityHeadersMiddleware (inkl. COOP-Header)
StaffMiddleware— prueft Admin oder Coach RolleAdminOnlyMiddleware— prueft explizit Admin-Rolle (Route-Level-Schutz)- Rate-Limiting auf Auth-Routes, User-Actions, Geocoding, Installer
Schutzmassnahmen
- Honeypot-Feld auf Login/Register-Formularen
- DSGVO-Consent-System mit Datei-Upload und Admin-Bestaetigung
- Factory Reset benoetigt Passwort + Bestaetigung "RESET-BESTAETIGT"
- File-Autorisierung:
authorizeFileAccess()in FileController prueft Team-Zugehoerigkeit - Settings-Whitelist: SettingsController akzeptiert nur bekannte Keys + validierte Locale-Suffixe
- SSRF-Schutz: GeocodingService mit Host-Whitelist, HTTPS-only, DNS-Rebinding-Check, Timeout 5s
- Installer-Sicherheit: Admin-Passwort sofort gehasht, Setup-Token nur als SHA256 geloggt
- Path-Traversal-Schutz: DSGVO-Datei-Downloads pruefen
str_starts_with('dsgvo/') - HTML-Sanitisierung: Alle User-Content-Ausgaben durch HtmlSanitizerService geschuetzt
- Invitation-Tokens: SHA-256 gehasht in DB gespeichert
- E-Mail-Normalisierung: Lowercase-Vergleich bei Login und Password-Reset
- Team-Scoping: Coach/ParentRep sehen nur ihre zugewiesenen Teams
Security-Audit-Historie (Maerz 2026)
6 Audits durchgefuehrt, Score: 6.5 → 9.5/10
- 95 Findings insgesamt, 88 behoben, 3 akzeptierte Risiken, 4 verbleibende Niedrig/Info
- Akzeptierte Risiken: MIME-Spoofing (F05), Enum-Reuse (F20), CSP unsafe-inline (W04, CDN-Abhaengigkeit)
Conventions
- Controller-Methoden: resourceful (index, create, store, show, edit, update, destroy)
- Blade-Components:
<x-layouts.admin>,<x-layouts.guest>,<x-layouts.app>,<x-layouts.installer> - Alpine.js fuer interaktive UI-Elemente
- Quill.js v1.3.7 fuer WYSIWYG-Editoren (via CDN mit SRI-Hashes)
- Keine Tests vorhanden — bei Aenderungen manuell testen
- Commit-Sprache: Deutsch oder Englisch
- Alle Uebersetzungsschluessel muessen in ALLEN 6 Sprachen hinzugefuegt werden
Haeufige Aufgaben
Neuen Translation-Key hinzufuegen
Immer in allen 6 Dateien: lang/de/, lang/en/, lang/pl/, lang/ru/, lang/ar/, lang/tr/
Neues Setting hinzufuegen
- Migration erstellen:
Setting::firstOrCreate(['key' => '...'], [...]) - In SettingsController
edit()laden - In View rendern
- In
update()speichern (mit Sanitization fuer HTML)
Neues locale-spezifisches Setting
- Keys:
{setting_name}_{locale}(z.B.impressum_html_de) - Migration fuer alle 6 Locales
- In SettingsController
$localeSettingsArray aufnehmen - In View mit Sprach-Flaggen-Selector anzeigen
- In
update()mit Whitelist undupdateOrCreate()behandeln - Wichtig: Neuen Key zur Whitelist in
SettingsController::update()hinzufuegen ($allowedLocaleKeys)
Neue Admin-Route hinzufuegen
- Route in
routes/web.phpim passenden Middleware-Block:- Alle Admin-Panel-Nutzer: direkt unter
adminPrefix - Staff (Admin + Coach): unter
staffMiddleware - Nur Admin: unter
admin-onlyMiddleware
- Alle Admin-Panel-Nutzer: direkt unter
- Controller-Methode mit Autorisierungs-Pruefung
- View erstellen
- Translation-Keys fuer alle 6 Sprachen