diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000..d4bc386
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,52 @@
+# AGENTS
+
+## Stack And Entry Points
+- This repo is a plain PHP app for Strato-style hosting. There is no Node, Composer, container, or build step.
+- Live web root is `httpdocs/`.
+- Main app entrypoint: `httpdocs/index.php`.
+- First-time setup entrypoint: `httpdocs/install.php`.
+- App wiring and request handling live in `httpdocs/app/bootstrap.php`.
+- All HTML/UI rendering lives in `httpdocs/app/views.php`.
+
+## Deployment Reality
+- Changes in this repo do nothing until the contents of `httpdocs/` are uploaded to the server.
+- If the user says “nothing changed”, verify whether the live site is serving the current workspace contents before changing logic again.
+- The live site can be checked directly at `http://arbeitsstunden.tc-ingelfingen.de`.
+
+## Runtime Behavior
+- The app supports two modes:
+ - With DB: MySQL/MariaDB via `DB_HOST`, `DB_NAME`, `DB_USER`, `DB_PASS`.
+ - Without DB: demo mode with in-code users from `findUserByEmail()` and in-code member/hour data from `fetchUsers()` / `fetchLogs()`.
+- `index.php` redirects to `install.php` only when a DB connection exists and no users are installed.
+- `install.php` only works with a DB connection; without DB it only shows an error.
+
+## Roles And UI Rules
+- Roles are `member`, `editor`, `admin`.
+- `member` should only see their own hours on the dashboard.
+- `editor` and `admin` should see their own hours plus all members in the dashboard table.
+- Admin-only menu item is `Vereinskonfiguration`.
+- Header should keep club name on the left and current user + logout on the right.
+- Navigation is implemented as a left sidebar inside `renderAppShell()`.
+
+## Persistence Gotchas
+- Club settings are persisted in DB table `settings` and read into `$config` in `bootstrap.php`.
+- If settings appear not to save, check DB mode first. In demo mode there is no DB persistence.
+- Schema is created in `initSchema()` at runtime. Keep `schema.sql` aligned with runtime-created tables.
+- `schema.sql` currently contains seed password hashes that may drift from runtime-generated demo passwords; trust runtime behavior in `bootstrap.php` over static SQL prose.
+
+## Session And Auth Gotchas
+- Session handling is configured manually in `bootstrap.php` with `session_set_cookie_params()` before `session_start()`.
+- Login redirects to `/?page=dashboard` after setting `$_SESSION['user']`.
+- If auth appears broken, inspect `currentUser()` and the session flow in `bootstrap.php` before changing UI conditionals.
+
+## Editing Guidance
+- Most app behavior changes require editing `httpdocs/app/views.php` and sometimes `httpdocs/app/bootstrap.php` together.
+- Prefer minimal inline changes over adding new abstractions; the app is intentionally small and file-local.
+- When changing page layout, update only `renderAppShell()` unless the login or install flow is involved.
+
+## Verification
+- There is no automated test suite in the repo.
+- Best available verification is:
+ - read the affected PHP files,
+ - check role-gated branches in `views.php` and action handling in `bootstrap.php`,
+ - optionally fetch the live URL to compare deployed output versus workspace output.
diff --git a/ANLEITUNG_ADMIN.md b/ANLEITUNG_ADMIN.md
new file mode 100644
index 0000000..9375e77
--- /dev/null
+++ b/ANLEITUNG_ADMIN.md
@@ -0,0 +1,153 @@
+# TC Ingelfingen
+
+## Arbeitsstundenverwaltung
+
+### Benutzeranleitung Für Administratoren
+
+Diese Anleitung beschreibt die wichtigsten Funktionen der Arbeitsstundenverwaltung aus Sicht eines Administrators.
+
+Administratoren verwalten die Anwendung, pflegen Vereinswerte und führen Sicherungs- und Wiederherstellungsaufgaben durch.
+
+## 1. Anmeldung
+
+Melden Sie sich mit Ihrer E-Mail-Adresse und Ihrem Passwort an.
+
+Falls Sie Ihr Passwort vergessen haben, können Sie den Passwort-Reset über die Anmeldeseite nutzen.
+
+## 2. Dashboard
+
+Als Administrator sehen Sie im Dashboard die Gesamtübersicht über alle Mitglieder.
+
+Angezeigt werden insbesondere:
+
+- Pflichtstunden gesamt
+- geleistete Stunden gesamt
+- noch offene Stunden gesamt
+- die jeweiligen Werte in EUR
+- der Fortschritt der geleisteten Arbeitsstunden in Prozent
+
+Zusätzlich wird ein Informationskasten angezeigt, sofern dieser vom Verein gepflegt wurde.
+
+## 3. Profil
+
+Über Ihren Namen oben rechts gelangen Sie in Ihr Profil.
+
+Dort können Sie:
+
+- Ihren Vornamen ändern
+- Ihren Nachnamen ändern
+- Ihr eigenes Passwort ändern
+
+## 4. Benutzerverwaltung
+
+Im Bereich `Benutzerverwaltung` können Sie:
+
+- neue Benutzer anlegen
+- Benutzer löschen
+- Benutzerpasswörter zurücksetzen
+- Benutzerrollen ändern
+
+Die Benutzerliste ist nach Nachnamen sortiert und auf 50 Einträge pro Seite paginiert.
+
+## 5. Stundenbuchung
+
+Im Bereich `Stundenbuchung` können Sie:
+
+- Stunden für Mitglieder buchen
+- alle Stundenbuchungen einsehen
+- einzelne Stundenbuchungen löschen
+
+Die Liste der Stundenbuchungen ist auf 50 Einträge pro Seite paginiert.
+
+## 6. Vereinskonfiguration
+
+Im Bereich `Vereinskonfiguration` können Sie:
+
+- Pflichtstunden pro Mitglied festlegen
+- den Wert pro Stunde festlegen
+- den Informationskasten im Dashboard pflegen
+- Benutzerdaten als CSV exportieren
+- Stundenbuchungen als CSV exportieren
+
+## 7. Administration
+
+Im Bereich `Administration` finden Sie erweiterte Verwaltungsfunktionen.
+
+Dazu gehören:
+
+- SQL-Dump herunterladen
+- SQL-Dump wiederherstellen
+- Benutzerdaten per CSV importieren
+- alle Arbeitsstunden auf 0 zurücksetzen
+- Logansicht aller Verwaltungsaktionen
+
+Die Logansicht ist auf 50 Einträge pro Seite paginiert.
+
+## 8. SQL-Backup Und Wiederherstellung
+
+Für vollständige Datensicherungen steht ein SQL-Dump zur Verfügung.
+
+Empfohlene Vorgehensweise:
+
+1. Laden Sie vor größeren Änderungen einen SQL-Dump herunter.
+2. Bewahren Sie die Datei an einem sicheren Ort auf.
+3. Verwenden Sie für eine Wiederherstellung ausschließlich vertrauenswürdige SQL-Dateien.
+
+Wichtiger Hinweis:
+
+- Die Wiederherstellung eines SQL-Dumps überschreibt die bestehenden App-Daten.
+
+## 9. CSV-Import
+
+Der CSV-Import dient zur Übernahme von Benutzerdaten.
+
+Erwartet werden folgende Spalten:
+
+- `firstname`
+- `lastname`
+- `email`
+- `role`
+- `hours_worked`
+
+Benutzer werden anhand der E-Mail-Adresse erkannt.
+
+## 10. Arbeitsstunden Zurücksetzen
+
+Mit dieser Funktion werden alle gebuchten Arbeitsstunden aller Mitglieder auf 0 gesetzt.
+
+Diese Funktion ist insbesondere für den Jahreswechsel vorgesehen und sollte nur mit entsprechender Sorgfalt verwendet werden.
+
+## 11. Logansicht
+
+In der Logansicht werden unter anderem folgende Aktionen protokolliert:
+
+- Benutzer anlegen
+- Benutzer löschen
+- Rollen ändern
+- Passwort zurücksetzen
+- eigenes Passwort ändern
+- Passwort per Reset-Link neu setzen
+- Speichern von Vereinswerten
+- CSV-Exporte
+- CSV-Import
+- Arbeitsstunden auf 0 setzen
+- SQL-Dump exportieren und wiederherstellen
+
+## 12. Passwort Vergessen
+
+Falls Sie Ihr Passwort vergessen haben, können Sie den Reset-Link über die Anmeldeseite anfordern und anschließend ein neues Passwort vergeben.
+
+## 13. Darkmode
+
+Über den Schalter links neben `Abmelden` kann zwischen hellem und dunklem Farbschema gewechselt werden.
+
+## 14. Abmelden
+
+Bitte melden Sie sich nach Abschluss Ihrer Arbeiten stets über `Abmelden` ab.
+
+## 15. Empfehlungen Für Den Betrieb
+
+- Erstellen Sie regelmäßig SQL-Backups.
+- Nutzen Sie CSV-Exporte für Auswertungen und Weitergaben.
+- Prüfen Sie Importe vor der Ausführung sorgfältig.
+- Dokumentieren Sie größere organisatorische oder technische Änderungen zusätzlich außerhalb der Anwendung.
diff --git a/ANLEITUNG_BEARBEITER.md b/ANLEITUNG_BEARBEITER.md
new file mode 100644
index 0000000..1732ffc
--- /dev/null
+++ b/ANLEITUNG_BEARBEITER.md
@@ -0,0 +1,146 @@
+# TC Ingelfingen
+
+## Arbeitsstundenverwaltung
+
+### Benutzeranleitung Für Bearbeiter
+
+Diese Anleitung beschreibt die wichtigsten Funktionen der Arbeitsstundenverwaltung aus Sicht eines Bearbeiters.
+
+Bearbeiter unterstützen den Verein insbesondere bei der Erfassung von Arbeitsstunden und bei der Pflege von Benutzerdaten.
+
+## 1. Anmeldung
+
+Rufen Sie die Arbeitsstundenverwaltung über den Vereinslink auf und melden Sie sich mit Ihrer E-Mail-Adresse und Ihrem Passwort an.
+
+Falls Sie Ihr Passwort vergessen haben, können Sie über `Passwort vergessen?` auf der Anmeldeseite einen Reset-Link anfordern.
+
+## 2. Dashboard
+
+Nach der Anmeldung gelangen Sie auf das Dashboard.
+
+Als Bearbeiter sehen Sie dort nicht nur persönliche Daten, sondern die Gesamtübersicht über alle Mitglieder.
+
+Angezeigt werden insbesondere:
+
+- Pflichtstunden gesamt
+- geleistete Stunden gesamt
+- noch offene Stunden gesamt
+- die jeweiligen Werte in EUR
+
+Zusätzlich wird ein Fortschrittsbalken angezeigt, der die geleisteten Arbeitsstunden in Prozent darstellt.
+
+Falls vom Verein gepflegt, erscheint außerdem ein Informationskasten mit aktuellen Mitteilungen.
+
+## 3. Profil
+
+Über Ihren Namen oben rechts gelangen Sie in den Bereich `Profil`.
+
+Dort können Sie:
+
+- Ihren Vornamen ändern
+- Ihren Nachnamen ändern
+- Ihr Passwort ändern
+
+Die hinterlegte E-Mail-Adresse wird angezeigt, kann jedoch nicht geändert werden.
+
+## 4. Benutzerverwaltung
+
+Über den Menüpunkt `Benutzerverwaltung` können Sie Benutzer verwalten.
+
+Zu Ihren Aufgaben gehören dort insbesondere:
+
+- neue Benutzer anlegen
+- die Benutzerliste einsehen
+- Passwörter von Benutzern zurücksetzen
+- Benutzer löschen
+
+Die Benutzerliste ist nach Nachnamen sortiert und in Seiten mit jeweils 50 Einträgen gegliedert.
+
+Hinweis:
+
+- Das Ändern von Rollen ist ausschließlich Administratoren vorbehalten.
+
+## 5. Stundenbuchung
+
+Über den Menüpunkt `Stundenbuchung` können Sie Arbeitsstunden für Mitglieder erfassen.
+
+Für jede Buchung werden erfasst:
+
+- der Benutzer
+- die Anzahl der Stunden
+- eine kurze Notiz
+
+Unterhalb des Formulars sehen Sie die vollständige Liste der Stundenbuchungen.
+
+Dort werden angezeigt:
+
+- Datum
+- Mitglied
+- gebucht von
+- Stunden
+- Notiz
+
+Die Liste ist in Seiten mit jeweils 50 Einträgen aufgeteilt.
+
+Hinweis:
+
+- Das Löschen von Stundenbuchungen ist ausschließlich Administratoren möglich.
+
+## 6. Vereinskonfiguration
+
+Als Bearbeiter haben Sie Zugriff auf den Bereich `Vereinskonfiguration`.
+
+Dort können Sie:
+
+- die Pflichtstunden pro Mitglied anpassen
+- den Wert pro Stunde festlegen
+- den Informationskasten für das Dashboard pflegen
+- Benutzerdaten als CSV exportieren
+- Stundenbuchungen als CSV exportieren
+
+Der Informationskasten im Dashboard unterstützt eine einfache Markdown-Formatierung, zum Beispiel:
+
+- Absätze
+- Listen mit `- `
+- `*kursiv*`
+- `**fett**`
+
+## 7. Nicht Verfügbare Funktionen Für Bearbeiter
+
+Der Bereich `Administration` ist nur für Administratoren vorgesehen.
+
+Dort befinden sich Funktionen wie:
+
+- SQL-Datensicherung
+- SQL-Wiederherstellung
+- CSV-Import
+- Zurücksetzen aller Arbeitsstunden auf 0
+- Logansicht der Verwaltungsaktionen
+
+## 8. Passwort Vergessen
+
+Wenn Sie Ihr Passwort vergessen haben, gehen Sie bitte wie folgt vor:
+
+1. Klicken Sie auf `Passwort vergessen?`
+2. Geben Sie Ihre E-Mail-Adresse ein
+3. Fordern Sie den Reset-Link an
+4. Öffnen Sie die E-Mail des Systems
+5. Vergeben Sie ein neues Passwort
+6. Melden Sie sich anschließend erneut an
+
+## 9. Darkmode
+
+Über den Schalter links neben `Abmelden` können Sie zwischen hellem und dunklem Farbschema wechseln.
+
+Die Auswahl wird im Browser gespeichert.
+
+## 10. Abmelden
+
+Bitte melden Sie sich nach Abschluss Ihrer Arbeiten über den Button `Abmelden` oben rechts ordnungsgemäß ab.
+
+## 11. Hinweise Für Die Praxis
+
+- Achten Sie bei der Stundenbuchung auf nachvollziehbare und kurze Notizen.
+- Prüfen Sie neue Benutzer sorgfältig auf korrekte Schreibweise von Namen und E-Mail-Adressen.
+- Nutzen Sie die Exportfunktionen regelmäßig für Auswertungen oder organisatorische Weitergaben.
+- Informieren Sie die Vereinsadministration bei Unklarheiten oder bei größeren Änderungen.
diff --git a/ANLEITUNG_MITGLIEDER.md b/ANLEITUNG_MITGLIEDER.md
new file mode 100644
index 0000000..abc2e6a
--- /dev/null
+++ b/ANLEITUNG_MITGLIEDER.md
@@ -0,0 +1,85 @@
+# TC Ingelfingen
+
+## Arbeitsstundenverwaltung
+
+### Benutzeranleitung Für Mitglieder
+
+Diese Anleitung dient als kurze Einführung in die Nutzung der Arbeitsstundenverwaltung für Mitglieder.
+
+## 1. Anmeldung
+
+Rufen Sie die Arbeitsstundenverwaltung über den vom Verein bereitgestellten Link auf.
+
+Für die Anmeldung benötigen Sie:
+
+- Ihre hinterlegte E-Mail-Adresse
+- Ihr persönliches Passwort
+
+Geben Sie beide Angaben auf der Anmeldeseite ein und klicken Sie anschließend auf `Anmelden`.
+
+## 2. Dashboard
+
+Nach der Anmeldung gelangen Sie direkt auf Ihr persönliches Dashboard.
+
+Dort erhalten Sie einen Überblick über:
+
+- Ihre Pflichtstunden
+- Ihre bereits geleisteten Arbeitsstunden
+- Ihre noch offenen Arbeitsstunden
+- den rechnerischen Geldwert der noch offenen Stunden
+
+Zusätzlich kann auf dem Dashboard ein Informationskasten des Vereins angezeigt werden. In diesem Bereich veröffentlicht der Verein wichtige Hinweise, organisatorische Informationen oder aktuelle Mitteilungen.
+
+## 3. Stundenbuchungen Einsehen
+
+Über den Menüpunkt `Stundenbuchung` können Sie Ihre eigenen gebuchten Arbeitsstunden einsehen.
+
+In der Übersicht werden unter anderem folgende Informationen angezeigt:
+
+- Datum der Buchung
+- Anzahl der gebuchten Stunden
+- Notiz zur Buchung
+- Person, die die Buchung eingetragen hat
+
+Als Mitglied sehen Sie ausschließlich Ihre eigenen Stundenbuchungen.
+
+## 4. Persönliche Daten Und Passwort
+
+Oben rechts in der Kopfzeile finden Sie Ihren Namen. Über diesen Button gelangen Sie in den Bereich `Profil`.
+
+Dort können Sie:
+
+- Ihren Vornamen ändern
+- Ihren Nachnamen ändern
+- Ihr Passwort ändern
+
+Ihre E-Mail-Adresse wird dort ebenfalls angezeigt, kann jedoch nicht geändert werden.
+
+## 5. Passwort Vergessen
+
+Wenn Sie Ihr Passwort nicht mehr kennen, nutzen Sie auf der Anmeldeseite den Link `Passwort vergessen?`.
+
+Gehen Sie dabei bitte wie folgt vor:
+
+1. Klicken Sie auf `Passwort vergessen?`
+2. Geben Sie Ihre E-Mail-Adresse ein
+3. Fordern Sie den Reset-Link an
+4. Öffnen Sie die E-Mail des Systems
+5. Vergeben Sie über den enthaltenen Link ein neues Passwort
+6. Melden Sie sich anschließend mit dem neuen Passwort erneut an
+
+## 6. Darkmode
+
+Links neben dem Button `Abmelden` befindet sich ein Schalter für den Darkmode.
+
+Damit können Sie zwischen einer hellen und einer dunklen Darstellung der Anwendung wechseln. Die gewählte Einstellung wird auf Ihrem Gerät gespeichert.
+
+## 7. Abmelden
+
+Wenn Sie Ihre Arbeit beendet haben, melden Sie sich bitte über den Button `Abmelden` oben rechts wieder ab.
+
+Dadurch wird Ihre Sitzung sicher beendet.
+
+## 8. Unterstützung
+
+Falls Ihnen Daten fehlen, Stunden nicht korrekt angezeigt werden oder Sie keinen Zugriff auf Ihr Konto haben, wenden Sie sich bitte an einen Bearbeiter oder an die Vereinsadministration.
diff --git a/README.md b/README.md
index aa05641..0fc9fca 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,7 @@ Strato-taugliche PHP-Webanwendung für die Arbeitszeiterfassung des TC Ingelfing
- Audit-Log für Verwaltungsaktionen wie Benutzer anlegen, löschen, Rollen ändern und Passwortaktionen
- CSV-Export und CSV-Import für Benutzerdaten inklusive geleisteter Stunden
- Separater CSV-Export für alle Stundenbuchungen
+- SQL-Dump-Export und SQL-Dump-Wiederherstellung für vollständige App-Backups
- Admin-Funktion zum Zurücksetzen aller Arbeitsstunden auf 0
- Tabler CSS via CDN für UI, Cards, Tabellen und Formulare
@@ -79,6 +80,8 @@ Die Anwendung ist so aufgebaut, dass sie mit oder ohne DB läuft. Bei gesetzter
- Informationskasten für das Dashboard pflegen
- Benutzerdaten als CSV exportieren
- Alle Stundenbuchungen als CSV exportieren
+ - SQL-Dump für vollständige Datensicherung herunterladen
+ - SQL-Dump zur Wiederherstellung hochladen
- Benutzerdaten aus CSV importieren
- Alle Arbeitsstunden auf 0 zurücksetzen
- Logansicht mit 50 Einträgen pro Seite
@@ -115,6 +118,24 @@ Beispiel-Kopfzeile:
`firstname,lastname,email,role,hours_worked`
+## Backup Und Wiederherstellung
+
+Zusätzlich zu den CSV-Exporten gibt es in der Vereinskonfiguration einen SQL-Dump für vollständige Backups der App-Datenbank.
+
+Enthalten sind die App-Tabellen:
+
+- `users`
+- `work_logs`
+- `settings`
+- `audit_logs`
+- `password_resets`
+
+Hinweise:
+
+- Der SQL-Dump ist für vollständige Sicherungen und Wiederherstellung gedacht.
+- Die SQL-Wiederherstellung überschreibt die bestehenden App-Daten.
+- CSV-Exporte bleiben zusätzlich für Auswertungen und Teilimporte erhalten.
+
## Passwort-Reset Und Konfiguration
Für den Passwort-Reset per E-Mail wird eine `config.php` im Projektwurzelverzeichnis verwendet. Eine Vorlage liegt als `config.php.example` vor.
@@ -147,6 +168,14 @@ Hinweis:
Wenn noch kein Benutzer vorhanden ist, leite `index.php` automatisch auf `install.php` weiter. Dort kannst du ein erstes Admin-Konto anlegen.
+## Handouts
+
+Für die Weitergabe an Anwender stehen folgende Anleitungen bereit:
+
+- `ANLEITUNG_MITGLIEDER.md`
+- `ANLEITUNG_BEARBEITER.md`
+- `ANLEITUNG_ADMIN.md`
+
## Dateien
- `httpdocs/index.php` Einstieg
@@ -154,3 +183,6 @@ Wenn noch kein Benutzer vorhanden ist, leite `index.php` automatisch auf `instal
- `httpdocs/app/bootstrap.php` DB, Login und Business-Logik
- `httpdocs/app/views.php` Tabler-UI
- `config.php.example` Vorlage für DB- und Mail-Konfiguration
+- `ANLEITUNG_MITGLIEDER.md` Handout für Mitglieder
+- `ANLEITUNG_BEARBEITER.md` Handout für Bearbeiter
+- `ANLEITUNG_ADMIN.md` Handout für Administratoren
diff --git a/config.php b/config.php
new file mode 100644
index 0000000..a2a1a1a
--- /dev/null
+++ b/config.php
@@ -0,0 +1,17 @@
+ 'OpenCode',
+ 'copyright' => 'Copyright 2026 TC-Ingelfingen',
+ 'app_version' => '1.0.0',
+ 'db' => [
+ 'host' => 'database-5020507124.webspace-host.com',
+ 'name' => 'dbs15701183',
+ 'user' => 'dbu747436',
+ 'pass' => 'KuTq0PHto5izfQ',
+ ],
+ 'smtp' => [
+ 'from_email' => 'webmaster@tc-ingelfingen.de',
+ 'from_name' => 'TC-Ingelfingen',
+ ],
+];
diff --git a/config.php.old b/config.php.old
new file mode 100644
index 0000000..07cf3cd
--- /dev/null
+++ b/config.php.old
@@ -0,0 +1,13 @@
+ [
+ 'host' => 'database-5020507124.webspace-host.com',
+ 'name' => 'dbs15701183',
+ 'user' => 'dbu747436',
+ 'pass' => 'KuTq0PHto5izfQ',
+ ],
+ 'hours_target' => 12,
+ 'hourly_rate_eur' => 10,
+];
diff --git a/httpdocs/app/bootstrap.php b/httpdocs/app/bootstrap.php
new file mode 100644
index 0000000..7043068
--- /dev/null
+++ b/httpdocs/app/bootstrap.php
@@ -0,0 +1,909 @@
+ 0,
+ 'path' => '/',
+ 'secure' => !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off',
+ 'httponly' => true,
+ 'samesite' => 'Lax',
+ ]);
+}
+
+session_start();
+
+$localConfig = [];
+$localConfigFile = dirname(__DIR__, 2) . '/config.php';
+if (is_file($localConfigFile)) {
+ $loaded = require $localConfigFile;
+ if (is_array($loaded)) {
+ $localConfig = $loaded;
+ }
+}
+
+$config = [
+ 'app_name' => 'TC Ingelfingen Arbeitszeiterfassung',
+ 'app_version' => (string)($localConfig['app_version'] ?? '1.0.0'),
+ 'author' => (string)($localConfig['author'] ?? 'OpenCode'),
+ 'copyright' => (string)($localConfig['copyright'] ?? 'Copyright 2026 TC-Ingelfingen'),
+ 'hours_target' => (int)($localConfig['hours_target'] ?? (getenv('HOURS_TARGET') ?: 12)),
+ 'hourly_rate_eur' => (float)($localConfig['hourly_rate_eur'] ?? (getenv('HOURLY_RATE_EUR') ?: 10)),
+ 'dashboard_info' => (string)($localConfig['dashboard_info'] ?? ''),
+];
+
+$smtpConfig = [
+ 'host' => (string)($localConfig['smtp']['host'] ?? ''),
+ 'port' => (int)($localConfig['smtp']['port'] ?? 587),
+ 'username' => (string)($localConfig['smtp']['username'] ?? ''),
+ 'password' => (string)($localConfig['smtp']['password'] ?? ''),
+ 'encryption' => (string)($localConfig['smtp']['encryption'] ?? 'tls'),
+ 'from_email' => (string)($localConfig['smtp']['from_email'] ?? ''),
+ 'from_name' => (string)($localConfig['smtp']['from_name'] ?? $config['app_name']),
+];
+
+$dbConfig = [
+ 'host' => (string)($localConfig['db']['host'] ?? (getenv('DB_HOST') ?: '')),
+ 'name' => (string)($localConfig['db']['name'] ?? (getenv('DB_NAME') ?: '')),
+ 'user' => (string)($localConfig['db']['user'] ?? (getenv('DB_USER') ?: '')),
+ 'pass' => (string)($localConfig['db']['pass'] ?? (getenv('DB_PASS') ?: '')),
+];
+
+$pdo = null;
+if ($dbConfig['host'] !== '' && $dbConfig['name'] !== '' && $dbConfig['user'] !== '') {
+ try {
+ $dsn = sprintf('mysql:host=%s;dbname=%s;charset=utf8mb4', $dbConfig['host'], $dbConfig['name']);
+ $pdo = new PDO($dsn, $dbConfig['user'], $dbConfig['pass'], [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]);
+ } catch (Throwable $e) {
+ $pdo = null;
+ }
+}
+
+function money(float $value): string
+{
+ return number_format($value, 2, ',', '.') . ' EUR';
+}
+
+function formatDateTime(string $value): string
+{
+ $timestamp = strtotime($value);
+ if ($timestamp === false) {
+ return $value;
+ }
+ return date('d.m.Y H:i', $timestamp);
+}
+
+function renderSimpleMarkdown(string $text): string
+{
+ $escaped = htmlspecialchars(trim($text), ENT_QUOTES, 'UTF-8');
+ if ($escaped === '') {
+ return '';
+ }
+
+ $escaped = preg_replace('/\*\*(.+?)\*\*/s', '$1', $escaped);
+ $escaped = preg_replace('/\*(.+?)\*/s', '$1', $escaped);
+ $blocks = preg_split('/\R{2,}/', $escaped) ?: [];
+ $html = [];
+ foreach ($blocks as $block) {
+ $block = trim($block);
+ if ($block === '') {
+ continue;
+ }
+ if (preg_match('/^(?:- .*(?:\R|$))+$/', $block)) {
+ $items = preg_split('/\R/', $block) ?: [];
+ $listItems = [];
+ foreach ($items as $item) {
+ $item = trim($item);
+ if (str_starts_with($item, '- ')) {
+ $listItems[] = '
\n*** End Patch"
+}
+```
+
+**Output:**
+```
+Success. Updated the following files:
+M Users/erik/Documents/DEV/arbeitsstunden/httpdocs/app/views.php
+```
+
+---
+
+## Assistant (Build · GPT-5.4 · 9.3s)
+
+Erledigt.
+
+Im Dashboard wurde der Progress-Bereich angepasst:
+- Text darunter jetzt:
+ - `Geleistete Arbeitsstunden in %.`
+- Im Balken selbst wird jetzt der Prozentwert angezeigt
+
+Geändert in:
+- `httpdocs/app/views.php`
+
+---
+
+## User
+
+den %-Wert Oberhalb vom Balken rechts auch mit so einem ZickZack Pfeil Icon
+
+---
+
+## Assistant (Build · GPT-5.4 · 16.9s)
+
+Ich ergänze den Prozentwert oberhalb des Balkens rechts mit einem kleinen Trend-/Zickzack-Icon und lasse die Anzeige im Balken bestehen.
+
+**Tool: apply_patch**
+
+**Input:**
+```json
+{
+ "patchText": "*** Begin Patch\n*** Update File: /Users/erik/Documents/DEV/arbeitsstunden/httpdocs/app/views.php\n@@\n-
\n*** End Patch"
+}
+```
+
+**Output:**
+```
+Success. Updated the following files:
+M Users/erik/Documents/DEV/arbeitsstunden/httpdocs/app/views.php
+```
+
+---
+
+## Assistant (Build · GPT-5.4 · 11.3s)
+
+Die Liste der Stundenbuchungen hat jetzt ebenfalls Paginierung mit 50 Einträgen pro Seite.
+
+Geändert:
+- `httpdocs/app/bootstrap.php`
+- `httpdocs/app/views.php`
+
+Neu:
+- paginierte Buchungsabfrage über `fetchBookingsPage(...)`
+- funktioniert rollenabhängig weiter korrekt:
+ - `member`: nur eigene Buchungen
+ - `editor` / `admin`: alle Buchungen
+- `Zurück` / `Weiter`
+- Anzeige von:
+ - aktueller Seite
+ - Gesamtseiten
+ - Gesamtanzahl der Einträge
+
+Aufruf:
+- `/?page=booking`
+- weitere Seiten: `/?page=booking&booking_page=2`
+
+Wichtig:
+- Das Buchungsformular oben bleibt unverändert
+- Nur die Liste darunter ist jetzt paginiert
+
+---
+
+## User
+
+bitte die readme anpassen
+
+---
+
+## Assistant (Build · GPT-5.4 · 6.7s)
+
+Ich lese die aktuelle README kurz ein und ergänze die neuen Punkte zu Passwort-Reset, Audit-Logs und den drei Paginierungen.
+
+**Tool: read**
+
+**Input:**
+```json
+{
+ "filePath": "/Users/erik/Documents/DEV/arbeitsstunden/README.md",
+ "offset": 1,
+ "limit": 260
+}
+```
+
+**Output:**
+```
+/Users/erik/Documents/DEV/arbeitsstunden/README.md
+file
+
+1: # TC Ingelfingen Arbeitszeiterfassung
+2:
+3: Strato-taugliche PHP-Webanwendung für die Arbeitszeiterfassung des TC Ingelfingen.
+4:
+5: ## Eigenschaften
+6:
+7: - Läuft direkt aus `httpdocs` ohne Shell, Node oder Container
+8: - Optional an externe MySQL/MariaDB-Datenbank anbindbar
+9: - Mitglieder-Login mit Rollenmodell
+10: - Mitglieder sehen Stundenstand, Reststunden und möglichen EUR-Abzug
+11: - Bearbeiter buchen Stunden und legen Mitglieder an
+12: - Admins können alles, inklusive Mitglieder anlegen, Rollen vergeben und Logs ansehen
+13: - Eigene Profilseite für Vorname, Nachname und Passwortänderung
+14: - Passwort-Reset über E-Mail-Link auf der Anmeldeseite
+15: - Darkmode-Schalter in der Kopfzeile mit lokaler Speicherung
+16: - Dashboard-Infokasten für alle Mitglieder, pflegbar durch Admins mit einfacher Markdown-Unterstützung
+17: - Aggregierte Dashboard-Übersicht für Bearbeiter und Admins über alle Mitglieder
+18: - Stundenbuchungen mit Rollenansicht: Mitglieder nur eigene, Bearbeiter und Admins alle
+19: - Admins können einzelne Stundenbuchungen löschen
+20: - CSV-Export und CSV-Import für Benutzerdaten inklusive geleisteter Stunden
+21: - Separater CSV-Export für alle Stundenbuchungen
+22: - Admin-Funktion zum Zurücksetzen aller Arbeitsstunden auf 0
+23: - Tabler CSS via CDN für UI, Cards, Tabellen und Formulare
+24:
+25: ## Strato-Setup
+26:
+27: 1. Inhalt von `httpdocs/` auf das Strato-Webverzeichnis hochladen
+28: 2. Optional diese Umgebungsvariablen oder Konfigurationswerte setzen:
+29: - `DB_HOST`
+30: - `DB_NAME`
+31: - `DB_USER`
+32: - `DB_PASS`
+33: - `SETUP_KEY` optional, schützt die Ersteinrichtung
+34: 3. PHP 8.1+ und `pdo_mysql` aktivieren
+35:
+36: ## Strato Schritte
+37:
+38: 1. DB in Strato anlegen
+39: 2. `DB_HOST`, `DB_NAME`, `DB_USER`, `DB_PASS` setzen
+40: 3. `httpdocs/install.php` öffnen und erstes Admin-Konto anlegen
+41: 4. Danach mit dem neuen Admin einloggen
+42: 5. Falls keine DB konfiguriert ist, nutzt die App Demo-Zugänge nur zum Anzeigen
+43:
+44: ## Datenbank
+45:
+46: Die Anwendung ist so aufgebaut, dass sie mit oder ohne DB läuft. Bei gesetzter DB werden Tabellen automatisch angelegt, sonst werden Demo-Daten genutzt.
+47:
+48: - Mitglieder
+49: - Benutzer/Rollen
+50: - Arbeitsstunden
+51: - Audit-Log
+52: - Einstellungen
+53:
+54: ## Rollen
+55:
+56: - `member`: sieht das eigene Dashboard, die eigene Profilseite und die eigenen Stundenbuchungen
+57: - `editor`: darf Stunden buchen, Mitglieder anlegen und alle Stundenbuchungen sehen
+58: - `admin`: darf alles, inklusive Mitglieder anlegen, Rollen vergeben, CSV-Import/Export und globalem Stunden-Reset
+59:
+60: ## Funktionen
+61:
+62: - Profil
+63: - Jeder Benutzer kann Vorname, Nachname und das eigene Passwort ändern
+64: - Die E-Mail-Adresse wird im Profil angezeigt, ist aber nicht editierbar
+65: - Für vergessene Passwörter gibt es einen Reset-Link per E-Mail
+66: - Dashboard
+67: - `member` sieht die eigenen Pflichtstunden, geleisteten Stunden und offenen Stunden
+68: - `editor` und `admin` sehen aggregierte Gesamtwerte aller Mitglieder inklusive EUR-Werten
+69: - Ein zusätzlicher Informationskasten kann durch Admins gepflegt werden
+70: - Stundenbuchungen
+71: - `member` sieht nur eigene Buchungen
+72: - `editor` und `admin` sehen alle Buchungen
+73: - `admin` kann einzelne Buchungen löschen
+74: - Vereinskonfiguration
+75: - Pflichtstunden und Stundenwert pflegen
+76: - Informationskasten für das Dashboard pflegen
+77: - Benutzerdaten als CSV exportieren
+78: - Alle Stundenbuchungen als CSV exportieren
+79: - Benutzerdaten aus CSV importieren
+80: - Alle Arbeitsstunden auf 0 zurücksetzen
+81:
+82: ## Markdown Im Informationskasten
+83:
+84: Der Informationskasten im Dashboard unterstützt eine einfache Markdown-Teilmenge:
+85:
+86: - Absätze
+87: - Listen mit `- `
+88: - `*kursiv*`
+89: - `**fett**`
+90:
+91: ## CSV-Format
+92:
+93: Der CSV-Export und CSV-Import für Benutzerdaten verwenden diese Spalten:
+94:
+95: - `firstname`
+96: - `lastname`
+97: - `email`
+98: - `role`
+99: - `hours_worked`
+100:
+101: Beispiel-Kopfzeile:
+102:
+103: `firstname,lastname,email,role,hours_worked`
+104:
+105: ## Passwort-Reset Und Konfiguration
+106:
+107: Für den Passwort-Reset per E-Mail wird eine `config.php` im Projektwurzelverzeichnis verwendet. Eine Vorlage liegt als `config.php.example` vor.
+108:
+109: Mindestens sinnvoll ist ein Absender für E-Mails:
+110:
+111: ```php
+112: [
+115: 'host' => '127.0.0.1',
+116: 'name' => 'arbeitsstunden',
+117: 'user' => 'dbuser',
+118: 'pass' => 'dbpass',
+119: ],
+120: 'smtp' => [
+121: 'from_email' => 'noreply@example.de',
+122: 'from_name' => 'TC Ingelfingen',
+123: ],
+124: ];
+125: ```
+126:
+127: Hinweis:
+128:
+129: - Die aktuelle Implementierung nutzt PHP `mail()` fuer den Versand.
+130: - Wenn das Hosting E-Mails direkt versenden kann, funktioniert der Passwort-Reset auch ohne vollstaendige SMTP-Implementierung.
+131: - Die Datei `config.php` sollte nicht in `httpdocs/`, sondern im Projektwurzelverzeichnis liegen.
+132:
+133: ## Ersteinrichtung
+134:
+135: Wenn noch kein Benutzer vorhanden ist, leite `index.php` automatisch auf `install.php` weiter. Dort kannst du ein erstes Admin-Konto anlegen.
+136:
+137: ## Dateien
+138:
+139: - `httpdocs/index.php` Einstieg
+140: - `httpdocs/install.php` Ersteinrichtung
+141: - `httpdocs/app/bootstrap.php` DB, Login und Business-Logik
+142: - `httpdocs/app/views.php` Tabler-UI
+143: - `config.php.example` Vorlage für DB- und Mail-Konfiguration
+
+(End of file - total 143 lines)
+
+```
+
+---
+
+## Assistant (Build · GPT-5.4 · 21.8s)
+
+Ich ergänze README jetzt um Audit-Logs und die neuen Paginierungen in Log-, Benutzer- und Buchungslisten.
+
+**Tool: apply_patch**
+
+**Input:**
+```json
+{
+ "patchText": "*** Begin Patch\n*** Update File: /Users/erik/Documents/DEV/arbeitsstunden/README.md\n@@\n - Aggregierte Dashboard-Übersicht für Bearbeiter und Admins über alle Mitglieder\n - Stundenbuchungen mit Rollenansicht: Mitglieder nur eigene, Bearbeiter und Admins alle\n - Admins können einzelne Stundenbuchungen löschen\n+- Paginierung mit 50 Einträgen pro Seite in Benutzerliste, Stundenbuchungen und Logansicht\n+- Audit-Log für Verwaltungsaktionen wie Benutzer anlegen, löschen, Rollen ändern und Passwortaktionen\n - CSV-Export und CSV-Import für Benutzerdaten inklusive geleisteter Stunden\n - Separater CSV-Export für alle Stundenbuchungen\n@@\n - Stundenbuchungen\n - `member` sieht nur eigene Buchungen\n - `editor` und `admin` sehen alle Buchungen\n - `admin` kann einzelne Buchungen löschen\n+ - Die Liste ist auf 50 Einträge pro Seite paginiert\n - Vereinskonfiguration\n - Pflichtstunden und Stundenwert pflegen\n - Informationskasten für das Dashboard pflegen\n - Benutzerdaten als CSV exportieren\n - Alle Stundenbuchungen als CSV exportieren\n - Benutzerdaten aus CSV importieren\n - Alle Arbeitsstunden auf 0 zurücksetzen\n+ - Logansicht mit 50 Einträgen pro Seite\n+ - Audit-Log für Verwaltungsaktionen\n+\n+## Listen Und Paginierung\n+\n+Die folgenden Bereiche nutzen eine Paginierung mit 50 Einträgen pro Seite:\n+\n+- Benutzerliste in der Benutzerverwaltung\n+- Stundenbuchungen\n+- Logansicht in der Vereinskonfiguration\n*** End Patch"
+}
+```
+
+**Output:**
+```
+Success. Updated the following files:
+M Users/erik/Documents/DEV/arbeitsstunden/README.md
+```
+
+---
+
+## Assistant (Build · GPT-5.4 · 11.3s)
+
+Die README ist angepasst.
+
+Neu dokumentiert:
+- Paginierung mit 50 Einträgen pro Seite
+- Audit-Log für Verwaltungsaktionen
+- Paginierung in:
+ - Benutzerliste
+ - Stundenbuchungen
+ - Logansicht
+
+Geändert in:
+- `README.md`
+
+---
+
+## User
+
+in der Benutzerliste der Benutzerverwaltung kann der Text eigener Benuter beim eigenen Benutzer entfallen
+
+---
+
+## Assistant (Build · GPT-5.4 · 76.4s)
+
+Ich entferne den Hinweis `Eigener Benutzer` aus der Benutzerliste und lasse für den eigenen Benutzer an dieser Stelle einfach keine Zusatzanzeige stehen.
+
+**Tool: apply_patch**
+
+**Input:**
+```json
+{
+ "patchText": "*** Begin Patch\n*** Update File: /Users/erik/Documents/DEV/arbeitsstunden/httpdocs/app/views.php\n@@\n-
\n*** End Patch"
+}
+```
+
+**Output:**
+```
+Success. Updated the following files:
+M Users/erik/Documents/DEV/arbeitsstunden/httpdocs/app/views.php
+```
+
+---
+
+## Assistant (Build · GPT-5.4 · 7.8s)
+
+Erledigt.
+
+In der Benutzerliste der Benutzerverwaltung entfällt jetzt beim eigenen Benutzer der Text:
+- `Eigener Benutzer`
+
+Geändert in:
+- `httpdocs/app/views.php`
+
+Verhalten jetzt:
+- Beim eigenen Benutzer bleibt das Rollenfeld deaktiviert
+- Es wird dort aber kein zusätzlicher Hinweistext mehr angezeigt
+
+---
+
+## User
+
+die Export Funktionen in der Verreinskonfiguration in eine extra Box Exporte nehmen
+
+---
+
+## Assistant (Build · GPT-5.4 · 9.1s)
+
+Ich trenne jetzt die Exportfunktionen in der Vereinskonfiguration in eine eigene Karte `Exporte` aus, ohne die restlichen Bereiche umzubauen.
+
+**Tool: read**
+
+**Input:**
+```json
+{
+ "filePath": "/Users/erik/Documents/DEV/arbeitsstunden/httpdocs/app/views.php",
+ "offset": 636,
+ "limit": 18
+}
+```
+
+**Output:**
+```
+/Users/erik/Documents/DEV/arbeitsstunden/httpdocs/app/views.php
+file
+
+636:
+637:
+638:
Vereinswerte
Unterstützt Absätze, - Listen, *kursiv* und **fett**.
CSV-Export Benutzer
Exportiert die Benutzerdaten inklusive geleisteter Stunden als CSV-Datei.
CSV-Export Stundenbuchungen
Exportiert alle Stundenbuchungen aller Mitglieder als CSV-Datei.
Setzt alle gebuchten Arbeitsstunden für alle Mitglieder auf 0. Diese Aktion ist für den Jahreswechsel gedacht.
\n*** End Patch"
+}
+```
+
+**Output:**
+```
+Success. Updated the following files:
+M Users/erik/Documents/DEV/arbeitsstunden/httpdocs/app/views.php
+```
+
+---
+
+## Assistant (Build · GPT-5.4 · 7.9s)
+
+Erledigt.
+
+In der `Vereinskonfiguration` sind die Exportfunktionen jetzt in einer eigenen Box:
+- `Exporte`
+
+Dort liegen jetzt:
+- `Benutzerdaten als CSV exportieren`
+- `Stundenbuchungen als CSV exportieren`
+
+Die übrigen Bereiche sind getrennt:
+- `Vereinswerte`
+- `CSV-Import`
+- `Arbeitsstunden zurücksetzen`
+
+Geändert in:
+- `httpdocs/app/views.php`
+
+---
+
+## User
+
+für den Informationskasten im Dashboard in der VEreinskonfiguration auch einen eigene Box
+
+---
+
+## Assistant (Build · GPT-5.4 · 7.6s)
+
+Ich trenne jetzt auch den Dashboard-Informationskasten in der Vereinskonfiguration in eine eigene Box vom Block `Vereinswerte`.
+
+**Tool: read**
+
+**Input:**
+```json
+{
+ "filePath": "/Users/erik/Documents/DEV/arbeitsstunden/httpdocs/app/views.php",
+ "offset": 636,
+ "limit": 18
+}
+```
+
+**Output:**
+```
+/Users/erik/Documents/DEV/arbeitsstunden/httpdocs/app/views.php
+file
+
+636:
+637:
+638:
Vereinswerte
Unterstützt Absätze, - Listen, *kursiv* und **fett**.
+639:
Exporte
Exportfunktionen für Benutzerdaten und Stundenbuchungen.
+640:
CSV-Import
Importiert Benutzerdaten aus einer CSV-Datei mit den Spalten firstname, lastname, email, role und hours_worked.
+645:
+646:
+647:
+648:
+649:
+650:
+651:
+652:
+```
+
+---
+
+## Assistant (Build · GPT-5.4 · 29.6s)
+
+Ich ziehe das Textfeld aus `Vereinswerte` heraus und gebe ihm eine eigene Box `Informationskasten im Dashboard`.
+
+**Tool: apply_patch**
+
+**Input:**
+```json
+{
+ "patchText": "*** Begin Patch\n*** Update File: /Users/erik/Documents/DEV/arbeitsstunden/httpdocs/app/views.php\n@@\n-
Vereinswerte
\">
\">
Unterstützt Absätze, - Listen, *kursiv* und **fett**.
\n+
Vereinswerte
\">
\">
\n+
Informationskasten im Dashboard
\">\">
Unterstützt Absätze, - Listen, *kursiv* und **fett**.
\n*** End Patch"
+}
+```
+
+**Output:**
+```
+Success. Updated the following files:
+M Users/erik/Documents/DEV/arbeitsstunden/httpdocs/app/views.php
+```
+
+---
+
+## Assistant (Build · GPT-5.4 · 14.0s)
+
+Erledigt.
+
+Der `Informationskasten im Dashboard` hat jetzt in der `Vereinskonfiguration` eine eigene Box.
+
+Aufteilung jetzt:
+- `Vereinswerte`
+- `Informationskasten im Dashboard`
+- `Exporte`
+- `CSV-Import`
+- `Arbeitsstunden zurücksetzen`
+- `Logansicht`
+
+Geändert in:
+- `httpdocs/app/views.php`
+
+Wichtiger technischer Hinweis:
+- Die neue Info-Box speichert weiterhin über `action=update_settings`
+- Damit Pflichtstunden und Stundenwert beim separaten Speichern nicht verloren gehen, werden diese Werte als Hidden Fields mitgegeben
+
+---
+
+## User
+
+bei der Box Vereinskonfiguration ist direkt darunter eine Linie, diese wird nicht benötigt
+
+---
+
+## Assistant (Build · GPT-5.4 · 12.0s)
+
+Ich entferne die unnötige Trennlinie unter der Überschrift der Vereinskonfiguration, indem ich den unteren Padding des ersten Card-Body wieder normalisiere.
+
+**Tool: apply_patch**
+
+**Input:**
+```json
+{
+ "patchText": "*** Begin Patch\n*** Update File: /Users/erik/Documents/DEV/arbeitsstunden/httpdocs/app/views.php\n@@\n-
\n-
Vereinskonfiguration
\n+
\n+
Vereinskonfiguration
\n
\n*** End Patch"
+}
+```
+
+**Output:**
+```
+Success. Updated the following files:
+M Users/erik/Documents/DEV/arbeitsstunden/httpdocs/app/views.php
+```
+
+---
+
+## Assistant (Build · GPT-5.4 · 8.0s)
+
+Erledigt.
+
+Die unnötige Linie direkt unter `Vereinskonfiguration` ist entfernt.
+
+Geändert in:
+- `httpdocs/app/views.php`
+
+---
+
+## User
+
+ich sehe noch eine Trennlinie, die jetzt aber etwas tiefer dargestellt wird wie bisher
+
+---
+
+## Assistant (Build · GPT-5.4 · 8.5s)
+
+Ich prüfe den Admin-Container und entferne die doppelte Card-Body-Struktur, die Tabler dort als Trennlinie zwischen den Bereichen rendert.
+
+**Tool: read**
+
+**Input:**
+```json
+{
+ "filePath": "/Users/erik/Documents/DEV/arbeitsstunden/httpdocs/app/views.php",
+ "offset": 634,
+ "limit": 14
+}
+```
+
+**Output:**
+```
+/Users/erik/Documents/DEV/arbeitsstunden/httpdocs/app/views.php
+file
+
+634:
+635:
Vereinskonfiguration
+636:
+637:
+638:
Vereinswerte
+639:
Informationskasten im Dashboard
Unterstützt Absätze, - Listen, *kursiv* und **fett**.
+640:
Exporte
Exportfunktionen für Benutzerdaten und Stundenbuchungen.
+641:
CSV-Import
Importiert Benutzerdaten aus einer CSV-Datei mit den Spalten firstname, lastname, email, role und hours_worked.