app/stripe.php: minimaler REST-Client fuer die Stripe-API auf Basis von
PHP-Streams statt eines vendorten SDKs - diese PHP-Installation hat keine
curl-Extension, Streams sind zudem portabler und brauchen kein
composer.json.
- Fuer jeden bezahlten Tarif per API ein Stripe-Produkt mit monatlichem
Preis angelegt, referenziert ueber einen stabilen lookup_key statt
hartcodierter Price-ID; Erstellung ist idempotent.
- abo-upgrade.php: erstellt eine Stripe-Checkout-Session fuer den
gewaehlten Tarif, tenant_id/plan_code als Metadaten auf Session UND
Subscription (damit spaetere Subscription-Events zuordenbar bleiben).
- abo-portal.php: oeffnet das Stripe Customer Portal fuer bestehende
Kunden (Zahlungsmittel/Kuendigung, ohne eigene UI dafuer).
- stripe-webhook.php: verifiziert die Stripe-Signature per HMAC-SHA256
mit Zeitstempel-Toleranz, verarbeitet checkout.session.completed,
customer.subscription.updated/.deleted, invoice.paid/.payment_failed
und haelt tenant_billing aktuell. Bewusst kein CSRF-/Login-Check
(Stripe ruft unauthentifiziert auf), stattdessen ausschliesslich
Signaturpruefung als Echtheitsnachweis.
- mandant-einstellungen.php: echter "Jetzt upgraden"-Button (Stripe
Checkout) sowie "Zahlungsmethode verwalten/Abo kuendigen" (Customer
Portal), sobald ein Stripe-Kunde existiert.
Live getestet (Stripe-Testmodus, kein echtes Geld): voller Checkout-Flow
bis zum echten Redirect auf checkout.stripe.com, Webhook-Verarbeitung
durch selbst erzeugte, korrekt signierte Test-Events (da diese
Dev-Umgebung keine oeffentlich erreichbare URL fuer echte Stripe-
Zustellung hat) inklusive Ablehnung falscher Signaturen, Customer Portal
mit echtem per API angelegtem Test-Kunden. Alle Regressionstests
weiterhin gruen (36 Seiten HTTP-Smoke, Golden Master, M8-Isolation/
Rollenmatrix).
Noch offen: echten Webhook-Endpunkt auf die Produktions-Domain eintragen,
sobald diese feststeht; Wechsel auf Live-Keys; Dolibarr-Sync (Phase 3).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
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>
Erste drei Bausteine der Haertung:
- Security-Headers (X-Content-Type-Options, X-Frame-Options, Referrer-
Policy, Permissions-Policy, HSTS bei HTTPS) laufen automatisch ueber
app_send_security_headers() am Ende von app/bootstrap.php fuer jede
dynamische Seite; landing.php war als einzige Seite ganz ohne PHP und
bekam einen minimalen Bootstrap-Aufruf. Bewusst kein CSP, da die
bestehenden Templates durchgaengig auf Inline-style-Attribute setzen.
- DB-gestuetzte Rate-Limits (neue Tabelle rate_limit_attempts) fuer
Login (10/15min je E-Mail, 20/15min je IP), Registrierung (5/h je IP)
und Passwort-Reset-Anfrage (5/h je E-Mail, 10/h je IP); bei
ausgereiztem Reset-Limit erscheint dieselbe generische Meldung wie im
Erfolgsfall, um kein Konto-Enumeration-Signal zu geben.
- Zentrales Audit-Log (neue Tabelle audit_log) fuer Mitgliederverwaltung,
Zugangsvergabe/-entzug, Storno, Mandant-Einstellungen, Hinweise,
CSV-Import, Jahresbonus-Verteilung und Live-Mailversand; sichtbar fuer
Owner/Admin auf mandant-einstellungen.php.
Live getestet: Rate-Limit greift nach 10 Fehlversuchen, Audit-Log-Eintrag
mit korrekten Metadaten und Nutzernamen ueber einen isolierten Test-
Mandanten geprueft. Alle Regressionstests weiterhin gruen (26/26 Smoke,
104 Golden-Master-Assertions).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>