diff --git a/README.md b/README.md index 3c60abc..9117cba 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,19 @@ # Legacy App Archiv -Dieses Verzeichnis enthaelt den bisherigen PHP-Bestand der Kaffeeliste. +Dieses Verzeichnis enthält den bisherigen PHP-Bestand der Kaffeeliste. -Es bleibt aus drei Gruenden im Repository: +Es bleibt aus drei Gründen im Repository: -- als Referenz fuer die bestehende Fachlogik -- als Quelle fuer Datenmigrationen in die SaaS-Version -- als Rueckfalloption waehrend der Uebergangsphase +- als Referenz für die bestehende Fachlogik +- als Quelle für Datenmigrationen in die SaaS-Version +- als Rückfalloption während der Übergangsphase ## Wichtige Legacy-Bereiche -- `index.php`: persoenliches Dashboard -- `stricheintragen.php`: Sammelerfassung fuer Kaffee-Striche -- `einzahlung.php`: Sammelerfassung fuer Einzahlungen -- `kaffeeliste.php`: operative Gesamtuebersicht +- `index.php`: persönliches Dashboard +- `stricheintragen.php`: Sammelerfassung für Kaffee-Striche +- `einzahlung.php`: Sammelerfassung für Einzahlungen +- `kaffeeliste.php`: operative Gesamtübersicht - `mitarbeiterverwalten.php`: Mitglieder- und Rollenpflege - `letzteneintraege.php`: Korrektur letzter Buchungen - `hinweise.php`: Banner/Hinweise @@ -21,5 +21,5 @@ Es bleibt aus drei Gruenden im Repository: ## Umgang Mit Dem Archiv - Keine neuen Produktfunktionen mehr hier entwickeln. -- Nur noch fuer Referenz, Datenabgleich oder Notfallbetrieb verwenden. -- Neue Arbeit findet ausschliesslich in `../saas-app/` und `../docs/` statt. +- Nur noch für Referenz, Datenabgleich oder Notfallbetrieb verwenden. +- Neue Arbeit findet ausschließlich in `../saas-app/` und `../docs/` statt. diff --git a/app/saas-auth.php b/app/saas-auth.php index aeb6c40..9207358 100644 --- a/app/saas-auth.php +++ b/app/saas-auth.php @@ -323,13 +323,13 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr $errors[] = 'Der Kundenname muss zwischen 3 und 255 Zeichen lang sein.'; } if (!in_array($timezone, DateTimeZone::listIdentifiers(), true)) { - $errors[] = 'Die Zeitzone ist ungueltig.'; + $errors[] = 'Die Zeitzone ist ungültig.'; } if (!preg_match('/^[a-z]{2}-[A-Z]{2}$/', $locale)) { $errors[] = 'Die Locale muss dem Muster de-DE entsprechen.'; } if (!preg_match('/^[A-Z]{3}$/', $currencyCode)) { - $errors[] = 'Der Waehrungscode muss aus drei Grossbuchstaben bestehen.'; + $errors[] = 'Der Währungscode muss aus drei Großbuchstaben bestehen.'; } if ($markPriceCents === null || $markPriceCents < 1 || $markPriceCents > 10000) { $errors[] = 'Der Preis pro Strich muss zwischen 0,01 und 100,00 liegen.'; @@ -615,7 +615,7 @@ function saas_request_password_reset(PDO $pdo, string $email, string $tenantSlug if (!filter_var($emailNorm, FILTER_VALIDATE_EMAIL)) { return [ 'ok' => false, - 'errors' => ['Bitte eine gueltige E-Mail-Adresse eingeben.'], + 'errors' => ['Bitte eine gültige E-Mail-Adresse eingeben.'], ]; } @@ -658,7 +658,7 @@ function saas_reset_password_with_token(PDO $pdo, string $token, string $passwor $tokenRow = saas_fetch_valid_auth_token($pdo, $token, 'password_reset'); if ($tokenRow === null) { - $errors[] = 'Der Link ist ungueltig oder abgelaufen.'; + $errors[] = 'Der Link ist ungültig oder abgelaufen.'; } if ($errors !== []) { @@ -730,7 +730,7 @@ function saas_verify_email_token(PDO $pdo, string $token): array if ($tokenRow === null) { return [ 'ok' => false, - 'errors' => ['Der Link ist ungueltig oder abgelaufen.'], + 'errors' => ['Der Link ist ungültig oder abgelaufen.'], ]; } @@ -748,7 +748,7 @@ function saas_verify_email_token(PDO $pdo, string $token): array return [ 'ok' => false, - 'errors' => ['Die E-Mail-Adresse konnte nicht bestaetigt werden.'], + 'errors' => ['Die E-Mail-Adresse konnte nicht bestätigt werden.'], ]; } @@ -765,7 +765,7 @@ function saas_authenticate(PDO $pdo, string $email, string $password, string $te if (!filter_var($emailNorm, FILTER_VALIDATE_EMAIL) || $password === '') { return [ 'ok' => false, - 'errors' => ['E-Mail oder Passwort ist ungueltig.'], + 'errors' => ['E-Mail oder Passwort ist ungültig.'], ]; } @@ -785,7 +785,7 @@ function saas_authenticate(PDO $pdo, string $email, string $password, string $te ) { return [ 'ok' => false, - 'errors' => ['E-Mail oder Passwort ist ungueltig.'], + 'errors' => ['E-Mail oder Passwort ist ungültig.'], ]; } @@ -817,7 +817,7 @@ function saas_authenticate(PDO $pdo, string $email, string $password, string $te if ($tenantIds === []) { return [ 'ok' => false, - 'errors' => ['Fuer dieses Konto ist kein aktiver Mandant verfuegbar.'], + 'errors' => ['Für dieses Konto ist kein aktiver Mandant verfügbar.'], ]; } @@ -835,7 +835,7 @@ function saas_authenticate(PDO $pdo, string $email, string $password, string $te if ($identity === null) { return [ 'ok' => false, - 'errors' => ['Fuer dieses Konto ist kein aktiver Mandant verfuegbar.'], + 'errors' => ['Für dieses Konto ist kein aktiver Mandant verfügbar.'], ]; } @@ -867,13 +867,13 @@ function saas_register_tenant_owner(PDO $pdo, array $input): array $errors[] = 'Der Kundenname muss zwischen 3 und 255 Zeichen lang sein.'; } if (!preg_match('/^[a-z0-9][a-z0-9-]{1,98}[a-z0-9]$/', $tenantSlug)) { - $errors[] = 'Das Kundenkuerzel darf nur Kleinbuchstaben, Zahlen und Bindestriche enthalten.'; + $errors[] = 'Das Kundenkürzel darf nur Kleinbuchstaben, Zahlen und Bindestriche enthalten.'; } if (strlen($displayName) < 2 || strlen($displayName) > 255) { $errors[] = 'Der Name muss zwischen 2 und 255 Zeichen lang sein.'; } if (!filter_var($emailNorm, FILTER_VALIDATE_EMAIL)) { - $errors[] = 'Bitte eine gueltige E-Mail-Adresse eingeben.'; + $errors[] = 'Bitte eine gültige E-Mail-Adresse eingeben.'; } if (strlen($password) < 8) { $errors[] = 'Das Passwort muss mindestens 8 Zeichen lang sein.'; @@ -910,7 +910,7 @@ function saas_register_tenant_owner(PDO $pdo, array $input): array if ((int)$stmt->fetchColumn() > 0) { return [ 'ok' => false, - 'errors' => ['Dieses Kundenkuerzel ist bereits vergeben.'], + 'errors' => ['Dieses Kundenkürzel ist bereits vergeben.'], ]; } diff --git a/app/saas-mail.php b/app/saas-mail.php index 7421bb6..90aeaac 100644 --- a/app/saas-mail.php +++ b/app/saas-mail.php @@ -117,8 +117,8 @@ function saas_send_password_reset_mail(string $to, string $token): array $body = implode("\n", [ 'Hallo,', '', - 'fuer dein Kaffeeliste-Konto wurde ein Passwort-Reset angefordert.', - 'Oeffne diesen Link, um ein neues Passwort zu setzen:', + 'für dein Kaffeeliste-Konto wurde ein Passwort-Reset angefordert.', + 'Öffne diesen Link, um ein neues Passwort zu setzen:', '', $link, '', @@ -128,7 +128,7 @@ function saas_send_password_reset_mail(string $to, string $token): array 'Deine Kaffeeliste', ]); - return saas_send_mail($to, 'Kaffeeliste Passwort zuruecksetzen', $body); + return saas_send_mail($to, 'Kaffeeliste Passwort zurücksetzen', $body); } function saas_send_email_verification_mail(string $to, string $token): array @@ -137,8 +137,8 @@ function saas_send_email_verification_mail(string $to, string $token): array $body = implode("\n", [ 'Hallo,', '', - 'bitte bestaetige deine E-Mail-Adresse fuer Kaffeeliste.', - 'Oeffne dazu diesen Link:', + 'bitte bestätige deine E-Mail-Adresse für Kaffeeliste.', + 'Öffne dazu diesen Link:', '', $link, '', @@ -147,5 +147,5 @@ function saas_send_email_verification_mail(string $to, string $token): array 'Deine Kaffeeliste', ]); - return saas_send_mail($to, 'Kaffeeliste E-Mail bestaetigen', $body); + return saas_send_mail($to, 'Kaffeeliste E-Mail bestätigen', $body); } diff --git a/csvupload.php b/csvupload.php index a17be34..3fd959a 100644 --- a/csvupload.php +++ b/csvupload.php @@ -33,7 +33,7 @@ function csv_prepare_upload(array $file): array } if (($file['size'] ?? 0) <= 0 || $file['size'] > 5 * 1024 * 1024) { - return [null, 'Die CSV-Datei ist leer oder groesser als 5 MB.']; + return [null, 'Die CSV-Datei ist leer oder größer als 5 MB.']; } $originalName = (string)($file['name'] ?? ''); @@ -248,7 +248,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") { }elseif($eintrag[3] == 3){ echo "Benutzer nicht gefunden"; }elseif($eintrag[3] == 4){ - echo "Ungueltige CSV-Zeile"; + echo "Ungültige CSV-Zeile"; } echo " diff --git a/docs/dev-mysql.md b/docs/dev-mysql.md index 24d7383..9ad296c 100644 --- a/docs/dev-mysql.md +++ b/docs/dev-mysql.md @@ -1,17 +1,17 @@ # Lokaler MySQL-Dev-Start -Die Legacy-App kann fuer Entwicklung gegen MySQL laufen. Dafuer gibt es eine -Kompatibilitaetsschicht, die die verwendeten `sqlsrv_*`-Funktionen im Dev-Modus +Die Legacy-App kann für Entwicklung gegen MySQL laufen. Dafür gibt es eine +Kompatibilitätsschicht, die die verwendeten `sqlsrv_*`-Funktionen im Dev-Modus auf PDO/MySQL abbildet. ## Voraussetzungen - PHP CLI mit `pdo_mysql`. - MySQL-Testdatenbank. -- Keine Produktivdaten und keine Produktivpasswoerter im Repository. +- Keine Produktivdaten und keine Produktivpasswörter im Repository. In dieser VS-Code-Server-Umgebung wurde PHP lokal unter `.local/` entpackt, -weil `sudo` nicht passwordless verfuegbar war. `.local/` wird von Git ignoriert. +weil `sudo` nicht passwordless verfügbar war. `.local/` wird von Git ignoriert. ## Umgebungsvariablen @@ -26,7 +26,7 @@ export DEV_AUTH_EMAIL="admin@test.local" export DEV_AUTH_NAME="Test Admin" # Optional: Standard ist var/sessions im Repository. export APP_SESSION_PATH="/path/to/writable/sessions" -# Optional fuer Passwort-Reset und E-Mail-Verifikation. +# Optional für Passwort-Reset und E-Mail-Verifikation. export APP_BASE_URL="http://127.0.0.1:8080" export APP_MAIL_TRANSPORT="log" export APP_MAIL_LOG_DIR="/path/to/writable/mail-log" @@ -64,18 +64,18 @@ HOST=127.0.0.1 PORT=8080 scripts/run-dev-server.sh ``` Danach ist die App unter `http://127.0.0.1:8080/` erreichbar. In VS Code kann -der Port ueber die Ports-Ansicht weitergeleitet werden. +der Port über die Ports-Ansicht weitergeleitet werden. ## Hinweise - Der Dev-Login umgeht AD/LDAP und nutzt `DEV_AUTH_EMAIL`. -- Der Dev-Mailversand nutzt standardmaessig `APP_MAIL_TRANSPORT=log` und legt - Nachrichten unter `var/mail` ab. Fuer Produktion kann zunaechst +- Der Dev-Mailversand nutzt standardmäßig `APP_MAIL_TRANSPORT=log` und legt + Nachrichten unter `var/mail` ab. Für Produktion kann zunächst `APP_MAIL_TRANSPORT=mail` mit passendem `APP_BASE_URL` und Absender gesetzt - werden; eine SMTP-/Provider-Anbindung bleibt ein spaeterer Betriebsausbau. -- Die Tabellen werden ueber `database/migrations/` angelegt. + werden; eine SMTP-/Provider-Anbindung bleibt ein späterer Betriebsausbau. +- Die Tabellen werden über `database/migrations/` angelegt. - `database/mysql-dev-schema.sql` bleibt als historische Dev-Schema-Baseline erhalten; der aktive Weg ist `scripts/migrate.php`. -- Session-Dateien liegen standardmaessig unter `var/sessions`; `var/` wird von +- Session-Dateien liegen standardmäßig unter `var/sessions`; `var/` wird von Git ignoriert. -- Der Dev-Modus ist nur fuer lokale Tests gedacht, nicht fuer Produktion. +- Der Dev-Modus ist nur für lokale Tests gedacht, nicht für Produktion. diff --git a/docs/m0/README.md b/docs/m0/README.md index fa0d7d5..f673499 100644 --- a/docs/m0/README.md +++ b/docs/m0/README.md @@ -3,7 +3,7 @@ Stand: 2026-07-11 M0 dokumentiert den aktuellen Legacy-Bestand, bevor die SaaS-Umstrukturierung -beginnt. Ziel ist eine belastbare Ausgangsbasis fuer Migration, Sicherheit, +beginnt. Ziel ist eine belastbare Ausgangsbasis für Migration, Sicherheit, Design-Erhalt und fachliche Vergleichstests. ## Status @@ -13,24 +13,24 @@ Design-Erhalt und fachliche Vergleichstests. | Code-Inventar | begonnen | Siehe `code-inventory.md` | | Prozesslandkarte | begonnen | In `code-inventory.md` enthalten | | Sicherheitsbaseline | begonnen | Siehe `security-baseline.md` | -| DB-Schema-Export | nicht aus Alt-DB verfuegbar | Siehe `legacy-db-status.md` | -| Golden-Master-Auswertungen | nicht aus Alt-DB verfuegbar | Siehe `legacy-db-status.md` | +| DB-Schema-Export | nicht aus Alt-DB verfügbar | Siehe `legacy-db-status.md` | +| Golden-Master-Auswertungen | nicht aus Alt-DB verfügbar | Siehe `legacy-db-status.md` | | Design-/Screenshot-Referenz | teilweise geliefert | Siehe `screenshot-checklist.md` | ## Lokal abgeschlossen - Legacy-Einstiegspunkte und Kernseiten identifiziert. - Fachliche Tabellen aus SQL-Strings abgeleitet. -- Schreibende Aktionen und kritische Datenfluesse markiert. -- Sicherheitsrisiken fuer M0 inventarisiert. -- SQL-Vorlagen fuer Schema- und Golden-Master-Export angelegt. -- Screenshot-Checkliste fuer Design-Erhalt angelegt. +- Schreibende Aktionen und kritische Datenflüsse markiert. +- Sicherheitsrisiken für M0 inventarisiert. +- SQL-Vorlagen für Schema- und Golden-Master-Export angelegt. +- Screenshot-Checkliste für Design-Erhalt angelegt. - Erste Screenshot-Referenzen unter `docs/m0/screenshots/` abgelegt. - Festgelegt: Ein alter MS-SQL-Datenbankstand steht aktuell nicht zur - Verfuegung; M0 arbeitet deshalb mit Code, Screenshots und rekonstruierter + Verfügung; M0 arbeitet deshalb mit Code, Screenshots und rekonstruierter MySQL-Dev-Datenbank als Ausgangsbasis. -## Lokale Einschraenkungen +## Lokale Einschränkungen - `php` ist in dieser Umgebung nicht im PATH, daher kein lokaler Syntaxcheck und kein lokaler App-Start. @@ -40,33 +40,33 @@ Design-Erhalt und fachliche Vergleichstests. ## Blockiert bis Input vorliegt -Diese Punkte kann ich ohne externe Informationen nicht abschliessen: +Diese Punkte kann ich ohne externe Informationen nicht abschließen: -1. Falls spaeter doch noch ein MS-SQL-Dump auftaucht: Schema und - Golden-Master-Werte nachtraeglich exportieren. +1. Falls später doch noch ein MS-SQL-Dump auftaucht: Schema und + Golden-Master-Werte nachträglich exportieren. 2. MySQL-Dev-Schema als neue rekonstruierte Baseline weiter verifizieren. -3. Fehlende Screenshot-Zustaende nachreichen oder bewusst als optional markieren. +3. Fehlende Screenshot-Zustände nachreichen oder bewusst als optional markieren. 4. Produktivumgebung dokumentieren: PHP-Version, Webserver, SQL-Server-Version, - Auth-Setup, Cron/Job-Ausfuehrung. + Auth-Setup, Cron/Job-Ausführung. ## Was ich von dir brauche -Falls ein alter MS-SQL-Stand spaeter noch auftaucht, bitte eines der folgenden +Falls ein alter MS-SQL-Stand später noch auftaucht, bitte eines der folgenden Pakete bereitstellen: - Idealerweise: einen anonymisierten SQL-Server-Schemaexport plus Rowcounts. - Alternativ: Zugriffsdaten zu einer Test-/Staging-DB, nicht zu Produktion. - Alternativ: die Ergebnisse aus `schema-export.sql` als CSV/Excel/Markdown. -Zusaetzlich hilfreich: +Zusätzlich hilfreich: - Ein erreichbarer Test-Link zur bestehenden App oder Screenshots der Seiten aus `screenshot-checklist.md`. -- Beispiel-Accounts oder Rollen fuer Admin und normales Mitglied, nur fuer eine +- Beispiel-Accounts oder Rollen für Admin und normales Mitglied, nur für eine Testumgebung. - Info, ob hart codierte Zugangsdaten aus Legacy-Skripten bereits rotiert wurden. - Entscheidung, ob M1/M2 nativ in PHP oder mit Framework vorbereitet werden sollen. -Bitte keine Produktivpasswoerter oder echten personenbezogenen Exportdaten in +Bitte keine Produktivpasswörter oder echten personenbezogenen Exportdaten in das Repository legen. diff --git a/docs/m0/code-inventory.md b/docs/m0/code-inventory.md index 60929bf..16dcc31 100644 --- a/docs/m0/code-inventory.md +++ b/docs/m0/code-inventory.md @@ -10,28 +10,28 @@ Das echte Datenbankschema muss noch mit `schema-export.sql` verifiziert werden. | Datei | Rolle | Wichtige Beobachtung | | --- | --- | --- | | `config.php` | AD-/DB-Konfiguration | Erstellt globale SQL-Server-Verbindung `$conn` | -| `functions.php` | Auth-/User-Helper | Liest `$_SERVER['AUTH_USER']`, inkludiert LDAP, prueft `kl_Mitarbeiter` | +| `functions.php` | Auth-/User-Helper | Liest `$_SERVER['AUTH_USER']`, inkludiert LDAP, prüft `kl_Mitarbeiter` | | `functionsLDAP.php` | LDAP-Mailauflösung | Ermittelt `$mailadress` aus AD | -| `header.php` | HTML-Head und Hinweisbanner | Laedt `assets/css/main.css`, liest `kl_hinweise` | -| `footer.php` | App-Sidebar und JS | Enthaelt die sichtbare Navigation und Admin-Menues | +| `header.php` | HTML-Head und Hinweisbanner | Lädt `assets/css/main.css`, liest `kl_hinweise` | +| `footer.php` | App-Sidebar und JS | Enthält die sichtbare Navigation und Admin-Menüs | | `nav.php` | Navigation | Aktuell praktisch leer | -| `headerline.php` | Headerfragment | Enthaelt NUL-Zeichen, fachlich unklar | -| `assets/css/main.css` | Hauptdesign | HTML5-UP Editorial, gruener Akzent, Tabellen, Buttons, Sidebar | +| `headerline.php` | Headerfragment | Enthält NUL-Zeichen, fachlich unklar | +| `assets/css/main.css` | Hauptdesign | HTML5-UP Editorial, grüner Akzent, Tabellen, Buttons, Sidebar | | `DataTables/` | Tabellen-Assets | Wird teilweise eingebunden, aber nicht konsequent initialisiert | -| `PHPMailer/` | Mailversand | Fuer Rundmails/Jahresauswertung genutzt | -| `TCPDF/` | PDF-Export | Fuer Kaffeelisten-Export genutzt | +| `PHPMailer/` | Mailversand | Für Rundmails/Jahresauswertung genutzt | +| `TCPDF/` | PDF-Export | Für Kaffeelisten-Export genutzt | ## Fachliche Kernseiten | Datei | Prozess | Tabellen | | --- | --- | --- | -| `index.php` | Persoenliches Dashboard, Saldo, Jahreswerte, eigene Striche, PayPal-Links | `kl_Mitarbeiter`, `kl_Einzahlungen`, `kl_Kaffeeverbrauch`, `kl_config` | -| `kaffeeliste.php` | Admin-Gesamtuebersicht mit Salden | `kl_Mitarbeiter`, `kl_Einzahlungen`, `kl_Kaffeeverbrauch` | +| `index.php` | Persönliches Dashboard, Saldo, Jahreswerte, eigene Striche, PayPal-Links | `kl_Mitarbeiter`, `kl_Einzahlungen`, `kl_Kaffeeverbrauch`, `kl_config` | +| `kaffeeliste.php` | Admin-Gesamtübersicht mit Salden | `kl_Mitarbeiter`, `kl_Einzahlungen`, `kl_Kaffeeverbrauch` | | `stricheintragen.php` | Sammelerfassung von Strichen | `kl_Mitarbeiter`, `kl_Kaffeeverbrauch`, `kl_config` | | `einzahlung.php` | Sammelerfassung von Einzahlungen | `kl_Mitarbeiter`, `kl_Einzahlungen`, `kl_Kaffeeverbrauch` | | `mitarbeiterverwalten.php` | Mitglieder anlegen, bearbeiten, aktivieren, deaktivieren | `kl_Mitarbeiter` | -| `namenanpassen.php` | Anzeigenamen aendern | `kl_Mitarbeiter` | -| `letzteneintraege.php` | Letzte Buchungen anzeigen und loeschen | `kl_Einzahlungen`, `kl_Kaffeeverbrauch`, `kl_Mitarbeiter` | +| `namenanpassen.php` | Anzeigenamen ändern | `kl_Mitarbeiter` | +| `letzteneintraege.php` | Letzte Buchungen anzeigen und löschen | `kl_Einzahlungen`, `kl_Kaffeeverbrauch`, `kl_Mitarbeiter` | | `csvupload.php` | Zahlungs-CSV importieren | `kl_Mitarbeiter`, `kl_Einzahlungen` | | `exportKaffeeliste.php` | PDF-/Listenexport | `kl_Mitarbeiter`, `kl_Kaffeeverbrauch`, `kl_Einzahlungen`, `kl_config` | | `mailausgebe.php` | Mailausgabe/Adressliste | `kl_Mitarbeiter` | @@ -44,7 +44,7 @@ Das echte Datenbankschema muss noch mit `schema-export.sql` verifiziert werden. ## Abgeleitete Tabellen und Spalten -Diese Spalten sind aus dem Code abgeleitet und muessen mit dem echten DB-Schema +Diese Spalten sind aus dem Code abgeleitet und müssen mit dem echten DB-Schema abgeglichen werden. | Tabelle | Abgeleitete Spalten | @@ -64,13 +64,13 @@ abgeglichen werden. 1. Seite inkludiert `functions.php`. 2. `functions.php` liest `$_SERVER['AUTH_USER']`. 3. `functionsLDAP.php` ermittelt Mailadresse aus LDAP. -4. Zugriff wird ueber `kl_Mitarbeiter.Email`, `aktiv` und `admin` geprueft. +4. Zugriff wird über `kl_Mitarbeiter.Email`, `aktiv` und `admin` geprüft. M0-Feststellung: -Login-Konto, Kaffee-Teilnehmer und Rolle sind im Legacy-Modell gekoppelt. Fuer -SaaS muessen `users`, `participants` und `tenant_memberships` getrennt werden. +Login-Konto, Kaffee-Teilnehmer und Rolle sind im Legacy-Modell gekoppelt. Für +SaaS müssen `users`, `participants` und `tenant_memberships` getrennt werden. -### Persoenliches Dashboard +### Persönliches Dashboard Quelle: `index.php`. @@ -81,7 +81,7 @@ Berechnungen: - Gesamtausgabe: Summe `kl_Kaffeeverbrauch.Kosten`. - Gesamtstriche: Summe `kl_Kaffeeverbrauch.AnzahlStriche`. - Aktueller Stand: Einzahlungen minus Ausgaben. -- Jahreswerte: dieselben Summen fuer aktuelles Jahr. +- Jahreswerte: dieselben Summen für aktuelles Jahr. - Bei aktivem `strichperweb`: eigener Strich-Eintrag. - Bei aktivem `paypaluse`: PayPal-Links anzeigen. @@ -123,19 +123,19 @@ M0-Feststellung: Das `admin`-Flag ist fachlich eine Rolleninformation und sollte in der SaaS-App in `tenant_memberships.role` wandern. -### Korrektur letzter Eintraege +### Korrektur letzter Einträge Quelle: `letzteneintraege.php`. Aktionen: - Letzte 100 Einzahlungen anzeigen. -- Einzahlung hart loeschen. -- Letzte 100 Strich-Eintraege anzeigen. -- Strich-Eintrag hart loeschen. +- Einzahlung hart löschen. +- Letzte 100 Strich-Einträge anzeigen. +- Strich-Eintrag hart löschen. M0-Feststellung: -Finanznahe Korrekturen sollten im Zielmodell nicht hart loeschen, sondern als +Finanznahe Korrekturen sollten im Zielmodell nicht hart löschen, sondern als Storno/Reversal mit Audit-Trail gespeichert werden. ### CSV-Import @@ -148,8 +148,8 @@ Ablauf: - CSV mit Komma-Trennung lesen. - Name aus Spalte 3, Betrag aus Spalte 7, Datum aus Spalte 0. - Mitarbeiter per Name oder `paypalname` finden. -- Dublette anhand Mitarbeiter, Betrag und Datumstag pruefen. -- Einzahlung einfuegen. +- Dublette anhand Mitarbeiter, Betrag und Datumstag prüfen. +- Einzahlung einfügen. - Ergebnis in Erfolg/Fehler klassifizieren. ### Jahresauswertung @@ -160,33 +160,33 @@ Ablauf: - Gesamtstriche des aktuellen Jahres je aktivem Mitarbeiter berechnen. - Konstante Anzahl neuer Striche/Gutschrift proportional verteilen. -- Einzahlung je Mitarbeiter einfuegen. +- Einzahlung je Mitarbeiter einfügen. - Mail an Mitarbeiter senden. M0-Feststellung: -Das ist ein Job/Skript mit direktem Schreibzugriff und Mailversand. Fuer SaaS +Das ist ein Job/Skript mit direktem Schreibzugriff und Mailversand. Für SaaS braucht es Dry-Run, Audit, Tenant-Scope und expliziten Operator. ## Offene Schemafragen -- Gibt es Primary Keys, Foreign Keys und Indizes fuer die `kl_`-Tabellen? -- Sind Datentypen fuer Geldwerte `decimal`, `money`, `float` oder etwas anderes? +- Gibt es Primary Keys, Foreign Keys und Indizes für die `kl_`-Tabellen? +- Sind Datentypen für Geldwerte `decimal`, `money`, `float` oder etwas anderes? - Gibt es historische Spalten, die im Code nicht sichtbar sind? - Gibt es Trigger oder Stored Procedures? -- Gibt es weitere Jobs ausser `jahresauswertung.php`? +- Gibt es weitere Jobs außer `jahresauswertung.php`? - Sind Umfragetabellen produktiv relevant oder Archiv/Randmodul? ## Technische Legacy-Inkonsistenzen - `csvupload.php` sucht in `getMitarbeiterID` nach `Name = ? or paypalname = ?`, - uebergibt aber nur einen Parameter. Das sollte vor der Uebernahme des + übergibt aber nur einen Parameter. Das sollte vor der Übernahme des CSV-Flows verifiziert werden. -- `einzahlung.php` prueft auf `$_GET["action"]`, die Buttons erzeugen aber - URLs mit `aktion=...`. Der Vorderseite-/Rueckseite-Filter kann dadurch +- `einzahlung.php` prüft auf `$_GET["action"]`, die Buttons erzeugen aber + URLs mit `aktion=...`. Der Vorderseite-/Rückseite-Filter kann dadurch abweichend vom erwarteten Verhalten laufen. -- `exportKaffeeliste.php` referenziert `tcpdf/tcpdf.php`, waehrend der Ordner im - Repository `TCPDF/` heisst. Auf case-sensitiven Dateisystemen kann das +- `exportKaffeeliste.php` referenziert `tcpdf/tcpdf.php`, während der Ordner im + Repository `TCPDF/` heißt. Auf case-sensitiven Dateisystemen kann das brechen. -- `headerline.php` ist fachlich leer beziehungsweise mit NUL-Zeichen gefuellt. - Vor der neuen App-Shell sollte geklaert werden, ob die Datei entfernt werden +- `headerline.php` ist fachlich leer beziehungsweise mit NUL-Zeichen gefüllt. + Vor der neuen App-Shell sollte geklärt werden, ob die Datei entfernt werden kann. diff --git a/docs/m0/golden-master-queries.sql b/docs/m0/golden-master-queries.sql index 849bcaa..e683007 100644 --- a/docs/m0/golden-master-queries.sql +++ b/docs/m0/golden-master-queries.sql @@ -3,10 +3,10 @@ M0 Golden-Master Queries Ziel: - Fachliche Legacy-Ergebnisse exportieren, damit Migration und neue SaaS-App - gegen denselben Stand verglichen werden koennen. + gegen denselben Stand verglichen werden können. -Ausfuehrung: -- In der Legacy-Datenbank ausfuehren. +Ausführung: +- In der Legacy-Datenbank ausführen. - Ergebnisse je Query als CSV speichern. - Keine personenbezogenen Exporte ins Repo committen. */ @@ -94,7 +94,7 @@ FROM kl_Einzahlungen e JOIN kl_Mitarbeiter m ON m.MitarbeiterID = e.MitarbeiterID ORDER BY e.Datum DESC, e.EinzahlungsID DESC; --- 5. Letzte Strich-/Verbrauchseintraege je Teilnehmer +-- 5. Letzte Strich-/Verbrauchseinträge je Teilnehmer SELECT v.VerbrauchID, v.MitarbeiterID, @@ -142,7 +142,7 @@ GROUP BY m.MitarbeiterID, m.Name, m.Email HAVING SUM(v.AnzahlStriche) >= 10 ORDER BY m.Name; --- 9. 100-Tage-Rueckseite analog Legacy-Stricherfassung +-- 9. 100-Tage-Rückseite analog Legacy-Stricherfassung SELECT m.MitarbeiterID, m.Name, @@ -182,4 +182,3 @@ WHERE YEAR(v.Datum) = @CurrentYear AND m.aktiv = 1 GROUP BY m.MitarbeiterID, m.Name, m.Email ORDER BY GesamtStriche DESC, m.Name; - diff --git a/docs/m0/legacy-db-status.md b/docs/m0/legacy-db-status.md index e182d82..dd58fa0 100644 --- a/docs/m0/legacy-db-status.md +++ b/docs/m0/legacy-db-status.md @@ -4,44 +4,43 @@ Stand: 2026-07-11 ## Entscheidung -Ein alter MS-SQL-Datenbankstand steht aktuell nicht zur Verfuegung. Deshalb -koennen `schema-export.sql` und `golden-master-queries.sql` derzeit nicht gegen -eine echte Legacy-Datenbank ausgefuehrt werden. +Ein alter MS-SQL-Datenbankstand steht aktuell nicht zur Verfügung. Deshalb +können `schema-export.sql` und `golden-master-queries.sql` derzeit nicht gegen +eine echte Legacy-Datenbank ausgeführt werden. -Fuer die weitere Umstrukturierung gilt daher: +Für die weitere Umstrukturierung gilt daher: -- Der Legacy-Code ist die primaere Quelle fuer das fachliche Verhalten. +- Der Legacy-Code ist die primäre Quelle für das fachliche Verhalten. - Die Screenshots unter `docs/m0/screenshots/` sind die visuelle Referenz. - Die MySQL-Testdatenbank ist die rekonstruierte Entwicklungsbasis. -- Fachliche Golden-Master-Werte werden aus rekonstruierten Testfaellen statt aus +- Fachliche Golden-Master-Werte werden aus rekonstruierten Testfällen statt aus historischer Produktivdatenbank aufgebaut. -## Konsequenz fuer M1 +## Konsequenz für M1 M1 wird nicht als Vergleich gegen echte Alt-Daten gestartet, sondern als rekonstruierter Golden-Master: 1. Fachliche Regeln aus dem Code ableiten. 2. Kleine, kontrollierte Testdaten erzeugen. -3. Erwartete Salden, Jahreswerte, Striche, Einzahlungen und CSV-Importfaelle +3. Erwartete Salden, Jahreswerte, Striche, Einzahlungen und CSV-Importfälle manuell beziehungsweise per Testskript definieren. 4. Neue Implementierung gegen diese erwarteten Werte testen. -Wenn spaeter doch noch ein MS-SQL-Dump oder Schemaexport auftaucht, werden die -urspruenglichen M0-SQL-Dateien nachtraeglich genutzt und die Baseline ergaenzt. +Wenn später doch noch ein MS-SQL-Dump oder Schemaexport auftaucht, werden die +ursprünglichen M0-SQL-Dateien nachträglich genutzt und die Baseline ergänzt. ## Aktuelle rekonstruierte Basis - MySQL-Dev-Schema: `database/mysql-dev-schema.sql` - Initialisierung: `scripts/init-mysql-dev.php` - Dev-Start: `scripts/run-dev-server.sh` -- MySQL-Kompatibilitaet: `lib/sqlsrv_mysql_compat.php` +- MySQL-Kompatibilität: `lib/sqlsrv_mysql_compat.php` ## Offene Punkte - Soll die MySQL-Testdatenbank ab jetzt die verbindliche Entwicklungsdatenbank - fuer M1/M2 sein? + für M1/M2 sein? - Soll das Ziel weiterhin eine angepasste Legacy-PHP-App sein oder ein sauberer - SaaS-Neuaufbau mit uebernommener Fachlogik? -- Welche Testfaelle muessen fachlich auf jeden Fall abgedeckt werden? - + SaaS-Neuaufbau mit übernommener Fachlogik? +- Welche Testfälle müssen fachlich auf jeden Fall abgedeckt werden? diff --git a/docs/m0/schema-export.sql b/docs/m0/schema-export.sql index dd5acbf..7db57c2 100644 --- a/docs/m0/schema-export.sql +++ b/docs/m0/schema-export.sql @@ -6,7 +6,7 @@ Ziel: aus der Legacy-Datenbank exportieren. Hinweise: -- In der Ziel-Datenbank ausfuehren. +- In der Ziel-Datenbank ausführen. - Ergebnisse als CSV/Excel speichern und nicht mit Produktiv-Secrets ins Repo legen. - Falls nur Kaffeelisten-Tabellen exportiert werden sollen, den WHERE-Block bei @@ -149,4 +149,3 @@ WHERE o.type IN ('P', 'FN', 'IF', 'TF') OR OBJECT_DEFINITION(o.object_id) LIKE '%CoffeeSurvey%' ) ORDER BY s.name, o.name; - diff --git a/docs/m0/screenshot-checklist.md b/docs/m0/screenshot-checklist.md index 5181304..9bfc447 100644 --- a/docs/m0/screenshot-checklist.md +++ b/docs/m0/screenshot-checklist.md @@ -3,7 +3,7 @@ Stand: 2026-07-11 Diese Checkliste friert die bestehende Optik ein, damit die SaaS-App vertraut -bleibt. Wenn die Legacy-App lokal nicht laeuft, koennen Screenshots aus der +bleibt. Wenn die Legacy-App lokal nicht läuft, können Screenshots aus der aktuellen Umgebung geliefert werden. ## Allgemeine Vorgaben @@ -11,24 +11,24 @@ aktuellen Umgebung geliefert werden. - Je Seite Desktop mit ca. 1440 px Breite aufnehmen. - Je Kernseite mobile Ansicht mit ca. 390 px Breite aufnehmen. - Je relevanter Rolle aufnehmen: normales Mitglied und Admin. -- Keine echten personenbezogenen Daten veroeffentlichen. +- Keine echten personenbezogenen Daten veröffentlichen. - Dateinamen nach Muster `m0---.png`. ## Kernseiten -| Prioritaet | Seite | Rolle | Status | Zweck | +| Priorität | Seite | Rolle | Status | Zweck | | --- | --- | --- | --- | --- | | Hoch | `index.php` | Mitglied | vorhanden: `m0-member-dashboard-desktop.png`, `m0-member-dashboard-mobile.png` | Dashboard, Saldo, Jahreswerte, eigene Striche, PayPal | | Hoch | `index.php` | Admin | aktuell identisch wie Mitglied | Dashboard mit Admin-Sidebar | -| Hoch | `kaffeeliste.php` | Admin | vorhanden: `m0-admin-kaffeeliste-desktop.png` | Gesamtuebersicht und Aktionsleiste | +| Hoch | `kaffeeliste.php` | Admin | vorhanden: `m0-admin-kaffeeliste-desktop.png` | Gesamtübersicht und Aktionsleiste | | Hoch | `stricheintragen.php` | Admin | vorhanden: `m0-admin-stricheintragen-desktop.png` | Sammelerfassung Striche | | Hoch | `einzahlung.php` | Admin | vorhanden: `m0-admin-einzahlung-desktop.png` | Sammelerfassung Einzahlungen | | Hoch | `mitarbeiterverwalten.php` | Admin | vorhanden: `m0-admin-mitglieder-desktop.png` | Mitgliederliste und Formular | -| Hoch | `letzteneintraege.php` | Admin | vorhanden: `m0-admin-letzteneintraege-desktop.png` | Korrekturansicht mit Loeschaktionen | +| Hoch | `letzteneintraege.php` | Admin | vorhanden: `m0-admin-letzteneintraege-desktop.png` | Korrekturansicht mit Löschaktionen | | Mittel | `csvupload.php` | Admin | vorhanden: `m0-admin-csv-upload-desktop.png` | CSV-Upload-Formular und Ergebniszustand | | Mittel | `hinweise.php` | Admin | vorhanden: `m0-admin-hinweise-desktop.png` | Hinweise anlegen und Liste | | Mittel | `faq.php` | Mitglied | vorhanden: `m0-member-faq-desktop.png` | FAQ-Inhalte und Typografie | -| Mittel | `namenanpassen.php` | Mitglied | offen | Formular fuer Anzeigenamen | +| Mittel | `namenanpassen.php` | Mitglied | offen | Formular für Anzeigenamen | | Niedrig | `teilnehmerauswertung.php` | Admin | offen | Detailauswertung pro Teilnehmer | | Niedrig | `mailausgebe.php` | Admin | offen | Mail-/Adressausgabe | | Niedrig | `umfrage.php` | Mitglied | offen, falls SaaS-relevant | Randmodul, falls SaaS-relevant | @@ -49,9 +49,9 @@ docs/m0/screenshots/m0-member-dashboard-mobile.png docs/m0/screenshots/m0-member-faq-desktop.png ``` -## Zustaende +## Zustände -Diese UI-Zustaende sollten, wenn moeglich, separat gesichert werden: +Diese UI-Zustände sollten, wenn möglich, separat gesichert werden: - Positiver Kontostand. - Negativer Kontostand. @@ -62,14 +62,14 @@ Diese UI-Zustaende sollten, wenn moeglich, separat gesichert werden: - CSV-Import mit Erfolg, Dublette und unbekanntem Nutzer. - Hinweisbanner aktiv. - Leere Tabellen oder keine Daten. -- Mobile Sidebar geoeffnet und geschlossen. +- Mobile Sidebar geöffnet und geschlossen. ## Designmerkmale, die erhalten bleiben sollen -- Gruener Akzent fuer Links, Buttons und Linien. -- Roboto-Slab-Ueberschriften. -- Open-Sans-Fliesstext. -- Weisse Hauptflaeche. +- Grüner Akzent für Links, Buttons und Linien. +- Roboto-Slab-Überschriften. +- Open-Sans-Fließtext. +- Weiße Hauptfläche. - Graue Sidebar in der App. - Tabellen als zentrale Datenansicht. - Schlichte Formularfelder und Buttons. @@ -84,5 +84,5 @@ docs/m0/screenshots/ ``` Vor dem Commit sollten Screenshots anonymisiert sein. Wenn echte Namen, -E-Mails, PayPal-Daten oder Salden sichtbar sind, besser ausserhalb des Repos +E-Mails, PayPal-Daten oder Salden sichtbar sind, besser außerhalb des Repos ablegen und nur als Referenz verwenden. diff --git a/docs/m0/security-baseline.md b/docs/m0/security-baseline.md index 8b4e810..9c7399a 100644 --- a/docs/m0/security-baseline.md +++ b/docs/m0/security-baseline.md @@ -3,17 +3,17 @@ Stand: 2026-07-11 Diese Baseline ist eine statische Erstbewertung. Sie ersetzt kein Penetration -Testing, markiert aber die wichtigsten Risiken fuer die SaaS-Umstrukturierung. +Testing, markiert aber die wichtigsten Risiken für die SaaS-Umstrukturierung. ## Kritische Sofortthemen | Risiko | Quelle | Auswirkung | Empfehlung | | --- | --- | --- | --- | | Hart codierte DB-Zugangsdaten | `jahresauswertung.php` Zeilen 4-8 | Secret-Leak, direkte Produktiv-DB-Gefahr | Zugangsdaten rotieren, Skript deaktivieren oder auf Env-Konfiguration umstellen | -| Schreibende Seiten ohne eigene Rollenpruefung | `stricheintragen.php`, `einzahlung.php`, `mailversenden.php`, `exportKaffeeliste.php` | Direkter URL-Aufruf kann Aktionen erlauben | Jede Seite serverseitig mit `requireRole` absichern | -| CSRF-Schutz nur teilweise vorhanden | viele POST-/Delete-Formulare; M2 hat `hinweise.php`, `mitarbeiterverwalten.php`, `namenanpassen.php`, `index.php`, `stricheintragen.php`, `einzahlung.php`, `letzteneintraege.php`, `csvupload.php` abgesichert | Ungewollte Buchungen, Loeschungen, Imports | CSRF fuer alle verbleibenden schreibenden Aktionen | -| Harte Deletes fuer Buchungen | `letzteneintraege.php` | Audit-Historie und Revisionsfaehigkeit gehen verloren | Storno-/Reversal-Modell statt Delete | -| CSV-Upload nur teilweise gehaertet | `csvupload.php`; M2 speichert temporaer unter `var/uploads`, prueft Dateityp und loescht nach Import | Ohne Importvorschau/Audit bleiben Fehlimporte schwer nachvollziehbar | Importvorschau, Batch-/Audit-Log und detaillierte Zeilenfehler in M6 | +| Schreibende Seiten ohne eigene Rollenprüfung | `stricheintragen.php`, `einzahlung.php`, `mailversenden.php`, `exportKaffeeliste.php` | Direkter URL-Aufruf kann Aktionen erlauben | Jede Seite serverseitig mit `requireRole` absichern | +| CSRF-Schutz nur teilweise vorhanden | viele POST-/Delete-Formulare; M2 hat `hinweise.php`, `mitarbeiterverwalten.php`, `namenanpassen.php`, `index.php`, `stricheintragen.php`, `einzahlung.php`, `letzteneintraege.php`, `csvupload.php` abgesichert | Ungewollte Buchungen, Löschungen, Imports | CSRF für alle verbleibenden schreibenden Aktionen | +| Harte Deletes für Buchungen | `letzteneintraege.php` | Audit-Historie und Revisionsfähigkeit gehen verloren | Storno-/Reversal-Modell statt Delete | +| CSV-Upload nur teilweise gehärtet | `csvupload.php`; M2 speichert temporär unter `var/uploads`, prüft Dateityp und löscht nach Import | Ohne Importvorschau/Audit bleiben Fehlimporte schwer nachvollziehbar | Importvorschau, Batch-/Audit-Log und detaillierte Zeilenfehler in M6 | | Kein Tenant-Scope | alle fachlichen Queries | Zentrales SaaS-Leak-Risiko | `tenant_id` verpflichtend und Query-Schicht testen | ## Weitere Befunde @@ -25,10 +25,10 @@ Testing, markiert aber die wichtigsten Risiken fuer die SaaS-Umstrukturierung. | Datumsformat `Y-d-m H:i:s` | `index.php`, `stricheintragen.php`, `einzahlung.php`, `hinweise.php` | ISO/DB-kompatibel `Y-m-d H:i:s` oder DB-Zeit verwenden | | Ausgabe von Namen/E-Mails teils unescaped | mehrere Tabellen, z.B. Mitgliederverwaltung | `htmlspecialchars` zentral erzwingen | | Fehlerausgabe mit `sqlsrv_errors()` an Nutzer | mehrere Dateien | Logging intern, neutrale Fehlermeldung extern | -| CSV-Mitarbeitersuche mit mutmasslich falscher Parameteranzahl | `csvupload.php` `getMitarbeiterID`; in M2 korrigiert | Mit Golden-Master weiter pruefen | +| CSV-Mitarbeitersuche mit mutmaßlich falscher Parameteranzahl | `csvupload.php` `getMitarbeiterID`; in M2 korrigiert | Mit Golden-Master weiter prüfen | | Basis-Auth-Beispiel mit Platzhalter-Passwort | `umfrageergebnisse.php` Kommentarblock | Entfernen oder echte Auth-Middleware nutzen | | App-Navigation ist in `footer.php` | Layoutstruktur | Trennung in App-Shell und Public-Shell | -| `headerline.php` enthaelt NUL-Zeichen | `headerline.php` | Datei pruefen/entfernen, wenn ungenutzt | +| `headerline.php` enthält NUL-Zeichen | `headerline.php` | Datei prüfen/entfernen, wenn ungenutzt | | Massenmail ohne Versandlog | `mailversenden.php`, `jahresauswertung.php` | Job-Modell mit Dry-Run, Audit, Rate-Limit | ## Rollen- und Zugriffsrisiken @@ -39,29 +39,29 @@ Aktuell gilt: gesteuert. - Einige Admin-Zielseiten haben eigene Checks. - Einige schreibende oder sensible Dateien verlassen sich nicht durchgehend auf - eine eigene Rollenpruefung. + eine eigene Rollenprüfung. -Fuer SaaS gilt: +Für SaaS gilt: -- Menue-Ausblendung ist keine Berechtigungspruefung. -- Jede Route braucht serverseitige Auth- und Rollenpruefung. +- Menü-Ausblendung ist keine Berechtigungsprüfung. +- Jede Route braucht serverseitige Auth- und Rollenprüfung. - Jede fachliche Route braucht Tenant-Kontext. -- IDs aus Requests muessen zum aktuellen Tenant gehoeren. +- IDs aus Requests müssen zum aktuellen Tenant gehören. -## Empfohlene Reihenfolge fuer Sicherheitsarbeit +## Empfohlene Reihenfolge für Sicherheitsarbeit 1. Secrets rotieren und aus dem Code entfernen. -2. Legacy-Schreibseiten bis zum Umbau hinter explizite Admin-Pruefung setzen. +2. Legacy-Schreibseiten bis zum Umbau hinter explizite Admin-Prüfung setzen. 3. CSRF-Schutz schrittweise auf alle verbleibenden Legacy-Schreibseiten ausrollen. -4. Finanzdaten im Zielmodell nur noch stornieren, nicht loeschen. +4. Finanzdaten im Zielmodell nur noch stornieren, nicht löschen. 5. CSV-Import mit Vorschau, Audit und Zeilenfehlern modellieren. -6. Einheitliche Escape-/View-Helfer einfuehren. +6. Einheitliche Escape-/View-Helfer einführen. 7. Tenant-Isolation mit Tests gegen zwei Tenants absichern. ## Nicht im Repo speichern -- Produktivpasswoerter. +- Produktivpasswörter. - Echte Nutzerlisten. - Bank-/PayPal-Exportdaten mit Personenbezug. - AD-/LDAP-Service-Account-Daten. -- Vollstaendige Produktiv-Dumps. +- Vollständige Produktiv-Dumps. diff --git a/docs/m1-reconstructed-golden-master.md b/docs/m1-reconstructed-golden-master.md index a94bc15..037fc0d 100644 --- a/docs/m1-reconstructed-golden-master.md +++ b/docs/m1-reconstructed-golden-master.md @@ -2,14 +2,14 @@ Stand: 2026-07-12 -Da kein alter MS-SQL-Datenbankstand verfuegbar ist, wird M1 als rekonstruierter +Da kein alter MS-SQL-Datenbankstand verfügbar ist, wird M1 als rekonstruierter Golden Master aufgebaut. Die Referenz entsteht aus Legacy-Code, Screenshots und kontrollierten Testdaten in der MySQL-Dev-Datenbank. ## Ziel Die wichtigsten fachlichen Regeln werden mit kleinen, nachvollziehbaren -Testfaellen festgeschrieben. Diese Tests dienen spaeter als Sicherheitsnetz fuer +Testfällen festgeschrieben. Diese Tests dienen später als Sicherheitsnetz für die SaaS-Umstrukturierung. ## Testdaten-Gruppen @@ -28,7 +28,7 @@ die SaaS-Umstrukturierung. - Mehrere Einzahlungen an unterschiedlichen Tagen. - Strichbuchung mit einem Strich. - Strichbuchung mit zwei Strichen. -- Sammelerfassung fuer mehrere Teilnehmer. +- Sammelerfassung für mehrere Teilnehmer. - Web-Strich-Eintrag mit `Eintragsart = 2`. ### Salden @@ -36,13 +36,13 @@ die SaaS-Umstrukturierung. - Positiver Kontostand. - Negativer Kontostand. - Nullsaldo. -- Jahreswerte fuer aktuelles Jahr. +- Jahreswerte für aktuelles Jahr. - Altdaten aus Vorjahr, die nicht in Jahreswerte fallen. ### CSV-Import -- Treffer ueber Name. -- Treffer ueber `paypalname`. +- Treffer über Name. +- Treffer über `paypalname`. - Dublette gleicher Teilnehmer, Betrag und Datum. - Unbekannter Name. - Negativer oder leerer Betrag. @@ -51,11 +51,11 @@ die SaaS-Umstrukturierung. - Aktiver Hinweis. - Abgelaufener Hinweis. -- Neuer Hinweis ueber Admin-Formular. +- Neuer Hinweis über Admin-Formular. ## Erwartete Referenzwerte -Fuer jeden Testfall sollen erwartete Werte dokumentiert werden: +Für jeden Testfall sollen erwartete Werte dokumentiert werden: - Summe Einzahlungen. - Summe Kosten. @@ -72,25 +72,25 @@ Fuer jeden Testfall sollen erwartete Werte dokumentiert werden: Seed-Skript anlegen. Erledigt mit `scripts/seed-golden-master.php`. 2. `scripts/init-mysql-dev.php` so erweitern, dass es die Testdaten idempotent anlegt. Entschieden: Golden-Master-Daten bleiben in einem separaten Skript, - damit normale Dev-Daten nicht zwangsweise ueberschrieben werden. + damit normale Dev-Daten nicht zwangsweise überschrieben werden. 3. Ein erstes Vergleichsskript `scripts/check-golden-master.php` erstellen. Erledigt. 4. Die wichtigsten Seiten per HTTP abrufen und auf erwartete Texte/Werte - pruefen. Erledigt mit `scripts/http-smoke.php`. -5. Danach M2 starten: technisches Fundament fuer SaaS-Struktur. M1 ist als + prüfen. Erledigt mit `scripts/http-smoke.php`. +5. Danach M2 starten: technisches Fundament für SaaS-Struktur. M1 ist als Sicherheitsnetz nutzbar; offene Dependency-Themen sind unten dokumentiert. ## Skripte -- `scripts/dev-db.php`: gemeinsame DB-Verbindung fuer Dev-Skripte. +- `scripts/dev-db.php`: gemeinsame DB-Verbindung für Dev-Skripte. - `scripts/golden-master-data.php`: definierte Testdaten und erwartete Werte. - `scripts/seed-golden-master.php`: legt Golden-Master-Testdaten idempotent an. -- `scripts/check-golden-master.php`: prueft Salden, Jahreswerte, Rollen, +- `scripts/check-golden-master.php`: prüft Salden, Jahreswerte, Rollen, Listenfilter, CSV-Lookup und Hinweise. -- `scripts/http-smoke.php`: ruft sichere GET-Seiten per HTTP ab und prueft auf +- `scripts/http-smoke.php`: ruft sichere GET-Seiten per HTTP ab und prüft auf HTTP 200, erwartete Texte und PHP-Fehlermarker. -## Ausfuehrung +## Ausführung Mit normal installierter PHP-CLI: @@ -122,7 +122,7 @@ LD_LIBRARY_PATH="$PWD/.local/php/usr/lib/x86_64-linux-gnu" \ Die Skripte erwarten die bekannten Dev-Umgebungsvariablen `DB_HOST`, `DB_NAME`, `DB_USER` und `DB_PASS`. -## Abgedeckte Testfaelle +## Abgedeckte Testfälle | Testfall | Fixture | | --- | --- | @@ -131,77 +131,77 @@ Die Skripte erwarten die bekannten Dev-Umgebungsvariablen `DB_HOST`, `DB_NAME`, | Negativer Saldo | `gm-negative@test.local` | | Nullsaldo | `gm-zero@test.local` | | Inaktives Mitglied | `gm-inactive@test.local` | -| PayPal-Name fuer CSV-Lookup | `gm-paypal@test.local` | +| PayPal-Name für CSV-Lookup | `gm-paypal@test.local` | | Mitglied ohne Buchungen | `gm-empty@test.local` | -| Vieltrinker fuer Vorderseite | `gm-heavy@test.local` | -| Aktiver Hinweis | `[GM] Aktiver Hinweis fuer Golden-Master-Test` | -| Abgelaufener Hinweis | `[GM] Abgelaufener Hinweis fuer Golden-Master-Test` | +| Vieltrinker für Vorderseite | `gm-heavy@test.local` | +| Aktiver Hinweis | `[GM] Aktiver Hinweis für Golden-Master-Test` | +| Abgelaufener Hinweis | `[GM] Abgelaufener Hinweis für Golden-Master-Test` | ## HTTP-Smoke-Abdeckung -Der HTTP-Smoke-Test prueft nur GET-Seiten ohne bekannte Schreib- oder +Der HTTP-Smoke-Test prüft nur GET-Seiten ohne bekannte Schreib- oder Versand-Nebenwirkungen. | Seite | Erwartung | | --- | --- | -| `index.php` | Dashboard laedt fuer `Test Admin` | -| `stricheintragen.php` | Stricherfassung laedt | -| `einzahlung.php` | Einzahlungserfassung laedt | -| `kaffeeliste.php` | Gesamtuebersicht laedt | -| `mitarbeiterverwalten.php` | Mitgliederverwaltung inkl. `PayPal-Name` laedt | +| `index.php` | Dashboard lädt für `Test Admin` | +| `stricheintragen.php` | Stricherfassung lädt | +| `einzahlung.php` | Einzahlungserfassung lädt | +| `kaffeeliste.php` | Gesamtübersicht lädt | +| `mitarbeiterverwalten.php` | Mitgliederverwaltung inkl. `PayPal-Name` lädt | | `letzteneintraege.php` | letzte Einzahlungen und Striche laden | -| `csvupload.php` | CSV-Upload-Formular laedt | -| `hinweise.php` | Hinweisverwaltung laedt | -| `faq.php` | FAQ laedt | -| `namenanpassen.php` | Namensanpassung laedt | -| `teilnehmerauswertung.php?user_id=1` | Teilnehmerauswertung fuer Dev-Admin laedt | -| `mailausgebe.php` | Mailadress-Ausgabe laedt | -| `umfrage.php` | geschlossene Umfrage laedt | -| `umfrageergebnisse.php` | Umfrageauswertung laedt | +| `csvupload.php` | CSV-Upload-Formular lädt | +| `hinweise.php` | Hinweisverwaltung lädt | +| `faq.php` | FAQ lädt | +| `namenanpassen.php` | Namensanpassung lädt | +| `teilnehmerauswertung.php?user_id=1` | Teilnehmerauswertung für Dev-Admin lädt | +| `mailausgebe.php` | Mailadress-Ausgabe lädt | +| `umfrage.php` | geschlossene Umfrage lädt | +| `umfrageergebnisse.php` | Umfrageauswertung lädt | ## Akzeptanzkriterien - Testdaten sind reproduzierbar. -- Tests koennen mehrfach laufen, ohne Duplikate zu erzeugen. -- Salden und Jahreswerte sind automatisch pruefbar. -- CSV-Importfaelle sind fachlich abgedeckt. +- Tests können mehrfach laufen, ohne Duplikate zu erzeugen. +- Salden und Jahreswerte sind automatisch prüfbar. +- CSV-Importfälle sind fachlich abgedeckt. - Die wichtigsten UI-Seiten liefern HTTP 200 ohne PHP-Warnings. - Seiten mit Schreib- oder Versand-Nebenwirkungen werden nicht automatisch per - GET ausgefuehrt, sondern als Risiko dokumentiert. + GET ausgeführt, sondern als Risiko dokumentiert. ## Gefundene Fehler und Bewertung -Im M1-Abschlusslauf wurden folgende Punkte geprueft: +Im M1-Abschlusslauf wurden folgende Punkte geprüft: - `number_format(null)` in `kaffeeliste.php`: behoben; leere Summen werden als `0` behandelt. - `paypalname` in der Mitgliederverwaltung: eingepflegt und im Golden Master abgedeckt. - `umfrage.php`: `mb_strtolower()` ist in der lokalen PHP-Umgebung nicht - verfuegbar; Fallback auf `strtolower()` ergaenzt. + verfügbar; Fallback auf `strtolower()` ergänzt. - `exportKaffeeliste.php`: Pfad auf `TCPDF/tcpdf.php` korrigiert. Der Export bleibt trotzdem als bekannter Dependency-Fehler offen, weil die TCPDF-Kopie im - Repo unvollstaendig ist und `TCPDF/include/tcpdf_font_data.php` fehlt. -- `mailversenden.php`: nicht automatisch per HTTP ausgefuehrt, weil ein GET bei - vollstaendiger PHPMailer-Installation E-Mails versenden kann. Zusaetzlich ist - die PHPMailer-Kopie im Repo unvollstaendig. -- `jahresauswertung.php`: nicht automatisch per HTTP ausgefuehrt, weil ein GET - Jahresbuchungen schreiben und E-Mails versenden kann. Zusaetzlich ist die - PHPMailer-Kopie im Repo unvollstaendig. + Repo unvollständig ist und `TCPDF/include/tcpdf_font_data.php` fehlt. +- `mailversenden.php`: nicht automatisch per HTTP ausgeführt, weil ein GET bei + vollständiger PHPMailer-Installation E-Mails versenden kann. Zusätzlich ist + die PHPMailer-Kopie im Repo unvollständig. +- `jahresauswertung.php`: nicht automatisch per HTTP ausgeführt, weil ein GET + Jahresbuchungen schreiben und E-Mails versenden kann. Zusätzlich ist die + PHPMailer-Kopie im Repo unvollständig. -## Aktueller Pruefstatus +## Aktueller Prüfstatus Stand 2026-07-12: - `scripts/seed-golden-master.php` erfolgreich gegen die MySQL-Dev-Datenbank - ausgefuehrt. -- `scripts/check-golden-master.php` erfolgreich ausgefuehrt. -- Zweiter Seed+Check-Lauf erfolgreich, Idempotenz bestaetigt. + ausgeführt. +- `scripts/check-golden-master.php` erfolgreich ausgeführt. +- Zweiter Seed+Check-Lauf erfolgreich, Idempotenz bestätigt. - Ergebnis: 104 Assertions bestanden. - `scripts/http-smoke.php` erfolgreich gegen `http://127.0.0.1:8080` - ausgefuehrt. + ausgeführt. - Ergebnis: 14 sichere Seiten bestanden ohne `Deprecated`, `Warning`, `Fatal error`, `Parse error`, `Notice` oder `Uncaught Error`. -- Bekannter offener Punkt: PDF-Export wegen unvollstaendiger TCPDF-Abhaengigkeit. -- Bewusst nicht automatisch ausgefuehrt: `mailversenden.php` und +- Bekannter offener Punkt: PDF-Export wegen unvollständiger TCPDF-Abhängigkeit. +- Bewusst nicht automatisch ausgeführt: `mailversenden.php` und `jahresauswertung.php`, da GET dort Nebenwirkungen haben kann. diff --git a/docs/m2-technical-foundation.md b/docs/m2-technical-foundation.md index 041fe00..5743aad 100644 --- a/docs/m2-technical-foundation.md +++ b/docs/m2-technical-foundation.md @@ -2,16 +2,16 @@ Stand: 2026-07-13 -M2 fuehrt die technischen Grundbausteine fuer den SaaS-Umbau ein, ohne das -Legacy-Verhalten oder das bestehende Design zu veraendern. +M2 führt die technischen Grundbausteine für den SaaS-Umbau ein, ohne das +Legacy-Verhalten oder das bestehende Design zu verändern. -Status: abgeschlossen fuer den M2-Scope. Bewusst ausgelagerte Themen sind unten -als Grenzen und M3-/M6-Uebergabe dokumentiert. +Status: abgeschlossen für den M2-Scope. Bewusst ausgelagerte Themen sind unten +als Grenzen und M3-/M6-Übergabe dokumentiert. ## Ziel -- Versionierte Datenbankmigrationen statt loser Schema-Ausfuehrung. -- Zentrales Bootstrap fuer Umgebung, Session und CSRF-Helper. +- Versionierte Datenbankmigrationen statt loser Schema-Ausführung. +- Zentrales Bootstrap für Umgebung, Session und CSRF-Helper. - Bestehende Legacy-Seiten bleiben kompatibel. - Layout-Trennung wird vorbereitet, aber noch nicht in bestehende Seiten hineingezogen. @@ -28,47 +28,47 @@ als Grenzen und M3-/M6-Uebergabe dokumentiert. - `app_csrf_field()` - `app_verify_csrf()` - `app_require_csrf()` -- `config.php` laedt den Bootstrap und startet die Session mit sicheren +- `config.php` lädt den Bootstrap und startet die Session mit sicheren Cookie-Optionen. -- Sessions werden standardmaessig unter `var/sessions` abgelegt, weil die +- Sessions werden standardmäßig unter `var/sessions` abgelegt, weil die lokale PHP-Umgebung keinen beschreibbaren Systempfad garantiert. `var/` ist - von Git ignoriert. Der Pfad kann ueber `APP_SESSION_PATH` ueberschrieben + von Git ignoriert. Der Pfad kann über `APP_SESSION_PATH` überschrieben werden. - CSRF ist bewusst noch nicht global erzwungen. Die vorhandenen POST-Seiten - werden spaeter einzeln umgestellt, damit keine Formulare oder Spezialflows + werden später einzeln umgestellt, damit keine Formulare oder Spezialflows brechen. ### CSRF-Rollout Erste Legacy-POST-Seiten sind opt-in abgesichert: -- `hinweise.php`: Hinweis anlegen und Hinweis loeschen. Der bisherige - GET-Loeschlink wurde durch ein POST-Formular mit CSRF-Token ersetzt. -- `mitarbeiterverwalten.php`: Mitglied anlegen, Bearbeitungsformular oeffnen, +- `hinweise.php`: Hinweis anlegen und Hinweis löschen. Der bisherige + GET-Löschlink wurde durch ein POST-Formular mit CSRF-Token ersetzt. +- `mitarbeiterverwalten.php`: Mitglied anlegen, Bearbeitungsformular öffnen, Mitglied speichern, aktivieren und deaktivieren. - `namenanpassen.php`: Anzeigenamen aktualisieren. - `index.php`: eigene Web-Striche eintragen. - `stricheintragen.php`: Sammelerfassung von Strichen. - `einzahlung.php`: Sammelerfassung von Einzahlungen. -- `letzteneintraege.php`: letzte Einzahlungen und Strich-Eintraege loeschen. +- `letzteneintraege.php`: letzte Einzahlungen und Strich-Einträge löschen. - `csvupload.php`: CSV-Zahlungsimport. Noch offen: - Spezialprozesse: `mailversenden.php`, `jahresauswertung.php`. -### CSV-Upload-Haertung +### CSV-Upload-Härtung - `csvupload.php` nutzt jetzt CSRF. - Uploads werden unter `var/uploads` gespeichert und nach der Verarbeitung - geloescht. Damit liegen importierte Dateien nicht mehr im Webroot. -- Dateiendung, Dateigroesse und MIME-Typ werden vor der Verarbeitung geprueft. + gelöscht. Damit liegen importierte Dateien nicht mehr im Webroot. +- Dateiendung, Dateigröße und MIME-Typ werden vor der Verarbeitung geprüft. - Hochgeladene Dateien bekommen serverseitig erzeugte Zufallsnamen. - CSV-Auswertungswerte werden HTML-escaped ausgegeben. - Die PayPal-Namenssuche nutzt `Name` und `paypalname` mit expliziter Parameterbindung. -Offen fuer M6: +Offen für M6: - Importvorschau vor dem Schreiben. - Import-Batch/Audit-Log. @@ -78,19 +78,19 @@ Offen fuer M6: - `database/migrations/0001_legacy_mysql_baseline.sql` bildet die bisherige MySQL-Dev-Baseline als erste versionierte Migration ab. -- `scripts/dev-db.php` verwaltet `schema_migrations` und fuehrt neue +- `scripts/dev-db.php` verwaltet `schema_migrations` und führt neue Migrationen idempotent aus. -- `scripts/migrate.php` ist der direkte Runner fuer Migrationen. +- `scripts/migrate.php` ist der direkte Runner für Migrationen. - `scripts/init-mysql-dev.php` nutzt ab jetzt ebenfalls die Migrationslogik. ### Layout - `header.php` und `footer.php` bleiben vorerst Legacy-Wrapper. -- Die spaetere Trennung in Public-Layout und App-Layout wird erst umgesetzt, +- Die spätere Trennung in Public-Layout und App-Layout wird erst umgesetzt, wenn die neue Route-/View-Struktur steht. -- Die bestehende HTML5-UP-Struktur, Sidebar und Assets bleiben unveraendert. +- Die bestehende HTML5-UP-Struktur, Sidebar und Assets bleiben unverändert. -## Ausfuehrung +## Ausführung Mit normaler PHP-CLI: @@ -111,43 +111,43 @@ LD_LIBRARY_PATH="$PWD/.local/php/usr/lib/x86_64-linux-gnu:$PWD/.local/php/usr/li ``` Die Skripte erwarten die bekannten Dev-Umgebungsvariablen `DB_HOST`, `DB_NAME`, -`DB_USER` und `DB_PASS`. `scripts/init-mysql-dev.php` braucht zusaetzlich +`DB_USER` und `DB_PASS`. `scripts/init-mysql-dev.php` braucht zusätzlich `DEV_AUTH_EMAIL`. -## Aktueller Pruefstatus +## Aktueller Prüfstatus - Migration `0001_legacy_mysql_baseline.sql` erfolgreich angewendet. - Zweiter Migrationslauf meldet: Datenbank ist aktuell. -- PHP-Syntax fuer Bootstrap, Migrationen, Init-Skript und Config ist sauber. -- Session-Start laeuft in der lokalen Dev-Umgebung ohne PHP-Warnings ueber +- PHP-Syntax für Bootstrap, Migrationen, Init-Skript und Config ist sauber. +- Session-Start läuft in der lokalen Dev-Umgebung ohne PHP-Warnings über `var/sessions`. - CSRF negative Tests: `hinweise.php`, `mitarbeiterverwalten.php` und `namenanpassen.php` liefern bei POST ohne Token HTTP 419. -- CSRF positive Tests: gueltige Token funktionieren fuer Hinweis-Anlage, - Mitglieder-Bearbeitungsformular und Namensanpassung. Der temporaere +- CSRF positive Tests: gültige Token funktionieren für Hinweis-Anlage, + Mitglieder-Bearbeitungsformular und Namensanpassung. Der temporäre Testhinweis wurde wieder entfernt. -- CSRF negative Tests fuer Buchungsflows: `index.php`, `stricheintragen.php` +- CSRF negative Tests für Buchungsflows: `index.php`, `stricheintragen.php` und `einzahlung.php` liefern bei POST ohne Token HTTP 419. -- CSRF positive Tests fuer Buchungsflows: gueltige Token funktionieren fuer - eigene Web-Striche, Sammelstriche und Sammeleinzahlungen. Die temporaeren +- CSRF positive Tests für Buchungsflows: gültige Token funktionieren für + eigene Web-Striche, Sammelstriche und Sammeleinzahlungen. Die temporären Testbuchungen wurden wieder entfernt. -- CSRF negative Tests fuer Korrektur-/Loeschflows: `letzteneintraege.php` +- CSRF negative Tests für Korrektur-/Löschflows: `letzteneintraege.php` liefert bei POST ohne Token HTTP 419. -- CSRF positive Tests fuer Korrektur-/Loeschflows: gueltige Token funktionieren - fuer das Loeschen temporaerer Einzahlungs- und Strich-Testeintraege. -- CSRF negative Test fuer CSV-Upload: POST ohne Token liefert HTTP 419. -- CSV-Upload positive Tests: gueltiges Token verarbeitet eine CSV-Datei, erkennt - eine PayPal-Alias-Dublette und hinterlaesst keine Datei in `var/uploads`. +- CSRF positive Tests für Korrektur-/Löschflows: gültige Token funktionieren + für das Löschen temporärer Einzahlungs- und Strich-Testeinträge. +- CSRF negative Test für CSV-Upload: POST ohne Token liefert HTTP 419. +- CSV-Upload positive Tests: gültiges Token verarbeitet eine CSV-Datei, erkennt + eine PayPal-Alias-Dublette und hinterlässt keine Datei in `var/uploads`. - CSV-Upload negative Tests: Nicht-CSV-Dateien werden abgewiesen. -- Golden Master weiterhin gruen mit 104 Assertions. -- HTTP-Smoke weiterhin gruen mit 23 sicheren Seiten inklusive Landingpage, Login, - Registrierung, Passwort-Reset, E-Mail-Verifikation und geschuetzter - Mandant-Einstellungen, geschuetzter Mandantenauswahl sowie Ledger-Preview. +- Golden Master weiterhin grün mit 104 Assertions. +- HTTP-Smoke weiterhin grün mit 23 sicheren Seiten inklusive Landingpage, Login, + Registrierung, Passwort-Reset, E-Mail-Verifikation und geschützter + Mandant-Einstellungen, geschützter Mandantenauswahl sowie Ledger-Preview. ## Bewusste Grenzen -- Keine Tenant-/User-/Rollen-Tabellen in M2. Diese gehoeren zu M3. -- Keine globale CSRF-Erzwingung fuer Spezialprozesse. `mailversenden.php` und +- Keine Tenant-/User-/Rollen-Tabellen in M2. Diese gehören zu M3. +- Keine globale CSRF-Erzwingung für Spezialprozesse. `mailversenden.php` und `jahresauswertung.php` werden in M6 als Jobs mit Dry-Run, Audit und Versandlog neu betrachtet. - Kein Layout-Umbau in M2. Die visuelle Struktur bleibt stabil; Public-/App- @@ -157,26 +157,26 @@ Die Skripte erwarten die bekannten Dev-Umgebungsvariablen `DB_HOST`, `DB_NAME`, ## Abschlusskriterien - Migrationsrunner ist vorhanden und idempotent. -- Bootstrap, Session und CSRF-Helper sind zentral verfuegbar. -- Die relevanten Legacy-Schreibseiten sind CSRF-geschuetzt. +- Bootstrap, Session und CSRF-Helper sind zentral verfügbar. +- Die relevanten Legacy-Schreibseiten sind CSRF-geschützt. - CSV-Uploads liegen nicht mehr im Webroot. - Bestehende Legacy-Seiten bleiben per HTTP-Smoke erreichbar. -- Golden-Master-Fachwerte bleiben unveraendert. +- Golden-Master-Fachwerte bleiben unverändert. -## Uebergabe an M3 +## Übergabe an M3 M3 startet mit additiven SaaS-Tabellen und einer Default-Tenant-Abbildung. Die -Legacy-Seiten sollen dabei weiterhin ueber die bestehenden Tabellen laufen, bis +Legacy-Seiten sollen dabei weiterhin über die bestehenden Tabellen laufen, bis der fachliche Kern in M4/M5 schrittweise auf das Zielmodell umgestellt wird. M3 wurde inzwischen gestartet. Umgesetzte Details stehen in -`docs/m3-saas-basis-vorbereitung.md`. Der urspruengliche Startpunkt war: +`docs/m3-saas-basis-vorbereitung.md`. Der ursprüngliche Startpunkt war: 1. `tenants`, `tenant_settings`, `users`, `tenant_memberships` und `participants` als neue Migration anlegen. -2. Einen Default-Tenant fuer die bestehende Kaffeeliste definieren. +2. Einen Default-Tenant für die bestehende Kaffeeliste definieren. 3. Bestehende `kl_Mitarbeiter` in `participants` spiegeln, inklusive `legacy_mitarbeiter_id`. 4. Admins aus `kl_Mitarbeiter.admin` als `tenant_memberships.role = 'admin'` - beziehungsweise fuer den ersten Hauptnutzer als `owner` abbilden. -5. Erst danach Login/Registrierung und Public-/App-Routen anschliessen. + beziehungsweise für den ersten Hauptnutzer als `owner` abbilden. +5. Erst danach Login/Registrierung und Public-/App-Routen anschließen. diff --git a/docs/m3-saas-basis-vorbereitung.md b/docs/m3-saas-basis-vorbereitung.md index 021295a..01c94dd 100644 --- a/docs/m3-saas-basis-vorbereitung.md +++ b/docs/m3-saas-basis-vorbereitung.md @@ -2,27 +2,27 @@ Stand: 2026-07-13 -M3 fuehrt Mandanten, Benutzer, Mitgliedschaften und Grundeinstellungen additiv -ein. Die bestehende Legacy-App bleibt dabei lauffaehig und wird noch nicht auf +M3 führt Mandanten, Benutzer, Mitgliedschaften und Grundeinstellungen additiv +ein. Die bestehende Legacy-App bleibt dabei lauffähig und wird noch nicht auf das neue Modell umgestellt. -Status: abgeschlossen fuer den M3-Scope. M4 startet mit der additiven +Status: abgeschlossen für den M3-Scope. M4 startet mit der additiven Migration von Einzahlungen und Kaffeeverbrauch nach `ledger_entries`. ## Ziel -- Einen Default-Tenant fuer den aktuellen Bestand erzeugen. +- Einen Default-Tenant für den aktuellen Bestand erzeugen. - Login-Benutzer und Kaffee-Teilnehmer fachlich trennen. - Rollen tenant-spezifisch vorbereiten. - Bestehende `kl_Mitarbeiter` ohne Datenverlust in `participants` spiegeln. -- Die Grundlage fuer Registrierung und Login schaffen, ohne die Legacy-Auth +- Die Grundlage für Registrierung und Login schaffen, ohne die Legacy-Auth sofort zu ersetzen. -## Nicht-Ziele fuer den ersten M3-Schritt +## Nicht-Ziele für den ersten M3-Schritt - Kein kompletter Login-Umbau in einem Schritt. - Keine Migration von Einzahlungen und Kaffeeverbrauch nach `ledger_entries`; - das gehoert zu M4. + das gehört zu M4. - Kein Design- oder Layout-Umbau. - Kein Billing und keine Tarife im ersten Schritt. - Kein produktiver Tenant-Wechsel in bestehenden Legacy-Seiten. @@ -47,7 +47,7 @@ Tabellen: - `participants` - `tenant_domains` -Ergaenzende Skripte: +Ergänzende Skripte: ```text scripts/backfill-default-tenant.php @@ -73,7 +73,7 @@ Wichtige Regeln: ## Default-Tenant -Fuer den Bestand wird ein erster Tenant angelegt: +Für den Bestand wird ein erster Tenant angelegt: ```text slug: default @@ -84,7 +84,7 @@ locale: de-DE currency_code: EUR ``` -Die Werte koennen spaeter in einer Tenant-Einstellungsseite angepasst werden. +Die Werte können später in einer Tenant-Einstellungsseite angepasst werden. ## Backfill @@ -98,9 +98,9 @@ Vorgang: 1. Default-Tenant anlegen oder laden. 2. `tenant_settings` aus `kl_config` erzeugen. -3. Fuer jede Zeile aus `kl_Mitarbeiter` einen `participant` anlegen oder +3. Für jede Zeile aus `kl_Mitarbeiter` einen `participant` anlegen oder aktualisieren. -4. Fuer aktive Admins optional einen `user` und eine `tenant_membership` +4. Für aktive Admins optional einen `user` und eine `tenant_membership` erzeugen. 5. `admin = 1` als Rolle `admin` abbilden; ein konfigurierter erster Benutzer kann Rolle `owner` erhalten. @@ -108,10 +108,10 @@ Vorgang: aus dem Default-Tenant entfernen. Der Backfill muss idempotent sein und darf keine bestehenden Legacy-Daten -loeschen. Geloescht werden nur SaaS-Spiegelungen, deren Legacy-Mitarbeiter in +löschen. Gelöscht werden nur SaaS-Spiegelungen, deren Legacy-Mitarbeiter in `kl_Mitarbeiter` nicht mehr existiert. -Ausgefuehrter Dev-Stand: +Ausgeführter Dev-Stand: - Default-Tenant `default` wurde angelegt. - 9 Legacy-Mitarbeiter wurden als `participants` gespiegelt. @@ -145,15 +145,15 @@ Umgesetzter Umfang: - Registrierung legt Tenant, Owner-User, Default-Settings, Membership und Owner-Participant in einer Transaktion an. -- Login prueft `users.password_hash`, aktive Membership und aktiven Tenant. +- Login prüft `users.password_hash`, aktive Membership und aktiven Tenant. - Hat ein User genau einen aktiven Mandanten, wird dieser direkt in die Session gelegt. -- Hat ein User mehrere aktive Mandanten, fuehrt der Login zur +- Hat ein User mehrere aktive Mandanten, führt der Login zur Mandantenauswahl. - Logout beendet die neue PHP-Login-Session. -- `konto.php` zeigt den aktuellen SaaS-Kontext fuer den angemeldeten User. -- `functions.php` akzeptiert eine SaaS-Login-Session als erste Identitaetsquelle, - laesst `DEV_AUTH_EMAIL` und `AUTH_USER` aber als Legacy-Fallback bestehen. +- `konto.php` zeigt den aktuellen SaaS-Kontext für den angemeldeten User. +- `functions.php` akzeptiert eine SaaS-Login-Session als erste Identitätsquelle, + lässt `DEV_AUTH_EMAIL` und `AUTH_USER` aber als Legacy-Fallback bestehen. - `footer.php` bleibt App-Sidebar und zeigt keine Public-Login- oder Registrierungslinks mehr. - Login, Registrierung, Passwort-Reset und E-Mail-Verifikation nutzen das @@ -161,7 +161,7 @@ Umgesetzter Umfang: - Passwort-Reset erzeugt Single-Use-Tokens und speichert nur Token-Hashes. - E-Mail-Verifikation erzeugt Single-Use-Tokens und setzt `users.email_verified_at`. -- Reset- und Verifikationslinks werden ueber `app/saas-mail.php` versendet. +- Reset- und Verifikationslinks werden über `app/saas-mail.php` versendet. Der Dev-Standard schreibt Mails nach `var/mail`; produktiv kann auf PHP `mail()` umgestellt werden. - Dev-Links werden weiterhin nur im Dev-Modus angezeigt, damit lokale Checks @@ -169,7 +169,7 @@ Umgesetzter Umfang: Noch offen im M3-Auth-Scope: -- Weitergehende Rollenmatrix fuer spaetere SaaS-Seiten. +- Weitergehende Rollenmatrix für spätere SaaS-Seiten. - Produktive SMTP-/Provider-Anbindung inklusive Bounce-/Fehlerprotokoll. ## Public-Landingpage @@ -184,35 +184,35 @@ assets/css/public.css Umgesetzter Umfang: -- Oeffentliche Landingpage ohne Legacy-DB-Zugriff. -- Hero mit generiertem Bild-Asset, bestehender Typografie und gruenem Akzent. +- Öffentliche Landingpage ohne Legacy-DB-Zugriff. +- Hero mit generiertem Bild-Asset, bestehender Typografie und grünem Akzent. - CTA zu Login und Registrierung. -- Login, Registrierung und oeffentliche Auth-Hilfsseiten sind optisch in den +- Login, Registrierung und öffentliche Auth-Hilfsseiten sind optisch in den Public-Bereich integriert. -- Kurzabschnitt zu Stricherfassung, Mandantenfaehigkeit und Webspace-Betrieb. -- Die geschuetzte App-Sidebar bleibt von der Public-Seite getrennt. +- Kurzabschnitt zu Stricherfassung, Mandantenfähigkeit und Webspace-Betrieb. +- Die geschützte App-Sidebar bleibt von der Public-Seite getrennt. -## Tenant-Aufloesung +## Tenant-Auflösung -Entscheidung fuer den Webspace-Betrieb: +Entscheidung für den Webspace-Betrieb: - Keine Wildcard-Subdomains im ersten Schritt. -- Primaere App-Adresse ist eine zentrale App-Domain wie `app.kaffeeliste.de`. -- Die Public-Seite kann ueber `kaffeeliste.de` beziehungsweise +- Primäre App-Adresse ist eine zentrale App-Domain wie `app.kaffeeliste.de`. +- Die Public-Seite kann über `kaffeeliste.de` beziehungsweise `www.kaffeeliste.de` laufen. -- Der aktive Mandant wird nach Login ueber `tenant_memberships` und die PHP- +- Der aktive Mandant wird nach Login über `tenant_memberships` und die PHP- Session gesetzt. - Bei genau einem Mandanten wird automatisch weitergeleitet. - Bei mehreren Mandanten nutzt der User `mandant-auswahl.php`. -- `tenant_domains` ist vorbereitet fuer spaeter gezielt eingerichtete feste - Domains oder Subdomains, aber nicht Voraussetzung fuer den Start. +- `tenant_domains` ist vorbereitet für später gezielt eingerichtete feste + Domains oder Subdomains, aber nicht Voraussetzung für den Start. Noch offen: - `APP_PRIMARY_HOST` in der Zielumgebung setzen. -- Optional `APP_PUBLIC_HOST` beziehungsweise Host-Rewrite fuer die Landingpage +- Optional `APP_PUBLIC_HOST` beziehungsweise Host-Rewrite für die Landingpage in der Zielumgebung definieren. -- Produktive Domain-/Zertifikatspruefung fuer einzelne feste Domains +- Produktive Domain-/Zertifikatsprüfung für einzelne feste Domains definieren. ## Rollen und Grundeinstellungen @@ -226,43 +226,43 @@ mandant-einstellungen.php Umgesetzter Umfang: - `saas_user_has_role()`, `saas_require_role()` und - `saas_can_manage_tenant_settings()` zentralisieren die erste Rollenpruefung. -- Owner und Admin duerfen Tenant-Grundeinstellungen bearbeiten. -- Die Seite bearbeitet Kundenname, Zeitzone, Locale, Waehrung, Preis pro + `saas_can_manage_tenant_settings()` zentralisieren die erste Rollenprüfung. +- Owner und Admin dürfen Tenant-Grundeinstellungen bearbeiten. +- Die Seite bearbeitet Kundenname, Zeitzone, Locale, Währung, Preis pro Strich, Web-Striche, PayPal-Link, Listenfenster und Schulden-Warnschwelle. - Geldwerte werden in der UI als Euro-Werte erfasst und weiterhin als Cent- Integer gespeichert. -- `konto.php` und die Sidebar verlinken die Einstellungen nur fuer passende +- `konto.php` und die Sidebar verlinken die Einstellungen nur für passende Rollen. ## Erste Akzeptanzkriterien -- Migrationen laufen mehrfach ohne Fehler: erfuellt. -- Default-Tenant existiert genau einmal: erfuellt. +- Migrationen laufen mehrfach ohne Fehler: erfüllt. +- Default-Tenant existiert genau einmal: erfüllt. - `tenant_settings` enthalten Preis pro Strich und bestehende PayPal-Optionen: - erfuellt. -- Jeder bestehende `kl_Mitarbeiter` hat genau einen `participant`: erfuellt. -- `participants.legacy_mitarbeiter_id` ist gesetzt: erfuellt. -- Admins werden als tenant-scoped Rolle abgebildet: erfuellt. -- Registrierung und Login funktionieren fuer einen neuen Test-Tenant: - erfuellt. -- Owner-/Admin-Grundeinstellungen koennen aktualisiert werden: erfuellt. + erfüllt. +- Jeder bestehende `kl_Mitarbeiter` hat genau einen `participant`: erfüllt. +- `participants.legacy_mitarbeiter_id` ist gesetzt: erfüllt. +- Admins werden als tenant-scoped Rolle abgebildet: erfüllt. +- Registrierung und Login funktionieren für einen neuen Test-Tenant: + erfüllt. +- Owner-/Admin-Grundeinstellungen können aktualisiert werden: erfüllt. - Passwort-Reset und E-Mail-Verifikation funktionieren mit Single-Use-Tokens: - erfuellt. + erfüllt. - Reset- und Verifikationslinks werden im Dev-/Testmodus als Mail-Log erzeugt: - erfuellt. -- Mandantenauswahl funktioniert fuer User mit mehreren Mandanten: erfuellt. -- Oeffentliche Landingpage ist per HTTP-Smoke erreichbar: erfuellt. -- Golden-Master und HTTP-Smoke bleiben gruen: erfuellt. + erfüllt. +- Mandantenauswahl funktioniert für User mit mehreren Mandanten: erfüllt. +- Öffentliche Landingpage ist per HTTP-Smoke erreichbar: erfüllt. +- Golden-Master und HTTP-Smoke bleiben grün: erfüllt. ## Risiken -| Risiko | Gegenmassnahme | +| Risiko | Gegenmaßnahme | | --- | --- | | Login-User und Kaffee-Teilnehmer werden vermischt | `users` und `participants` strikt getrennt halten | | Mehrfacher Backfill erzeugt Duplikate | Eindeutige Constraints und Upsert-Logik | | Legacy-App bricht durch neue Tabellen | M3 nur additiv, keine Legacy-Queries umstellen | -| Rollen werden global statt tenant-scoped | Rollen ausschliesslich in `tenant_memberships` speichern | +| Rollen werden global statt tenant-scoped | Rollen ausschließlich in `tenant_memberships` speichern | | Falsche Owner-Zuordnung | Owner per Env-Konfiguration oder manuell dokumentierter Entscheidung setzen | ## Empfohlene Reihenfolge @@ -270,24 +270,24 @@ Umgesetzter Umfang: 1. Migration `0002_saas_identity_tenants.sql` erstellen: erledigt. 2. Migration `0003_saas_auth_account_fields.sql` erstellen: erledigt. 3. `scripts/backfill-default-tenant.php` erstellen: erledigt. -4. Backfill gegen die Dev-Datenbank ausfuehren: erledigt. -5. Kontrollskript fuer Tenant/Participant/Role-Counts schreiben: erledigt. +4. Backfill gegen die Dev-Datenbank ausführen: erledigt. +5. Kontrollskript für Tenant/Participant/Role-Counts schreiben: erledigt. 6. Login-/Registrierungsrouten bauen: erledigt. 7. Auth-Flow-Kontrollskript schreiben: erledigt. -8. Zentrale Rollenpruefung und Mandant-Einstellungen bauen: erledigt. +8. Zentrale Rollenprüfung und Mandant-Einstellungen bauen: erledigt. 9. Settings-Flow-Kontrollskript schreiben: erledigt. 10. Migration `0004_saas_auth_tokens.sql` erstellen: erledigt. 11. Passwort-Reset und E-Mail-Verifikation bauen: erledigt. 12. Password-/E-Mail-Flow-Kontrollskript schreiben: erledigt. 13. Migration `0005_saas_tenant_resolution.sql` erstellen: erledigt. -14. Mandantenauswahl und zentrale Session-Aufloesung bauen: erledigt. +14. Mandantenauswahl und zentrale Session-Auflösung bauen: erledigt. 15. Tenant-Resolution-Kontrollskript schreiben: erledigt. -16. Golden-Master und HTTP-Smoke ausfuehren: erledigt. +16. Golden-Master und HTTP-Smoke ausführen: erledigt. 17. Mail-Transport-Abstraktion und Mail-Flow-Kontrollskript bauen: erledigt. 18. Public-Landingpage mit erstem Hero-Asset vorbereiten: erledigt. 19. M3-Abschlusscheck dokumentieren und M4-Datenmigration starten: erledigt. -## Uebergabe an M4 +## Übergabe an M4 M4 ist in `docs/m4-data-migration.md` dokumentiert. Der erste M4-Schritt ist bewusst additiv: diff --git a/docs/m4-data-migration.md b/docs/m4-data-migration.md index 4c87606..4e59f23 100644 --- a/docs/m4-data-migration.md +++ b/docs/m4-data-migration.md @@ -2,20 +2,20 @@ Stand: 2026-07-14 -M4 uebernimmt die finanznahen Legacy-Buchungen additiv in das neue +M4 übernimmt die finanznahen Legacy-Buchungen additiv in das neue tenant-sichere Ledger-Modell. Die bestehenden Legacy-Seiten lesen und schreiben -weiterhin die bisherigen `kl_*`-Tabellen; das Ledger dient zunaechst als -vergleichbare, pruefbare Zielstruktur. Erste App-Abfragen koennen nun ueber +weiterhin die bisherigen `kl_*`-Tabellen; das Ledger dient zunächst als +vergleichbare, prüfbare Zielstruktur. Erste App-Abfragen können nun über einen zentralen Ledger-Service gegen `ledger_entries` laufen. ## Ziel - `kl_Einzahlungen` nach `ledger_entries` spiegeln. - `kl_Kaffeeverbrauch` nach `ledger_entries` spiegeln. -- Legacy-IDs erhalten, damit Paritaet und spaetere Delta-Migration moeglich +- Legacy-IDs erhalten, damit Parität und spätere Delta-Migration möglich bleiben. -- Summen gegen den Golden Master pruefen. -- Keine bestehenden Legacy-Buchungen loeschen oder veraendern. +- Summen gegen den Golden Master prüfen. +- Keine bestehenden Legacy-Buchungen löschen oder verändern. ## Nicht-Ziele @@ -36,7 +36,7 @@ Neue Tabelle: - `ledger_entries` -Ergaenzende Skripte: +Ergänzende Skripte: ```text scripts/backfill-ledger-entries.php @@ -44,20 +44,20 @@ scripts/check-m4-ledger-migration.php scripts/check-m4-ledger-service.php ``` -Ergaenzende App-Dateien: +Ergänzende App-Dateien: ```text app/ledger.php ledger-preview.php ``` -Ausgefuehrter Dev-Stand: +Ausgeführter Dev-Stand: - Migration `0006_saas_ledger_entries.sql` wurde angewendet. - 9 Legacy-Einzahlungen wurden als `payment` gespiegelt. - 12 Legacy-Kaffeeverbrauch-Zeilen wurden als `consumption` gespiegelt. - Ein zweiter Backfill-Lauf blieb idempotent und erzeugte keine Dubletten. -- `app/ledger.php` stellt zentrale Abfragen fuer Tenant-Summen, +- `app/ledger.php` stellt zentrale Abfragen für Tenant-Summen, Teilnehmer-Summen, einzelne Teilnehmer und letzte Buchungen bereit. - `ledger-preview.php` zeigt eine read-only App-Vorschau auf Tenant-Summen, aktive Teilnehmer und die letzten Ledger-Buchungen. @@ -109,16 +109,16 @@ ledger_entries.legacy_id = VerbrauchID Verbrauch wird negativ gespeichert. Damit ergibt `SUM(amount_cents)` direkt den aktuellen Saldo eines Teilnehmers. -## Idempotenz und Aufraeumen +## Idempotenz und Aufräumen Das Backfill-Skript nutzt `tenant_id`, `legacy_table` und `legacy_id` als -eindeutige Quelle. Wiederholte Laeufe aktualisieren vorhandene Ledger-Zeilen. +eindeutige Quelle. Wiederholte Läufe aktualisieren vorhandene Ledger-Zeilen. -Fuer den Default-Tenant werden nur solche Legacy-Spiegelungen entfernt, deren -urspruengliche Legacy-Zeile nicht mehr existiert. Fachliche Daten werden dabei -nicht aus den `kl_*`-Tabellen geloescht. +Für den Default-Tenant werden nur solche Legacy-Spiegelungen entfernt, deren +ursprüngliche Legacy-Zeile nicht mehr existiert. Fachliche Daten werden dabei +nicht aus den `kl_*`-Tabellen gelöscht. -## Ausfuehrung +## Ausführung ```bash php scripts/backfill-default-tenant.php @@ -133,33 +133,33 @@ Installation aus `.local/` verwendet werden. ## Akzeptanzkriterien -- Migration `0006_saas_ledger_entries.sql` laeuft erfolgreich: erfuellt. -- Jede Legacy-Einzahlung hat genau eine Ledger-Zeile: erfuellt. -- Jeder Legacy-Kaffeeverbrauch hat genau eine Ledger-Zeile: erfuellt. -- Legacy-IDs sind je Tenant eindeutig: erfuellt. -- Einzahlungen sind positiv, Verbrauch ist negativ: erfuellt. -- Verbrauch behaelt Strichanzahl und Preis pro Strich: erfuellt. +- Migration `0006_saas_ledger_entries.sql` läuft erfolgreich: erfüllt. +- Jede Legacy-Einzahlung hat genau eine Ledger-Zeile: erfüllt. +- Jeder Legacy-Kaffeeverbrauch hat genau eine Ledger-Zeile: erfüllt. +- Legacy-IDs sind je Tenant eindeutig: erfüllt. +- Einzahlungen sind positiv, Verbrauch ist negativ: erfüllt. +- Verbrauch behält Strichanzahl und Preis pro Strich: erfüllt. - Web-Striche aus `Eintragsart = 2` bleiben als `source = legacy_web` - erkennbar: erfuellt. -- Ledger-Summen entsprechen dem Golden Master: erfuellt. + erkennbar: erfüllt. +- Ledger-Summen entsprechen dem Golden Master: erfüllt. - Zentrale Ledger-Abfragen liefern dieselben Teilnehmer-Summen wie der Golden - Master: erfuellt. + Master: erfüllt. - Tenant-Summen, aktive Teilnehmer, Einzelteilnehmer und letzte Buchungen sind - ueber `app/ledger.php` abrufbar: erfuellt. -- Read-only Ledger-Preview ist im Browser erreichbar: erfuellt. + über `app/ledger.php` abrufbar: erfüllt. +- Read-only Ledger-Preview ist im Browser erreichbar: erfüllt. -## Aktueller Pruefstatus +## Aktueller Prüfstatus -- M4 Ledger-Migration: gruen mit 73 Assertions. -- M4 Ledger-Service: gruen mit 110 Assertions. -- M3 SaaS-Basis: weiterhin gruen. -- M3 Tenant-Aufloesung: weiterhin gruen. -- M3 Passwort/E-Mail: weiterhin gruen. -- M3 Auth-Flow: weiterhin gruen. -- M3 Settings-Flow: weiterhin gruen. -- M3 Mail-Flow: weiterhin gruen. -- Golden Master: weiterhin gruen mit 104 Assertions. -- HTTP-Smoke: weiterhin gruen mit 23 geprueften Seiten inklusive +- M4 Ledger-Migration: grün mit 73 Assertions. +- M4 Ledger-Service: grün mit 110 Assertions. +- M3 SaaS-Basis: weiterhin grün. +- M3 Tenant-Auflösung: weiterhin grün. +- M3 Passwort/E-Mail: weiterhin grün. +- M3 Auth-Flow: weiterhin grün. +- M3 Settings-Flow: weiterhin grün. +- M3 Mail-Flow: weiterhin grün. +- Golden Master: weiterhin grün mit 104 Assertions. +- HTTP-Smoke: weiterhin grün mit 23 geprüften Seiten inklusive `ledger-preview.php`. ## Noch offen in M4 @@ -167,4 +167,4 @@ Installation aus `.local/` verwendet werden. - Tenant-sichere Dashboard-, Strich-, Einzahlungs- und Listenqueries schrittweise von Legacy-Tabellen auf das Ledger umstellen. - Storno-/Reversal-Modell in der UI statt harter Deletes. -- Delta-Strategie fuer den finalen Cutover. +- Delta-Strategie für den finalen Cutover. diff --git a/docs/m5-app-kern.md b/docs/m5-app-kern.md index e1d6d9b..faf10d4 100644 --- a/docs/m5-app-kern.md +++ b/docs/m5-app-kern.md @@ -4,13 +4,13 @@ Stand: 2026-07-14 M5 stellt die operativen App-Seiten schrittweise auf das neue tenant-sichere Modell um. Der Start erfolgt bewusst read-only, damit Summen, Links und -Darstellung gegen die bestehende Legacy-Oberflaeche vergleichbar bleiben. +Darstellung gegen die bestehende Legacy-Oberfläche vergleichbar bleiben. ## Ziel - Kernseiten aus `app/ledger.php` lesen lassen. -- Bestehendes Tabellenlayout und Bediengefuehl erhalten. -- Schreibende Legacy-Flows erst nach stabiler Leseparitaet umstellen. +- Bestehendes Tabellenlayout und Bediengefühl erhalten. +- Schreibende Legacy-Flows erst nach stabiler Leseparität umstellen. - Tenant-Kontext serverseitig bestimmen, nicht aus Formularfeldern. ## Umgesetzter erster Schritt @@ -23,18 +23,18 @@ kaffeeliste.php Umgesetzter Umfang: -- Die Gesamtuebersicht liest aktive Teilnehmer aus +- Die Gesamtübersicht liest aktive Teilnehmer aus `ledger_fetch_participant_summaries()`. - Angezeigte Werte bleiben fachlich gleich: aktueller Stand, Gesamtausgabe, Gesamtstriche und Gesamteinzahlungen. -- Links zur bestehenden `teilnehmerauswertung.php` bleiben ueber +- Links zur bestehenden `teilnehmerauswertung.php` bleiben über `participants.legacy_mitarbeiter_id` erhalten. -- Owner, Admin und Treasurer duerfen die SaaS-Ansicht lesen. +- Owner, Admin und Treasurer dürfen die SaaS-Ansicht lesen. - Der lokale Legacy-/Dev-Admin-Fallback nutzt nur ohne SaaS-Session den Default-Tenant. -- Die Sidebar zeigt Legacy-Schreibseiten weiterhin nur fuer Legacy-Admins; - Ledger-Leseansichten sind fuer passende SaaS-Rollen sichtbar. -- Export, letzte Eintraege, CSV-Upload und Info-Mail bleiben noch Legacy-Flows. +- Die Sidebar zeigt Legacy-Schreibseiten weiterhin nur für Legacy-Admins; + Ledger-Leseansichten sind für passende SaaS-Rollen sichtbar. +- Export, letzte Einträge, CSV-Upload und Info-Mail bleiben noch Legacy-Flows. ## Noch offen @@ -44,9 +44,9 @@ Umgesetzter Umfang: Storno-/Reversal-Strategie vorbereiten. - Export, Mail und Jahresprozesse bleiben M6-Themen. -## Aktueller Pruefstatus +## Aktueller Prüfstatus -- M4 Ledger-Migration: gruen mit 73 Assertions. -- M4 Ledger-Service: gruen mit 110 Assertions. -- Golden Master: gruen mit 104 Assertions. -- HTTP-Smoke: gruen mit 23 geprueften Seiten. +- M4 Ledger-Migration: grün mit 73 Assertions. +- M4 Ledger-Service: grün mit 110 Assertions. +- Golden Master: grün mit 104 Assertions. +- HTTP-Smoke: grün mit 23 geprüften Seiten. diff --git a/docs/saas-umstrukturierungsplan.md b/docs/saas-umstrukturierungsplan.md index 169c1a1..c6b2f2c 100644 --- a/docs/saas-umstrukturierungsplan.md +++ b/docs/saas-umstrukturierungsplan.md @@ -3,28 +3,28 @@ Stand: 2026-07-13 Dieses Dokument beschreibt den geplanten Umbau der bestehenden Kaffeelisten-App zu -einer mehrkundenfaehigen SaaS-Anwendung mit oeffentlicher Landingpage, -Kundenregistrierung und geschuetzter App. Die bestehende Bedienlogik und das +einer mehrkundenfähigen SaaS-Anwendung mit öffentlicher Landingpage, +Kundenregistrierung und geschützter App. Die bestehende Bedienlogik und das visuelle Grunddesign sollen bewusst erhalten bleiben. ## Zielbild -- Mehrere Kunden koennen eigene Kaffeelisten betreiben. +- Mehrere Kunden können eigene Kaffeelisten betreiben. - Jeder Kunde hat isolierte Daten, Einstellungen, Mitglieder und Buchungen. -- Neue Kunden koennen sich ueber eine oeffentliche Landingpage registrieren. +- Neue Kunden können sich über eine öffentliche Landingpage registrieren. - Die operative App bleibt optisch nah am aktuellen Bestand: Sidebar, Tabellen, schlichte Formulare, HTML5-UP-Anmutung. -- Authentifizierung, Rollen, Mandantenkontext und Sicherheitspruefungen werden +- Authentifizierung, Rollen, Mandantenkontext und Sicherheitsprüfungen werden zentralisiert. -- Finanznahe Vorgaenge werden nachvollziehbar und revisionsfreundlich +- Finanznahe Vorgänge werden nachvollziehbar und revisionsfreundlich gespeichert. -## Nicht-Ziele fuer den ersten Umbau +## Nicht-Ziele für den ersten Umbau - Kein kompletter Design-Relaunch. -- Keine verspielte Marketing-App statt der bestehenden Arbeitsoberflaeche. -- Kein gleichzeitiger Neubau aller Randmodule, wenn diese fuer den MVP nicht - benoetigt werden. +- Keine verspielte Marketing-App statt der bestehenden Arbeitsoberfläche. +- Kein gleichzeitiger Neubau aller Randmodule, wenn diese für den MVP nicht + benötigt werden. - Kein Dual-Write zwischen Legacy und neuer App als Standardbetrieb. - Keine Mandanten-ID aus Formularfeldern oder URL-Parametern als alleinige Sicherheitsbasis. @@ -35,12 +35,12 @@ Die aktuelle App ist eine flache PHP/sqlsrv-Legacy-App im Webroot. Wichtige Bereiche: -- `index.php`: persoenliches Dashboard. +- `index.php`: persönliches Dashboard. - `stricheintragen.php`: Sammelerfassung von Kaffee-Strichen. - `einzahlung.php`: Sammelerfassung von Einzahlungen. -- `kaffeeliste.php`: Gesamtuebersicht. +- `kaffeeliste.php`: Gesamtübersicht. - `mitarbeiterverwalten.php`: Mitglieder- und Adminpflege. -- `letzteneintraege.php`: Korrektur beziehungsweise Loeschung letzter Buchungen. +- `letzteneintraege.php`: Korrektur beziehungsweise Löschung letzter Buchungen. - `csvupload.php`: Zahlungsimport. - `exportKaffeeliste.php`: PDF-/Listenexport. - `mailversenden.php`: Massenmail. @@ -49,7 +49,7 @@ Wichtige Bereiche: Zentrale technische Beobachtungen: -- Authentifizierung haengt an Windows/IIS `AUTH_USER` und LDAP. +- Authentifizierung hängt an Windows/IIS `AUTH_USER` und LDAP. - Die Mailadresse des Nutzers wird in `functionsLDAP.php` ermittelt. - Rollen liegen als Boolean `admin` direkt auf `kl_Mitarbeiter`. - Datenzugriff findet direkt in den einzelnen PHP-Seiten per `sqlsrv_query` @@ -66,23 +66,23 @@ mit einem stabilen SaaS-Fundament: 1. Bestand dokumentieren und fachliche Ergebnisse einfrieren. 2. Mandantenmodell, Auth und Rollen sauber aufbauen. -3. Bestehende Fachlogik schrittweise tenant-sicher uebernehmen. +3. Bestehende Fachlogik schrittweise tenant-sicher übernehmen. 4. Landingpage und App-Shell trennen, ohne das App-Design neu zu erfinden. -So bleibt die vertraute Kaffeelisten-Oberflaeche erhalten, waehrend die -Datenbasis und Sicherheit SaaS-faehig werden. +So bleibt die vertraute Kaffeelisten-Oberfläche erhalten, während die +Datenbasis und Sicherheit SaaS-fähig werden. ## Zielarchitektur ### Public-Bereich -Der Public-Bereich ist ohne Login erreichbar und laedt keine Mandantendaten. +Der Public-Bereich ist ohne Login erreichbar und lädt keine Mandantendaten. Empfohlene Routen: - `/`: Landingpage. -- `/preise` oder spaeter `/pricing`: optional, falls Tarife eingefuehrt werden. -- `/faq`: oeffentliche FAQ oder FAQ-Auszug. +- `/preise` oder später `/pricing`: optional, falls Tarife eingeführt werden. +- `/faq`: öffentliche FAQ oder FAQ-Auszug. - `/registrieren` beziehungsweise aktuell `register.php`: Kundenregistrierung. - `/login` beziehungsweise aktuell `login.php`: Login. - `/passwort-vergessen` beziehungsweise aktuell `passwort-vergessen.php`: @@ -91,16 +91,16 @@ Empfohlene Routen: Landingpage-Inhalte: - Hero mit Name `Kaffeeliste` und kurzer Nutzenbeschreibung. -- Drei Kernablaeufe: Kaffee nehmen, Strich setzen, bei Bedarf bezahlen. +- Drei Kernabläufe: Kaffee nehmen, Strich setzen, bei Bedarf bezahlen. - Kurzer Blick auf Funktionen: Mitglieder, Guthaben, Einzahlungen, Export, Hinweise. - App-Screenshot oder Demo-Ansicht im bestehenden Stil. - FAQ-Auszug. - Call-to-Action zu Registrierung und Login. -### Geschuetzte App +### Geschützte App -Die geschuetzte App bleibt die operative Arbeitsoberflaeche. +Die geschützte App bleibt die operative Arbeitsoberfläche. Empfohlene Routen: @@ -109,8 +109,8 @@ Empfohlene Routen: - `/app/striche`: Eigene Striche erfassen, falls erlaubt. - `/app/einzahlungen`: Zahlungen und PayPal-Optionen. - `/app/mitglieder`: Mitgliederverwaltung. -- `/app/liste`: Gesamtuebersicht. -- `/app/buchungen`: Letzte Eintraege und Korrekturen. +- `/app/liste`: Gesamtübersicht. +- `/app/buchungen`: Letzte Einträge und Korrekturen. - `/app/importe`: CSV-Importe. - `/app/export/pdf`: PDF-/Listenexport. - `/app/hinweise`: Hinweise. @@ -118,29 +118,29 @@ Empfohlene Routen: Die App sollte eine Sidebar behalten, aber besser gruppiert werden: -- Persoenlich: Meine Kaffeeliste, Namensanpassung, FAQ. +- Persönlich: Meine Kaffeeliste, Namensanpassung, FAQ. - Erfassung: Striche, Einzahlungen. - Auswertung: Kaffeeliste, Buchungen, Export. - Administration: Mitglieder, Hinweise, Einstellungen, Importe. - Konto: Kundenkonto und Logout. Public-Links wie Login und Registrierung - gehoeren nicht in die App-Sidebar. + gehören nicht in die App-Sidebar. ### Webspace- und Host-Strategie -Empfohlen fuer den Start: +Empfohlen für den Start: -- `kaffeeliste.de` oder `www.kaffeeliste.de` fuer Landingpage, Registrierung +- `kaffeeliste.de` oder `www.kaffeeliste.de` für Landingpage, Registrierung und Login. -- `app.kaffeeliste.de` fuer die geschuetzte App. -- Keine Wildcard-Subdomains fuer Kunden. -- Mandantenauswahl nach Login ueber Session und `tenant_memberships`. -- Kundeneigene feste Domains oder Subdomains erst spaeter gezielt einrichten, - wenn DNS und Zertifikat pro Domain sauber geprueft sind. +- `app.kaffeeliste.de` für die geschützte App. +- Keine Wildcard-Subdomains für Kunden. +- Mandantenauswahl nach Login über Session und `tenant_memberships`. +- Kundeneigene feste Domains oder Subdomains erst später gezielt einrichten, + wenn DNS und Zertifikat pro Domain sauber geprüft sind. -Damit bleibt der Betrieb webspace-tauglich: Fuer den Start reichen zwei feste -Hosts mit normalen Let's-Encrypt-Zertifikaten. Die fachliche Tenant-Aufloesung +Damit bleibt der Betrieb webspace-tauglich: Für den Start reichen zwei feste +Hosts mit normalen Let's-Encrypt-Zertifikaten. Die fachliche Tenant-Auflösung ist in M3 vorbereitet; produktive Host-Rewrites, Cookie-Domain und Zertifikats- -Details gehoeren zur M8-Betriebshaertung. +Details gehören zur M8-Betriebshärtung. ## Datenmodell @@ -218,9 +218,9 @@ Wichtige Modellierungsregeln: - `users` sind Login-Konten. - `participants` sind Kaffee-Teilnehmer. - Ein Teilnehmer kann, muss aber nicht, ein Login-Konto haben. -- Rollen gehoeren in `tenant_memberships`, nicht direkt auf Teilnehmer. -- Buchungen sollten nicht hart geloescht werden. -- Korrekturen laufen ueber Storno- oder Reversal-Eintraege. +- Rollen gehören in `tenant_memberships`, nicht direkt auf Teilnehmer. +- Buchungen sollten nicht hart gelöscht werden. +- Korrekturen laufen über Storno- oder Reversal-Einträge. - Legacy-IDs werden bei Migration gespeichert, damit Ergebnisse vergleichbar bleiben. - Geldwerte sollten als Cent-Integer gespeichert werden, nicht als Float. @@ -229,7 +229,7 @@ Wichtige Modellierungsregeln: Empfohlene Rollen: -- `owner`: Kunde verwalten, Billing, Admins, Loeschung, Grundeinstellungen. +- `owner`: Kunde verwalten, Billing, Admins, Löschung, Grundeinstellungen. - `admin`: Mitglieder, Hinweise, fachliche Einstellungen, Auswertungen. - `treasurer`: Zahlungen, CSV-Import, Korrekturen, Exporte, Mails. - `member`: eigenes Dashboard, eigene Striche, eigener Anzeigename. @@ -246,22 +246,22 @@ SaaS-Basis: - E-Mail-Verifikation. - Passwort-Reset. - Sichere Session-Cookies. -- CSRF-Schutz fuer alle schreibenden Aktionen. -- Rate-Limits fuer Login, Registrierung und Passwort-Reset. +- CSRF-Schutz für alle schreibenden Aktionen. +- Rate-Limits für Login, Registrierung und Passwort-Reset. - Zentrale Funktionen oder Middleware: `requireLogin`, `requireTenant`, `requireRole`, `csrfToken`. -Tenant-Aufloesung: +Tenant-Auflösung: -- Primaer serverseitig aus Subdomain, Custom Domain oder tenantgebundener +- Primär serverseitig aus Subdomain, Custom Domain oder tenantgebundener Auswahl nach Login. - Nicht allein aus Hidden Inputs oder frei manipulierbaren IDs. - Jede fachliche Query braucht einen Tenant-Scope. -Spaeter moeglich: +Später möglich: - LDAP/AD oder SSO pro Kunde als optionaler Identity Provider. -- MFA fuer Owner/Admins. +- MFA für Owner/Admins. - Row-Level-Security in der Datenbank. ## Design-Leitplanken @@ -270,12 +270,12 @@ Das bestehende Design soll erhalten bleiben. Beibehalten: -- Gruener Akzent `#38761d`. -- Weiss/Grau als ruhige Grundflaeche. -- Roboto Slab fuer Ueberschriften. -- Open Sans fuer Fliesstext. -- Sidebar fuer die geschuetzte App. -- Tabellen als primaere Darstellung fuer operative Daten. +- Grüner Akzent `#38761d`. +- Weiß/Grau als ruhige Grundfläche. +- Roboto Slab für Überschriften. +- Open Sans für Fließtext. +- Sidebar für die geschützte App. +- Tabellen als primäre Darstellung für operative Daten. - Schlichte Formularfelder und Buttons. Verbessern ohne Relaunch: @@ -283,38 +283,38 @@ Verbessern ohne Relaunch: - Hinweise als wiederverwendbare Komponente statt Inline-Style. - Einheitliche Erfolgs-, Fehler- und Warnmeldungen. - Dashboardwerte als kompakte Statusbereiche. -- Aktionsleisten ueber Tabellen. +- Aktionsleisten über Tabellen. - Sidebar-Gruppierung und aktive Navigation. -- FAQ strukturieren, aber Inhalte nicht stark veraendern. +- FAQ strukturieren, aber Inhalte nicht stark verändern. Nicht tun: - Kein komplett neues Farbsystem. - Keine dekorative Marketingoptik in der App. -- Keine App-Tabellen in Kartenlandschaften aufloesen. -- Keine Navigationsstruktur, die die heutigen Kernablaeufe versteckt. +- Keine App-Tabellen in Kartenlandschaften auflösen. +- Keine Navigationsstruktur, die die heutigen Kernabläufe versteckt. ## Meilensteinplan -Uebersicht: +Übersicht: | Meilenstein | Schwerpunkt | Hauptergebnis | | --- | --- | --- | | M0 | Baseline | Bestand, Sicherheit und Designreferenz sind dokumentiert | -| M1 | Golden Master | Legacy-Ergebnisse sind als Vergleichsbasis eingefroren; HTTP-Smoke prueft sichere Seiten | +| M1 | Golden Master | Legacy-Ergebnisse sind als Vergleichsbasis eingefroren; HTTP-Smoke prüft sichere Seiten | | M2 | Technisches Fundament | Abgeschlossen: Migrationen, Bootstrap, Session, CSRF-Helper und Legacy-Schreibseitenschutz stehen | | M3 | SaaS-Basis | Abgeschlossen: Tenants, User, Registrierung, Login, Rollen, Mail-Links und zentrale Mandantenauswahl funktionieren | -| M4 | Datenmigration | Gestartet: Ledger-Tabelle, Legacy-Backfill, Paritaetscheck, Ledger-Service und Preview sind umgesetzt | -| M5 | App-Kern | Gestartet: Gesamtuebersicht liest read-only aus dem Ledger | +| M4 | Datenmigration | Gestartet: Ledger-Tabelle, Legacy-Backfill, Paritätscheck, Ledger-Service und Preview sind umgesetzt | +| M5 | App-Kern | Gestartet: Gesamtübersicht liest read-only aus dem Ledger | | M6 | Betriebsflows | Import, Export, Mail und Jahresprozesse sind auditierbar | -| M7 | Landingpage | Public-Seite und Auth-Seiten sind im gemeinsamen Stil nutzbar; spaetere Ausbaustufen folgen | -| M8 | Haertung | Betrieb, Datenschutz, Monitoring und Isolation sind geprueft | +| M7 | Landingpage | Public-Seite und Auth-Seiten sind im gemeinsamen Stil nutzbar; spätere Ausbaustufen folgen | +| M8 | Härtung | Betrieb, Datenschutz, Monitoring und Isolation sind geprüft | | M9 | Cutover | Produktivumstellung ist vorbereitet und Legacy ist read-only | ### M0: Planungs- und Sicherheitsbaseline Ziel: -Den aktuellen Zustand verlaesslich dokumentieren, bevor umgebaut wird. +Den aktuellen Zustand verlässlich dokumentieren, bevor umgebaut wird. Arbeitsartefakte: @@ -331,7 +331,7 @@ Schritte: - Tabellen, Spalten, Indizes und Constraints dokumentieren. - Bekannte Jobs/Skripte erfassen, zum Beispiel Mailversand und Jahresauswertung. - Secrets inventarisieren und rotieren, insbesondere hart codierte Zugangsdaten. -- Bestehende Seiten und UI-Zustaende per Screenshots festhalten. +- Bestehende Seiten und UI-Zustände per Screenshots festhalten. - Fachliche Kernregeln dokumentieren: Saldo, Jahreswerte, Preis pro Strich, 100-Tage-Listen, CSV-Deduplizierung, PDF-Ausgabe. @@ -342,7 +342,7 @@ Ergebnis: - Designreferenz. - Liste kritischer Sicherheitsrisiken. -Abhaengigkeiten: +Abhängigkeiten: - Zugriff auf echte oder anonymisierte Datenbank. - Kenntnis der Produktivumgebung. @@ -350,7 +350,7 @@ Abhaengigkeiten: ### M1: Golden-Master-Validierung Ziel: -Sicherstellen, dass spaetere neue Berechnungen dieselben Ergebnisse wie der +Sicherstellen, dass spätere neue Berechnungen dieselben Ergebnisse wie der Bestand liefern. Schritte: @@ -359,42 +359,42 @@ Schritte: Master in der MySQL-Dev-Datenbank. - Pro Mitglied berechnen: Gesamteinzahlungen, Gesamtausgaben, Gesamtstriche, aktueller Stand, Jahreswerte. Erledigt mit `scripts/check-golden-master.php`. -- CSV-Importfaelle sammeln: Treffer, Dubletten, unbekannte Namen. Erledigt im +- CSV-Importfälle sammeln: Treffer, Dubletten, unbekannte Namen. Erledigt im Golden-Master-Check. -- Testfaelle fuer Guthaben, Schulden, Nullsaldo und inaktive Teilnehmer +- Testfälle für Guthaben, Schulden, Nullsaldo und inaktive Teilnehmer anlegen. Erledigt. -- Sichere GET-Seiten per HTTP-Smoke pruefen. Erledigt mit +- Sichere GET-Seiten per HTTP-Smoke prüfen. Erledigt mit `scripts/http-smoke.php`. - PDF-/Export-Summen als Referenz sichern. Offen, weil die TCPDF-Kopie im Repo - unvollstaendig ist. + unvollständig ist. Ergebnis: - Golden-Master-Daten. - Vergleichsqueries oder Vergleichsskript. -- HTTP-Smoke-Test fuer sichere UI-Seiten. -- Akzeptanzkriterien fuer Migration und neue App. -- Dokumentierte offene Punkte: PDF-Export/TCPDF, PHPMailer-Abhaengigkeit, +- HTTP-Smoke-Test für sichere UI-Seiten. +- Akzeptanzkriterien für Migration und neue App. +- Dokumentierte offene Punkte: PDF-Export/TCPDF, PHPMailer-Abhängigkeit, GET-Nebenwirkungen bei Mailversand und Jahresauswertung. -Abhaengigkeiten: +Abhängigkeiten: - M0 abgeschlossen. - PDF-/Mail-/Jahresprozesse werden in M6 gezielt neu gestaltet, statt sie in M1 - per GET-Smoke auszufuehren. + per GET-Smoke auszuführen. ### M2: Technisches Fundament Ziel: -Eine saubere Basis fuer App, Public-Seiten, Auth und Mandanten schaffen. +Eine saubere Basis für App, Public-Seiten, Auth und Mandanten schaffen. Schritte: - Projektstruktur festlegen: Public-Routes, App-Routes, Views/Templates, Services/Repositories. -- Zentrales Bootstrap fuer Config, DB-Verbindung, Session und Fehlerbehandlung. +- Zentrales Bootstrap für Config, DB-Verbindung, Session und Fehlerbehandlung. Begonnen mit `app/bootstrap.php`. -- Versionierte Migrationen einfuehren. Begonnen mit +- Versionierte Migrationen einführen. Begonnen mit `database/migrations/0001_legacy_mysql_baseline.sql` und `scripts/migrate.php`. - Layouts trennen: Public-Layout und App-Layout. Noch offen; Header/Footer @@ -405,36 +405,36 @@ Schritte: abgesichert: `hinweise.php`, `mitarbeiterverwalten.php`, `namenanpassen.php`, `index.php`, `stricheintragen.php`, `einzahlung.php`, `letzteneintraege.php`, `csvupload.php`. -- CSV-Upload ausserhalb des Webroots speichern. In M2 als Legacy-Haertung - umgesetzt: temporaer unter `var/uploads`, Dateityp-/Groessenpruefung und - Loeschung nach Verarbeitung. +- CSV-Upload außerhalb des Webroots speichern. In M2 als Legacy-Härtung + umgesetzt: temporär unter `var/uploads`, Dateityp-/Größenprüfung und + Löschung nach Verarbeitung. - Konfigurationswerte aus Code in Umgebung oder Settings verschieben. Ergebnis: -- Grundgeruest fuer neue SaaS-App. -- Kein fachlicher Rewrite, aber klare Struktur fuer die Migration. +- Grundgerüst für neue SaaS-App. +- Kein fachlicher Rewrite, aber klare Struktur für die Migration. - Dokumentation: `docs/m2-technical-foundation.md`. -- Status: abgeschlossen fuer den M2-Scope. +- Status: abgeschlossen für den M2-Scope. -Abhaengigkeiten: +Abhängigkeiten: -- Entscheidung, ob PHP nativ weitergefuehrt oder ein Framework genutzt wird. +- Entscheidung, ob PHP nativ weitergeführt oder ein Framework genutzt wird. - M2 bleibt bewusst ohne Tenant-/User-/Rollen-Tabellen; diese starten in M3. ### M3: Mandanten, Registrierung und Login Ziel: -Mehrkundenfaehigkeit und Kunden-Onboarding technisch aktivieren. +Mehrkundenfähigkeit und Kunden-Onboarding technisch aktivieren. Schritte: -- Tabellen fuer `tenants`, `users`, `tenant_memberships` und +- Tabellen für `tenants`, `users`, `tenant_memberships` und `tenant_settings` anlegen. Vorbereitung dokumentiert in `docs/m3-saas-basis-vorbereitung.md`: erster Schritt erledigt. -- Zusaetzlich `participants` als getrennte Kaffee-Teilnehmer-Tabelle anlegen: +- Zusätzlich `participants` als getrennte Kaffee-Teilnehmer-Tabelle anlegen: erledigt. -- Default-Tenant fuer den aktuellen Bestand anlegen: erledigt. +- Default-Tenant für den aktuellen Bestand anlegen: erledigt. - Bestehende `kl_Mitarbeiter` idempotent in `participants` spiegeln: erledigt. - Registrierung: Tenant + Owner-User + Default-Settings erzeugen: erster @@ -442,10 +442,10 @@ Schritte: - Login und Logout bauen: erster Flow erledigt. - Passwort-Reset und E-Mail-Verifikation bauen: Dev-Flow mit Single-Use-Tokens und Mail-Transport-Abstraktion erledigt. -- Tenant-Aufloesung definieren: zentrale App-Domain mit Session-Kontext und +- Tenant-Auflösung definieren: zentrale App-Domain mit Session-Kontext und Mandantenauswahl erledigt; feste Domains vorbereitet, keine Wildcards. -- Rollenpruefung zentralisieren: erster Owner/Admin-Check erledigt. -- Erste Admin-/Owner-Seite fuer Grundeinstellungen: erledigt. +- Rollenprüfung zentralisieren: erster Owner/Admin-Check erledigt. +- Erste Admin-/Owner-Seite für Grundeinstellungen: erledigt. - Erste Public-Landingpage mit CTA zu Login und Registrierung: erledigt. - Login, Registrierung, Passwort-Reset und E-Mail-Verifikation im Public-Stil: erledigt. @@ -454,51 +454,51 @@ Schritte: Ergebnis: - Ein neuer Kunde kann sich registrieren und in seine eigene App gelangen. -- Rollen und Tenant-Kontext sind serverseitig verfuegbar. -- Reset- und Verifikationslinks koennen im Dev-Modus geloggt und produktiv ueber +- Rollen und Tenant-Kontext sind serverseitig verfügbar. +- Reset- und Verifikationslinks können im Dev-Modus geloggt und produktiv über einen konfigurierten Mail-Transport versendet werden. -- Status: abgeschlossen fuer den M3-Scope. +- Status: abgeschlossen für den M3-Scope. -Abhaengigkeiten: +Abhängigkeiten: - M2 abgeschlossen. ### M4: Migration des fachlichen Kerns Ziel: -Bestehende Kaffeelisten-Daten tenant-sicher uebernehmen. +Bestehende Kaffeelisten-Daten tenant-sicher übernehmen. Schritte: -- Initialen Tenant fuer den bisherigen Bestand anlegen: erledigt in M3. +- Initialen Tenant für den bisherigen Bestand anlegen: erledigt in M3. - `kl_Mitarbeiter` nach `participants` migrieren: erledigt in M3. -- `admin`-Informationen in `tenant_memberships` oder Admin-Rollen ueberfuehren: +- `admin`-Informationen in `tenant_memberships` oder Admin-Rollen überführen: erledigt in M3. - `kl_config` nach `tenant_settings` migrieren: erledigt in M3. - `ledger_entries` als tenant-sichere Buchungstabelle anlegen: erledigt. - `kl_Einzahlungen` und `kl_Kaffeeverbrauch` additiv nach `ledger_entries` spiegeln: erster Backfill erledigt. -- Legacy-IDs speichern: erledigt ueber `legacy_table` und `legacy_id`. +- Legacy-IDs speichern: erledigt über `legacy_table` und `legacy_id`. - Salden gegen Golden-Master vergleichen: Kontrollskript erledigt. -- Ledger-Service fuer Tenant-Summen, Teilnehmer-Summen und letzte Buchungen: +- Ledger-Service für Tenant-Summen, Teilnehmer-Summen und letzte Buchungen: erledigt. -- Read-only Ledger-Preview fuer Browservergleich: erledigt. +- Read-only Ledger-Preview für Browservergleich: erledigt. Ergebnis: - Bestehender Datenbestand kann im neuen Modell abgebildet werden. -- Saldenparitaet ist ueber `scripts/check-m4-ledger-migration.php` +- Saldenparität ist über `scripts/check-m4-ledger-migration.php` nachweisbar. -- Erste App-Abfragen koennen ueber `app/ledger.php` tenant-sicher aus dem neuen +- Erste App-Abfragen können über `app/ledger.php` tenant-sicher aus dem neuen Modell lesen. - `ledger-preview.php` zeigt die neue Ledger-Auswertung ohne Schreibzugriffe. - Dokumentation: `docs/m4-data-migration.md`. -Abhaengigkeiten: +Abhängigkeiten: - M1 und M3 abgeschlossen. -### M5: Geschuetzte App-Funktionen +### M5: Geschützte App-Funktionen Ziel: Die operativen Kernseiten im neuen Modell bereitstellen. @@ -509,9 +509,9 @@ Schritte: - Eigene Stricherfassung umsetzen. - Zahlungs-/PayPal-Bereich umsetzen. - Mitgliederverwaltung tenant- und rollenbasiert umsetzen. -- Gesamtuebersicht umsetzen: erster read-only Stand in `kaffeeliste.php` +- Gesamtübersicht umsetzen: erster read-only Stand in `kaffeeliste.php` erledigt. -- Letzte Eintraege und Korrekturen als Storno statt Delete umsetzen. +- Letzte Einträge und Korrekturen als Storno statt Delete umsetzen. - Hinweise als tenant-spezifische Notices umsetzen. Ergebnis: @@ -520,7 +520,7 @@ Ergebnis: - App sieht weiterhin nach bestehender Kaffeeliste aus. - Erster M5-Stand ist in `docs/m5-app-kern.md` dokumentiert. -Abhaengigkeiten: +Abhängigkeiten: - M4 abgeschlossen. @@ -531,8 +531,8 @@ Admin- und Treasurer-Flows produktionsreif machen. Schritte: -- CSV-Import mit Vorschau, Dublettenpruefung und Audit bauen. -- Uploads ausserhalb des Webroots speichern. +- CSV-Import mit Vorschau, Dublettenprüfung und Audit bauen. +- Uploads außerhalb des Webroots speichern. - PDF-/Listenexport aus neuem Datenmodell bauen. - Mailversand als nachvollziehbaren Versandjob mit Dry-Run und Versandlog gestalten. @@ -540,22 +540,22 @@ Schritte: Ergebnis: -- Kassenverwaltung ist fuer reale Betriebsablaeufe vollstaendig. +- Kassenverwaltung ist für reale Betriebsabläufe vollständig. - Import/Export/Mail sind auditierbar. -Abhaengigkeiten: +Abhängigkeiten: -- M5 fuer die Kernansichten. +- M5 für die Kernansichten. -### M7: Oeffentliche Landingpage +### M7: Öffentliche Landingpage Ziel: -Werbliche Einstiegseite und Registrierung verfuegbar machen, ohne die App-Optik +Werbliche Einstiegseite und Registrierung verfügbar machen, ohne die App-Optik zu verwischen. Schritte: -- Public-Layout mit bestehender Typografie und gruenem Akzent bauen. Erster +- Public-Layout mit bestehender Typografie und grünem Akzent bauen. Erster Stand als `landing.php` und `assets/css/public.css` erledigt. - Landingpage-Inhalte erstellen. Erster Stand erledigt. - Demo-Screenshot oder Demo-Ansicht einbinden. @@ -568,26 +568,26 @@ Schritte: Ergebnis: -- Interessenten verstehen das Produkt und koennen sich registrieren. -- Bestehende App bleibt optisch eigenstaendig und arbeitsorientiert. +- Interessenten verstehen das Produkt und können sich registrieren. +- Bestehende App bleibt optisch eigenständig und arbeitsorientiert. -Abhaengigkeiten: +Abhängigkeiten: -- M3 fuer Registrierung. -- M5 fuer echte App-Screens oder Demo. +- M3 für Registrierung. +- M5 für echte App-Screens oder Demo. -### M8: Haertung, Datenschutz und Betrieb +### M8: Härtung, Datenschutz und Betrieb Ziel: -Die SaaS-App fuer mehrere Kunden sicher betreiben. +Die SaaS-App für mehrere Kunden sicher betreiben. Schritte: - Backups und Restore-Prozess definieren. - Monitoring und Fehlerlogging einrichten. -- Audit-Log fuer Admin-Aktionen pruefen. +- Audit-Log für Admin-Aktionen prüfen. - Datenexport pro Tenant. -- Loesch-/Anonymisierungsprozess fuer Teilnehmer und Kunden. +- Lösch-/Anonymisierungsprozess für Teilnehmer und Kunden. - Rate-Limits und Security Headers. - Mandanten-Isolation testen. - Rollenmatrix testen. @@ -596,7 +596,7 @@ Ergebnis: - SaaS ist betrieblich und datenschutzseitig belastbarer. -Abhaengigkeiten: +Abhängigkeiten: - M3 bis M6. @@ -607,10 +607,10 @@ Produktive Umstellung ohne Datenverlust. Schritte: -- Legacy fuer Schreibzugriffe sperren. +- Legacy für Schreibzugriffe sperren. - Finalen Delta-Export ziehen. -- Migration ausfuehren. -- Rowcounts, Salden, PDF-Stichproben und Importhistorie pruefen. +- Migration ausführen. +- Rowcounts, Salden, PDF-Stichproben und Importhistorie prüfen. - DNS oder Reverse Proxy umschalten. - Legacy 30 bis 90 Tage read-only als Archiv behalten. - Rollback-Fenster und Vorgehen dokumentieren. @@ -618,15 +618,15 @@ Schritte: Ergebnis: - Neuer SaaS-Betrieb ist live. -- Alter Bestand bleibt fuer Rueckfragen lesbar. +- Alter Bestand bleibt für Rückfragen lesbar. -Abhaengigkeiten: +Abhängigkeiten: - M8 abgeschlossen. ## Empfohlene MVP-Reihenfolge -Fuer den ersten produktnahen MVP sollten nicht alle Randmodule gleichzeitig +Für den ersten produktnahen MVP sollten nicht alle Randmodule gleichzeitig umgebaut werden. MVP-Paket: @@ -634,12 +634,12 @@ MVP-Paket: 1. Tenant, User, Login, Registrierung. 2. Mail-Links, zentrale Mandantenauswahl und erste Landingpage. 3. Teilnehmer, Settings, Ledger. -4. Dashboard, Striche, Einzahlungen, Gesamtuebersicht. +4. Dashboard, Striche, Einzahlungen, Gesamtübersicht. 5. Mitgliederverwaltung. 6. Hinweise. 7. CSV-Import, Export. -Spaeter: +Später: - Umfrage-Modul. - SSO/LDAP pro Kunde. @@ -650,7 +650,7 @@ Spaeter: ## Validierung -Fachliche Pruefungen: +Fachliche Prüfungen: - Saldo je Teilnehmer alt gegen neu. - Jahreswerte alt gegen neu. @@ -659,37 +659,37 @@ Fachliche Pruefungen: - Export-Summen alt gegen neu. - CSV-Import: identische Treffer- und Dublettenlogik. -Sicherheitspruefungen: +Sicherheitsprüfungen: - Fremde Tenant-IDs liefern keine Daten. - Fremde Teilnehmer-IDs liefern keine Daten. - Admin-Funktionen sind ohne Rolle blockiert. - Alle POST-Aktionen brauchen CSRF. -- Uploads sind nicht direkt ausfuehrbar. +- Uploads sind nicht direkt ausführbar. - Ausgabe von Namen, Mails und Hinweisen ist escaped. -UX-Pruefungen: +UX-Prüfungen: - Kernseiten bleiben optisch wiedererkennbar. -- Sidebar bleibt fuer App-Nutzer vertraut. +- Sidebar bleibt für App-Nutzer vertraut. - Landingpage zeigt keine App-Adminnavigation. - Mobile Darstellung bleibt bedienbar. - Tabellen bleiben lesbar. -## Risiken und Gegenmassnahmen +## Risiken und Gegenmaßnahmen -| Risiko | Gegenmassnahme | +| Risiko | Gegenmaßnahme | | --- | --- | | Tenant-Leak durch vergessene Query-Filter | Zentrale Repository-/Query-Schicht, Tests mit zwei Tenants | | Falsche Salden nach Migration | Golden-Master-Vergleich vor Cutover | -| Harte Deletes verlieren Audit-Historie | Storno-/Reversal-Modell fuer Buchungen | +| Harte Deletes verlieren Audit-Historie | Storno-/Reversal-Modell für Buchungen | | Login und Teilnehmer werden vermischt | `users` und `participants` strikt trennen | | Bestehendes Design driftet weg | Designreferenz und App-Komponenten definieren | -| CSV-Upload unsicher | Upload ausserhalb Webroot, Dateityppruefung, Importvorschau | +| CSV-Upload unsicher | Upload außerhalb Webroot, Dateitypprüfung, Importvorschau | | Mailversand nicht nachvollziehbar | Versandlog, Dry-Run, Job-Status | -| Unvollstaendige Vendor-Kopien fuer PDF/Mail | Dependencies sauber vendoren oder ersetzen, Smoke-Tests danach erweitern | -| AD/LDAP blockiert SaaS-Onboarding | E-Mail/Passwort als Basis, SSO spaeter optional | -| Kein DB-Schema im Repo | Schema exportieren und Migrationen einfuehren | +| Unvollständige Vendor-Kopien für PDF/Mail | Dependencies sauber vendoren oder ersetzen, Smoke-Tests danach erweitern | +| AD/LDAP blockiert SaaS-Onboarding | E-Mail/Passwort als Basis, SSO später optional | +| Kein DB-Schema im Repo | Schema exportieren und Migrationen einführen | ## Offene Entscheidungen @@ -703,9 +703,9 @@ UX-Pruefungen: - Braucht der MVP schon Tarife/Billing oder erstmal nur Registrierung? - Sollen bestehende Kunden per Einladung oder per Self-Service onboarden? -## Naechster konkreter Arbeitsschritt +## Nächster konkreter Arbeitsschritt -Als naechstes sollte M0 gestartet werden: +Als nächstes sollte M0 gestartet werden: 1. Produktiv-/Testdatenbankschema exportieren. 2. Screenshot-Referenz der wichtigsten Seiten erstellen. diff --git a/email-verifikation-senden.php b/email-verifikation-senden.php index 45504a4..0b91189 100644 --- a/email-verifikation-senden.php +++ b/email-verifikation-senden.php @@ -15,7 +15,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { if ($result['ok']) { if (!empty($result['already_verified'])) { - $message = 'Die E-Mail-Adresse ist bereits bestaetigt.'; + $message = 'Die E-Mail-Adresse ist bereits bestätigt.'; } else { $message = 'Der Verifizierungslink wurde vorbereitet.'; if (saas_should_show_auth_links() && !empty($result['token'])) { @@ -61,7 +61,7 @@ include 'nav.php';

