Deutsche Umlaute in UI und Dokumentation korrigieren

This commit is contained in:
2026-07-14 22:11:33 +02:00
parent f9544f24fd
commit 539117b409
31 changed files with 561 additions and 564 deletions
+12 -12
View File
@@ -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.
+18 -18
View File
@@ -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.
+36 -36
View File
@@ -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.
+5 -6
View File
@@ -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;
+14 -15
View File
@@ -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?
+1 -2
View File
@@ -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;
+14 -14
View File
@@ -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-<rolle>-<seite>-<viewport>.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.
+18 -18
View File
@@ -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.
+54 -54
View File
@@ -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.
+53 -53
View File
@@ -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.
+61 -61
View File
@@ -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:
+39 -39
View File
@@ -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.
+14 -14
View File
@@ -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.
+151 -151
View File
@@ -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.