Bugfixes aus dem Code-Review:
- XSS: unescaptes $_SERVER['PHP_SELF'] in csvupload.php und
letzteneintraege.php durch feste Seitennamen ersetzt.
- Stripe-Webhook: Event-Deduplizierung (neue Tabelle stripe_webhook_events)
gegen doppelte Verarbeitung/Dolibarr-Rechnungen bei Retry-Zustellung.
- Stripe-Webhook: Tarifwechsel aus dem Kundenportal wird lokal nachgezogen
(plan_code aus dem Preis-lookup_key bei subscription.updated).
- Post-Redirect-Get fuer jahresauswertung, mailversenden und die
Selbst-Stricheintragung - verhindert Doppelbuchung/Doppelversand per
Browser-Refresh.
- Jahresbonus: Mails erst nach erfolgreichem Commit; Restcent-Ausgleich
beim letzten Empfaenger, damit die Summe exakt stimmt.
- Verschachtelte HTML-Dokumente in csvupload/einzahlung/stricheintragen
entfernt (Layout kommt aus header.php).
- Rate-Limit fuer den Versand von E-Mail-Verifizierungslinks.
Neue Funktionen:
- Mitglieder koennen ihren zuletzt selbst eingetragenen Strich wieder
stornieren (nur eigene Web-Eintraege, Kassenwart-Eintraege bleiben).
- Monatsuebersicht des eigenen Verbrauchs im Mitglieder-Dashboard.
- Automatische Zahlungserinnerung: opt-in pro Mandant ab der
Warnschwelle, mit Intervall; Cron-Skript scripts/send-payment-reminders.php.
- CSV-Import fuer Mitgliederlisten inkl. herunterladbarer Vorlage
(mitglieder-vorlage.php), Semikolon-/Komma- und BOM-Erkennung.
- Logo als PDF-Wasserzeichen pro Mandant (Upload in den Mandant-
Einstellungen, geschuetzt unter var/tenant_logos/, ersetzt den
Text-Wasserzeichen im Ausdruck).
Robusterer Teilnehmer-Lookup im Dashboard ueber user_id (Fallback E-Mail).
Der PDF-Export war bisher immer zweiseitig (Vieltrinker-/Wenigtrinker)
mit fester Mindestzeilenzahl, unabhängig von der tatsächlichen
Mitgliederzahl. Umgestellt auf:
- Bis 49 aktive Mitglieder: eine Seite ohne Trennung.
- Ab 50 Mitgliedern: weiterhin zwei Seiten (Vorder-/Rückseite).
- Zeilenhöhe richtet sich nach der Mitgliederzahl (16-40px), statt fest
16px für alle.
- Neue Mandanten-Einstellungen: freie Zeilen für neue Mitglieder an/aus,
Trennmodus bei zwei Seiten (Trinkverhalten oder alphabetisch).
Migration 0015 ergänzt die dafür nötigen tenant_settings-Spalten.
Gegen die Dev-DB verifiziert: 8 Mitglieder -> einseitiges PDF,
53 Mitglieder (temporäre Testdaten) -> zweiseitiges PDF, Einstellungen
inkl. Validierung geprüft.
Vorbereitung fuer Stripe Billing (Zahlungseinzug) + bestehendes Dolibarr
des Kunden (Rechnungsstellung/Buchhaltung) statt eines eigenen Rechnungs-
systems oder eines zusaetzlichen ERP nur fuer Kaffeeliste - Begruendung
in docs/billing.md.
- Neue Tabelle tenant_billing (plan_code, subscription_status, sowie
bereits vorbereitete, noch ungenutzte Felder fuer Stripe/Dolibarr-IDs).
- app/billing.php: billing_plans() als einzige Quelle der Tarifstufen
(synchron mit preise.php), billing_required_plan_code() anhand aktiver
Teilnehmerzahl, billing_check_tenant() vergleicht gebuchten mit
benoetigtem Tarif - rein informativ, kein Enforcement, solange Stripe
nicht angebunden ist.
- Neue Mandanten starten automatisch auf plan_code='free' bei der
Registrierung.
- mandant-einstellungen.php zeigt Owner/Admin ihren aktuellen Tarif und
Teilnehmerstand, mit Hinweis bei Bedarf einer hoeheren Stufe.
- Back-Office zeigt zusaetzlich zur Mandantenliste den gebuchten und
(falls abweichend) den tatsaechlich benoetigten Tarif.
Live getestet: Tarifgrenzen (10/25/50/150) mit einem Mandanten unter und
einem ueber dem Freikontingent geprueft, UI in Mandant-Einstellungen und
Back-Office verifiziert. Alle M8-Isolations-/Rollenmatrix-Tests weiterhin
gruen.
Phase 2 (Stripe) und Phase 3 (Dolibarr-Sync) folgen, sobald Test-Keys
beziehungsweise Sandbox-Zugang vorliegen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
faq.php zeigte bislang fuer jeden Mandanten denselben, komplett
AOK-spezifischen Inhalt (Kaffeemaschinen-Bedienung, interner
Ansprechpartner) - fuer andere Kunden unbrauchbar und inhaltlich falsch.
- Neue Tabelle faq_entries (tenant-scoped, Soft-Delete, sort_order).
- Migration uebernimmt die bisherigen AOK-Inhalte einmalig als FAQ des
migrierten Default-Mandanten; andere Mandanten sehen sie nicht.
- Neue Mandanten bekommen bei der Registrierung automatisch eine kurze
generische Starter-FAQ (faq_seed_default_entries), frei editierbar.
- faq.php: lesbar fuer alle angemeldeten Mitglieder eines Mandanten,
Anlegen/Bearbeiten/Entfernen auf owner/admin beschraenkt.
- Landingpage verweist nicht mehr auf faq.php (jetzt interner,
mandantengebundener Inhalt statt oeffentlicher Marketing-Seite).
Live getestet: AOK-Carry-over fuer Default-Mandant, frisch registrierter
Test-Mandant bekam isolierte generische Starter-FAQ, Anlegen mit
HTML-Payload (korrekt escaped), Bearbeiten und Soft-Delete geprueft.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Hinweise:
- Neue Tabelle notices (tenant-scoped, Soft-Delete via deleted_at) loest
die global unscoped kl_hinweise als aktive Datenquelle ab; Migration
uebernimmt einmalig aktuell gueltige kl_hinweise-Eintraege fuer den
Default-Mandanten. kl_hinweise bleibt als Golden-Master-Referenz stehen.
- hinweise.php und der Banner in header.php sind tenant-scoped umgestellt.
Mitgliederverwaltung:
- mitarbeiterverwalten.php verwaltet jetzt participants (tenant-scoped)
statt der global unscoped kl_Mitarbeiter-Tabelle als primaere Quelle.
Das behebt nebenbei ein Mandanten-Datenleck: jeder SaaS-Mandant mit
Owner/Admin-Rolle haette zuvor die komplette Default-Mandanten-
Mitgliederliste sehen und bearbeiten koennen.
- Fuer den Default-Mandanten bleibt Dual-Write nach kl_Mitarbeiter
bestehen, damit stricheintragen.php/einzahlung.php weiter funktionieren;
andere Mandanten werden rein participant-nativ verwaltet.
- Die Legacy-Administrator-Checkbox ist raus. Stattdessen kann ein Admin
je Mitglied unabhaengig von Name/E-Mail einen Login-Zugang mit Rolle
(member/treasurer/admin) gewaehren oder entziehen
(saas_grant_participant_access / saas_revoke_participant_access).
Einladung laeuft ueber den bestehenden Passwort-Reset-Mechanismus,
Entzug setzt die Mitgliedschaft auf revoked statt sie zu loeschen.
- Kompletter Flow live getestet: anlegen, Zugang gewaehren, Einladungsmail,
Passwort setzen, Login, Rollenschutz, Zugang entziehen, Login-Sperre.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Auth-Token-Tabelle mit gehashten Single-Use-Tokens einführen
- Passwort-Reset und E-Mail-Verifikation als Dev-Flow bauen
- Token-Flow-Test, Smoke-Abdeckung und M3-Dokumentation aktualisieren