diff --git a/email-verifizieren.php b/email-verifizieren.php index 68cbe5d..8483831 100644 --- a/email-verifizieren.php +++ b/email-verifizieren.php @@ -6,7 +6,7 @@ $pdo = app_db_pdo(); $token = trim((string)($_GET['token'] ?? '')); $result = $token !== '' ? saas_verify_email_token($pdo, $token) - : ['ok' => false, 'errors' => ['Der Link ist ungueltig oder abgelaufen.']]; + : ['ok' => false, 'errors' => ['Der Link ist ungültig oder abgelaufen.']]; ?> @@ -32,14 +32,14 @@ $result = $token !== ''

E-Mail verifizieren

-

Bestaetige deine Adresse, damit dein Kundenkonto vollstaendig eingerichtet ist.

+

Bestätige deine Adresse, damit dein Kundenkonto vollständig eingerichtet ist.

Status

-

Die E-Mail-Adresse wurde bestaetigt.

+

Die E-Mail-Adresse wurde bestätigt.

diff --git a/konto.php b/konto.php index b2533a3..42bdf69 100644 --- a/konto.php +++ b/konto.php @@ -43,7 +43,7 @@ include 'nav.php'; - Kundenkuerzel + Kundenkürzel @@ -51,7 +51,7 @@ include 'nav.php'; - E-Mail bestaetigt + E-Mail bestätigt diff --git a/landing.php b/landing.php index 06af1a8..c7eabc9 100644 --- a/landing.php +++ b/landing.php @@ -19,7 +19,7 @@

