- Mandantenauswahl fuer Benutzer mit mehreren Tenants bauen - feste Tenant-Domains ohne Wildcard-Abhaengigkeit vorbereiten - Login, Backfill, Smoke-Checks und M3-Dokumentation aktualisieren
671 lines
21 KiB
Markdown
671 lines
21 KiB
Markdown
# SaaS-Umstrukturierungsplan Kaffeeliste
|
|
|
|
Stand: 2026-07-11
|
|
|
|
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
|
|
visuelle Grunddesign sollen bewusst erhalten bleiben.
|
|
|
|
## Zielbild
|
|
|
|
- Mehrere Kunden koennen eigene Kaffeelisten betreiben.
|
|
- Jeder Kunde hat isolierte Daten, Einstellungen, Mitglieder und Buchungen.
|
|
- Neue Kunden koennen sich ueber eine oeffentliche Landingpage registrieren.
|
|
- Die operative App bleibt optisch nah am aktuellen Bestand: Sidebar, Tabellen,
|
|
schlichte Formulare, HTML5-UP-Anmutung.
|
|
- Authentifizierung, Rollen, Mandantenkontext und Sicherheitspruefungen werden
|
|
zentralisiert.
|
|
- Finanznahe Vorgaenge werden nachvollziehbar und revisionsfreundlich
|
|
gespeichert.
|
|
|
|
## Nicht-Ziele fuer 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.
|
|
- Kein Dual-Write zwischen Legacy und neuer App als Standardbetrieb.
|
|
- Keine Mandanten-ID aus Formularfeldern oder URL-Parametern als alleinige
|
|
Sicherheitsbasis.
|
|
|
|
## Ist-Zustand
|
|
|
|
Die aktuelle App ist eine flache PHP/sqlsrv-Legacy-App im Webroot.
|
|
|
|
Wichtige Bereiche:
|
|
|
|
- `index.php`: persoenliches Dashboard.
|
|
- `stricheintragen.php`: Sammelerfassung von Kaffee-Strichen.
|
|
- `einzahlung.php`: Sammelerfassung von Einzahlungen.
|
|
- `kaffeeliste.php`: Gesamtuebersicht.
|
|
- `mitarbeiterverwalten.php`: Mitglieder- und Adminpflege.
|
|
- `letzteneintraege.php`: Korrektur beziehungsweise Loeschung letzter Buchungen.
|
|
- `csvupload.php`: Zahlungsimport.
|
|
- `exportKaffeeliste.php`: PDF-/Listenexport.
|
|
- `mailversenden.php`: Massenmail.
|
|
- `hinweise.php`: Hinweise.
|
|
- `faq.php`: FAQ.
|
|
|
|
Zentrale technische Beobachtungen:
|
|
|
|
- Authentifizierung haengt 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`
|
|
statt.
|
|
- Es gibt kein sichtbares Migrationssystem und kein DB-Schema im Repository.
|
|
- Fachliche Tabellen haben aktuell keinen Mandantenbezug.
|
|
- Das Design kommt vor allem aus `assets/css/main.css` und dem HTML5-UP-Layout.
|
|
- Die App-Navigation sitzt faktisch in `footer.php`; `nav.php` ist leer.
|
|
|
|
## Grundsatzentscheidung
|
|
|
|
Der Umbau sollte nicht mit einer rein kosmetischen Landingpage starten, sondern
|
|
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.
|
|
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.
|
|
|
|
## Zielarchitektur
|
|
|
|
### Public-Bereich
|
|
|
|
Der Public-Bereich ist ohne Login erreichbar und laedt keine Mandantendaten.
|
|
|
|
Empfohlene Routen:
|
|
|
|
- `/`: Landingpage.
|
|
- `/preise` oder spaeter `/pricing`: optional, falls Tarife eingefuehrt werden.
|
|
- `/faq`: oeffentliche FAQ oder FAQ-Auszug.
|
|
- `/registrieren`: Kundenregistrierung.
|
|
- `/login`: Login.
|
|
- `/passwort-vergessen`: Passwort-Reset.
|
|
|
|
Landingpage-Inhalte:
|
|
|
|
- Hero mit Name `Kaffeeliste` und kurzer Nutzenbeschreibung.
|
|
- Drei Kernablaeufe: 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
|
|
|
|
Die geschuetzte App bleibt die operative Arbeitsoberflaeche.
|
|
|
|
Empfohlene Routen:
|
|
|
|
- `/app`: Dashboard oder Weiterleitung auf `/app/dashboard`.
|
|
- `/app/dashboard`: Meine Kaffeeliste.
|
|
- `/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/importe`: CSV-Importe.
|
|
- `/app/export/pdf`: PDF-/Listenexport.
|
|
- `/app/hinweise`: Hinweise.
|
|
- `/app/einstellungen`: Tenant-Einstellungen.
|
|
|
|
Die App sollte eine Sidebar behalten, aber besser gruppiert werden:
|
|
|
|
- Persoenlich: Meine Kaffeeliste, Namensanpassung, FAQ.
|
|
- Erfassung: Striche, Einzahlungen.
|
|
- Auswertung: Kaffeeliste, Buchungen, Export.
|
|
- Administration: Mitglieder, Hinweise, Einstellungen, Importe.
|
|
|
|
## Datenmodell
|
|
|
|
Empfohlen wird ein Shared-Database/Shared-Schema-Modell mit verpflichtendem
|
|
`tenant_id` auf allen fachlichen Tabellen.
|
|
|
|
Kernschema:
|
|
|
|
```text
|
|
tenants(
|
|
id, slug, name, status, timezone, locale, currency_code,
|
|
created_at, updated_at
|
|
)
|
|
|
|
tenant_settings(
|
|
tenant_id, mark_price_cents, self_entry_enabled, paypal_enabled,
|
|
paypal_url_template, sheet_window_days, negative_warning_cents,
|
|
positive_highlight_cents, branding_json, updated_by_user_id
|
|
)
|
|
|
|
users(
|
|
id, email_norm, password_hash, name, email_verified_at,
|
|
mfa_enabled, disabled_at, last_login_at, created_at, updated_at
|
|
)
|
|
|
|
tenant_memberships(
|
|
id, tenant_id, user_id, role, status, invited_at, joined_at,
|
|
created_at, updated_at,
|
|
UNIQUE(tenant_id, user_id)
|
|
)
|
|
|
|
participants(
|
|
id, tenant_id, user_id NULL, display_name, email_norm NULL,
|
|
paypal_name NULL, active, legacy_mitarbeiter_id,
|
|
created_at, updated_at,
|
|
UNIQUE(tenant_id, email_norm)
|
|
)
|
|
|
|
ledger_entries(
|
|
id, tenant_id, participant_id, type, amount_cents, marks_count,
|
|
unit_price_cents, booked_at, source, note, created_by_user_id,
|
|
import_batch_id NULL, legacy_table, legacy_id,
|
|
voided_at NULL, reversal_of_entry_id NULL,
|
|
created_at
|
|
)
|
|
|
|
notices(
|
|
id, tenant_id, message, valid_from, valid_until,
|
|
created_by_user_id, deleted_at, created_at, updated_at
|
|
)
|
|
|
|
payment_import_batches(
|
|
id, tenant_id, original_filename, checksum, status,
|
|
created_by_user_id, created_at
|
|
)
|
|
|
|
payment_import_rows(
|
|
id, batch_id, row_number, participant_id NULL, raw_name,
|
|
amount_cents, booked_at, status, raw_json
|
|
)
|
|
|
|
audit_log(
|
|
id, tenant_id, actor_user_id, action, subject_type, subject_id,
|
|
metadata_json, ip, created_at
|
|
)
|
|
|
|
outbound_emails(
|
|
id, tenant_id, participant_id, template, subject, status,
|
|
sent_at, error, created_at
|
|
)
|
|
```
|
|
|
|
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.
|
|
- Legacy-IDs werden bei Migration gespeichert, damit Ergebnisse vergleichbar
|
|
bleiben.
|
|
- Geldwerte sollten als Cent-Integer gespeichert werden, nicht als Float.
|
|
|
|
## Rollenmodell
|
|
|
|
Empfohlene Rollen:
|
|
|
|
- `owner`: Kunde verwalten, Billing, Admins, Loeschung, Grundeinstellungen.
|
|
- `admin`: Mitglieder, Hinweise, fachliche Einstellungen, Auswertungen.
|
|
- `treasurer`: Zahlungen, CSV-Import, Korrekturen, Exporte, Mails.
|
|
- `member`: eigenes Dashboard, eigene Striche, eigener Anzeigename.
|
|
- `viewer`: lesende Auswertungen.
|
|
|
|
Alle Rollen sind tenant-scoped. Ein User kann also bei Kunde A Admin und bei
|
|
Kunde B nur Mitglied sein.
|
|
|
|
## Authentifizierung und Sicherheit
|
|
|
|
SaaS-Basis:
|
|
|
|
- E-Mail/Passwort-Login mit `password_hash`.
|
|
- E-Mail-Verifikation.
|
|
- Passwort-Reset.
|
|
- Sichere Session-Cookies.
|
|
- CSRF-Schutz fuer alle schreibenden Aktionen.
|
|
- Rate-Limits fuer Login, Registrierung und Passwort-Reset.
|
|
- Zentrale Funktionen oder Middleware: `requireLogin`, `requireTenant`,
|
|
`requireRole`, `csrfToken`.
|
|
|
|
Tenant-Aufloesung:
|
|
|
|
- Primaer 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:
|
|
|
|
- LDAP/AD oder SSO pro Kunde als optionaler Identity Provider.
|
|
- MFA fuer Owner/Admins.
|
|
- Row-Level-Security in der Datenbank.
|
|
|
|
## Design-Leitplanken
|
|
|
|
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.
|
|
- Schlichte Formularfelder und Buttons.
|
|
|
|
Verbessern ohne Relaunch:
|
|
|
|
- Hinweise als wiederverwendbare Komponente statt Inline-Style.
|
|
- Einheitliche Erfolgs-, Fehler- und Warnmeldungen.
|
|
- Dashboardwerte als kompakte Statusbereiche.
|
|
- Aktionsleisten ueber Tabellen.
|
|
- Sidebar-Gruppierung und aktive Navigation.
|
|
- FAQ strukturieren, aber Inhalte nicht stark veraendern.
|
|
|
|
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.
|
|
|
|
## Meilensteinplan
|
|
|
|
Uebersicht:
|
|
|
|
| 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 |
|
|
| M2 | Technisches Fundament | Abgeschlossen: Migrationen, Bootstrap, Session, CSRF-Helper und Legacy-Schreibseitenschutz stehen |
|
|
| M3 | SaaS-Basis | Tenants, User, Registrierung, Login und Rollen funktionieren |
|
|
| M4 | Datenmigration | Legacy-Daten sind tenant-sicher im Zielmodell abgebildet |
|
|
| M5 | App-Kern | Dashboard, Striche, Einzahlungen, Mitglieder und Liste laufen |
|
|
| M6 | Betriebsflows | Import, Export, Mail und Jahresprozesse sind auditierbar |
|
|
| M7 | Landingpage | Werbliche Seite und Registrierung sind oeffentlich nutzbar |
|
|
| M8 | Haertung | Betrieb, Datenschutz, Monitoring und Isolation sind geprueft |
|
|
| M9 | Cutover | Produktivumstellung ist vorbereitet und Legacy ist read-only |
|
|
|
|
### M0: Planungs- und Sicherheitsbaseline
|
|
|
|
Ziel:
|
|
Den aktuellen Zustand verlaesslich dokumentieren, bevor umgebaut wird.
|
|
|
|
Arbeitsartefakte:
|
|
|
|
- `docs/m0/README.md`
|
|
- `docs/m0/code-inventory.md`
|
|
- `docs/m0/security-baseline.md`
|
|
- `docs/m0/schema-export.sql`
|
|
- `docs/m0/golden-master-queries.sql`
|
|
- `docs/m0/screenshot-checklist.md`
|
|
|
|
Schritte:
|
|
|
|
- Live-DB-Schema exportieren.
|
|
- 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.
|
|
- Fachliche Kernregeln dokumentieren: Saldo, Jahreswerte, Preis pro Strich,
|
|
100-Tage-Listen, CSV-Deduplizierung, PDF-Ausgabe.
|
|
|
|
Ergebnis:
|
|
|
|
- Datenkatalog.
|
|
- Prozesslandkarte.
|
|
- Designreferenz.
|
|
- Liste kritischer Sicherheitsrisiken.
|
|
|
|
Abhaengigkeiten:
|
|
|
|
- Zugriff auf echte oder anonymisierte Datenbank.
|
|
- Kenntnis der Produktivumgebung.
|
|
|
|
### M1: Golden-Master-Validierung
|
|
|
|
Ziel:
|
|
Sicherstellen, dass spaetere neue Berechnungen dieselben Ergebnisse wie der
|
|
Bestand liefern.
|
|
|
|
Schritte:
|
|
|
|
- Referenzdatensatz aus Legacy erzeugen. Erledigt als rekonstruierter Golden
|
|
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
|
|
Golden-Master-Check.
|
|
- Testfaelle fuer Guthaben, Schulden, Nullsaldo und inaktive Teilnehmer
|
|
anlegen. Erledigt.
|
|
- Sichere GET-Seiten per HTTP-Smoke pruefen. Erledigt mit
|
|
`scripts/http-smoke.php`.
|
|
- PDF-/Export-Summen als Referenz sichern. Offen, weil die TCPDF-Kopie im Repo
|
|
unvollstaendig 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,
|
|
GET-Nebenwirkungen bei Mailversand und Jahresauswertung.
|
|
|
|
Abhaengigkeiten:
|
|
|
|
- M0 abgeschlossen.
|
|
- PDF-/Mail-/Jahresprozesse werden in M6 gezielt neu gestaltet, statt sie in M1
|
|
per GET-Smoke auszufuehren.
|
|
|
|
### M2: Technisches Fundament
|
|
|
|
Ziel:
|
|
Eine saubere Basis fuer 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.
|
|
Begonnen mit `app/bootstrap.php`.
|
|
- Versionierte Migrationen einfuehren. Begonnen mit
|
|
`database/migrations/0001_legacy_mysql_baseline.sql` und
|
|
`scripts/migrate.php`.
|
|
- Layouts trennen: Public-Layout und App-Layout. Noch offen; Header/Footer
|
|
bleiben vorerst Legacy-Wrapper.
|
|
- Bestehende Assets weiterverwenden.
|
|
- CSRF- und Session-Basis einziehen. Session und CSRF-Helper sind vorhanden;
|
|
globale Erzwingung erfolgt schrittweise pro POST-Seite. Erste Seiten sind
|
|
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.
|
|
- Konfigurationswerte aus Code in Umgebung oder Settings verschieben.
|
|
|
|
Ergebnis:
|
|
|
|
- Grundgeruest fuer neue SaaS-App.
|
|
- Kein fachlicher Rewrite, aber klare Struktur fuer die Migration.
|
|
- Dokumentation: `docs/m2-technical-foundation.md`.
|
|
- Status: abgeschlossen fuer den M2-Scope.
|
|
|
|
Abhaengigkeiten:
|
|
|
|
- Entscheidung, ob PHP nativ weitergefuehrt 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.
|
|
|
|
Schritte:
|
|
|
|
- Tabellen fuer `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:
|
|
erledigt.
|
|
- Default-Tenant fuer den aktuellen Bestand anlegen: erledigt.
|
|
- Bestehende `kl_Mitarbeiter` idempotent in `participants` spiegeln:
|
|
erledigt.
|
|
- Registrierung: Tenant + Owner-User + Default-Settings erzeugen: erster
|
|
Flow erledigt.
|
|
- Login und Logout bauen: erster Flow erledigt.
|
|
- Passwort-Reset und E-Mail-Verifikation bauen: Dev-Flow mit Single-Use-Tokens
|
|
erledigt.
|
|
- Tenant-Aufloesung 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.
|
|
|
|
Ergebnis:
|
|
|
|
- Ein neuer Kunde kann sich registrieren und in seine eigene App gelangen.
|
|
- Rollen und Tenant-Kontext sind serverseitig verfuegbar.
|
|
|
|
Abhaengigkeiten:
|
|
|
|
- M2 abgeschlossen.
|
|
|
|
### M4: Migration des fachlichen Kerns
|
|
|
|
Ziel:
|
|
Bestehende Kaffeelisten-Daten tenant-sicher uebernehmen.
|
|
|
|
Schritte:
|
|
|
|
- Initialen Tenant fuer den bisherigen Bestand anlegen.
|
|
- `kl_Mitarbeiter` nach `participants` migrieren.
|
|
- `admin`-Informationen in `tenant_memberships` oder Admin-Rollen ueberfuehren.
|
|
- `kl_config` nach `tenant_settings` migrieren.
|
|
- `kl_Einzahlungen` und `kl_Kaffeeverbrauch` nach `ledger_entries` migrieren.
|
|
- Legacy-IDs speichern.
|
|
- Salden gegen Golden-Master vergleichen.
|
|
|
|
Ergebnis:
|
|
|
|
- Bestehender Datenbestand ist im neuen Modell abgebildet.
|
|
- Saldenparitaet ist nachweisbar.
|
|
|
|
Abhaengigkeiten:
|
|
|
|
- M1 und M3 abgeschlossen.
|
|
|
|
### M5: Geschuetzte App-Funktionen
|
|
|
|
Ziel:
|
|
Die operativen Kernseiten im neuen Modell bereitstellen.
|
|
|
|
Schritte:
|
|
|
|
- Dashboard `Meine Kaffeeliste` umsetzen.
|
|
- Eigene Stricherfassung umsetzen.
|
|
- Zahlungs-/PayPal-Bereich umsetzen.
|
|
- Mitgliederverwaltung tenant- und rollenbasiert umsetzen.
|
|
- Gesamtuebersicht umsetzen.
|
|
- Letzte Eintraege und Korrekturen als Storno statt Delete umsetzen.
|
|
- Hinweise als tenant-spezifische Notices umsetzen.
|
|
|
|
Ergebnis:
|
|
|
|
- Ein Kunde kann seine Kaffeeliste operativ nutzen.
|
|
- App sieht weiterhin nach bestehender Kaffeeliste aus.
|
|
|
|
Abhaengigkeiten:
|
|
|
|
- M4 abgeschlossen.
|
|
|
|
### M6: Import, Export und Mail
|
|
|
|
Ziel:
|
|
Admin- und Treasurer-Flows produktionsreif machen.
|
|
|
|
Schritte:
|
|
|
|
- CSV-Import mit Vorschau, Dublettenpruefung und Audit bauen.
|
|
- Uploads ausserhalb des Webroots speichern.
|
|
- PDF-/Listenexport aus neuem Datenmodell bauen.
|
|
- Mailversand als nachvollziehbaren Versandjob mit Dry-Run und Versandlog
|
|
gestalten.
|
|
- Jahresauswertung beziehungsweise Jahresbuchungen tenant-sicher abbilden.
|
|
|
|
Ergebnis:
|
|
|
|
- Kassenverwaltung ist fuer reale Betriebsablaeufe vollstaendig.
|
|
- Import/Export/Mail sind auditierbar.
|
|
|
|
Abhaengigkeiten:
|
|
|
|
- M5 fuer die Kernansichten.
|
|
|
|
### M7: Oeffentliche Landingpage
|
|
|
|
Ziel:
|
|
Werbliche Einstiegseite und Registrierung verfuegbar machen, ohne die App-Optik
|
|
zu verwischen.
|
|
|
|
Schritte:
|
|
|
|
- Public-Layout mit bestehender Typografie und gruenem Akzent bauen.
|
|
- Landingpage-Inhalte erstellen.
|
|
- Demo-Screenshot oder Demo-Ansicht einbinden.
|
|
- CTA zu Registrierung und Login.
|
|
- FAQ-Auszug strukturieren.
|
|
- Keine App-Sidebar im Public-Bereich.
|
|
|
|
Ergebnis:
|
|
|
|
- Interessenten verstehen das Produkt und koennen sich registrieren.
|
|
- Bestehende App bleibt optisch eigenstaendig und arbeitsorientiert.
|
|
|
|
Abhaengigkeiten:
|
|
|
|
- M3 fuer Registrierung.
|
|
- M5 fuer echte App-Screens oder Demo.
|
|
|
|
### M8: Haertung, Datenschutz und Betrieb
|
|
|
|
Ziel:
|
|
Die SaaS-App fuer mehrere Kunden sicher betreiben.
|
|
|
|
Schritte:
|
|
|
|
- Backups und Restore-Prozess definieren.
|
|
- Monitoring und Fehlerlogging einrichten.
|
|
- Audit-Log fuer Admin-Aktionen pruefen.
|
|
- Datenexport pro Tenant.
|
|
- Loesch-/Anonymisierungsprozess fuer Teilnehmer und Kunden.
|
|
- Rate-Limits und Security Headers.
|
|
- Mandanten-Isolation testen.
|
|
- Rollenmatrix testen.
|
|
|
|
Ergebnis:
|
|
|
|
- SaaS ist betrieblich und datenschutzseitig belastbarer.
|
|
|
|
Abhaengigkeiten:
|
|
|
|
- M3 bis M6.
|
|
|
|
### M9: Cutover und Legacy-Archiv
|
|
|
|
Ziel:
|
|
Produktive Umstellung ohne Datenverlust.
|
|
|
|
Schritte:
|
|
|
|
- Legacy fuer Schreibzugriffe sperren.
|
|
- Finalen Delta-Export ziehen.
|
|
- Migration ausfuehren.
|
|
- Rowcounts, Salden, PDF-Stichproben und Importhistorie pruefen.
|
|
- DNS oder Reverse Proxy umschalten.
|
|
- Legacy 30 bis 90 Tage read-only als Archiv behalten.
|
|
- Rollback-Fenster und Vorgehen dokumentieren.
|
|
|
|
Ergebnis:
|
|
|
|
- Neuer SaaS-Betrieb ist live.
|
|
- Alter Bestand bleibt fuer Rueckfragen lesbar.
|
|
|
|
Abhaengigkeiten:
|
|
|
|
- M8 abgeschlossen.
|
|
|
|
## Empfohlene MVP-Reihenfolge
|
|
|
|
Fuer den ersten produktnahen MVP sollten nicht alle Randmodule gleichzeitig
|
|
umgebaut werden.
|
|
|
|
MVP-Paket:
|
|
|
|
1. Tenant, User, Login, Registrierung.
|
|
2. Teilnehmer, Settings, Ledger.
|
|
3. Dashboard, Striche, Einzahlungen, Gesamtuebersicht.
|
|
4. Mitgliederverwaltung.
|
|
5. Hinweise.
|
|
6. CSV-Import, Export.
|
|
7. Landingpage.
|
|
|
|
Spaeter:
|
|
|
|
- Umfrage-Modul.
|
|
- SSO/LDAP pro Kunde.
|
|
- Billing/Tarife.
|
|
- MFA.
|
|
- Custom Domains.
|
|
- Erweiterte Mandanten-Branding-Optionen.
|
|
|
|
## Validierung
|
|
|
|
Fachliche Pruefungen:
|
|
|
|
- Saldo je Teilnehmer alt gegen neu.
|
|
- Jahreswerte alt gegen neu.
|
|
- Gesamtstriche alt gegen neu.
|
|
- Einzahlungen alt gegen neu.
|
|
- Export-Summen alt gegen neu.
|
|
- CSV-Import: identische Treffer- und Dublettenlogik.
|
|
|
|
Sicherheitspruefungen:
|
|
|
|
- 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.
|
|
- Ausgabe von Namen, Mails und Hinweisen ist escaped.
|
|
|
|
UX-Pruefungen:
|
|
|
|
- Kernseiten bleiben optisch wiedererkennbar.
|
|
- Sidebar bleibt fuer App-Nutzer vertraut.
|
|
- Landingpage zeigt keine App-Adminnavigation.
|
|
- Mobile Darstellung bleibt bedienbar.
|
|
- Tabellen bleiben lesbar.
|
|
|
|
## Risiken und Gegenmassnahmen
|
|
|
|
| Risiko | Gegenmassnahme |
|
|
| --- | --- |
|
|
| 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 |
|
|
| 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 |
|
|
| 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 |
|
|
|
|
## Offene Entscheidungen
|
|
|
|
- Soll die neue App weiterhin nativ in PHP entstehen oder mit einem Framework?
|
|
- Soll SQL Server bleiben oder mittelfristig eine andere Datenbank genutzt
|
|
werden?
|
|
- Wie sollen Kunden-Tenants adressiert werden: Subdomain, Pfad oder Auswahl nach
|
|
Login?
|
|
- Welche Rolle soll `treasurer` haben: eigene Rolle oder Teil von `admin`?
|
|
- Wird das Umfrage-Modul Teil des SaaS-Produkts oder nur archiviert?
|
|
- Braucht der MVP schon Tarife/Billing oder erstmal nur Registrierung?
|
|
- Sollen bestehende Kunden per Einladung oder per Self-Service onboarden?
|
|
|
|
## Naechster konkreter Arbeitsschritt
|
|
|
|
Als naechstes sollte M0 gestartet werden:
|
|
|
|
1. Produktiv-/Testdatenbankschema exportieren.
|
|
2. Screenshot-Referenz der wichtigsten Seiten erstellen.
|
|
3. Golden-Master-Auswertungen definieren.
|
|
4. Entscheidung treffen, ob der neue SaaS-Kern im bestehenden PHP-Stil oder mit
|
|
einem Framework aufgebaut wird.
|