- 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>
148 lines
8.1 KiB
Markdown
148 lines
8.1 KiB
Markdown
# 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, ResetPassword
|
|
- `app/Http/Middleware/` — InstallerMiddleware, SetLocaleMiddleware, SecurityHeadersMiddleware, ActiveUserMiddleware, DsgvoConsentMiddleware, StaffMiddleware, AdminOnlyMiddleware
|
|
- `app/Services/` — HtmlSanitizerService (HTMLPurifier), GeocodingService, SupportApiService
|
|
- `app/Enums/` — UserRole, EventType, EventStatus, ParticipantStatus, CateringStatus
|
|
- `app/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, Tuerkisch
|
|
- `database/migrations/` — Nummeriert mit Prefix 0001-0035
|
|
- `database/seeders/` — AdminSeeder, DemoSeeder, FaqSeeder
|
|
|
|
### Wichtige Patterns
|
|
- **Settings**: Key-Value Store in `settings` Tabelle. `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_pl` etc.
|
|
- **Passwort-Hashing**: User-Model nutzt Laravel Cast `'password' => 'hashed'` — KEIN manuelles Hash::make beim Setzen via `$user->password = $pw` noetig
|
|
- **HTML-Output**: Alle `{!! !!}`-Ausgaben von User-Content muessen durch `HtmlSanitizerService::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 `Notifiable` Trait (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->locale` oder Session gesetzt
|
|
- RTL-Support fuer Arabisch (ar)
|
|
- **Alle Uebersetzungsschluessel muessen in ALLEN 6 Sprachen hinzugefuegt werden**
|
|
|
|
### Installer (5-Step Wizard)
|
|
1. Systemcheck (PHP-Version, Extensions, Berechtigungen)
|
|
2. Datenbank (SQLite/MySQL Konfiguration)
|
|
3. Einstellungen (App-Name, Admin-Account)
|
|
4. E-Mail (SMTP-Konfiguration mit Verbindungstest, oder Log-Modus zum Ueberspringen)
|
|
5. Abschluss (Finalize, Demo-Daten, Lizenz)
|
|
|
|
- `InstallerMiddleware` prueft `storage/installed` Datei
|
|
- 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
|
|
1. User klickt "Passwort vergessen?" auf Login-Seite
|
|
2. ForgotPasswordController sendet Reset-Link via Laravel Password Broker
|
|
3. ResetPasswordNotification laedt Custom-Template aus `Setting::get('password_reset_email_{locale}')`
|
|
4. Platzhalter: `{name}`, `{link}`, `{app_name}`
|
|
5. 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 Erstellung
|
|
- `syncEditors()` synchronisiert nur tatsaechlich initialisierte Editoren
|
|
|
|
### Route-Struktur (Middleware)
|
|
- Installer: `throttle:10,1`, ohne SetLocaleMiddleware/ActiveUserMiddleware
|
|
- Oeffentlich: Login, Register, Legal-Pages, Locale-Switch
|
|
- User-Bereich: `auth` Middleware
|
|
- Admin-Bereich: `auth` + `admin` + `prefix('admin')`
|
|
- Staff-Routes (Admin + Coach): `staff` Middleware
|
|
- Admin-Only-Routes: `admin-only` Middleware (Settings, Locations, Support)
|
|
|
|
## Security
|
|
|
|
### Middleware-Stack
|
|
- CSP und Permissions-Policy via SecurityHeadersMiddleware (inkl. COOP-Header)
|
|
- `StaffMiddleware` — prueft Admin oder Coach Rolle
|
|
- `AdminOnlyMiddleware` — 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
|
|
1. Migration erstellen: `Setting::firstOrCreate(['key' => '...'], [...])`
|
|
2. In SettingsController `edit()` laden
|
|
3. In View rendern
|
|
4. In `update()` speichern (mit Sanitization fuer HTML)
|
|
|
|
### Neues locale-spezifisches Setting
|
|
1. Keys: `{setting_name}_{locale}` (z.B. `impressum_html_de`)
|
|
2. Migration fuer alle 6 Locales
|
|
3. In SettingsController `$localeSettings` Array aufnehmen
|
|
4. In View mit Sprach-Flaggen-Selector anzeigen
|
|
5. In `update()` mit Whitelist und `updateOrCreate()` behandeln
|
|
6. **Wichtig**: Neuen Key zur Whitelist in `SettingsController::update()` hinzufuegen ($allowedLocaleKeys)
|
|
|
|
### Neue Admin-Route hinzufuegen
|
|
1. Route in `routes/web.php` im passenden Middleware-Block:
|
|
- Alle Admin-Panel-Nutzer: direkt unter `admin` Prefix
|
|
- Staff (Admin + Coach): unter `staff` Middleware
|
|
- Nur Admin: unter `admin-only` Middleware
|
|
2. Controller-Methode mit Autorisierungs-Pruefung
|
|
3. View erstellen
|
|
4. Translation-Keys fuer alle 6 Sprachen
|