Kaffeeliste

-

Die digitale Kaffeekasse fuer Teams, Bueros und Vereine: Striche, Einzahlungen und offene Betraege bleiben nachvollziehbar an einem Ort.

+

Die digitale Kaffeekasse für Teams, Büros und Vereine: Striche, Einzahlungen und offene Beträge bleiben nachvollziehbar an einem Ort.

  • Kundenkonto anlegen
  • Zur App
  • @@ -37,12 +37,12 @@

    Teilnehmer und Admins behalten Verbrauch, Einzahlungen und Salden im Blick.

    -

    Mandantenfaehig

    +

    Mandantenfähig

    Jeder Kunde arbeitet in seinem eigenen Bereich mit eigenen Einstellungen.

    Webspace-tauglich

    -

    Der Start erfolgt ueber eine zentrale App-Adresse mit Login und Mandantenauswahl.

    +

    Der Start erfolgt über eine zentrale App-Adresse mit Login und Mandantenauswahl.

diff --git a/ledger-preview.php b/ledger-preview.php index 6e95abb..07fb0e7 100644 --- a/ledger-preview.php +++ b/ledger-preview.php @@ -71,7 +71,7 @@ include 'nav.php';

Kein Zugriff.

- Read-only Vorschau aus ledger_entries fuer + Read-only Vorschau aus ledger_entries für (). Die bestehenden App-Seiten schreiben weiterhin in die Legacy-Tabellen. diff --git a/login.php b/login.php index 49d22be..33c1f60 100644 --- a/login.php +++ b/login.php @@ -56,7 +56,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {

Login

-

Melde dich mit deinem Kundenkonto an. Wenn du mehreren Mandanten zugeordnet bist, waehlst du danach den passenden Bereich aus.

+

Melde dich mit deinem Kundenkonto an. Wenn du mehreren Mandanten zugeordnet bist, wählst du danach den passenden Bereich aus.

@@ -86,7 +86,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
- +
diff --git a/mandant-auswahl.php b/mandant-auswahl.php index 181b41a..7ea026e 100644 --- a/mandant-auswahl.php +++ b/mandant-auswahl.php @@ -19,7 +19,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') { $identity = $tenantId > 0 ? saas_identity_for_user_tenant($pdo, $pendingUserId, $tenantId) : null; if ($identity === null) { - $errors[] = 'Dieser Mandant ist fuer dein Konto nicht verfuegbar.'; + $errors[] = 'Dieser Mandant ist für dein Konto nicht verfügbar.'; } else { saas_session_login($identity); header('Location: konto.php'); @@ -34,7 +34,7 @@ include 'nav.php';