- mitarbeiterverwalten.php war rein ueber Legacy-Admin gesperrt und haette neue SaaS-Mandanten ausgeschlossen; jetzt Rollen-/Legacy-Fallback wie in kaffeeliste.php (owner/admin). - Anlegen/Bearbeiten/Aktivieren/Deaktivieren spiegeln transaktional nach participants (ledger_mirror_legacy_participant neu ergaenzt), damit Ledger-Ansichten sofort den aktuellen Mitgliederstand zeigen. - Gespeicherte XSS-Luecke behoben: Name/E-Mail waren in Formular und Liste ungeschuetzt ausgegeben, jetzt ueber saas_html(). - Admin-Rollenvergabe bleibt bewusst Legacy-only (kein automatischer Login-Account ohne Einladungsflow); dokumentiert als offener Punkt. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
190 lines
7.9 KiB
Markdown
190 lines
7.9 KiB
Markdown
# M5 App-Kern
|
|
|
|
Stand: 2026-07-14 (fortgeführt)
|
|
|
|
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-Oberfläche vergleichbar bleiben.
|
|
|
|
## Ziel
|
|
|
|
- Kernseiten aus `app/ledger.php` lesen lassen.
|
|
- Bestehendes Tabellenlayout und Bediengefühl erhalten.
|
|
- Schreibende Legacy-Flows erst nach stabiler Leseparität umstellen.
|
|
- Tenant-Kontext serverseitig bestimmen, nicht aus Formularfeldern.
|
|
|
|
## Umgesetzte Schritte
|
|
|
|
Umgesetzte Dateien:
|
|
|
|
```text
|
|
kaffeeliste.php
|
|
teilnehmerauswertung.php
|
|
index.php
|
|
```
|
|
|
|
Umgesetzter Umfang `kaffeeliste.php`:
|
|
|
|
- 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 über
|
|
`participants.legacy_mitarbeiter_id` erhalten.
|
|
- 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 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.
|
|
|
|
Umgesetzter Umfang `teilnehmerauswertung.php`:
|
|
|
|
- Die Detailauswertung liest Teilnehmerdaten über
|
|
`ledger_fetch_participant_summary_by_legacy_id()`.
|
|
- Die Route bleibt kompatibel zu bestehenden Links:
|
|
`teilnehmerauswertung.php?user_id=<legacy_mitarbeiter_id>`.
|
|
- Gesamtwerte, Jahresübersicht und letzte Buchungen werden aus
|
|
`ledger_entries` geladen.
|
|
- PayPal-Anzeige nutzt die neuen Tenant-Settings statt `kl_config`.
|
|
- Owner, Admin und Treasurer dürfen die SaaS-Ansicht lesen; der lokale
|
|
Legacy-/Dev-Admin-Fallback nutzt weiterhin den Default-Tenant.
|
|
|
|
Ergänzte Ledger-Helfer:
|
|
|
|
- `ledger_fetch_default_tenant()`
|
|
- `ledger_fetch_participant_summary_by_legacy_id()`
|
|
- `ledger_mirror_legacy_consumption()`
|
|
- Filter `legacy_mitarbeiter_ids` in `ledger_fetch_participant_summaries()`
|
|
|
|
Umgesetzter Umfang `index.php`:
|
|
|
|
- Das persönliche Dashboard liest den aktuellen Stand, Jahreswerte und letzte
|
|
Buchungen aus `ledger_entries`.
|
|
- Die Teilnehmerzuordnung erfolgt über den aktuellen SaaS-User oder im lokalen
|
|
Legacy-/Dev-Fallback über die E-Mail-Adresse des Legacy-Mitarbeiters.
|
|
- PayPal-Anzeige und Preis pro Strich nutzen die Tenant-Settings.
|
|
- Eigene Web-Striche bleiben mit dem bestehenden Legacy-Datensatz kompatibel
|
|
und werden direkt ins Ledger gespiegelt.
|
|
|
|
## Fortsetzung: Schreibseiten und Storno
|
|
|
|
Umgesetzte Dateien:
|
|
|
|
```text
|
|
stricheintragen.php
|
|
einzahlung.php
|
|
letzteneintraege.php
|
|
app/ledger.php
|
|
scripts/check-m4-ledger-migration.php
|
|
```
|
|
|
|
Umgesetzter Umfang `stricheintragen.php` und `einzahlung.php`:
|
|
|
|
- Beide Sammelerfassungsseiten waren zuvor ohne jede Zugriffsprüfung
|
|
erreichbar (nur CSRF-Schutz, kein `checkKaffeelisteAdmin`- oder Rollen-Check).
|
|
Das ist jetzt behoben: Zugriff erfordert SaaS-Rolle `owner`, `admin` oder
|
|
`treasurer`, oder im Legacy-/Dev-Fallback `checkKaffeelisteAdmin` mit dem
|
|
Default-Tenant.
|
|
- Jede eingetragene Legacy-Zeile (`kl_Kaffeeverbrauch` beziehungsweise
|
|
`kl_Einzahlungen`) wird innerhalb derselben Transaktion sofort über
|
|
`ledger_mirror_legacy_consumption()` beziehungsweise die neue
|
|
`ledger_mirror_legacy_payment()` ins Ledger gespiegelt. Schlägt die
|
|
Spiegelung fehl, wird die gesamte Sammelerfassung zurückgerollt statt
|
|
teilweise gespeichert zu werden.
|
|
- Ein vorbestehender Bug wurde nebenbei behoben: Bei einer POST-Anfrage blieb
|
|
`$sqlMitarbeiter` unbelegt, was einen PHP-Warning erzeugte und die
|
|
Mitarbeiterliste nach dem Speichern leer ließ.
|
|
|
|
Umgesetzter Umfang `letzteneintraege.php`:
|
|
|
|
- Der Seitenzugriff nutzte bisher ausschließlich den Legacy-Check
|
|
`checkKaffeelisteAdmin`, wodurch neu registrierte SaaS-Mandanten (ohne
|
|
Legacy-`kl_Mitarbeiter`-Zeile) die Seite nie hätten nutzen können. Jetzt gilt
|
|
dieselbe Rollen-/Fallback-Logik wie in `kaffeeliste.php`.
|
|
- Löschen erzeugt keinen harten Delete im Ledger mehr. Neue Funktion
|
|
`ledger_void_entry_by_legacy_id()` setzt `voided_at` auf dem gespiegelten
|
|
Ledger-Eintrag, bevor die Legacy-Zeile aus `kl_Einzahlungen` oder
|
|
`kl_Kaffeeverbrauch` entfernt wird (in einer Transaktion). Der Ledger-Eintrag
|
|
bleibt damit für die Revision erhalten; alle Lesepfade filtern bereits
|
|
konsistent auf `voided_at IS NULL`.
|
|
- Zwei nie aufgerufene Funktionen (`berechneGesamtausgabe`,
|
|
`berechneGesamtstriche`, `berechneGesamteinzahlungen`) wurden als toten Code
|
|
entfernt.
|
|
|
|
Angepasstes Check-Skript:
|
|
|
|
- `scripts/check-m4-ledger-migration.php` ging bisher davon aus, dass jeder
|
|
gespiegelte Ledger-Eintrag eine noch existierende Legacy-Zeile hat. Das ist
|
|
durch das Storno-Modell nicht mehr korrekt: Ein stornierter Eintrag hat
|
|
absichtlich keine Legacy-Zeile mehr, bleibt aber im Ledger stehen. Die
|
|
Prüfungen filtern jetzt zusätzlich auf `voided_at IS NULL`, sodass echte
|
|
Dateninkonsistenzen weiterhin erkannt werden, stornierte Einträge aber nicht
|
|
mehr als Fehler zählen.
|
|
|
|
Alle drei Flows wurden gegen die Remote-Dev-Datenbank live per HTTP getestet
|
|
(Sammeleintrag Striche, Sammeleinzahlung, Storno beider Buchungsarten über
|
|
`letzteneintraege.php`) und anschließend wieder auf den Ausgangsstand
|
|
zurückgesetzt.
|
|
|
|
## Fortsetzung: Mitgliederverwaltung
|
|
|
|
Umgesetzte Dateien:
|
|
|
|
```text
|
|
mitarbeiterverwalten.php
|
|
app/ledger.php
|
|
```
|
|
|
|
Umfang:
|
|
|
|
- Zugriff nutzte bisher ausschließlich `checkKaffeelisteAdmin` und hätte neue
|
|
SaaS-Mandanten ohne Legacy-Mitarbeiterzeile ausgeschlossen. Jetzt gilt die
|
|
gleiche Rollen-/Fallback-Logik wie in `kaffeeliste.php`, mit den Rollen
|
|
`owner` und `admin` (nicht `treasurer`, da Mitgliederpflege sensibler ist
|
|
als reine Zahlungsvorgänge).
|
|
- Anlegen, Bearbeiten, Aktivieren und Deaktivieren schreiben weiterhin zuerst
|
|
in `kl_Mitarbeiter` und spiegeln danach in derselben Transaktion über die
|
|
neue Funktion `ledger_mirror_legacy_participant()` nach `participants`.
|
|
Ledger-Ansichten (Dashboard, Kaffeeliste, Teilnehmerauswertung) sehen neue
|
|
oder geänderte Mitglieder damit sofort, ohne auf einen manuellen Lauf von
|
|
`scripts/backfill-default-tenant.php` zu warten.
|
|
- Eine gespeicherte-XSS-Lücke wurde behoben: Name und E-Mail wurden beim
|
|
Bearbeiten-Formular und in der Mitgliederliste bisher ungeschützt
|
|
ausgegeben (nur `paypalname` war escaped). Beide Stellen nutzen jetzt
|
|
`saas_html()`.
|
|
- Live gegen die Dev-Datenbank getestet: Anlegen mit einem
|
|
HTML/Skript-Payload im Namen (korrekt escaped in der Ausgabe, korrekt
|
|
gespiegelt in `participants`), Deaktivieren (spiegelt `active = 0`).
|
|
|
|
Bewusst nicht umgesetzt:
|
|
|
|
- Der Haken "Administrator" bleibt ein reines Legacy-Feld auf
|
|
`kl_Mitarbeiter.admin` und wird nicht automatisch in eine
|
|
`tenant_memberships`-Rolle übersetzt. Das würde einen Login-Account ohne
|
|
Einladung/Passwort-Setzung anlegen, was ein eigenes, sauber zu
|
|
bauendes Einladungs-Flow braucht (E-Mail-Versand, Token, Passwortsetzung).
|
|
Admin-Rollen für neue SaaS-Nutzer laufen bis dahin weiter über
|
|
`scripts/backfill-default-tenant.php` oder die Registrierung.
|
|
|
|
## Noch offen
|
|
|
|
- Eigene PayPal-/Zahlungsbereich als eigenständiger App-Screen (aktuell nur im
|
|
Dashboard integriert).
|
|
- Einladungs-Flow, um bestehenden Teilnehmern nachträglich einen
|
|
Login-Account mit `tenant_memberships`-Rolle zuzuweisen.
|
|
- Hinweise als tenant-spezifische Notices umsetzen.
|
|
- Export, Mail und Jahresprozesse bleiben M6-Themen.
|
|
|
|
## Aktueller Prüfstatus
|
|
|
|
- M4 Ledger-Migration: grün mit 73 Assertions (Storno-fähig).
|
|
- M4 Ledger-Service: grün mit 115 Assertions.
|
|
- Golden Master: grün mit 104 Assertions.
|
|
- HTTP-Smoke: grün mit 23 geprüften Seiten.
|
|
- Live-Test der Schreibflows gegen die Dev-DB: Sammelstriche, Sammeleinzahlung
|
|
und Storno beider Buchungsarten erfolgreich geprüft.
|
|
- Live-Test der Mitgliederverwaltung gegen die Dev-DB: Anlegen (inklusive
|
|
XSS-Payload-Check), Deaktivieren, participants-Spiegelung erfolgreich
|
|
geprüft.
|