Files
kaffeekasse-saas/docs/m3-saas-basis-vorbereitung.md
T

10 KiB

M3 SaaS-Basis Vorbereitung

Stand: 2026-07-13

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 für den M3-Scope. M4 startet mit der additiven Migration von Einzahlungen und Kaffeeverbrauch nach ledger_entries.

Ziel

  • 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 für Registrierung und Login schaffen, ohne die Legacy-Auth sofort zu ersetzen.

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 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.

Umgesetzter erster Schritt

Umgesetzte Migrationen:

database/migrations/0002_saas_identity_tenants.sql
database/migrations/0003_saas_auth_account_fields.sql
database/migrations/0004_saas_auth_tokens.sql
database/migrations/0005_saas_tenant_resolution.sql

Tabellen:

  • tenants
  • tenant_settings
  • users
  • tenant_memberships
  • participants
  • tenant_domains

Ergänzende Skripte:

scripts/backfill-default-tenant.php
scripts/check-m3-saas-basis.php
scripts/check-m3-auth-flow.php
scripts/check-m3-settings-flow.php
scripts/check-m3-password-email-flow.php
scripts/check-m3-tenant-resolution-flow.php
scripts/check-m3-mail-flow.php

Wichtige Regeln:

  • users sind Login-Konten.
  • participants sind Kaffeelisten-Teilnehmer.
  • Ein participant kann optional auf einen user zeigen.
  • Rollen liegen in tenant_memberships, nicht in participants.
  • participants.legacy_mitarbeiter_id speichert die alte ID aus kl_Mitarbeiter.
  • Geldwerte in neuen Settings als Cent-Integer speichern.
  • Die Migration ist rein additiv; bestehende Legacy-Seiten fragen weiter die bisherigen kl_*-Tabellen ab.

Default-Tenant

Für den Bestand wird ein erster Tenant angelegt:

slug: default
name: Kaffeeliste Bestand
status: active
timezone: Europe/Berlin
locale: de-DE
currency_code: EUR

Die Werte können später in einer Tenant-Einstellungsseite angepasst werden.

Backfill

Ein separates Skript spiegelt die bestehenden Mitarbeiter:

scripts/backfill-default-tenant.php

Vorgang:

  1. Default-Tenant anlegen oder laden.
  2. tenant_settings aus kl_config erzeugen.
  3. Für jede Zeile aus kl_Mitarbeiter einen participant anlegen oder aktualisieren.
  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.
  6. Verwaiste participants mit nicht mehr vorhandener legacy_mitarbeiter_id aus dem Default-Tenant entfernen.

Der Backfill muss idempotent sein und darf keine bestehenden Legacy-Daten löschen. Gelöscht werden nur SaaS-Spiegelungen, deren Legacy-Mitarbeiter in kl_Mitarbeiter nicht mehr existiert.

Ausgeführter Dev-Stand:

  • Default-Tenant default wurde angelegt.
  • 9 Legacy-Mitarbeiter wurden als participants gespiegelt.
  • 2 aktive Admin-/Owner-Logins wurden als users und tenant_memberships angelegt.
  • Ein zweiter Backfill-Lauf blieb idempotent.

Registrierung und Login

Umgesetzte Dateien:

app/database.php
app/saas-auth.php
app/saas-mail.php
login.php
register.php
konto.php
logout.php
mandant-auswahl.php
passwort-vergessen.php
passwort-zuruecksetzen.php
email-verifikation-senden.php
email-verifizieren.php
landing.php
assets/images/landing-hero.png
assets/css/public.css

Umgesetzter Umfang:

  • Registrierung legt Tenant, Owner-User, Default-Settings, Membership und Owner-Participant in einer Transaktion an.
  • 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, führt der Login zur Mandantenauswahl.
  • Logout beendet die neue PHP-Login-Session.
  • 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 Public-Layout im Stil der Landingpage.
  • 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 ü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 ohne echten Postausgang reproduzierbar bleiben.

Noch offen im M3-Auth-Scope:

  • Weitergehende Rollenmatrix für spätere SaaS-Seiten.
  • Produktive SMTP-/Provider-Anbindung inklusive Bounce-/Fehlerprotokoll.

Public-Landingpage

Umgesetzte Dateien:

landing.php
assets/images/landing-hero.png
assets/css/public.css

Umgesetzter Umfang:

  • Ö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 öffentliche Auth-Hilfsseiten sind optisch in den Public-Bereich integriert.
  • Kurzabschnitt zu Stricherfassung, Mandantenfähigkeit und Webspace-Betrieb.
  • Die geschützte App-Sidebar bleibt von der Public-Seite getrennt.

Tenant-Auflösung

Entscheidung für den Webspace-Betrieb:

  • Keine Wildcard-Subdomains im ersten Schritt.
  • 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 ü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 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 für die Landingpage in der Zielumgebung definieren.
  • Produktive Domain-/Zertifikatsprüfung für einzelne feste Domains definieren.

Rollen und Grundeinstellungen

Umgesetzte Dateien:

mandant-einstellungen.php

Umgesetzter Umfang:

  • saas_user_has_role(), saas_require_role() und 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 für passende Rollen.

Erste Akzeptanzkriterien

  • Migrationen laufen mehrfach ohne Fehler: erfüllt.
  • Default-Tenant existiert genau einmal: erfüllt.
  • tenant_settings enthalten Preis pro Strich und bestehende PayPal-Optionen: 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: erfüllt.
  • Reset- und Verifikationslinks werden im Dev-/Testmodus als Mail-Log erzeugt: 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 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 ausschließlich in tenant_memberships speichern
Falsche Owner-Zuordnung Owner per Env-Konfiguration oder manuell dokumentierter Entscheidung setzen

Empfohlene Reihenfolge

  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 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 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-Auflösung bauen: erledigt.
  15. Tenant-Resolution-Kontrollskript schreiben: 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.

Übergabe an M4

M4 ist in docs/m4-data-migration.md dokumentiert. Der erste M4-Schritt ist bewusst additiv:

  • ledger_entries wird als neue tenant-sichere Buchungstabelle angelegt.
  • Legacy-Einzahlungen und Legacy-Kaffeeverbrauch werden gespiegelt.
  • Bestehende Seiten bleiben vorerst auf den kl_*-Tabellen.
  • Summen werden gegen den Golden Master verglichen.