Deutsche Umlaute in UI und Dokumentation korrigieren
This commit is contained in:
@@ -1,19 +1,19 @@
|
|||||||
# Legacy App Archiv
|
# Legacy App Archiv
|
||||||
|
|
||||||
Dieses Verzeichnis enthaelt den bisherigen PHP-Bestand der Kaffeeliste.
|
Dieses Verzeichnis enthält den bisherigen PHP-Bestand der Kaffeeliste.
|
||||||
|
|
||||||
Es bleibt aus drei Gruenden im Repository:
|
Es bleibt aus drei Gründen im Repository:
|
||||||
|
|
||||||
- als Referenz fuer die bestehende Fachlogik
|
- als Referenz für die bestehende Fachlogik
|
||||||
- als Quelle fuer Datenmigrationen in die SaaS-Version
|
- als Quelle für Datenmigrationen in die SaaS-Version
|
||||||
- als Rueckfalloption waehrend der Uebergangsphase
|
- als Rückfalloption während der Übergangsphase
|
||||||
|
|
||||||
## Wichtige Legacy-Bereiche
|
## Wichtige Legacy-Bereiche
|
||||||
|
|
||||||
- `index.php`: persoenliches Dashboard
|
- `index.php`: persönliches Dashboard
|
||||||
- `stricheintragen.php`: Sammelerfassung fuer Kaffee-Striche
|
- `stricheintragen.php`: Sammelerfassung für Kaffee-Striche
|
||||||
- `einzahlung.php`: Sammelerfassung fuer Einzahlungen
|
- `einzahlung.php`: Sammelerfassung für Einzahlungen
|
||||||
- `kaffeeliste.php`: operative Gesamtuebersicht
|
- `kaffeeliste.php`: operative Gesamtübersicht
|
||||||
- `mitarbeiterverwalten.php`: Mitglieder- und Rollenpflege
|
- `mitarbeiterverwalten.php`: Mitglieder- und Rollenpflege
|
||||||
- `letzteneintraege.php`: Korrektur letzter Buchungen
|
- `letzteneintraege.php`: Korrektur letzter Buchungen
|
||||||
- `hinweise.php`: Banner/Hinweise
|
- `hinweise.php`: Banner/Hinweise
|
||||||
@@ -21,5 +21,5 @@ Es bleibt aus drei Gruenden im Repository:
|
|||||||
## Umgang Mit Dem Archiv
|
## Umgang Mit Dem Archiv
|
||||||
|
|
||||||
- Keine neuen Produktfunktionen mehr hier entwickeln.
|
- Keine neuen Produktfunktionen mehr hier entwickeln.
|
||||||
- Nur noch fuer Referenz, Datenabgleich oder Notfallbetrieb verwenden.
|
- Nur noch für Referenz, Datenabgleich oder Notfallbetrieb verwenden.
|
||||||
- Neue Arbeit findet ausschliesslich in `../saas-app/` und `../docs/` statt.
|
- Neue Arbeit findet ausschließlich in `../saas-app/` und `../docs/` statt.
|
||||||
|
|||||||
+13
-13
@@ -323,13 +323,13 @@ function saas_update_tenant_settings(PDO $pdo, int $tenantId, array $input): arr
|
|||||||
$errors[] = 'Der Kundenname muss zwischen 3 und 255 Zeichen lang sein.';
|
$errors[] = 'Der Kundenname muss zwischen 3 und 255 Zeichen lang sein.';
|
||||||
}
|
}
|
||||||
if (!in_array($timezone, DateTimeZone::listIdentifiers(), true)) {
|
if (!in_array($timezone, DateTimeZone::listIdentifiers(), true)) {
|
||||||
$errors[] = 'Die Zeitzone ist ungueltig.';
|
$errors[] = 'Die Zeitzone ist ungültig.';
|
||||||
}
|
}
|
||||||
if (!preg_match('/^[a-z]{2}-[A-Z]{2}$/', $locale)) {
|
if (!preg_match('/^[a-z]{2}-[A-Z]{2}$/', $locale)) {
|
||||||
$errors[] = 'Die Locale muss dem Muster de-DE entsprechen.';
|
$errors[] = 'Die Locale muss dem Muster de-DE entsprechen.';
|
||||||
}
|
}
|
||||||
if (!preg_match('/^[A-Z]{3}$/', $currencyCode)) {
|
if (!preg_match('/^[A-Z]{3}$/', $currencyCode)) {
|
||||||
$errors[] = 'Der Waehrungscode muss aus drei Grossbuchstaben bestehen.';
|
$errors[] = 'Der Währungscode muss aus drei Großbuchstaben bestehen.';
|
||||||
}
|
}
|
||||||
if ($markPriceCents === null || $markPriceCents < 1 || $markPriceCents > 10000) {
|
if ($markPriceCents === null || $markPriceCents < 1 || $markPriceCents > 10000) {
|
||||||
$errors[] = 'Der Preis pro Strich muss zwischen 0,01 und 100,00 liegen.';
|
$errors[] = 'Der Preis pro Strich muss zwischen 0,01 und 100,00 liegen.';
|
||||||
@@ -615,7 +615,7 @@ function saas_request_password_reset(PDO $pdo, string $email, string $tenantSlug
|
|||||||
if (!filter_var($emailNorm, FILTER_VALIDATE_EMAIL)) {
|
if (!filter_var($emailNorm, FILTER_VALIDATE_EMAIL)) {
|
||||||
return [
|
return [
|
||||||
'ok' => false,
|
'ok' => false,
|
||||||
'errors' => ['Bitte eine gueltige E-Mail-Adresse eingeben.'],
|
'errors' => ['Bitte eine gültige E-Mail-Adresse eingeben.'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,7 +658,7 @@ function saas_reset_password_with_token(PDO $pdo, string $token, string $passwor
|
|||||||
|
|
||||||
$tokenRow = saas_fetch_valid_auth_token($pdo, $token, 'password_reset');
|
$tokenRow = saas_fetch_valid_auth_token($pdo, $token, 'password_reset');
|
||||||
if ($tokenRow === null) {
|
if ($tokenRow === null) {
|
||||||
$errors[] = 'Der Link ist ungueltig oder abgelaufen.';
|
$errors[] = 'Der Link ist ungültig oder abgelaufen.';
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($errors !== []) {
|
if ($errors !== []) {
|
||||||
@@ -730,7 +730,7 @@ function saas_verify_email_token(PDO $pdo, string $token): array
|
|||||||
if ($tokenRow === null) {
|
if ($tokenRow === null) {
|
||||||
return [
|
return [
|
||||||
'ok' => false,
|
'ok' => false,
|
||||||
'errors' => ['Der Link ist ungueltig oder abgelaufen.'],
|
'errors' => ['Der Link ist ungültig oder abgelaufen.'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -748,7 +748,7 @@ function saas_verify_email_token(PDO $pdo, string $token): array
|
|||||||
|
|
||||||
return [
|
return [
|
||||||
'ok' => false,
|
'ok' => false,
|
||||||
'errors' => ['Die E-Mail-Adresse konnte nicht bestaetigt werden.'],
|
'errors' => ['Die E-Mail-Adresse konnte nicht bestätigt werden.'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -765,7 +765,7 @@ function saas_authenticate(PDO $pdo, string $email, string $password, string $te
|
|||||||
if (!filter_var($emailNorm, FILTER_VALIDATE_EMAIL) || $password === '') {
|
if (!filter_var($emailNorm, FILTER_VALIDATE_EMAIL) || $password === '') {
|
||||||
return [
|
return [
|
||||||
'ok' => false,
|
'ok' => false,
|
||||||
'errors' => ['E-Mail oder Passwort ist ungueltig.'],
|
'errors' => ['E-Mail oder Passwort ist ungültig.'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -785,7 +785,7 @@ function saas_authenticate(PDO $pdo, string $email, string $password, string $te
|
|||||||
) {
|
) {
|
||||||
return [
|
return [
|
||||||
'ok' => false,
|
'ok' => false,
|
||||||
'errors' => ['E-Mail oder Passwort ist ungueltig.'],
|
'errors' => ['E-Mail oder Passwort ist ungültig.'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -817,7 +817,7 @@ function saas_authenticate(PDO $pdo, string $email, string $password, string $te
|
|||||||
if ($tenantIds === []) {
|
if ($tenantIds === []) {
|
||||||
return [
|
return [
|
||||||
'ok' => false,
|
'ok' => false,
|
||||||
'errors' => ['Fuer dieses Konto ist kein aktiver Mandant verfuegbar.'],
|
'errors' => ['Für dieses Konto ist kein aktiver Mandant verfügbar.'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -835,7 +835,7 @@ function saas_authenticate(PDO $pdo, string $email, string $password, string $te
|
|||||||
if ($identity === null) {
|
if ($identity === null) {
|
||||||
return [
|
return [
|
||||||
'ok' => false,
|
'ok' => false,
|
||||||
'errors' => ['Fuer dieses Konto ist kein aktiver Mandant verfuegbar.'],
|
'errors' => ['Für dieses Konto ist kein aktiver Mandant verfügbar.'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -867,13 +867,13 @@ function saas_register_tenant_owner(PDO $pdo, array $input): array
|
|||||||
$errors[] = 'Der Kundenname muss zwischen 3 und 255 Zeichen lang sein.';
|
$errors[] = 'Der Kundenname muss zwischen 3 und 255 Zeichen lang sein.';
|
||||||
}
|
}
|
||||||
if (!preg_match('/^[a-z0-9][a-z0-9-]{1,98}[a-z0-9]$/', $tenantSlug)) {
|
if (!preg_match('/^[a-z0-9][a-z0-9-]{1,98}[a-z0-9]$/', $tenantSlug)) {
|
||||||
$errors[] = 'Das Kundenkuerzel darf nur Kleinbuchstaben, Zahlen und Bindestriche enthalten.';
|
$errors[] = 'Das Kundenkürzel darf nur Kleinbuchstaben, Zahlen und Bindestriche enthalten.';
|
||||||
}
|
}
|
||||||
if (strlen($displayName) < 2 || strlen($displayName) > 255) {
|
if (strlen($displayName) < 2 || strlen($displayName) > 255) {
|
||||||
$errors[] = 'Der Name muss zwischen 2 und 255 Zeichen lang sein.';
|
$errors[] = 'Der Name muss zwischen 2 und 255 Zeichen lang sein.';
|
||||||
}
|
}
|
||||||
if (!filter_var($emailNorm, FILTER_VALIDATE_EMAIL)) {
|
if (!filter_var($emailNorm, FILTER_VALIDATE_EMAIL)) {
|
||||||
$errors[] = 'Bitte eine gueltige E-Mail-Adresse eingeben.';
|
$errors[] = 'Bitte eine gültige E-Mail-Adresse eingeben.';
|
||||||
}
|
}
|
||||||
if (strlen($password) < 8) {
|
if (strlen($password) < 8) {
|
||||||
$errors[] = 'Das Passwort muss mindestens 8 Zeichen lang sein.';
|
$errors[] = 'Das Passwort muss mindestens 8 Zeichen lang sein.';
|
||||||
@@ -910,7 +910,7 @@ function saas_register_tenant_owner(PDO $pdo, array $input): array
|
|||||||
if ((int)$stmt->fetchColumn() > 0) {
|
if ((int)$stmt->fetchColumn() > 0) {
|
||||||
return [
|
return [
|
||||||
'ok' => false,
|
'ok' => false,
|
||||||
'errors' => ['Dieses Kundenkuerzel ist bereits vergeben.'],
|
'errors' => ['Dieses Kundenkürzel ist bereits vergeben.'],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -117,8 +117,8 @@ function saas_send_password_reset_mail(string $to, string $token): array
|
|||||||
$body = implode("\n", [
|
$body = implode("\n", [
|
||||||
'Hallo,',
|
'Hallo,',
|
||||||
'',
|
'',
|
||||||
'fuer dein Kaffeeliste-Konto wurde ein Passwort-Reset angefordert.',
|
'für dein Kaffeeliste-Konto wurde ein Passwort-Reset angefordert.',
|
||||||
'Oeffne diesen Link, um ein neues Passwort zu setzen:',
|
'Öffne diesen Link, um ein neues Passwort zu setzen:',
|
||||||
'',
|
'',
|
||||||
$link,
|
$link,
|
||||||
'',
|
'',
|
||||||
@@ -128,7 +128,7 @@ function saas_send_password_reset_mail(string $to, string $token): array
|
|||||||
'Deine Kaffeeliste',
|
'Deine Kaffeeliste',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return saas_send_mail($to, 'Kaffeeliste Passwort zuruecksetzen', $body);
|
return saas_send_mail($to, 'Kaffeeliste Passwort zurücksetzen', $body);
|
||||||
}
|
}
|
||||||
|
|
||||||
function saas_send_email_verification_mail(string $to, string $token): array
|
function saas_send_email_verification_mail(string $to, string $token): array
|
||||||
@@ -137,8 +137,8 @@ function saas_send_email_verification_mail(string $to, string $token): array
|
|||||||
$body = implode("\n", [
|
$body = implode("\n", [
|
||||||
'Hallo,',
|
'Hallo,',
|
||||||
'',
|
'',
|
||||||
'bitte bestaetige deine E-Mail-Adresse fuer Kaffeeliste.',
|
'bitte bestätige deine E-Mail-Adresse für Kaffeeliste.',
|
||||||
'Oeffne dazu diesen Link:',
|
'Öffne dazu diesen Link:',
|
||||||
'',
|
'',
|
||||||
$link,
|
$link,
|
||||||
'',
|
'',
|
||||||
@@ -147,5 +147,5 @@ function saas_send_email_verification_mail(string $to, string $token): array
|
|||||||
'Deine Kaffeeliste',
|
'Deine Kaffeeliste',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return saas_send_mail($to, 'Kaffeeliste E-Mail bestaetigen', $body);
|
return saas_send_mail($to, 'Kaffeeliste E-Mail bestätigen', $body);
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -33,7 +33,7 @@ function csv_prepare_upload(array $file): array
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (($file['size'] ?? 0) <= 0 || $file['size'] > 5 * 1024 * 1024) {
|
if (($file['size'] ?? 0) <= 0 || $file['size'] > 5 * 1024 * 1024) {
|
||||||
return [null, 'Die CSV-Datei ist leer oder groesser als 5 MB.'];
|
return [null, 'Die CSV-Datei ist leer oder größer als 5 MB.'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$originalName = (string)($file['name'] ?? '');
|
$originalName = (string)($file['name'] ?? '');
|
||||||
@@ -248,7 +248,7 @@ if ($_SERVER["REQUEST_METHOD"] == "POST") {
|
|||||||
}elseif($eintrag[3] == 3){
|
}elseif($eintrag[3] == 3){
|
||||||
echo "Benutzer nicht gefunden";
|
echo "Benutzer nicht gefunden";
|
||||||
}elseif($eintrag[3] == 4){
|
}elseif($eintrag[3] == 4){
|
||||||
echo "Ungueltige CSV-Zeile";
|
echo "Ungültige CSV-Zeile";
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "</td>
|
echo "</td>
|
||||||
|
|||||||
+12
-12
@@ -1,17 +1,17 @@
|
|||||||
# Lokaler MySQL-Dev-Start
|
# Lokaler MySQL-Dev-Start
|
||||||
|
|
||||||
Die Legacy-App kann fuer Entwicklung gegen MySQL laufen. Dafuer gibt es eine
|
Die Legacy-App kann für Entwicklung gegen MySQL laufen. Dafür gibt es eine
|
||||||
Kompatibilitaetsschicht, die die verwendeten `sqlsrv_*`-Funktionen im Dev-Modus
|
Kompatibilitätsschicht, die die verwendeten `sqlsrv_*`-Funktionen im Dev-Modus
|
||||||
auf PDO/MySQL abbildet.
|
auf PDO/MySQL abbildet.
|
||||||
|
|
||||||
## Voraussetzungen
|
## Voraussetzungen
|
||||||
|
|
||||||
- PHP CLI mit `pdo_mysql`.
|
- PHP CLI mit `pdo_mysql`.
|
||||||
- MySQL-Testdatenbank.
|
- MySQL-Testdatenbank.
|
||||||
- Keine Produktivdaten und keine Produktivpasswoerter im Repository.
|
- Keine Produktivdaten und keine Produktivpasswörter im Repository.
|
||||||
|
|
||||||
In dieser VS-Code-Server-Umgebung wurde PHP lokal unter `.local/` entpackt,
|
In dieser VS-Code-Server-Umgebung wurde PHP lokal unter `.local/` entpackt,
|
||||||
weil `sudo` nicht passwordless verfuegbar war. `.local/` wird von Git ignoriert.
|
weil `sudo` nicht passwordless verfügbar war. `.local/` wird von Git ignoriert.
|
||||||
|
|
||||||
## Umgebungsvariablen
|
## Umgebungsvariablen
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ export DEV_AUTH_EMAIL="admin@test.local"
|
|||||||
export DEV_AUTH_NAME="Test Admin"
|
export DEV_AUTH_NAME="Test Admin"
|
||||||
# Optional: Standard ist var/sessions im Repository.
|
# Optional: Standard ist var/sessions im Repository.
|
||||||
export APP_SESSION_PATH="/path/to/writable/sessions"
|
export APP_SESSION_PATH="/path/to/writable/sessions"
|
||||||
# Optional fuer Passwort-Reset und E-Mail-Verifikation.
|
# Optional für Passwort-Reset und E-Mail-Verifikation.
|
||||||
export APP_BASE_URL="http://127.0.0.1:8080"
|
export APP_BASE_URL="http://127.0.0.1:8080"
|
||||||
export APP_MAIL_TRANSPORT="log"
|
export APP_MAIL_TRANSPORT="log"
|
||||||
export APP_MAIL_LOG_DIR="/path/to/writable/mail-log"
|
export APP_MAIL_LOG_DIR="/path/to/writable/mail-log"
|
||||||
@@ -64,18 +64,18 @@ HOST=127.0.0.1 PORT=8080 scripts/run-dev-server.sh
|
|||||||
```
|
```
|
||||||
|
|
||||||
Danach ist die App unter `http://127.0.0.1:8080/` erreichbar. In VS Code kann
|
Danach ist die App unter `http://127.0.0.1:8080/` erreichbar. In VS Code kann
|
||||||
der Port ueber die Ports-Ansicht weitergeleitet werden.
|
der Port über die Ports-Ansicht weitergeleitet werden.
|
||||||
|
|
||||||
## Hinweise
|
## Hinweise
|
||||||
|
|
||||||
- Der Dev-Login umgeht AD/LDAP und nutzt `DEV_AUTH_EMAIL`.
|
- Der Dev-Login umgeht AD/LDAP und nutzt `DEV_AUTH_EMAIL`.
|
||||||
- Der Dev-Mailversand nutzt standardmaessig `APP_MAIL_TRANSPORT=log` und legt
|
- Der Dev-Mailversand nutzt standardmäßig `APP_MAIL_TRANSPORT=log` und legt
|
||||||
Nachrichten unter `var/mail` ab. Fuer Produktion kann zunaechst
|
Nachrichten unter `var/mail` ab. Für Produktion kann zunächst
|
||||||
`APP_MAIL_TRANSPORT=mail` mit passendem `APP_BASE_URL` und Absender gesetzt
|
`APP_MAIL_TRANSPORT=mail` mit passendem `APP_BASE_URL` und Absender gesetzt
|
||||||
werden; eine SMTP-/Provider-Anbindung bleibt ein spaeterer Betriebsausbau.
|
werden; eine SMTP-/Provider-Anbindung bleibt ein späterer Betriebsausbau.
|
||||||
- Die Tabellen werden ueber `database/migrations/` angelegt.
|
- Die Tabellen werden über `database/migrations/` angelegt.
|
||||||
- `database/mysql-dev-schema.sql` bleibt als historische Dev-Schema-Baseline
|
- `database/mysql-dev-schema.sql` bleibt als historische Dev-Schema-Baseline
|
||||||
erhalten; der aktive Weg ist `scripts/migrate.php`.
|
erhalten; der aktive Weg ist `scripts/migrate.php`.
|
||||||
- Session-Dateien liegen standardmaessig unter `var/sessions`; `var/` wird von
|
- Session-Dateien liegen standardmäßig unter `var/sessions`; `var/` wird von
|
||||||
Git ignoriert.
|
Git ignoriert.
|
||||||
- Der Dev-Modus ist nur fuer lokale Tests gedacht, nicht fuer Produktion.
|
- Der Dev-Modus ist nur für lokale Tests gedacht, nicht für Produktion.
|
||||||
|
|||||||
+18
-18
@@ -3,7 +3,7 @@
|
|||||||
Stand: 2026-07-11
|
Stand: 2026-07-11
|
||||||
|
|
||||||
M0 dokumentiert den aktuellen Legacy-Bestand, bevor die SaaS-Umstrukturierung
|
M0 dokumentiert den aktuellen Legacy-Bestand, bevor die SaaS-Umstrukturierung
|
||||||
beginnt. Ziel ist eine belastbare Ausgangsbasis fuer Migration, Sicherheit,
|
beginnt. Ziel ist eine belastbare Ausgangsbasis für Migration, Sicherheit,
|
||||||
Design-Erhalt und fachliche Vergleichstests.
|
Design-Erhalt und fachliche Vergleichstests.
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
@@ -13,24 +13,24 @@ Design-Erhalt und fachliche Vergleichstests.
|
|||||||
| Code-Inventar | begonnen | Siehe `code-inventory.md` |
|
| Code-Inventar | begonnen | Siehe `code-inventory.md` |
|
||||||
| Prozesslandkarte | begonnen | In `code-inventory.md` enthalten |
|
| Prozesslandkarte | begonnen | In `code-inventory.md` enthalten |
|
||||||
| Sicherheitsbaseline | begonnen | Siehe `security-baseline.md` |
|
| Sicherheitsbaseline | begonnen | Siehe `security-baseline.md` |
|
||||||
| DB-Schema-Export | nicht aus Alt-DB verfuegbar | Siehe `legacy-db-status.md` |
|
| DB-Schema-Export | nicht aus Alt-DB verfügbar | Siehe `legacy-db-status.md` |
|
||||||
| Golden-Master-Auswertungen | nicht aus Alt-DB verfuegbar | Siehe `legacy-db-status.md` |
|
| Golden-Master-Auswertungen | nicht aus Alt-DB verfügbar | Siehe `legacy-db-status.md` |
|
||||||
| Design-/Screenshot-Referenz | teilweise geliefert | Siehe `screenshot-checklist.md` |
|
| Design-/Screenshot-Referenz | teilweise geliefert | Siehe `screenshot-checklist.md` |
|
||||||
|
|
||||||
## Lokal abgeschlossen
|
## Lokal abgeschlossen
|
||||||
|
|
||||||
- Legacy-Einstiegspunkte und Kernseiten identifiziert.
|
- Legacy-Einstiegspunkte und Kernseiten identifiziert.
|
||||||
- Fachliche Tabellen aus SQL-Strings abgeleitet.
|
- Fachliche Tabellen aus SQL-Strings abgeleitet.
|
||||||
- Schreibende Aktionen und kritische Datenfluesse markiert.
|
- Schreibende Aktionen und kritische Datenflüsse markiert.
|
||||||
- Sicherheitsrisiken fuer M0 inventarisiert.
|
- Sicherheitsrisiken für M0 inventarisiert.
|
||||||
- SQL-Vorlagen fuer Schema- und Golden-Master-Export angelegt.
|
- SQL-Vorlagen für Schema- und Golden-Master-Export angelegt.
|
||||||
- Screenshot-Checkliste fuer Design-Erhalt angelegt.
|
- Screenshot-Checkliste für Design-Erhalt angelegt.
|
||||||
- Erste Screenshot-Referenzen unter `docs/m0/screenshots/` abgelegt.
|
- Erste Screenshot-Referenzen unter `docs/m0/screenshots/` abgelegt.
|
||||||
- Festgelegt: Ein alter MS-SQL-Datenbankstand steht aktuell nicht zur
|
- Festgelegt: Ein alter MS-SQL-Datenbankstand steht aktuell nicht zur
|
||||||
Verfuegung; M0 arbeitet deshalb mit Code, Screenshots und rekonstruierter
|
Verfügung; M0 arbeitet deshalb mit Code, Screenshots und rekonstruierter
|
||||||
MySQL-Dev-Datenbank als Ausgangsbasis.
|
MySQL-Dev-Datenbank als Ausgangsbasis.
|
||||||
|
|
||||||
## Lokale Einschraenkungen
|
## Lokale Einschränkungen
|
||||||
|
|
||||||
- `php` ist in dieser Umgebung nicht im PATH, daher kein lokaler Syntaxcheck und
|
- `php` ist in dieser Umgebung nicht im PATH, daher kein lokaler Syntaxcheck und
|
||||||
kein lokaler App-Start.
|
kein lokaler App-Start.
|
||||||
@@ -40,33 +40,33 @@ Design-Erhalt und fachliche Vergleichstests.
|
|||||||
|
|
||||||
## Blockiert bis Input vorliegt
|
## Blockiert bis Input vorliegt
|
||||||
|
|
||||||
Diese Punkte kann ich ohne externe Informationen nicht abschliessen:
|
Diese Punkte kann ich ohne externe Informationen nicht abschließen:
|
||||||
|
|
||||||
1. Falls spaeter doch noch ein MS-SQL-Dump auftaucht: Schema und
|
1. Falls später doch noch ein MS-SQL-Dump auftaucht: Schema und
|
||||||
Golden-Master-Werte nachtraeglich exportieren.
|
Golden-Master-Werte nachträglich exportieren.
|
||||||
2. MySQL-Dev-Schema als neue rekonstruierte Baseline weiter verifizieren.
|
2. MySQL-Dev-Schema als neue rekonstruierte Baseline weiter verifizieren.
|
||||||
3. Fehlende Screenshot-Zustaende nachreichen oder bewusst als optional markieren.
|
3. Fehlende Screenshot-Zustände nachreichen oder bewusst als optional markieren.
|
||||||
4. Produktivumgebung dokumentieren: PHP-Version, Webserver, SQL-Server-Version,
|
4. Produktivumgebung dokumentieren: PHP-Version, Webserver, SQL-Server-Version,
|
||||||
Auth-Setup, Cron/Job-Ausfuehrung.
|
Auth-Setup, Cron/Job-Ausführung.
|
||||||
|
|
||||||
## Was ich von dir brauche
|
## Was ich von dir brauche
|
||||||
|
|
||||||
Falls ein alter MS-SQL-Stand spaeter noch auftaucht, bitte eines der folgenden
|
Falls ein alter MS-SQL-Stand später noch auftaucht, bitte eines der folgenden
|
||||||
Pakete bereitstellen:
|
Pakete bereitstellen:
|
||||||
|
|
||||||
- Idealerweise: einen anonymisierten SQL-Server-Schemaexport plus Rowcounts.
|
- Idealerweise: einen anonymisierten SQL-Server-Schemaexport plus Rowcounts.
|
||||||
- Alternativ: Zugriffsdaten zu einer Test-/Staging-DB, nicht zu Produktion.
|
- Alternativ: Zugriffsdaten zu einer Test-/Staging-DB, nicht zu Produktion.
|
||||||
- Alternativ: die Ergebnisse aus `schema-export.sql` als CSV/Excel/Markdown.
|
- Alternativ: die Ergebnisse aus `schema-export.sql` als CSV/Excel/Markdown.
|
||||||
|
|
||||||
Zusaetzlich hilfreich:
|
Zusätzlich hilfreich:
|
||||||
|
|
||||||
- Ein erreichbarer Test-Link zur bestehenden App oder Screenshots der Seiten aus
|
- Ein erreichbarer Test-Link zur bestehenden App oder Screenshots der Seiten aus
|
||||||
`screenshot-checklist.md`.
|
`screenshot-checklist.md`.
|
||||||
- Beispiel-Accounts oder Rollen fuer Admin und normales Mitglied, nur fuer eine
|
- Beispiel-Accounts oder Rollen für Admin und normales Mitglied, nur für eine
|
||||||
Testumgebung.
|
Testumgebung.
|
||||||
- Info, ob hart codierte Zugangsdaten aus Legacy-Skripten bereits rotiert wurden.
|
- Info, ob hart codierte Zugangsdaten aus Legacy-Skripten bereits rotiert wurden.
|
||||||
- Entscheidung, ob M1/M2 nativ in PHP oder mit Framework vorbereitet werden
|
- Entscheidung, ob M1/M2 nativ in PHP oder mit Framework vorbereitet werden
|
||||||
sollen.
|
sollen.
|
||||||
|
|
||||||
Bitte keine Produktivpasswoerter oder echten personenbezogenen Exportdaten in
|
Bitte keine Produktivpasswörter oder echten personenbezogenen Exportdaten in
|
||||||
das Repository legen.
|
das Repository legen.
|
||||||
|
|||||||
+36
-36
@@ -10,28 +10,28 @@ Das echte Datenbankschema muss noch mit `schema-export.sql` verifiziert werden.
|
|||||||
| Datei | Rolle | Wichtige Beobachtung |
|
| Datei | Rolle | Wichtige Beobachtung |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `config.php` | AD-/DB-Konfiguration | Erstellt globale SQL-Server-Verbindung `$conn` |
|
| `config.php` | AD-/DB-Konfiguration | Erstellt globale SQL-Server-Verbindung `$conn` |
|
||||||
| `functions.php` | Auth-/User-Helper | Liest `$_SERVER['AUTH_USER']`, inkludiert LDAP, prueft `kl_Mitarbeiter` |
|
| `functions.php` | Auth-/User-Helper | Liest `$_SERVER['AUTH_USER']`, inkludiert LDAP, prüft `kl_Mitarbeiter` |
|
||||||
| `functionsLDAP.php` | LDAP-Mailauflösung | Ermittelt `$mailadress` aus AD |
|
| `functionsLDAP.php` | LDAP-Mailauflösung | Ermittelt `$mailadress` aus AD |
|
||||||
| `header.php` | HTML-Head und Hinweisbanner | Laedt `assets/css/main.css`, liest `kl_hinweise` |
|
| `header.php` | HTML-Head und Hinweisbanner | Lädt `assets/css/main.css`, liest `kl_hinweise` |
|
||||||
| `footer.php` | App-Sidebar und JS | Enthaelt die sichtbare Navigation und Admin-Menues |
|
| `footer.php` | App-Sidebar und JS | Enthält die sichtbare Navigation und Admin-Menüs |
|
||||||
| `nav.php` | Navigation | Aktuell praktisch leer |
|
| `nav.php` | Navigation | Aktuell praktisch leer |
|
||||||
| `headerline.php` | Headerfragment | Enthaelt NUL-Zeichen, fachlich unklar |
|
| `headerline.php` | Headerfragment | Enthält NUL-Zeichen, fachlich unklar |
|
||||||
| `assets/css/main.css` | Hauptdesign | HTML5-UP Editorial, gruener Akzent, Tabellen, Buttons, Sidebar |
|
| `assets/css/main.css` | Hauptdesign | HTML5-UP Editorial, grüner Akzent, Tabellen, Buttons, Sidebar |
|
||||||
| `DataTables/` | Tabellen-Assets | Wird teilweise eingebunden, aber nicht konsequent initialisiert |
|
| `DataTables/` | Tabellen-Assets | Wird teilweise eingebunden, aber nicht konsequent initialisiert |
|
||||||
| `PHPMailer/` | Mailversand | Fuer Rundmails/Jahresauswertung genutzt |
|
| `PHPMailer/` | Mailversand | Für Rundmails/Jahresauswertung genutzt |
|
||||||
| `TCPDF/` | PDF-Export | Fuer Kaffeelisten-Export genutzt |
|
| `TCPDF/` | PDF-Export | Für Kaffeelisten-Export genutzt |
|
||||||
|
|
||||||
## Fachliche Kernseiten
|
## Fachliche Kernseiten
|
||||||
|
|
||||||
| Datei | Prozess | Tabellen |
|
| Datei | Prozess | Tabellen |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `index.php` | Persoenliches Dashboard, Saldo, Jahreswerte, eigene Striche, PayPal-Links | `kl_Mitarbeiter`, `kl_Einzahlungen`, `kl_Kaffeeverbrauch`, `kl_config` |
|
| `index.php` | Persönliches Dashboard, Saldo, Jahreswerte, eigene Striche, PayPal-Links | `kl_Mitarbeiter`, `kl_Einzahlungen`, `kl_Kaffeeverbrauch`, `kl_config` |
|
||||||
| `kaffeeliste.php` | Admin-Gesamtuebersicht mit Salden | `kl_Mitarbeiter`, `kl_Einzahlungen`, `kl_Kaffeeverbrauch` |
|
| `kaffeeliste.php` | Admin-Gesamtübersicht mit Salden | `kl_Mitarbeiter`, `kl_Einzahlungen`, `kl_Kaffeeverbrauch` |
|
||||||
| `stricheintragen.php` | Sammelerfassung von Strichen | `kl_Mitarbeiter`, `kl_Kaffeeverbrauch`, `kl_config` |
|
| `stricheintragen.php` | Sammelerfassung von Strichen | `kl_Mitarbeiter`, `kl_Kaffeeverbrauch`, `kl_config` |
|
||||||
| `einzahlung.php` | Sammelerfassung von Einzahlungen | `kl_Mitarbeiter`, `kl_Einzahlungen`, `kl_Kaffeeverbrauch` |
|
| `einzahlung.php` | Sammelerfassung von Einzahlungen | `kl_Mitarbeiter`, `kl_Einzahlungen`, `kl_Kaffeeverbrauch` |
|
||||||
| `mitarbeiterverwalten.php` | Mitglieder anlegen, bearbeiten, aktivieren, deaktivieren | `kl_Mitarbeiter` |
|
| `mitarbeiterverwalten.php` | Mitglieder anlegen, bearbeiten, aktivieren, deaktivieren | `kl_Mitarbeiter` |
|
||||||
| `namenanpassen.php` | Anzeigenamen aendern | `kl_Mitarbeiter` |
|
| `namenanpassen.php` | Anzeigenamen ändern | `kl_Mitarbeiter` |
|
||||||
| `letzteneintraege.php` | Letzte Buchungen anzeigen und loeschen | `kl_Einzahlungen`, `kl_Kaffeeverbrauch`, `kl_Mitarbeiter` |
|
| `letzteneintraege.php` | Letzte Buchungen anzeigen und löschen | `kl_Einzahlungen`, `kl_Kaffeeverbrauch`, `kl_Mitarbeiter` |
|
||||||
| `csvupload.php` | Zahlungs-CSV importieren | `kl_Mitarbeiter`, `kl_Einzahlungen` |
|
| `csvupload.php` | Zahlungs-CSV importieren | `kl_Mitarbeiter`, `kl_Einzahlungen` |
|
||||||
| `exportKaffeeliste.php` | PDF-/Listenexport | `kl_Mitarbeiter`, `kl_Kaffeeverbrauch`, `kl_Einzahlungen`, `kl_config` |
|
| `exportKaffeeliste.php` | PDF-/Listenexport | `kl_Mitarbeiter`, `kl_Kaffeeverbrauch`, `kl_Einzahlungen`, `kl_config` |
|
||||||
| `mailausgebe.php` | Mailausgabe/Adressliste | `kl_Mitarbeiter` |
|
| `mailausgebe.php` | Mailausgabe/Adressliste | `kl_Mitarbeiter` |
|
||||||
@@ -44,7 +44,7 @@ Das echte Datenbankschema muss noch mit `schema-export.sql` verifiziert werden.
|
|||||||
|
|
||||||
## Abgeleitete Tabellen und Spalten
|
## Abgeleitete Tabellen und Spalten
|
||||||
|
|
||||||
Diese Spalten sind aus dem Code abgeleitet und muessen mit dem echten DB-Schema
|
Diese Spalten sind aus dem Code abgeleitet und müssen mit dem echten DB-Schema
|
||||||
abgeglichen werden.
|
abgeglichen werden.
|
||||||
|
|
||||||
| Tabelle | Abgeleitete Spalten |
|
| Tabelle | Abgeleitete Spalten |
|
||||||
@@ -64,13 +64,13 @@ abgeglichen werden.
|
|||||||
1. Seite inkludiert `functions.php`.
|
1. Seite inkludiert `functions.php`.
|
||||||
2. `functions.php` liest `$_SERVER['AUTH_USER']`.
|
2. `functions.php` liest `$_SERVER['AUTH_USER']`.
|
||||||
3. `functionsLDAP.php` ermittelt Mailadresse aus LDAP.
|
3. `functionsLDAP.php` ermittelt Mailadresse aus LDAP.
|
||||||
4. Zugriff wird ueber `kl_Mitarbeiter.Email`, `aktiv` und `admin` geprueft.
|
4. Zugriff wird über `kl_Mitarbeiter.Email`, `aktiv` und `admin` geprüft.
|
||||||
|
|
||||||
M0-Feststellung:
|
M0-Feststellung:
|
||||||
Login-Konto, Kaffee-Teilnehmer und Rolle sind im Legacy-Modell gekoppelt. Fuer
|
Login-Konto, Kaffee-Teilnehmer und Rolle sind im Legacy-Modell gekoppelt. Für
|
||||||
SaaS muessen `users`, `participants` und `tenant_memberships` getrennt werden.
|
SaaS müssen `users`, `participants` und `tenant_memberships` getrennt werden.
|
||||||
|
|
||||||
### Persoenliches Dashboard
|
### Persönliches Dashboard
|
||||||
|
|
||||||
Quelle: `index.php`.
|
Quelle: `index.php`.
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ Berechnungen:
|
|||||||
- Gesamtausgabe: Summe `kl_Kaffeeverbrauch.Kosten`.
|
- Gesamtausgabe: Summe `kl_Kaffeeverbrauch.Kosten`.
|
||||||
- Gesamtstriche: Summe `kl_Kaffeeverbrauch.AnzahlStriche`.
|
- Gesamtstriche: Summe `kl_Kaffeeverbrauch.AnzahlStriche`.
|
||||||
- Aktueller Stand: Einzahlungen minus Ausgaben.
|
- Aktueller Stand: Einzahlungen minus Ausgaben.
|
||||||
- Jahreswerte: dieselben Summen fuer aktuelles Jahr.
|
- Jahreswerte: dieselben Summen für aktuelles Jahr.
|
||||||
- Bei aktivem `strichperweb`: eigener Strich-Eintrag.
|
- Bei aktivem `strichperweb`: eigener Strich-Eintrag.
|
||||||
- Bei aktivem `paypaluse`: PayPal-Links anzeigen.
|
- Bei aktivem `paypaluse`: PayPal-Links anzeigen.
|
||||||
|
|
||||||
@@ -123,19 +123,19 @@ M0-Feststellung:
|
|||||||
Das `admin`-Flag ist fachlich eine Rolleninformation und sollte in der SaaS-App
|
Das `admin`-Flag ist fachlich eine Rolleninformation und sollte in der SaaS-App
|
||||||
in `tenant_memberships.role` wandern.
|
in `tenant_memberships.role` wandern.
|
||||||
|
|
||||||
### Korrektur letzter Eintraege
|
### Korrektur letzter Einträge
|
||||||
|
|
||||||
Quelle: `letzteneintraege.php`.
|
Quelle: `letzteneintraege.php`.
|
||||||
|
|
||||||
Aktionen:
|
Aktionen:
|
||||||
|
|
||||||
- Letzte 100 Einzahlungen anzeigen.
|
- Letzte 100 Einzahlungen anzeigen.
|
||||||
- Einzahlung hart loeschen.
|
- Einzahlung hart löschen.
|
||||||
- Letzte 100 Strich-Eintraege anzeigen.
|
- Letzte 100 Strich-Einträge anzeigen.
|
||||||
- Strich-Eintrag hart loeschen.
|
- Strich-Eintrag hart löschen.
|
||||||
|
|
||||||
M0-Feststellung:
|
M0-Feststellung:
|
||||||
Finanznahe Korrekturen sollten im Zielmodell nicht hart loeschen, sondern als
|
Finanznahe Korrekturen sollten im Zielmodell nicht hart löschen, sondern als
|
||||||
Storno/Reversal mit Audit-Trail gespeichert werden.
|
Storno/Reversal mit Audit-Trail gespeichert werden.
|
||||||
|
|
||||||
### CSV-Import
|
### CSV-Import
|
||||||
@@ -148,8 +148,8 @@ Ablauf:
|
|||||||
- CSV mit Komma-Trennung lesen.
|
- CSV mit Komma-Trennung lesen.
|
||||||
- Name aus Spalte 3, Betrag aus Spalte 7, Datum aus Spalte 0.
|
- Name aus Spalte 3, Betrag aus Spalte 7, Datum aus Spalte 0.
|
||||||
- Mitarbeiter per Name oder `paypalname` finden.
|
- Mitarbeiter per Name oder `paypalname` finden.
|
||||||
- Dublette anhand Mitarbeiter, Betrag und Datumstag pruefen.
|
- Dublette anhand Mitarbeiter, Betrag und Datumstag prüfen.
|
||||||
- Einzahlung einfuegen.
|
- Einzahlung einfügen.
|
||||||
- Ergebnis in Erfolg/Fehler klassifizieren.
|
- Ergebnis in Erfolg/Fehler klassifizieren.
|
||||||
|
|
||||||
### Jahresauswertung
|
### Jahresauswertung
|
||||||
@@ -160,33 +160,33 @@ Ablauf:
|
|||||||
|
|
||||||
- Gesamtstriche des aktuellen Jahres je aktivem Mitarbeiter berechnen.
|
- Gesamtstriche des aktuellen Jahres je aktivem Mitarbeiter berechnen.
|
||||||
- Konstante Anzahl neuer Striche/Gutschrift proportional verteilen.
|
- Konstante Anzahl neuer Striche/Gutschrift proportional verteilen.
|
||||||
- Einzahlung je Mitarbeiter einfuegen.
|
- Einzahlung je Mitarbeiter einfügen.
|
||||||
- Mail an Mitarbeiter senden.
|
- Mail an Mitarbeiter senden.
|
||||||
|
|
||||||
M0-Feststellung:
|
M0-Feststellung:
|
||||||
Das ist ein Job/Skript mit direktem Schreibzugriff und Mailversand. Fuer SaaS
|
Das ist ein Job/Skript mit direktem Schreibzugriff und Mailversand. Für SaaS
|
||||||
braucht es Dry-Run, Audit, Tenant-Scope und expliziten Operator.
|
braucht es Dry-Run, Audit, Tenant-Scope und expliziten Operator.
|
||||||
|
|
||||||
## Offene Schemafragen
|
## Offene Schemafragen
|
||||||
|
|
||||||
- Gibt es Primary Keys, Foreign Keys und Indizes fuer die `kl_`-Tabellen?
|
- Gibt es Primary Keys, Foreign Keys und Indizes für die `kl_`-Tabellen?
|
||||||
- Sind Datentypen fuer Geldwerte `decimal`, `money`, `float` oder etwas anderes?
|
- Sind Datentypen für Geldwerte `decimal`, `money`, `float` oder etwas anderes?
|
||||||
- Gibt es historische Spalten, die im Code nicht sichtbar sind?
|
- Gibt es historische Spalten, die im Code nicht sichtbar sind?
|
||||||
- Gibt es Trigger oder Stored Procedures?
|
- Gibt es Trigger oder Stored Procedures?
|
||||||
- Gibt es weitere Jobs ausser `jahresauswertung.php`?
|
- Gibt es weitere Jobs außer `jahresauswertung.php`?
|
||||||
- Sind Umfragetabellen produktiv relevant oder Archiv/Randmodul?
|
- Sind Umfragetabellen produktiv relevant oder Archiv/Randmodul?
|
||||||
|
|
||||||
## Technische Legacy-Inkonsistenzen
|
## Technische Legacy-Inkonsistenzen
|
||||||
|
|
||||||
- `csvupload.php` sucht in `getMitarbeiterID` nach `Name = ? or paypalname = ?`,
|
- `csvupload.php` sucht in `getMitarbeiterID` nach `Name = ? or paypalname = ?`,
|
||||||
uebergibt aber nur einen Parameter. Das sollte vor der Uebernahme des
|
übergibt aber nur einen Parameter. Das sollte vor der Übernahme des
|
||||||
CSV-Flows verifiziert werden.
|
CSV-Flows verifiziert werden.
|
||||||
- `einzahlung.php` prueft auf `$_GET["action"]`, die Buttons erzeugen aber
|
- `einzahlung.php` prüft auf `$_GET["action"]`, die Buttons erzeugen aber
|
||||||
URLs mit `aktion=...`. Der Vorderseite-/Rueckseite-Filter kann dadurch
|
URLs mit `aktion=...`. Der Vorderseite-/Rückseite-Filter kann dadurch
|
||||||
abweichend vom erwarteten Verhalten laufen.
|
abweichend vom erwarteten Verhalten laufen.
|
||||||
- `exportKaffeeliste.php` referenziert `tcpdf/tcpdf.php`, waehrend der Ordner im
|
- `exportKaffeeliste.php` referenziert `tcpdf/tcpdf.php`, während der Ordner im
|
||||||
Repository `TCPDF/` heisst. Auf case-sensitiven Dateisystemen kann das
|
Repository `TCPDF/` heißt. Auf case-sensitiven Dateisystemen kann das
|
||||||
brechen.
|
brechen.
|
||||||
- `headerline.php` ist fachlich leer beziehungsweise mit NUL-Zeichen gefuellt.
|
- `headerline.php` ist fachlich leer beziehungsweise mit NUL-Zeichen gefüllt.
|
||||||
Vor der neuen App-Shell sollte geklaert werden, ob die Datei entfernt werden
|
Vor der neuen App-Shell sollte geklärt werden, ob die Datei entfernt werden
|
||||||
kann.
|
kann.
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ M0 Golden-Master Queries
|
|||||||
|
|
||||||
Ziel:
|
Ziel:
|
||||||
- Fachliche Legacy-Ergebnisse exportieren, damit Migration und neue SaaS-App
|
- Fachliche Legacy-Ergebnisse exportieren, damit Migration und neue SaaS-App
|
||||||
gegen denselben Stand verglichen werden koennen.
|
gegen denselben Stand verglichen werden können.
|
||||||
|
|
||||||
Ausfuehrung:
|
Ausführung:
|
||||||
- In der Legacy-Datenbank ausfuehren.
|
- In der Legacy-Datenbank ausführen.
|
||||||
- Ergebnisse je Query als CSV speichern.
|
- Ergebnisse je Query als CSV speichern.
|
||||||
- Keine personenbezogenen Exporte ins Repo committen.
|
- Keine personenbezogenen Exporte ins Repo committen.
|
||||||
*/
|
*/
|
||||||
@@ -94,7 +94,7 @@ FROM kl_Einzahlungen e
|
|||||||
JOIN kl_Mitarbeiter m ON m.MitarbeiterID = e.MitarbeiterID
|
JOIN kl_Mitarbeiter m ON m.MitarbeiterID = e.MitarbeiterID
|
||||||
ORDER BY e.Datum DESC, e.EinzahlungsID DESC;
|
ORDER BY e.Datum DESC, e.EinzahlungsID DESC;
|
||||||
|
|
||||||
-- 5. Letzte Strich-/Verbrauchseintraege je Teilnehmer
|
-- 5. Letzte Strich-/Verbrauchseinträge je Teilnehmer
|
||||||
SELECT
|
SELECT
|
||||||
v.VerbrauchID,
|
v.VerbrauchID,
|
||||||
v.MitarbeiterID,
|
v.MitarbeiterID,
|
||||||
@@ -142,7 +142,7 @@ GROUP BY m.MitarbeiterID, m.Name, m.Email
|
|||||||
HAVING SUM(v.AnzahlStriche) >= 10
|
HAVING SUM(v.AnzahlStriche) >= 10
|
||||||
ORDER BY m.Name;
|
ORDER BY m.Name;
|
||||||
|
|
||||||
-- 9. 100-Tage-Rueckseite analog Legacy-Stricherfassung
|
-- 9. 100-Tage-Rückseite analog Legacy-Stricherfassung
|
||||||
SELECT
|
SELECT
|
||||||
m.MitarbeiterID,
|
m.MitarbeiterID,
|
||||||
m.Name,
|
m.Name,
|
||||||
@@ -182,4 +182,3 @@ WHERE YEAR(v.Datum) = @CurrentYear
|
|||||||
AND m.aktiv = 1
|
AND m.aktiv = 1
|
||||||
GROUP BY m.MitarbeiterID, m.Name, m.Email
|
GROUP BY m.MitarbeiterID, m.Name, m.Email
|
||||||
ORDER BY GesamtStriche DESC, m.Name;
|
ORDER BY GesamtStriche DESC, m.Name;
|
||||||
|
|
||||||
|
|||||||
+14
-15
@@ -4,44 +4,43 @@ Stand: 2026-07-11
|
|||||||
|
|
||||||
## Entscheidung
|
## Entscheidung
|
||||||
|
|
||||||
Ein alter MS-SQL-Datenbankstand steht aktuell nicht zur Verfuegung. Deshalb
|
Ein alter MS-SQL-Datenbankstand steht aktuell nicht zur Verfügung. Deshalb
|
||||||
koennen `schema-export.sql` und `golden-master-queries.sql` derzeit nicht gegen
|
können `schema-export.sql` und `golden-master-queries.sql` derzeit nicht gegen
|
||||||
eine echte Legacy-Datenbank ausgefuehrt werden.
|
eine echte Legacy-Datenbank ausgeführt werden.
|
||||||
|
|
||||||
Fuer die weitere Umstrukturierung gilt daher:
|
Für die weitere Umstrukturierung gilt daher:
|
||||||
|
|
||||||
- Der Legacy-Code ist die primaere Quelle fuer das fachliche Verhalten.
|
- Der Legacy-Code ist die primäre Quelle für das fachliche Verhalten.
|
||||||
- Die Screenshots unter `docs/m0/screenshots/` sind die visuelle Referenz.
|
- Die Screenshots unter `docs/m0/screenshots/` sind die visuelle Referenz.
|
||||||
- Die MySQL-Testdatenbank ist die rekonstruierte Entwicklungsbasis.
|
- Die MySQL-Testdatenbank ist die rekonstruierte Entwicklungsbasis.
|
||||||
- Fachliche Golden-Master-Werte werden aus rekonstruierten Testfaellen statt aus
|
- Fachliche Golden-Master-Werte werden aus rekonstruierten Testfällen statt aus
|
||||||
historischer Produktivdatenbank aufgebaut.
|
historischer Produktivdatenbank aufgebaut.
|
||||||
|
|
||||||
## Konsequenz fuer M1
|
## Konsequenz für M1
|
||||||
|
|
||||||
M1 wird nicht als Vergleich gegen echte Alt-Daten gestartet, sondern als
|
M1 wird nicht als Vergleich gegen echte Alt-Daten gestartet, sondern als
|
||||||
rekonstruierter Golden-Master:
|
rekonstruierter Golden-Master:
|
||||||
|
|
||||||
1. Fachliche Regeln aus dem Code ableiten.
|
1. Fachliche Regeln aus dem Code ableiten.
|
||||||
2. Kleine, kontrollierte Testdaten erzeugen.
|
2. Kleine, kontrollierte Testdaten erzeugen.
|
||||||
3. Erwartete Salden, Jahreswerte, Striche, Einzahlungen und CSV-Importfaelle
|
3. Erwartete Salden, Jahreswerte, Striche, Einzahlungen und CSV-Importfälle
|
||||||
manuell beziehungsweise per Testskript definieren.
|
manuell beziehungsweise per Testskript definieren.
|
||||||
4. Neue Implementierung gegen diese erwarteten Werte testen.
|
4. Neue Implementierung gegen diese erwarteten Werte testen.
|
||||||
|
|
||||||
Wenn spaeter doch noch ein MS-SQL-Dump oder Schemaexport auftaucht, werden die
|
Wenn später doch noch ein MS-SQL-Dump oder Schemaexport auftaucht, werden die
|
||||||
urspruenglichen M0-SQL-Dateien nachtraeglich genutzt und die Baseline ergaenzt.
|
ursprünglichen M0-SQL-Dateien nachträglich genutzt und die Baseline ergänzt.
|
||||||
|
|
||||||
## Aktuelle rekonstruierte Basis
|
## Aktuelle rekonstruierte Basis
|
||||||
|
|
||||||
- MySQL-Dev-Schema: `database/mysql-dev-schema.sql`
|
- MySQL-Dev-Schema: `database/mysql-dev-schema.sql`
|
||||||
- Initialisierung: `scripts/init-mysql-dev.php`
|
- Initialisierung: `scripts/init-mysql-dev.php`
|
||||||
- Dev-Start: `scripts/run-dev-server.sh`
|
- Dev-Start: `scripts/run-dev-server.sh`
|
||||||
- MySQL-Kompatibilitaet: `lib/sqlsrv_mysql_compat.php`
|
- MySQL-Kompatibilität: `lib/sqlsrv_mysql_compat.php`
|
||||||
|
|
||||||
## Offene Punkte
|
## Offene Punkte
|
||||||
|
|
||||||
- Soll die MySQL-Testdatenbank ab jetzt die verbindliche Entwicklungsdatenbank
|
- Soll die MySQL-Testdatenbank ab jetzt die verbindliche Entwicklungsdatenbank
|
||||||
fuer M1/M2 sein?
|
für M1/M2 sein?
|
||||||
- Soll das Ziel weiterhin eine angepasste Legacy-PHP-App sein oder ein sauberer
|
- Soll das Ziel weiterhin eine angepasste Legacy-PHP-App sein oder ein sauberer
|
||||||
SaaS-Neuaufbau mit uebernommener Fachlogik?
|
SaaS-Neuaufbau mit übernommener Fachlogik?
|
||||||
- Welche Testfaelle muessen fachlich auf jeden Fall abgedeckt werden?
|
- Welche Testfälle müssen fachlich auf jeden Fall abgedeckt werden?
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Ziel:
|
|||||||
aus der Legacy-Datenbank exportieren.
|
aus der Legacy-Datenbank exportieren.
|
||||||
|
|
||||||
Hinweise:
|
Hinweise:
|
||||||
- In der Ziel-Datenbank ausfuehren.
|
- In der Ziel-Datenbank ausführen.
|
||||||
- Ergebnisse als CSV/Excel speichern und nicht mit Produktiv-Secrets ins Repo
|
- Ergebnisse als CSV/Excel speichern und nicht mit Produktiv-Secrets ins Repo
|
||||||
legen.
|
legen.
|
||||||
- Falls nur Kaffeelisten-Tabellen exportiert werden sollen, den WHERE-Block bei
|
- Falls nur Kaffeelisten-Tabellen exportiert werden sollen, den WHERE-Block bei
|
||||||
@@ -149,4 +149,3 @@ WHERE o.type IN ('P', 'FN', 'IF', 'TF')
|
|||||||
OR OBJECT_DEFINITION(o.object_id) LIKE '%CoffeeSurvey%'
|
OR OBJECT_DEFINITION(o.object_id) LIKE '%CoffeeSurvey%'
|
||||||
)
|
)
|
||||||
ORDER BY s.name, o.name;
|
ORDER BY s.name, o.name;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
Stand: 2026-07-11
|
Stand: 2026-07-11
|
||||||
|
|
||||||
Diese Checkliste friert die bestehende Optik ein, damit die SaaS-App vertraut
|
Diese Checkliste friert die bestehende Optik ein, damit die SaaS-App vertraut
|
||||||
bleibt. Wenn die Legacy-App lokal nicht laeuft, koennen Screenshots aus der
|
bleibt. Wenn die Legacy-App lokal nicht läuft, können Screenshots aus der
|
||||||
aktuellen Umgebung geliefert werden.
|
aktuellen Umgebung geliefert werden.
|
||||||
|
|
||||||
## Allgemeine Vorgaben
|
## Allgemeine Vorgaben
|
||||||
@@ -11,24 +11,24 @@ aktuellen Umgebung geliefert werden.
|
|||||||
- Je Seite Desktop mit ca. 1440 px Breite aufnehmen.
|
- Je Seite Desktop mit ca. 1440 px Breite aufnehmen.
|
||||||
- Je Kernseite mobile Ansicht mit ca. 390 px Breite aufnehmen.
|
- Je Kernseite mobile Ansicht mit ca. 390 px Breite aufnehmen.
|
||||||
- Je relevanter Rolle aufnehmen: normales Mitglied und Admin.
|
- Je relevanter Rolle aufnehmen: normales Mitglied und Admin.
|
||||||
- Keine echten personenbezogenen Daten veroeffentlichen.
|
- Keine echten personenbezogenen Daten veröffentlichen.
|
||||||
- Dateinamen nach Muster `m0-<rolle>-<seite>-<viewport>.png`.
|
- Dateinamen nach Muster `m0-<rolle>-<seite>-<viewport>.png`.
|
||||||
|
|
||||||
## Kernseiten
|
## Kernseiten
|
||||||
|
|
||||||
| Prioritaet | Seite | Rolle | Status | Zweck |
|
| Priorität | Seite | Rolle | Status | Zweck |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| Hoch | `index.php` | Mitglied | vorhanden: `m0-member-dashboard-desktop.png`, `m0-member-dashboard-mobile.png` | Dashboard, Saldo, Jahreswerte, eigene Striche, PayPal |
|
| Hoch | `index.php` | Mitglied | vorhanden: `m0-member-dashboard-desktop.png`, `m0-member-dashboard-mobile.png` | Dashboard, Saldo, Jahreswerte, eigene Striche, PayPal |
|
||||||
| Hoch | `index.php` | Admin | aktuell identisch wie Mitglied | Dashboard mit Admin-Sidebar |
|
| Hoch | `index.php` | Admin | aktuell identisch wie Mitglied | Dashboard mit Admin-Sidebar |
|
||||||
| Hoch | `kaffeeliste.php` | Admin | vorhanden: `m0-admin-kaffeeliste-desktop.png` | Gesamtuebersicht und Aktionsleiste |
|
| Hoch | `kaffeeliste.php` | Admin | vorhanden: `m0-admin-kaffeeliste-desktop.png` | Gesamtübersicht und Aktionsleiste |
|
||||||
| Hoch | `stricheintragen.php` | Admin | vorhanden: `m0-admin-stricheintragen-desktop.png` | Sammelerfassung Striche |
|
| Hoch | `stricheintragen.php` | Admin | vorhanden: `m0-admin-stricheintragen-desktop.png` | Sammelerfassung Striche |
|
||||||
| Hoch | `einzahlung.php` | Admin | vorhanden: `m0-admin-einzahlung-desktop.png` | Sammelerfassung Einzahlungen |
|
| Hoch | `einzahlung.php` | Admin | vorhanden: `m0-admin-einzahlung-desktop.png` | Sammelerfassung Einzahlungen |
|
||||||
| Hoch | `mitarbeiterverwalten.php` | Admin | vorhanden: `m0-admin-mitglieder-desktop.png` | Mitgliederliste und Formular |
|
| Hoch | `mitarbeiterverwalten.php` | Admin | vorhanden: `m0-admin-mitglieder-desktop.png` | Mitgliederliste und Formular |
|
||||||
| Hoch | `letzteneintraege.php` | Admin | vorhanden: `m0-admin-letzteneintraege-desktop.png` | Korrekturansicht mit Loeschaktionen |
|
| Hoch | `letzteneintraege.php` | Admin | vorhanden: `m0-admin-letzteneintraege-desktop.png` | Korrekturansicht mit Löschaktionen |
|
||||||
| Mittel | `csvupload.php` | Admin | vorhanden: `m0-admin-csv-upload-desktop.png` | CSV-Upload-Formular und Ergebniszustand |
|
| Mittel | `csvupload.php` | Admin | vorhanden: `m0-admin-csv-upload-desktop.png` | CSV-Upload-Formular und Ergebniszustand |
|
||||||
| Mittel | `hinweise.php` | Admin | vorhanden: `m0-admin-hinweise-desktop.png` | Hinweise anlegen und Liste |
|
| Mittel | `hinweise.php` | Admin | vorhanden: `m0-admin-hinweise-desktop.png` | Hinweise anlegen und Liste |
|
||||||
| Mittel | `faq.php` | Mitglied | vorhanden: `m0-member-faq-desktop.png` | FAQ-Inhalte und Typografie |
|
| Mittel | `faq.php` | Mitglied | vorhanden: `m0-member-faq-desktop.png` | FAQ-Inhalte und Typografie |
|
||||||
| Mittel | `namenanpassen.php` | Mitglied | offen | Formular fuer Anzeigenamen |
|
| Mittel | `namenanpassen.php` | Mitglied | offen | Formular für Anzeigenamen |
|
||||||
| Niedrig | `teilnehmerauswertung.php` | Admin | offen | Detailauswertung pro Teilnehmer |
|
| Niedrig | `teilnehmerauswertung.php` | Admin | offen | Detailauswertung pro Teilnehmer |
|
||||||
| Niedrig | `mailausgebe.php` | Admin | offen | Mail-/Adressausgabe |
|
| Niedrig | `mailausgebe.php` | Admin | offen | Mail-/Adressausgabe |
|
||||||
| Niedrig | `umfrage.php` | Mitglied | offen, falls SaaS-relevant | Randmodul, falls SaaS-relevant |
|
| Niedrig | `umfrage.php` | Mitglied | offen, falls SaaS-relevant | Randmodul, falls SaaS-relevant |
|
||||||
@@ -49,9 +49,9 @@ docs/m0/screenshots/m0-member-dashboard-mobile.png
|
|||||||
docs/m0/screenshots/m0-member-faq-desktop.png
|
docs/m0/screenshots/m0-member-faq-desktop.png
|
||||||
```
|
```
|
||||||
|
|
||||||
## Zustaende
|
## Zustände
|
||||||
|
|
||||||
Diese UI-Zustaende sollten, wenn moeglich, separat gesichert werden:
|
Diese UI-Zustände sollten, wenn möglich, separat gesichert werden:
|
||||||
|
|
||||||
- Positiver Kontostand.
|
- Positiver Kontostand.
|
||||||
- Negativer Kontostand.
|
- Negativer Kontostand.
|
||||||
@@ -62,14 +62,14 @@ Diese UI-Zustaende sollten, wenn moeglich, separat gesichert werden:
|
|||||||
- CSV-Import mit Erfolg, Dublette und unbekanntem Nutzer.
|
- CSV-Import mit Erfolg, Dublette und unbekanntem Nutzer.
|
||||||
- Hinweisbanner aktiv.
|
- Hinweisbanner aktiv.
|
||||||
- Leere Tabellen oder keine Daten.
|
- Leere Tabellen oder keine Daten.
|
||||||
- Mobile Sidebar geoeffnet und geschlossen.
|
- Mobile Sidebar geöffnet und geschlossen.
|
||||||
|
|
||||||
## Designmerkmale, die erhalten bleiben sollen
|
## Designmerkmale, die erhalten bleiben sollen
|
||||||
|
|
||||||
- Gruener Akzent fuer Links, Buttons und Linien.
|
- Grüner Akzent für Links, Buttons und Linien.
|
||||||
- Roboto-Slab-Ueberschriften.
|
- Roboto-Slab-Überschriften.
|
||||||
- Open-Sans-Fliesstext.
|
- Open-Sans-Fließtext.
|
||||||
- Weisse Hauptflaeche.
|
- Weiße Hauptfläche.
|
||||||
- Graue Sidebar in der App.
|
- Graue Sidebar in der App.
|
||||||
- Tabellen als zentrale Datenansicht.
|
- Tabellen als zentrale Datenansicht.
|
||||||
- Schlichte Formularfelder und Buttons.
|
- Schlichte Formularfelder und Buttons.
|
||||||
@@ -84,5 +84,5 @@ docs/m0/screenshots/
|
|||||||
```
|
```
|
||||||
|
|
||||||
Vor dem Commit sollten Screenshots anonymisiert sein. Wenn echte Namen,
|
Vor dem Commit sollten Screenshots anonymisiert sein. Wenn echte Namen,
|
||||||
E-Mails, PayPal-Daten oder Salden sichtbar sind, besser ausserhalb des Repos
|
E-Mails, PayPal-Daten oder Salden sichtbar sind, besser außerhalb des Repos
|
||||||
ablegen und nur als Referenz verwenden.
|
ablegen und nur als Referenz verwenden.
|
||||||
|
|||||||
@@ -3,17 +3,17 @@
|
|||||||
Stand: 2026-07-11
|
Stand: 2026-07-11
|
||||||
|
|
||||||
Diese Baseline ist eine statische Erstbewertung. Sie ersetzt kein Penetration
|
Diese Baseline ist eine statische Erstbewertung. Sie ersetzt kein Penetration
|
||||||
Testing, markiert aber die wichtigsten Risiken fuer die SaaS-Umstrukturierung.
|
Testing, markiert aber die wichtigsten Risiken für die SaaS-Umstrukturierung.
|
||||||
|
|
||||||
## Kritische Sofortthemen
|
## Kritische Sofortthemen
|
||||||
|
|
||||||
| Risiko | Quelle | Auswirkung | Empfehlung |
|
| Risiko | Quelle | Auswirkung | Empfehlung |
|
||||||
| --- | --- | --- | --- |
|
| --- | --- | --- | --- |
|
||||||
| Hart codierte DB-Zugangsdaten | `jahresauswertung.php` Zeilen 4-8 | Secret-Leak, direkte Produktiv-DB-Gefahr | Zugangsdaten rotieren, Skript deaktivieren oder auf Env-Konfiguration umstellen |
|
| Hart codierte DB-Zugangsdaten | `jahresauswertung.php` Zeilen 4-8 | Secret-Leak, direkte Produktiv-DB-Gefahr | Zugangsdaten rotieren, Skript deaktivieren oder auf Env-Konfiguration umstellen |
|
||||||
| Schreibende Seiten ohne eigene Rollenpruefung | `stricheintragen.php`, `einzahlung.php`, `mailversenden.php`, `exportKaffeeliste.php` | Direkter URL-Aufruf kann Aktionen erlauben | Jede Seite serverseitig mit `requireRole` absichern |
|
| Schreibende Seiten ohne eigene Rollenprüfung | `stricheintragen.php`, `einzahlung.php`, `mailversenden.php`, `exportKaffeeliste.php` | Direkter URL-Aufruf kann Aktionen erlauben | Jede Seite serverseitig mit `requireRole` absichern |
|
||||||
| CSRF-Schutz nur teilweise vorhanden | viele POST-/Delete-Formulare; M2 hat `hinweise.php`, `mitarbeiterverwalten.php`, `namenanpassen.php`, `index.php`, `stricheintragen.php`, `einzahlung.php`, `letzteneintraege.php`, `csvupload.php` abgesichert | Ungewollte Buchungen, Loeschungen, Imports | CSRF fuer alle verbleibenden schreibenden Aktionen |
|
| CSRF-Schutz nur teilweise vorhanden | viele POST-/Delete-Formulare; M2 hat `hinweise.php`, `mitarbeiterverwalten.php`, `namenanpassen.php`, `index.php`, `stricheintragen.php`, `einzahlung.php`, `letzteneintraege.php`, `csvupload.php` abgesichert | Ungewollte Buchungen, Löschungen, Imports | CSRF für alle verbleibenden schreibenden Aktionen |
|
||||||
| Harte Deletes fuer Buchungen | `letzteneintraege.php` | Audit-Historie und Revisionsfaehigkeit gehen verloren | Storno-/Reversal-Modell statt Delete |
|
| Harte Deletes für Buchungen | `letzteneintraege.php` | Audit-Historie und Revisionsfähigkeit gehen verloren | Storno-/Reversal-Modell statt Delete |
|
||||||
| CSV-Upload nur teilweise gehaertet | `csvupload.php`; M2 speichert temporaer unter `var/uploads`, prueft Dateityp und loescht nach Import | Ohne Importvorschau/Audit bleiben Fehlimporte schwer nachvollziehbar | Importvorschau, Batch-/Audit-Log und detaillierte Zeilenfehler in M6 |
|
| CSV-Upload nur teilweise gehärtet | `csvupload.php`; M2 speichert temporär unter `var/uploads`, prüft Dateityp und löscht nach Import | Ohne Importvorschau/Audit bleiben Fehlimporte schwer nachvollziehbar | Importvorschau, Batch-/Audit-Log und detaillierte Zeilenfehler in M6 |
|
||||||
| Kein Tenant-Scope | alle fachlichen Queries | Zentrales SaaS-Leak-Risiko | `tenant_id` verpflichtend und Query-Schicht testen |
|
| Kein Tenant-Scope | alle fachlichen Queries | Zentrales SaaS-Leak-Risiko | `tenant_id` verpflichtend und Query-Schicht testen |
|
||||||
|
|
||||||
## Weitere Befunde
|
## Weitere Befunde
|
||||||
@@ -25,10 +25,10 @@ Testing, markiert aber die wichtigsten Risiken fuer die SaaS-Umstrukturierung.
|
|||||||
| Datumsformat `Y-d-m H:i:s` | `index.php`, `stricheintragen.php`, `einzahlung.php`, `hinweise.php` | ISO/DB-kompatibel `Y-m-d H:i:s` oder DB-Zeit verwenden |
|
| Datumsformat `Y-d-m H:i:s` | `index.php`, `stricheintragen.php`, `einzahlung.php`, `hinweise.php` | ISO/DB-kompatibel `Y-m-d H:i:s` oder DB-Zeit verwenden |
|
||||||
| Ausgabe von Namen/E-Mails teils unescaped | mehrere Tabellen, z.B. Mitgliederverwaltung | `htmlspecialchars` zentral erzwingen |
|
| Ausgabe von Namen/E-Mails teils unescaped | mehrere Tabellen, z.B. Mitgliederverwaltung | `htmlspecialchars` zentral erzwingen |
|
||||||
| Fehlerausgabe mit `sqlsrv_errors()` an Nutzer | mehrere Dateien | Logging intern, neutrale Fehlermeldung extern |
|
| Fehlerausgabe mit `sqlsrv_errors()` an Nutzer | mehrere Dateien | Logging intern, neutrale Fehlermeldung extern |
|
||||||
| CSV-Mitarbeitersuche mit mutmasslich falscher Parameteranzahl | `csvupload.php` `getMitarbeiterID`; in M2 korrigiert | Mit Golden-Master weiter pruefen |
|
| CSV-Mitarbeitersuche mit mutmaßlich falscher Parameteranzahl | `csvupload.php` `getMitarbeiterID`; in M2 korrigiert | Mit Golden-Master weiter prüfen |
|
||||||
| Basis-Auth-Beispiel mit Platzhalter-Passwort | `umfrageergebnisse.php` Kommentarblock | Entfernen oder echte Auth-Middleware nutzen |
|
| Basis-Auth-Beispiel mit Platzhalter-Passwort | `umfrageergebnisse.php` Kommentarblock | Entfernen oder echte Auth-Middleware nutzen |
|
||||||
| App-Navigation ist in `footer.php` | Layoutstruktur | Trennung in App-Shell und Public-Shell |
|
| App-Navigation ist in `footer.php` | Layoutstruktur | Trennung in App-Shell und Public-Shell |
|
||||||
| `headerline.php` enthaelt NUL-Zeichen | `headerline.php` | Datei pruefen/entfernen, wenn ungenutzt |
|
| `headerline.php` enthält NUL-Zeichen | `headerline.php` | Datei prüfen/entfernen, wenn ungenutzt |
|
||||||
| Massenmail ohne Versandlog | `mailversenden.php`, `jahresauswertung.php` | Job-Modell mit Dry-Run, Audit, Rate-Limit |
|
| Massenmail ohne Versandlog | `mailversenden.php`, `jahresauswertung.php` | Job-Modell mit Dry-Run, Audit, Rate-Limit |
|
||||||
|
|
||||||
## Rollen- und Zugriffsrisiken
|
## Rollen- und Zugriffsrisiken
|
||||||
@@ -39,29 +39,29 @@ Aktuell gilt:
|
|||||||
gesteuert.
|
gesteuert.
|
||||||
- Einige Admin-Zielseiten haben eigene Checks.
|
- Einige Admin-Zielseiten haben eigene Checks.
|
||||||
- Einige schreibende oder sensible Dateien verlassen sich nicht durchgehend auf
|
- Einige schreibende oder sensible Dateien verlassen sich nicht durchgehend auf
|
||||||
eine eigene Rollenpruefung.
|
eine eigene Rollenprüfung.
|
||||||
|
|
||||||
Fuer SaaS gilt:
|
Für SaaS gilt:
|
||||||
|
|
||||||
- Menue-Ausblendung ist keine Berechtigungspruefung.
|
- Menü-Ausblendung ist keine Berechtigungsprüfung.
|
||||||
- Jede Route braucht serverseitige Auth- und Rollenpruefung.
|
- Jede Route braucht serverseitige Auth- und Rollenprüfung.
|
||||||
- Jede fachliche Route braucht Tenant-Kontext.
|
- Jede fachliche Route braucht Tenant-Kontext.
|
||||||
- IDs aus Requests muessen zum aktuellen Tenant gehoeren.
|
- IDs aus Requests müssen zum aktuellen Tenant gehören.
|
||||||
|
|
||||||
## Empfohlene Reihenfolge fuer Sicherheitsarbeit
|
## Empfohlene Reihenfolge für Sicherheitsarbeit
|
||||||
|
|
||||||
1. Secrets rotieren und aus dem Code entfernen.
|
1. Secrets rotieren und aus dem Code entfernen.
|
||||||
2. Legacy-Schreibseiten bis zum Umbau hinter explizite Admin-Pruefung setzen.
|
2. Legacy-Schreibseiten bis zum Umbau hinter explizite Admin-Prüfung setzen.
|
||||||
3. CSRF-Schutz schrittweise auf alle verbleibenden Legacy-Schreibseiten ausrollen.
|
3. CSRF-Schutz schrittweise auf alle verbleibenden Legacy-Schreibseiten ausrollen.
|
||||||
4. Finanzdaten im Zielmodell nur noch stornieren, nicht loeschen.
|
4. Finanzdaten im Zielmodell nur noch stornieren, nicht löschen.
|
||||||
5. CSV-Import mit Vorschau, Audit und Zeilenfehlern modellieren.
|
5. CSV-Import mit Vorschau, Audit und Zeilenfehlern modellieren.
|
||||||
6. Einheitliche Escape-/View-Helfer einfuehren.
|
6. Einheitliche Escape-/View-Helfer einführen.
|
||||||
7. Tenant-Isolation mit Tests gegen zwei Tenants absichern.
|
7. Tenant-Isolation mit Tests gegen zwei Tenants absichern.
|
||||||
|
|
||||||
## Nicht im Repo speichern
|
## Nicht im Repo speichern
|
||||||
|
|
||||||
- Produktivpasswoerter.
|
- Produktivpasswörter.
|
||||||
- Echte Nutzerlisten.
|
- Echte Nutzerlisten.
|
||||||
- Bank-/PayPal-Exportdaten mit Personenbezug.
|
- Bank-/PayPal-Exportdaten mit Personenbezug.
|
||||||
- AD-/LDAP-Service-Account-Daten.
|
- AD-/LDAP-Service-Account-Daten.
|
||||||
- Vollstaendige Produktiv-Dumps.
|
- Vollständige Produktiv-Dumps.
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
Stand: 2026-07-12
|
Stand: 2026-07-12
|
||||||
|
|
||||||
Da kein alter MS-SQL-Datenbankstand verfuegbar ist, wird M1 als rekonstruierter
|
Da kein alter MS-SQL-Datenbankstand verfügbar ist, wird M1 als rekonstruierter
|
||||||
Golden Master aufgebaut. Die Referenz entsteht aus Legacy-Code, Screenshots und
|
Golden Master aufgebaut. Die Referenz entsteht aus Legacy-Code, Screenshots und
|
||||||
kontrollierten Testdaten in der MySQL-Dev-Datenbank.
|
kontrollierten Testdaten in der MySQL-Dev-Datenbank.
|
||||||
|
|
||||||
## Ziel
|
## Ziel
|
||||||
|
|
||||||
Die wichtigsten fachlichen Regeln werden mit kleinen, nachvollziehbaren
|
Die wichtigsten fachlichen Regeln werden mit kleinen, nachvollziehbaren
|
||||||
Testfaellen festgeschrieben. Diese Tests dienen spaeter als Sicherheitsnetz fuer
|
Testfällen festgeschrieben. Diese Tests dienen später als Sicherheitsnetz für
|
||||||
die SaaS-Umstrukturierung.
|
die SaaS-Umstrukturierung.
|
||||||
|
|
||||||
## Testdaten-Gruppen
|
## Testdaten-Gruppen
|
||||||
@@ -28,7 +28,7 @@ die SaaS-Umstrukturierung.
|
|||||||
- Mehrere Einzahlungen an unterschiedlichen Tagen.
|
- Mehrere Einzahlungen an unterschiedlichen Tagen.
|
||||||
- Strichbuchung mit einem Strich.
|
- Strichbuchung mit einem Strich.
|
||||||
- Strichbuchung mit zwei Strichen.
|
- Strichbuchung mit zwei Strichen.
|
||||||
- Sammelerfassung fuer mehrere Teilnehmer.
|
- Sammelerfassung für mehrere Teilnehmer.
|
||||||
- Web-Strich-Eintrag mit `Eintragsart = 2`.
|
- Web-Strich-Eintrag mit `Eintragsart = 2`.
|
||||||
|
|
||||||
### Salden
|
### Salden
|
||||||
@@ -36,13 +36,13 @@ die SaaS-Umstrukturierung.
|
|||||||
- Positiver Kontostand.
|
- Positiver Kontostand.
|
||||||
- Negativer Kontostand.
|
- Negativer Kontostand.
|
||||||
- Nullsaldo.
|
- Nullsaldo.
|
||||||
- Jahreswerte fuer aktuelles Jahr.
|
- Jahreswerte für aktuelles Jahr.
|
||||||
- Altdaten aus Vorjahr, die nicht in Jahreswerte fallen.
|
- Altdaten aus Vorjahr, die nicht in Jahreswerte fallen.
|
||||||
|
|
||||||
### CSV-Import
|
### CSV-Import
|
||||||
|
|
||||||
- Treffer ueber Name.
|
- Treffer über Name.
|
||||||
- Treffer ueber `paypalname`.
|
- Treffer über `paypalname`.
|
||||||
- Dublette gleicher Teilnehmer, Betrag und Datum.
|
- Dublette gleicher Teilnehmer, Betrag und Datum.
|
||||||
- Unbekannter Name.
|
- Unbekannter Name.
|
||||||
- Negativer oder leerer Betrag.
|
- Negativer oder leerer Betrag.
|
||||||
@@ -51,11 +51,11 @@ die SaaS-Umstrukturierung.
|
|||||||
|
|
||||||
- Aktiver Hinweis.
|
- Aktiver Hinweis.
|
||||||
- Abgelaufener Hinweis.
|
- Abgelaufener Hinweis.
|
||||||
- Neuer Hinweis ueber Admin-Formular.
|
- Neuer Hinweis über Admin-Formular.
|
||||||
|
|
||||||
## Erwartete Referenzwerte
|
## Erwartete Referenzwerte
|
||||||
|
|
||||||
Fuer jeden Testfall sollen erwartete Werte dokumentiert werden:
|
Für jeden Testfall sollen erwartete Werte dokumentiert werden:
|
||||||
|
|
||||||
- Summe Einzahlungen.
|
- Summe Einzahlungen.
|
||||||
- Summe Kosten.
|
- Summe Kosten.
|
||||||
@@ -72,25 +72,25 @@ Fuer jeden Testfall sollen erwartete Werte dokumentiert werden:
|
|||||||
Seed-Skript anlegen. Erledigt mit `scripts/seed-golden-master.php`.
|
Seed-Skript anlegen. Erledigt mit `scripts/seed-golden-master.php`.
|
||||||
2. `scripts/init-mysql-dev.php` so erweitern, dass es die Testdaten idempotent
|
2. `scripts/init-mysql-dev.php` so erweitern, dass es die Testdaten idempotent
|
||||||
anlegt. Entschieden: Golden-Master-Daten bleiben in einem separaten Skript,
|
anlegt. Entschieden: Golden-Master-Daten bleiben in einem separaten Skript,
|
||||||
damit normale Dev-Daten nicht zwangsweise ueberschrieben werden.
|
damit normale Dev-Daten nicht zwangsweise überschrieben werden.
|
||||||
3. Ein erstes Vergleichsskript `scripts/check-golden-master.php` erstellen.
|
3. Ein erstes Vergleichsskript `scripts/check-golden-master.php` erstellen.
|
||||||
Erledigt.
|
Erledigt.
|
||||||
4. Die wichtigsten Seiten per HTTP abrufen und auf erwartete Texte/Werte
|
4. Die wichtigsten Seiten per HTTP abrufen und auf erwartete Texte/Werte
|
||||||
pruefen. Erledigt mit `scripts/http-smoke.php`.
|
prüfen. Erledigt mit `scripts/http-smoke.php`.
|
||||||
5. Danach M2 starten: technisches Fundament fuer SaaS-Struktur. M1 ist als
|
5. Danach M2 starten: technisches Fundament für SaaS-Struktur. M1 ist als
|
||||||
Sicherheitsnetz nutzbar; offene Dependency-Themen sind unten dokumentiert.
|
Sicherheitsnetz nutzbar; offene Dependency-Themen sind unten dokumentiert.
|
||||||
|
|
||||||
## Skripte
|
## Skripte
|
||||||
|
|
||||||
- `scripts/dev-db.php`: gemeinsame DB-Verbindung fuer Dev-Skripte.
|
- `scripts/dev-db.php`: gemeinsame DB-Verbindung für Dev-Skripte.
|
||||||
- `scripts/golden-master-data.php`: definierte Testdaten und erwartete Werte.
|
- `scripts/golden-master-data.php`: definierte Testdaten und erwartete Werte.
|
||||||
- `scripts/seed-golden-master.php`: legt Golden-Master-Testdaten idempotent an.
|
- `scripts/seed-golden-master.php`: legt Golden-Master-Testdaten idempotent an.
|
||||||
- `scripts/check-golden-master.php`: prueft Salden, Jahreswerte, Rollen,
|
- `scripts/check-golden-master.php`: prüft Salden, Jahreswerte, Rollen,
|
||||||
Listenfilter, CSV-Lookup und Hinweise.
|
Listenfilter, CSV-Lookup und Hinweise.
|
||||||
- `scripts/http-smoke.php`: ruft sichere GET-Seiten per HTTP ab und prueft auf
|
- `scripts/http-smoke.php`: ruft sichere GET-Seiten per HTTP ab und prüft auf
|
||||||
HTTP 200, erwartete Texte und PHP-Fehlermarker.
|
HTTP 200, erwartete Texte und PHP-Fehlermarker.
|
||||||
|
|
||||||
## Ausfuehrung
|
## Ausführung
|
||||||
|
|
||||||
Mit normal installierter PHP-CLI:
|
Mit normal installierter PHP-CLI:
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ LD_LIBRARY_PATH="$PWD/.local/php/usr/lib/x86_64-linux-gnu" \
|
|||||||
Die Skripte erwarten die bekannten Dev-Umgebungsvariablen `DB_HOST`, `DB_NAME`,
|
Die Skripte erwarten die bekannten Dev-Umgebungsvariablen `DB_HOST`, `DB_NAME`,
|
||||||
`DB_USER` und `DB_PASS`.
|
`DB_USER` und `DB_PASS`.
|
||||||
|
|
||||||
## Abgedeckte Testfaelle
|
## Abgedeckte Testfälle
|
||||||
|
|
||||||
| Testfall | Fixture |
|
| Testfall | Fixture |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
@@ -131,77 +131,77 @@ Die Skripte erwarten die bekannten Dev-Umgebungsvariablen `DB_HOST`, `DB_NAME`,
|
|||||||
| Negativer Saldo | `gm-negative@test.local` |
|
| Negativer Saldo | `gm-negative@test.local` |
|
||||||
| Nullsaldo | `gm-zero@test.local` |
|
| Nullsaldo | `gm-zero@test.local` |
|
||||||
| Inaktives Mitglied | `gm-inactive@test.local` |
|
| Inaktives Mitglied | `gm-inactive@test.local` |
|
||||||
| PayPal-Name fuer CSV-Lookup | `gm-paypal@test.local` |
|
| PayPal-Name für CSV-Lookup | `gm-paypal@test.local` |
|
||||||
| Mitglied ohne Buchungen | `gm-empty@test.local` |
|
| Mitglied ohne Buchungen | `gm-empty@test.local` |
|
||||||
| Vieltrinker fuer Vorderseite | `gm-heavy@test.local` |
|
| Vieltrinker für Vorderseite | `gm-heavy@test.local` |
|
||||||
| Aktiver Hinweis | `[GM] Aktiver Hinweis fuer Golden-Master-Test` |
|
| Aktiver Hinweis | `[GM] Aktiver Hinweis für Golden-Master-Test` |
|
||||||
| Abgelaufener Hinweis | `[GM] Abgelaufener Hinweis fuer Golden-Master-Test` |
|
| Abgelaufener Hinweis | `[GM] Abgelaufener Hinweis für Golden-Master-Test` |
|
||||||
|
|
||||||
## HTTP-Smoke-Abdeckung
|
## HTTP-Smoke-Abdeckung
|
||||||
|
|
||||||
Der HTTP-Smoke-Test prueft nur GET-Seiten ohne bekannte Schreib- oder
|
Der HTTP-Smoke-Test prüft nur GET-Seiten ohne bekannte Schreib- oder
|
||||||
Versand-Nebenwirkungen.
|
Versand-Nebenwirkungen.
|
||||||
|
|
||||||
| Seite | Erwartung |
|
| Seite | Erwartung |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `index.php` | Dashboard laedt fuer `Test Admin` |
|
| `index.php` | Dashboard lädt für `Test Admin` |
|
||||||
| `stricheintragen.php` | Stricherfassung laedt |
|
| `stricheintragen.php` | Stricherfassung lädt |
|
||||||
| `einzahlung.php` | Einzahlungserfassung laedt |
|
| `einzahlung.php` | Einzahlungserfassung lädt |
|
||||||
| `kaffeeliste.php` | Gesamtuebersicht laedt |
|
| `kaffeeliste.php` | Gesamtübersicht lädt |
|
||||||
| `mitarbeiterverwalten.php` | Mitgliederverwaltung inkl. `PayPal-Name` laedt |
|
| `mitarbeiterverwalten.php` | Mitgliederverwaltung inkl. `PayPal-Name` lädt |
|
||||||
| `letzteneintraege.php` | letzte Einzahlungen und Striche laden |
|
| `letzteneintraege.php` | letzte Einzahlungen und Striche laden |
|
||||||
| `csvupload.php` | CSV-Upload-Formular laedt |
|
| `csvupload.php` | CSV-Upload-Formular lädt |
|
||||||
| `hinweise.php` | Hinweisverwaltung laedt |
|
| `hinweise.php` | Hinweisverwaltung lädt |
|
||||||
| `faq.php` | FAQ laedt |
|
| `faq.php` | FAQ lädt |
|
||||||
| `namenanpassen.php` | Namensanpassung laedt |
|
| `namenanpassen.php` | Namensanpassung lädt |
|
||||||
| `teilnehmerauswertung.php?user_id=1` | Teilnehmerauswertung fuer Dev-Admin laedt |
|
| `teilnehmerauswertung.php?user_id=1` | Teilnehmerauswertung für Dev-Admin lädt |
|
||||||
| `mailausgebe.php` | Mailadress-Ausgabe laedt |
|
| `mailausgebe.php` | Mailadress-Ausgabe lädt |
|
||||||
| `umfrage.php` | geschlossene Umfrage laedt |
|
| `umfrage.php` | geschlossene Umfrage lädt |
|
||||||
| `umfrageergebnisse.php` | Umfrageauswertung laedt |
|
| `umfrageergebnisse.php` | Umfrageauswertung lädt |
|
||||||
|
|
||||||
## Akzeptanzkriterien
|
## Akzeptanzkriterien
|
||||||
|
|
||||||
- Testdaten sind reproduzierbar.
|
- Testdaten sind reproduzierbar.
|
||||||
- Tests koennen mehrfach laufen, ohne Duplikate zu erzeugen.
|
- Tests können mehrfach laufen, ohne Duplikate zu erzeugen.
|
||||||
- Salden und Jahreswerte sind automatisch pruefbar.
|
- Salden und Jahreswerte sind automatisch prüfbar.
|
||||||
- CSV-Importfaelle sind fachlich abgedeckt.
|
- CSV-Importfälle sind fachlich abgedeckt.
|
||||||
- Die wichtigsten UI-Seiten liefern HTTP 200 ohne PHP-Warnings.
|
- Die wichtigsten UI-Seiten liefern HTTP 200 ohne PHP-Warnings.
|
||||||
- Seiten mit Schreib- oder Versand-Nebenwirkungen werden nicht automatisch per
|
- Seiten mit Schreib- oder Versand-Nebenwirkungen werden nicht automatisch per
|
||||||
GET ausgefuehrt, sondern als Risiko dokumentiert.
|
GET ausgeführt, sondern als Risiko dokumentiert.
|
||||||
|
|
||||||
## Gefundene Fehler und Bewertung
|
## Gefundene Fehler und Bewertung
|
||||||
|
|
||||||
Im M1-Abschlusslauf wurden folgende Punkte geprueft:
|
Im M1-Abschlusslauf wurden folgende Punkte geprüft:
|
||||||
|
|
||||||
- `number_format(null)` in `kaffeeliste.php`: behoben; leere Summen werden als
|
- `number_format(null)` in `kaffeeliste.php`: behoben; leere Summen werden als
|
||||||
`0` behandelt.
|
`0` behandelt.
|
||||||
- `paypalname` in der Mitgliederverwaltung: eingepflegt und im Golden Master
|
- `paypalname` in der Mitgliederverwaltung: eingepflegt und im Golden Master
|
||||||
abgedeckt.
|
abgedeckt.
|
||||||
- `umfrage.php`: `mb_strtolower()` ist in der lokalen PHP-Umgebung nicht
|
- `umfrage.php`: `mb_strtolower()` ist in der lokalen PHP-Umgebung nicht
|
||||||
verfuegbar; Fallback auf `strtolower()` ergaenzt.
|
verfügbar; Fallback auf `strtolower()` ergänzt.
|
||||||
- `exportKaffeeliste.php`: Pfad auf `TCPDF/tcpdf.php` korrigiert. Der Export
|
- `exportKaffeeliste.php`: Pfad auf `TCPDF/tcpdf.php` korrigiert. Der Export
|
||||||
bleibt trotzdem als bekannter Dependency-Fehler offen, weil die TCPDF-Kopie im
|
bleibt trotzdem als bekannter Dependency-Fehler offen, weil die TCPDF-Kopie im
|
||||||
Repo unvollstaendig ist und `TCPDF/include/tcpdf_font_data.php` fehlt.
|
Repo unvollständig ist und `TCPDF/include/tcpdf_font_data.php` fehlt.
|
||||||
- `mailversenden.php`: nicht automatisch per HTTP ausgefuehrt, weil ein GET bei
|
- `mailversenden.php`: nicht automatisch per HTTP ausgeführt, weil ein GET bei
|
||||||
vollstaendiger PHPMailer-Installation E-Mails versenden kann. Zusaetzlich ist
|
vollständiger PHPMailer-Installation E-Mails versenden kann. Zusätzlich ist
|
||||||
die PHPMailer-Kopie im Repo unvollstaendig.
|
die PHPMailer-Kopie im Repo unvollständig.
|
||||||
- `jahresauswertung.php`: nicht automatisch per HTTP ausgefuehrt, weil ein GET
|
- `jahresauswertung.php`: nicht automatisch per HTTP ausgeführt, weil ein GET
|
||||||
Jahresbuchungen schreiben und E-Mails versenden kann. Zusaetzlich ist die
|
Jahresbuchungen schreiben und E-Mails versenden kann. Zusätzlich ist die
|
||||||
PHPMailer-Kopie im Repo unvollstaendig.
|
PHPMailer-Kopie im Repo unvollständig.
|
||||||
|
|
||||||
## Aktueller Pruefstatus
|
## Aktueller Prüfstatus
|
||||||
|
|
||||||
Stand 2026-07-12:
|
Stand 2026-07-12:
|
||||||
|
|
||||||
- `scripts/seed-golden-master.php` erfolgreich gegen die MySQL-Dev-Datenbank
|
- `scripts/seed-golden-master.php` erfolgreich gegen die MySQL-Dev-Datenbank
|
||||||
ausgefuehrt.
|
ausgeführt.
|
||||||
- `scripts/check-golden-master.php` erfolgreich ausgefuehrt.
|
- `scripts/check-golden-master.php` erfolgreich ausgeführt.
|
||||||
- Zweiter Seed+Check-Lauf erfolgreich, Idempotenz bestaetigt.
|
- Zweiter Seed+Check-Lauf erfolgreich, Idempotenz bestätigt.
|
||||||
- Ergebnis: 104 Assertions bestanden.
|
- Ergebnis: 104 Assertions bestanden.
|
||||||
- `scripts/http-smoke.php` erfolgreich gegen `http://127.0.0.1:8080`
|
- `scripts/http-smoke.php` erfolgreich gegen `http://127.0.0.1:8080`
|
||||||
ausgefuehrt.
|
ausgeführt.
|
||||||
- Ergebnis: 14 sichere Seiten bestanden ohne `Deprecated`, `Warning`,
|
- Ergebnis: 14 sichere Seiten bestanden ohne `Deprecated`, `Warning`,
|
||||||
`Fatal error`, `Parse error`, `Notice` oder `Uncaught Error`.
|
`Fatal error`, `Parse error`, `Notice` oder `Uncaught Error`.
|
||||||
- Bekannter offener Punkt: PDF-Export wegen unvollstaendiger TCPDF-Abhaengigkeit.
|
- Bekannter offener Punkt: PDF-Export wegen unvollständiger TCPDF-Abhängigkeit.
|
||||||
- Bewusst nicht automatisch ausgefuehrt: `mailversenden.php` und
|
- Bewusst nicht automatisch ausgeführt: `mailversenden.php` und
|
||||||
`jahresauswertung.php`, da GET dort Nebenwirkungen haben kann.
|
`jahresauswertung.php`, da GET dort Nebenwirkungen haben kann.
|
||||||
|
|||||||
@@ -2,16 +2,16 @@
|
|||||||
|
|
||||||
Stand: 2026-07-13
|
Stand: 2026-07-13
|
||||||
|
|
||||||
M2 fuehrt die technischen Grundbausteine fuer den SaaS-Umbau ein, ohne das
|
M2 führt die technischen Grundbausteine für den SaaS-Umbau ein, ohne das
|
||||||
Legacy-Verhalten oder das bestehende Design zu veraendern.
|
Legacy-Verhalten oder das bestehende Design zu verändern.
|
||||||
|
|
||||||
Status: abgeschlossen fuer den M2-Scope. Bewusst ausgelagerte Themen sind unten
|
Status: abgeschlossen für den M2-Scope. Bewusst ausgelagerte Themen sind unten
|
||||||
als Grenzen und M3-/M6-Uebergabe dokumentiert.
|
als Grenzen und M3-/M6-Übergabe dokumentiert.
|
||||||
|
|
||||||
## Ziel
|
## Ziel
|
||||||
|
|
||||||
- Versionierte Datenbankmigrationen statt loser Schema-Ausfuehrung.
|
- Versionierte Datenbankmigrationen statt loser Schema-Ausführung.
|
||||||
- Zentrales Bootstrap fuer Umgebung, Session und CSRF-Helper.
|
- Zentrales Bootstrap für Umgebung, Session und CSRF-Helper.
|
||||||
- Bestehende Legacy-Seiten bleiben kompatibel.
|
- Bestehende Legacy-Seiten bleiben kompatibel.
|
||||||
- Layout-Trennung wird vorbereitet, aber noch nicht in bestehende Seiten
|
- Layout-Trennung wird vorbereitet, aber noch nicht in bestehende Seiten
|
||||||
hineingezogen.
|
hineingezogen.
|
||||||
@@ -28,47 +28,47 @@ als Grenzen und M3-/M6-Uebergabe dokumentiert.
|
|||||||
- `app_csrf_field()`
|
- `app_csrf_field()`
|
||||||
- `app_verify_csrf()`
|
- `app_verify_csrf()`
|
||||||
- `app_require_csrf()`
|
- `app_require_csrf()`
|
||||||
- `config.php` laedt den Bootstrap und startet die Session mit sicheren
|
- `config.php` lädt den Bootstrap und startet die Session mit sicheren
|
||||||
Cookie-Optionen.
|
Cookie-Optionen.
|
||||||
- Sessions werden standardmaessig unter `var/sessions` abgelegt, weil die
|
- Sessions werden standardmäßig unter `var/sessions` abgelegt, weil die
|
||||||
lokale PHP-Umgebung keinen beschreibbaren Systempfad garantiert. `var/` ist
|
lokale PHP-Umgebung keinen beschreibbaren Systempfad garantiert. `var/` ist
|
||||||
von Git ignoriert. Der Pfad kann ueber `APP_SESSION_PATH` ueberschrieben
|
von Git ignoriert. Der Pfad kann über `APP_SESSION_PATH` überschrieben
|
||||||
werden.
|
werden.
|
||||||
- CSRF ist bewusst noch nicht global erzwungen. Die vorhandenen POST-Seiten
|
- CSRF ist bewusst noch nicht global erzwungen. Die vorhandenen POST-Seiten
|
||||||
werden spaeter einzeln umgestellt, damit keine Formulare oder Spezialflows
|
werden später einzeln umgestellt, damit keine Formulare oder Spezialflows
|
||||||
brechen.
|
brechen.
|
||||||
|
|
||||||
### CSRF-Rollout
|
### CSRF-Rollout
|
||||||
|
|
||||||
Erste Legacy-POST-Seiten sind opt-in abgesichert:
|
Erste Legacy-POST-Seiten sind opt-in abgesichert:
|
||||||
|
|
||||||
- `hinweise.php`: Hinweis anlegen und Hinweis loeschen. Der bisherige
|
- `hinweise.php`: Hinweis anlegen und Hinweis löschen. Der bisherige
|
||||||
GET-Loeschlink wurde durch ein POST-Formular mit CSRF-Token ersetzt.
|
GET-Löschlink wurde durch ein POST-Formular mit CSRF-Token ersetzt.
|
||||||
- `mitarbeiterverwalten.php`: Mitglied anlegen, Bearbeitungsformular oeffnen,
|
- `mitarbeiterverwalten.php`: Mitglied anlegen, Bearbeitungsformular öffnen,
|
||||||
Mitglied speichern, aktivieren und deaktivieren.
|
Mitglied speichern, aktivieren und deaktivieren.
|
||||||
- `namenanpassen.php`: Anzeigenamen aktualisieren.
|
- `namenanpassen.php`: Anzeigenamen aktualisieren.
|
||||||
- `index.php`: eigene Web-Striche eintragen.
|
- `index.php`: eigene Web-Striche eintragen.
|
||||||
- `stricheintragen.php`: Sammelerfassung von Strichen.
|
- `stricheintragen.php`: Sammelerfassung von Strichen.
|
||||||
- `einzahlung.php`: Sammelerfassung von Einzahlungen.
|
- `einzahlung.php`: Sammelerfassung von Einzahlungen.
|
||||||
- `letzteneintraege.php`: letzte Einzahlungen und Strich-Eintraege loeschen.
|
- `letzteneintraege.php`: letzte Einzahlungen und Strich-Einträge löschen.
|
||||||
- `csvupload.php`: CSV-Zahlungsimport.
|
- `csvupload.php`: CSV-Zahlungsimport.
|
||||||
|
|
||||||
Noch offen:
|
Noch offen:
|
||||||
|
|
||||||
- Spezialprozesse: `mailversenden.php`, `jahresauswertung.php`.
|
- Spezialprozesse: `mailversenden.php`, `jahresauswertung.php`.
|
||||||
|
|
||||||
### CSV-Upload-Haertung
|
### CSV-Upload-Härtung
|
||||||
|
|
||||||
- `csvupload.php` nutzt jetzt CSRF.
|
- `csvupload.php` nutzt jetzt CSRF.
|
||||||
- Uploads werden unter `var/uploads` gespeichert und nach der Verarbeitung
|
- Uploads werden unter `var/uploads` gespeichert und nach der Verarbeitung
|
||||||
geloescht. Damit liegen importierte Dateien nicht mehr im Webroot.
|
gelöscht. Damit liegen importierte Dateien nicht mehr im Webroot.
|
||||||
- Dateiendung, Dateigroesse und MIME-Typ werden vor der Verarbeitung geprueft.
|
- Dateiendung, Dateigröße und MIME-Typ werden vor der Verarbeitung geprüft.
|
||||||
- Hochgeladene Dateien bekommen serverseitig erzeugte Zufallsnamen.
|
- Hochgeladene Dateien bekommen serverseitig erzeugte Zufallsnamen.
|
||||||
- CSV-Auswertungswerte werden HTML-escaped ausgegeben.
|
- CSV-Auswertungswerte werden HTML-escaped ausgegeben.
|
||||||
- Die PayPal-Namenssuche nutzt `Name` und `paypalname` mit expliziter
|
- Die PayPal-Namenssuche nutzt `Name` und `paypalname` mit expliziter
|
||||||
Parameterbindung.
|
Parameterbindung.
|
||||||
|
|
||||||
Offen fuer M6:
|
Offen für M6:
|
||||||
|
|
||||||
- Importvorschau vor dem Schreiben.
|
- Importvorschau vor dem Schreiben.
|
||||||
- Import-Batch/Audit-Log.
|
- Import-Batch/Audit-Log.
|
||||||
@@ -78,19 +78,19 @@ Offen fuer M6:
|
|||||||
|
|
||||||
- `database/migrations/0001_legacy_mysql_baseline.sql` bildet die bisherige
|
- `database/migrations/0001_legacy_mysql_baseline.sql` bildet die bisherige
|
||||||
MySQL-Dev-Baseline als erste versionierte Migration ab.
|
MySQL-Dev-Baseline als erste versionierte Migration ab.
|
||||||
- `scripts/dev-db.php` verwaltet `schema_migrations` und fuehrt neue
|
- `scripts/dev-db.php` verwaltet `schema_migrations` und führt neue
|
||||||
Migrationen idempotent aus.
|
Migrationen idempotent aus.
|
||||||
- `scripts/migrate.php` ist der direkte Runner fuer Migrationen.
|
- `scripts/migrate.php` ist der direkte Runner für Migrationen.
|
||||||
- `scripts/init-mysql-dev.php` nutzt ab jetzt ebenfalls die Migrationslogik.
|
- `scripts/init-mysql-dev.php` nutzt ab jetzt ebenfalls die Migrationslogik.
|
||||||
|
|
||||||
### Layout
|
### Layout
|
||||||
|
|
||||||
- `header.php` und `footer.php` bleiben vorerst Legacy-Wrapper.
|
- `header.php` und `footer.php` bleiben vorerst Legacy-Wrapper.
|
||||||
- Die spaetere Trennung in Public-Layout und App-Layout wird erst umgesetzt,
|
- Die spätere Trennung in Public-Layout und App-Layout wird erst umgesetzt,
|
||||||
wenn die neue Route-/View-Struktur steht.
|
wenn die neue Route-/View-Struktur steht.
|
||||||
- Die bestehende HTML5-UP-Struktur, Sidebar und Assets bleiben unveraendert.
|
- Die bestehende HTML5-UP-Struktur, Sidebar und Assets bleiben unverändert.
|
||||||
|
|
||||||
## Ausfuehrung
|
## Ausführung
|
||||||
|
|
||||||
Mit normaler PHP-CLI:
|
Mit normaler PHP-CLI:
|
||||||
|
|
||||||
@@ -111,43 +111,43 @@ LD_LIBRARY_PATH="$PWD/.local/php/usr/lib/x86_64-linux-gnu:$PWD/.local/php/usr/li
|
|||||||
```
|
```
|
||||||
|
|
||||||
Die Skripte erwarten die bekannten Dev-Umgebungsvariablen `DB_HOST`, `DB_NAME`,
|
Die Skripte erwarten die bekannten Dev-Umgebungsvariablen `DB_HOST`, `DB_NAME`,
|
||||||
`DB_USER` und `DB_PASS`. `scripts/init-mysql-dev.php` braucht zusaetzlich
|
`DB_USER` und `DB_PASS`. `scripts/init-mysql-dev.php` braucht zusätzlich
|
||||||
`DEV_AUTH_EMAIL`.
|
`DEV_AUTH_EMAIL`.
|
||||||
|
|
||||||
## Aktueller Pruefstatus
|
## Aktueller Prüfstatus
|
||||||
|
|
||||||
- Migration `0001_legacy_mysql_baseline.sql` erfolgreich angewendet.
|
- Migration `0001_legacy_mysql_baseline.sql` erfolgreich angewendet.
|
||||||
- Zweiter Migrationslauf meldet: Datenbank ist aktuell.
|
- Zweiter Migrationslauf meldet: Datenbank ist aktuell.
|
||||||
- PHP-Syntax fuer Bootstrap, Migrationen, Init-Skript und Config ist sauber.
|
- PHP-Syntax für Bootstrap, Migrationen, Init-Skript und Config ist sauber.
|
||||||
- Session-Start laeuft in der lokalen Dev-Umgebung ohne PHP-Warnings ueber
|
- Session-Start läuft in der lokalen Dev-Umgebung ohne PHP-Warnings über
|
||||||
`var/sessions`.
|
`var/sessions`.
|
||||||
- CSRF negative Tests: `hinweise.php`, `mitarbeiterverwalten.php` und
|
- CSRF negative Tests: `hinweise.php`, `mitarbeiterverwalten.php` und
|
||||||
`namenanpassen.php` liefern bei POST ohne Token HTTP 419.
|
`namenanpassen.php` liefern bei POST ohne Token HTTP 419.
|
||||||
- CSRF positive Tests: gueltige Token funktionieren fuer Hinweis-Anlage,
|
- CSRF positive Tests: gültige Token funktionieren für Hinweis-Anlage,
|
||||||
Mitglieder-Bearbeitungsformular und Namensanpassung. Der temporaere
|
Mitglieder-Bearbeitungsformular und Namensanpassung. Der temporäre
|
||||||
Testhinweis wurde wieder entfernt.
|
Testhinweis wurde wieder entfernt.
|
||||||
- CSRF negative Tests fuer Buchungsflows: `index.php`, `stricheintragen.php`
|
- CSRF negative Tests für Buchungsflows: `index.php`, `stricheintragen.php`
|
||||||
und `einzahlung.php` liefern bei POST ohne Token HTTP 419.
|
und `einzahlung.php` liefern bei POST ohne Token HTTP 419.
|
||||||
- CSRF positive Tests fuer Buchungsflows: gueltige Token funktionieren fuer
|
- CSRF positive Tests für Buchungsflows: gültige Token funktionieren für
|
||||||
eigene Web-Striche, Sammelstriche und Sammeleinzahlungen. Die temporaeren
|
eigene Web-Striche, Sammelstriche und Sammeleinzahlungen. Die temporären
|
||||||
Testbuchungen wurden wieder entfernt.
|
Testbuchungen wurden wieder entfernt.
|
||||||
- CSRF negative Tests fuer Korrektur-/Loeschflows: `letzteneintraege.php`
|
- CSRF negative Tests für Korrektur-/Löschflows: `letzteneintraege.php`
|
||||||
liefert bei POST ohne Token HTTP 419.
|
liefert bei POST ohne Token HTTP 419.
|
||||||
- CSRF positive Tests fuer Korrektur-/Loeschflows: gueltige Token funktionieren
|
- CSRF positive Tests für Korrektur-/Löschflows: gültige Token funktionieren
|
||||||
fuer das Loeschen temporaerer Einzahlungs- und Strich-Testeintraege.
|
für das Löschen temporärer Einzahlungs- und Strich-Testeinträge.
|
||||||
- CSRF negative Test fuer CSV-Upload: POST ohne Token liefert HTTP 419.
|
- CSRF negative Test für CSV-Upload: POST ohne Token liefert HTTP 419.
|
||||||
- CSV-Upload positive Tests: gueltiges Token verarbeitet eine CSV-Datei, erkennt
|
- CSV-Upload positive Tests: gültiges Token verarbeitet eine CSV-Datei, erkennt
|
||||||
eine PayPal-Alias-Dublette und hinterlaesst keine Datei in `var/uploads`.
|
eine PayPal-Alias-Dublette und hinterlässt keine Datei in `var/uploads`.
|
||||||
- CSV-Upload negative Tests: Nicht-CSV-Dateien werden abgewiesen.
|
- CSV-Upload negative Tests: Nicht-CSV-Dateien werden abgewiesen.
|
||||||
- Golden Master weiterhin gruen mit 104 Assertions.
|
- Golden Master weiterhin grün mit 104 Assertions.
|
||||||
- HTTP-Smoke weiterhin gruen mit 23 sicheren Seiten inklusive Landingpage, Login,
|
- HTTP-Smoke weiterhin grün mit 23 sicheren Seiten inklusive Landingpage, Login,
|
||||||
Registrierung, Passwort-Reset, E-Mail-Verifikation und geschuetzter
|
Registrierung, Passwort-Reset, E-Mail-Verifikation und geschützter
|
||||||
Mandant-Einstellungen, geschuetzter Mandantenauswahl sowie Ledger-Preview.
|
Mandant-Einstellungen, geschützter Mandantenauswahl sowie Ledger-Preview.
|
||||||
|
|
||||||
## Bewusste Grenzen
|
## Bewusste Grenzen
|
||||||
|
|
||||||
- Keine Tenant-/User-/Rollen-Tabellen in M2. Diese gehoeren zu M3.
|
- Keine Tenant-/User-/Rollen-Tabellen in M2. Diese gehören zu M3.
|
||||||
- Keine globale CSRF-Erzwingung fuer Spezialprozesse. `mailversenden.php` und
|
- Keine globale CSRF-Erzwingung für Spezialprozesse. `mailversenden.php` und
|
||||||
`jahresauswertung.php` werden in M6 als Jobs mit Dry-Run, Audit und
|
`jahresauswertung.php` werden in M6 als Jobs mit Dry-Run, Audit und
|
||||||
Versandlog neu betrachtet.
|
Versandlog neu betrachtet.
|
||||||
- Kein Layout-Umbau in M2. Die visuelle Struktur bleibt stabil; Public-/App-
|
- Kein Layout-Umbau in M2. Die visuelle Struktur bleibt stabil; Public-/App-
|
||||||
@@ -157,26 +157,26 @@ Die Skripte erwarten die bekannten Dev-Umgebungsvariablen `DB_HOST`, `DB_NAME`,
|
|||||||
## Abschlusskriterien
|
## Abschlusskriterien
|
||||||
|
|
||||||
- Migrationsrunner ist vorhanden und idempotent.
|
- Migrationsrunner ist vorhanden und idempotent.
|
||||||
- Bootstrap, Session und CSRF-Helper sind zentral verfuegbar.
|
- Bootstrap, Session und CSRF-Helper sind zentral verfügbar.
|
||||||
- Die relevanten Legacy-Schreibseiten sind CSRF-geschuetzt.
|
- Die relevanten Legacy-Schreibseiten sind CSRF-geschützt.
|
||||||
- CSV-Uploads liegen nicht mehr im Webroot.
|
- CSV-Uploads liegen nicht mehr im Webroot.
|
||||||
- Bestehende Legacy-Seiten bleiben per HTTP-Smoke erreichbar.
|
- Bestehende Legacy-Seiten bleiben per HTTP-Smoke erreichbar.
|
||||||
- Golden-Master-Fachwerte bleiben unveraendert.
|
- Golden-Master-Fachwerte bleiben unverändert.
|
||||||
|
|
||||||
## Uebergabe an M3
|
## Übergabe an M3
|
||||||
|
|
||||||
M3 startet mit additiven SaaS-Tabellen und einer Default-Tenant-Abbildung. Die
|
M3 startet mit additiven SaaS-Tabellen und einer Default-Tenant-Abbildung. Die
|
||||||
Legacy-Seiten sollen dabei weiterhin ueber die bestehenden Tabellen laufen, bis
|
Legacy-Seiten sollen dabei weiterhin über die bestehenden Tabellen laufen, bis
|
||||||
der fachliche Kern in M4/M5 schrittweise auf das Zielmodell umgestellt wird.
|
der fachliche Kern in M4/M5 schrittweise auf das Zielmodell umgestellt wird.
|
||||||
|
|
||||||
M3 wurde inzwischen gestartet. Umgesetzte Details stehen in
|
M3 wurde inzwischen gestartet. Umgesetzte Details stehen in
|
||||||
`docs/m3-saas-basis-vorbereitung.md`. Der urspruengliche Startpunkt war:
|
`docs/m3-saas-basis-vorbereitung.md`. Der ursprüngliche Startpunkt war:
|
||||||
|
|
||||||
1. `tenants`, `tenant_settings`, `users`, `tenant_memberships` und
|
1. `tenants`, `tenant_settings`, `users`, `tenant_memberships` und
|
||||||
`participants` als neue Migration anlegen.
|
`participants` als neue Migration anlegen.
|
||||||
2. Einen Default-Tenant fuer die bestehende Kaffeeliste definieren.
|
2. Einen Default-Tenant für die bestehende Kaffeeliste definieren.
|
||||||
3. Bestehende `kl_Mitarbeiter` in `participants` spiegeln, inklusive
|
3. Bestehende `kl_Mitarbeiter` in `participants` spiegeln, inklusive
|
||||||
`legacy_mitarbeiter_id`.
|
`legacy_mitarbeiter_id`.
|
||||||
4. Admins aus `kl_Mitarbeiter.admin` als `tenant_memberships.role = 'admin'`
|
4. Admins aus `kl_Mitarbeiter.admin` als `tenant_memberships.role = 'admin'`
|
||||||
beziehungsweise fuer den ersten Hauptnutzer als `owner` abbilden.
|
beziehungsweise für den ersten Hauptnutzer als `owner` abbilden.
|
||||||
5. Erst danach Login/Registrierung und Public-/App-Routen anschliessen.
|
5. Erst danach Login/Registrierung und Public-/App-Routen anschließen.
|
||||||
|
|||||||
@@ -2,27 +2,27 @@
|
|||||||
|
|
||||||
Stand: 2026-07-13
|
Stand: 2026-07-13
|
||||||
|
|
||||||
M3 fuehrt Mandanten, Benutzer, Mitgliedschaften und Grundeinstellungen additiv
|
M3 führt Mandanten, Benutzer, Mitgliedschaften und Grundeinstellungen additiv
|
||||||
ein. Die bestehende Legacy-App bleibt dabei lauffaehig und wird noch nicht auf
|
ein. Die bestehende Legacy-App bleibt dabei lauffähig und wird noch nicht auf
|
||||||
das neue Modell umgestellt.
|
das neue Modell umgestellt.
|
||||||
|
|
||||||
Status: abgeschlossen fuer den M3-Scope. M4 startet mit der additiven
|
Status: abgeschlossen für den M3-Scope. M4 startet mit der additiven
|
||||||
Migration von Einzahlungen und Kaffeeverbrauch nach `ledger_entries`.
|
Migration von Einzahlungen und Kaffeeverbrauch nach `ledger_entries`.
|
||||||
|
|
||||||
## Ziel
|
## Ziel
|
||||||
|
|
||||||
- Einen Default-Tenant fuer den aktuellen Bestand erzeugen.
|
- Einen Default-Tenant für den aktuellen Bestand erzeugen.
|
||||||
- Login-Benutzer und Kaffee-Teilnehmer fachlich trennen.
|
- Login-Benutzer und Kaffee-Teilnehmer fachlich trennen.
|
||||||
- Rollen tenant-spezifisch vorbereiten.
|
- Rollen tenant-spezifisch vorbereiten.
|
||||||
- Bestehende `kl_Mitarbeiter` ohne Datenverlust in `participants` spiegeln.
|
- Bestehende `kl_Mitarbeiter` ohne Datenverlust in `participants` spiegeln.
|
||||||
- Die Grundlage fuer Registrierung und Login schaffen, ohne die Legacy-Auth
|
- Die Grundlage für Registrierung und Login schaffen, ohne die Legacy-Auth
|
||||||
sofort zu ersetzen.
|
sofort zu ersetzen.
|
||||||
|
|
||||||
## Nicht-Ziele fuer den ersten M3-Schritt
|
## Nicht-Ziele für den ersten M3-Schritt
|
||||||
|
|
||||||
- Kein kompletter Login-Umbau in einem Schritt.
|
- Kein kompletter Login-Umbau in einem Schritt.
|
||||||
- Keine Migration von Einzahlungen und Kaffeeverbrauch nach `ledger_entries`;
|
- Keine Migration von Einzahlungen und Kaffeeverbrauch nach `ledger_entries`;
|
||||||
das gehoert zu M4.
|
das gehört zu M4.
|
||||||
- Kein Design- oder Layout-Umbau.
|
- Kein Design- oder Layout-Umbau.
|
||||||
- Kein Billing und keine Tarife im ersten Schritt.
|
- Kein Billing und keine Tarife im ersten Schritt.
|
||||||
- Kein produktiver Tenant-Wechsel in bestehenden Legacy-Seiten.
|
- Kein produktiver Tenant-Wechsel in bestehenden Legacy-Seiten.
|
||||||
@@ -47,7 +47,7 @@ Tabellen:
|
|||||||
- `participants`
|
- `participants`
|
||||||
- `tenant_domains`
|
- `tenant_domains`
|
||||||
|
|
||||||
Ergaenzende Skripte:
|
Ergänzende Skripte:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
scripts/backfill-default-tenant.php
|
scripts/backfill-default-tenant.php
|
||||||
@@ -73,7 +73,7 @@ Wichtige Regeln:
|
|||||||
|
|
||||||
## Default-Tenant
|
## Default-Tenant
|
||||||
|
|
||||||
Fuer den Bestand wird ein erster Tenant angelegt:
|
Für den Bestand wird ein erster Tenant angelegt:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
slug: default
|
slug: default
|
||||||
@@ -84,7 +84,7 @@ locale: de-DE
|
|||||||
currency_code: EUR
|
currency_code: EUR
|
||||||
```
|
```
|
||||||
|
|
||||||
Die Werte koennen spaeter in einer Tenant-Einstellungsseite angepasst werden.
|
Die Werte können später in einer Tenant-Einstellungsseite angepasst werden.
|
||||||
|
|
||||||
## Backfill
|
## Backfill
|
||||||
|
|
||||||
@@ -98,9 +98,9 @@ Vorgang:
|
|||||||
|
|
||||||
1. Default-Tenant anlegen oder laden.
|
1. Default-Tenant anlegen oder laden.
|
||||||
2. `tenant_settings` aus `kl_config` erzeugen.
|
2. `tenant_settings` aus `kl_config` erzeugen.
|
||||||
3. Fuer jede Zeile aus `kl_Mitarbeiter` einen `participant` anlegen oder
|
3. Für jede Zeile aus `kl_Mitarbeiter` einen `participant` anlegen oder
|
||||||
aktualisieren.
|
aktualisieren.
|
||||||
4. Fuer aktive Admins optional einen `user` und eine `tenant_membership`
|
4. Für aktive Admins optional einen `user` und eine `tenant_membership`
|
||||||
erzeugen.
|
erzeugen.
|
||||||
5. `admin = 1` als Rolle `admin` abbilden; ein konfigurierter erster Benutzer
|
5. `admin = 1` als Rolle `admin` abbilden; ein konfigurierter erster Benutzer
|
||||||
kann Rolle `owner` erhalten.
|
kann Rolle `owner` erhalten.
|
||||||
@@ -108,10 +108,10 @@ Vorgang:
|
|||||||
aus dem Default-Tenant entfernen.
|
aus dem Default-Tenant entfernen.
|
||||||
|
|
||||||
Der Backfill muss idempotent sein und darf keine bestehenden Legacy-Daten
|
Der Backfill muss idempotent sein und darf keine bestehenden Legacy-Daten
|
||||||
loeschen. Geloescht werden nur SaaS-Spiegelungen, deren Legacy-Mitarbeiter in
|
löschen. Gelöscht werden nur SaaS-Spiegelungen, deren Legacy-Mitarbeiter in
|
||||||
`kl_Mitarbeiter` nicht mehr existiert.
|
`kl_Mitarbeiter` nicht mehr existiert.
|
||||||
|
|
||||||
Ausgefuehrter Dev-Stand:
|
Ausgeführter Dev-Stand:
|
||||||
|
|
||||||
- Default-Tenant `default` wurde angelegt.
|
- Default-Tenant `default` wurde angelegt.
|
||||||
- 9 Legacy-Mitarbeiter wurden als `participants` gespiegelt.
|
- 9 Legacy-Mitarbeiter wurden als `participants` gespiegelt.
|
||||||
@@ -145,15 +145,15 @@ Umgesetzter Umfang:
|
|||||||
|
|
||||||
- Registrierung legt Tenant, Owner-User, Default-Settings, Membership und
|
- Registrierung legt Tenant, Owner-User, Default-Settings, Membership und
|
||||||
Owner-Participant in einer Transaktion an.
|
Owner-Participant in einer Transaktion an.
|
||||||
- Login prueft `users.password_hash`, aktive Membership und aktiven Tenant.
|
- Login prüft `users.password_hash`, aktive Membership und aktiven Tenant.
|
||||||
- Hat ein User genau einen aktiven Mandanten, wird dieser direkt in die Session
|
- Hat ein User genau einen aktiven Mandanten, wird dieser direkt in die Session
|
||||||
gelegt.
|
gelegt.
|
||||||
- Hat ein User mehrere aktive Mandanten, fuehrt der Login zur
|
- Hat ein User mehrere aktive Mandanten, führt der Login zur
|
||||||
Mandantenauswahl.
|
Mandantenauswahl.
|
||||||
- Logout beendet die neue PHP-Login-Session.
|
- Logout beendet die neue PHP-Login-Session.
|
||||||
- `konto.php` zeigt den aktuellen SaaS-Kontext fuer den angemeldeten User.
|
- `konto.php` zeigt den aktuellen SaaS-Kontext für den angemeldeten User.
|
||||||
- `functions.php` akzeptiert eine SaaS-Login-Session als erste Identitaetsquelle,
|
- `functions.php` akzeptiert eine SaaS-Login-Session als erste Identitätsquelle,
|
||||||
laesst `DEV_AUTH_EMAIL` und `AUTH_USER` aber als Legacy-Fallback bestehen.
|
lässt `DEV_AUTH_EMAIL` und `AUTH_USER` aber als Legacy-Fallback bestehen.
|
||||||
- `footer.php` bleibt App-Sidebar und zeigt keine Public-Login- oder
|
- `footer.php` bleibt App-Sidebar und zeigt keine Public-Login- oder
|
||||||
Registrierungslinks mehr.
|
Registrierungslinks mehr.
|
||||||
- Login, Registrierung, Passwort-Reset und E-Mail-Verifikation nutzen das
|
- Login, Registrierung, Passwort-Reset und E-Mail-Verifikation nutzen das
|
||||||
@@ -161,7 +161,7 @@ Umgesetzter Umfang:
|
|||||||
- Passwort-Reset erzeugt Single-Use-Tokens und speichert nur Token-Hashes.
|
- Passwort-Reset erzeugt Single-Use-Tokens und speichert nur Token-Hashes.
|
||||||
- E-Mail-Verifikation erzeugt Single-Use-Tokens und setzt
|
- E-Mail-Verifikation erzeugt Single-Use-Tokens und setzt
|
||||||
`users.email_verified_at`.
|
`users.email_verified_at`.
|
||||||
- Reset- und Verifikationslinks werden ueber `app/saas-mail.php` versendet.
|
- Reset- und Verifikationslinks werden über `app/saas-mail.php` versendet.
|
||||||
Der Dev-Standard schreibt Mails nach `var/mail`; produktiv kann auf PHP
|
Der Dev-Standard schreibt Mails nach `var/mail`; produktiv kann auf PHP
|
||||||
`mail()` umgestellt werden.
|
`mail()` umgestellt werden.
|
||||||
- Dev-Links werden weiterhin nur im Dev-Modus angezeigt, damit lokale Checks
|
- Dev-Links werden weiterhin nur im Dev-Modus angezeigt, damit lokale Checks
|
||||||
@@ -169,7 +169,7 @@ Umgesetzter Umfang:
|
|||||||
|
|
||||||
Noch offen im M3-Auth-Scope:
|
Noch offen im M3-Auth-Scope:
|
||||||
|
|
||||||
- Weitergehende Rollenmatrix fuer spaetere SaaS-Seiten.
|
- Weitergehende Rollenmatrix für spätere SaaS-Seiten.
|
||||||
- Produktive SMTP-/Provider-Anbindung inklusive Bounce-/Fehlerprotokoll.
|
- Produktive SMTP-/Provider-Anbindung inklusive Bounce-/Fehlerprotokoll.
|
||||||
|
|
||||||
## Public-Landingpage
|
## Public-Landingpage
|
||||||
@@ -184,35 +184,35 @@ assets/css/public.css
|
|||||||
|
|
||||||
Umgesetzter Umfang:
|
Umgesetzter Umfang:
|
||||||
|
|
||||||
- Oeffentliche Landingpage ohne Legacy-DB-Zugriff.
|
- Öffentliche Landingpage ohne Legacy-DB-Zugriff.
|
||||||
- Hero mit generiertem Bild-Asset, bestehender Typografie und gruenem Akzent.
|
- Hero mit generiertem Bild-Asset, bestehender Typografie und grünem Akzent.
|
||||||
- CTA zu Login und Registrierung.
|
- CTA zu Login und Registrierung.
|
||||||
- Login, Registrierung und oeffentliche Auth-Hilfsseiten sind optisch in den
|
- Login, Registrierung und öffentliche Auth-Hilfsseiten sind optisch in den
|
||||||
Public-Bereich integriert.
|
Public-Bereich integriert.
|
||||||
- Kurzabschnitt zu Stricherfassung, Mandantenfaehigkeit und Webspace-Betrieb.
|
- Kurzabschnitt zu Stricherfassung, Mandantenfähigkeit und Webspace-Betrieb.
|
||||||
- Die geschuetzte App-Sidebar bleibt von der Public-Seite getrennt.
|
- Die geschützte App-Sidebar bleibt von der Public-Seite getrennt.
|
||||||
|
|
||||||
## Tenant-Aufloesung
|
## Tenant-Auflösung
|
||||||
|
|
||||||
Entscheidung fuer den Webspace-Betrieb:
|
Entscheidung für den Webspace-Betrieb:
|
||||||
|
|
||||||
- Keine Wildcard-Subdomains im ersten Schritt.
|
- Keine Wildcard-Subdomains im ersten Schritt.
|
||||||
- Primaere App-Adresse ist eine zentrale App-Domain wie `app.kaffeeliste.de`.
|
- Primäre App-Adresse ist eine zentrale App-Domain wie `app.kaffeeliste.de`.
|
||||||
- Die Public-Seite kann ueber `kaffeeliste.de` beziehungsweise
|
- Die Public-Seite kann über `kaffeeliste.de` beziehungsweise
|
||||||
`www.kaffeeliste.de` laufen.
|
`www.kaffeeliste.de` laufen.
|
||||||
- Der aktive Mandant wird nach Login ueber `tenant_memberships` und die PHP-
|
- Der aktive Mandant wird nach Login über `tenant_memberships` und die PHP-
|
||||||
Session gesetzt.
|
Session gesetzt.
|
||||||
- Bei genau einem Mandanten wird automatisch weitergeleitet.
|
- Bei genau einem Mandanten wird automatisch weitergeleitet.
|
||||||
- Bei mehreren Mandanten nutzt der User `mandant-auswahl.php`.
|
- Bei mehreren Mandanten nutzt der User `mandant-auswahl.php`.
|
||||||
- `tenant_domains` ist vorbereitet fuer spaeter gezielt eingerichtete feste
|
- `tenant_domains` ist vorbereitet für später gezielt eingerichtete feste
|
||||||
Domains oder Subdomains, aber nicht Voraussetzung fuer den Start.
|
Domains oder Subdomains, aber nicht Voraussetzung für den Start.
|
||||||
|
|
||||||
Noch offen:
|
Noch offen:
|
||||||
|
|
||||||
- `APP_PRIMARY_HOST` in der Zielumgebung setzen.
|
- `APP_PRIMARY_HOST` in der Zielumgebung setzen.
|
||||||
- Optional `APP_PUBLIC_HOST` beziehungsweise Host-Rewrite fuer die Landingpage
|
- Optional `APP_PUBLIC_HOST` beziehungsweise Host-Rewrite für die Landingpage
|
||||||
in der Zielumgebung definieren.
|
in der Zielumgebung definieren.
|
||||||
- Produktive Domain-/Zertifikatspruefung fuer einzelne feste Domains
|
- Produktive Domain-/Zertifikatsprüfung für einzelne feste Domains
|
||||||
definieren.
|
definieren.
|
||||||
|
|
||||||
## Rollen und Grundeinstellungen
|
## Rollen und Grundeinstellungen
|
||||||
@@ -226,43 +226,43 @@ mandant-einstellungen.php
|
|||||||
Umgesetzter Umfang:
|
Umgesetzter Umfang:
|
||||||
|
|
||||||
- `saas_user_has_role()`, `saas_require_role()` und
|
- `saas_user_has_role()`, `saas_require_role()` und
|
||||||
`saas_can_manage_tenant_settings()` zentralisieren die erste Rollenpruefung.
|
`saas_can_manage_tenant_settings()` zentralisieren die erste Rollenprüfung.
|
||||||
- Owner und Admin duerfen Tenant-Grundeinstellungen bearbeiten.
|
- Owner und Admin dürfen Tenant-Grundeinstellungen bearbeiten.
|
||||||
- Die Seite bearbeitet Kundenname, Zeitzone, Locale, Waehrung, Preis pro
|
- Die Seite bearbeitet Kundenname, Zeitzone, Locale, Währung, Preis pro
|
||||||
Strich, Web-Striche, PayPal-Link, Listenfenster und Schulden-Warnschwelle.
|
Strich, Web-Striche, PayPal-Link, Listenfenster und Schulden-Warnschwelle.
|
||||||
- Geldwerte werden in der UI als Euro-Werte erfasst und weiterhin als Cent-
|
- Geldwerte werden in der UI als Euro-Werte erfasst und weiterhin als Cent-
|
||||||
Integer gespeichert.
|
Integer gespeichert.
|
||||||
- `konto.php` und die Sidebar verlinken die Einstellungen nur fuer passende
|
- `konto.php` und die Sidebar verlinken die Einstellungen nur für passende
|
||||||
Rollen.
|
Rollen.
|
||||||
|
|
||||||
## Erste Akzeptanzkriterien
|
## Erste Akzeptanzkriterien
|
||||||
|
|
||||||
- Migrationen laufen mehrfach ohne Fehler: erfuellt.
|
- Migrationen laufen mehrfach ohne Fehler: erfüllt.
|
||||||
- Default-Tenant existiert genau einmal: erfuellt.
|
- Default-Tenant existiert genau einmal: erfüllt.
|
||||||
- `tenant_settings` enthalten Preis pro Strich und bestehende PayPal-Optionen:
|
- `tenant_settings` enthalten Preis pro Strich und bestehende PayPal-Optionen:
|
||||||
erfuellt.
|
erfüllt.
|
||||||
- Jeder bestehende `kl_Mitarbeiter` hat genau einen `participant`: erfuellt.
|
- Jeder bestehende `kl_Mitarbeiter` hat genau einen `participant`: erfüllt.
|
||||||
- `participants.legacy_mitarbeiter_id` ist gesetzt: erfuellt.
|
- `participants.legacy_mitarbeiter_id` ist gesetzt: erfüllt.
|
||||||
- Admins werden als tenant-scoped Rolle abgebildet: erfuellt.
|
- Admins werden als tenant-scoped Rolle abgebildet: erfüllt.
|
||||||
- Registrierung und Login funktionieren fuer einen neuen Test-Tenant:
|
- Registrierung und Login funktionieren für einen neuen Test-Tenant:
|
||||||
erfuellt.
|
erfüllt.
|
||||||
- Owner-/Admin-Grundeinstellungen koennen aktualisiert werden: erfuellt.
|
- Owner-/Admin-Grundeinstellungen können aktualisiert werden: erfüllt.
|
||||||
- Passwort-Reset und E-Mail-Verifikation funktionieren mit Single-Use-Tokens:
|
- Passwort-Reset und E-Mail-Verifikation funktionieren mit Single-Use-Tokens:
|
||||||
erfuellt.
|
erfüllt.
|
||||||
- Reset- und Verifikationslinks werden im Dev-/Testmodus als Mail-Log erzeugt:
|
- Reset- und Verifikationslinks werden im Dev-/Testmodus als Mail-Log erzeugt:
|
||||||
erfuellt.
|
erfüllt.
|
||||||
- Mandantenauswahl funktioniert fuer User mit mehreren Mandanten: erfuellt.
|
- Mandantenauswahl funktioniert für User mit mehreren Mandanten: erfüllt.
|
||||||
- Oeffentliche Landingpage ist per HTTP-Smoke erreichbar: erfuellt.
|
- Öffentliche Landingpage ist per HTTP-Smoke erreichbar: erfüllt.
|
||||||
- Golden-Master und HTTP-Smoke bleiben gruen: erfuellt.
|
- Golden-Master und HTTP-Smoke bleiben grün: erfüllt.
|
||||||
|
|
||||||
## Risiken
|
## Risiken
|
||||||
|
|
||||||
| Risiko | Gegenmassnahme |
|
| Risiko | Gegenmaßnahme |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Login-User und Kaffee-Teilnehmer werden vermischt | `users` und `participants` strikt getrennt halten |
|
| Login-User und Kaffee-Teilnehmer werden vermischt | `users` und `participants` strikt getrennt halten |
|
||||||
| Mehrfacher Backfill erzeugt Duplikate | Eindeutige Constraints und Upsert-Logik |
|
| Mehrfacher Backfill erzeugt Duplikate | Eindeutige Constraints und Upsert-Logik |
|
||||||
| Legacy-App bricht durch neue Tabellen | M3 nur additiv, keine Legacy-Queries umstellen |
|
| Legacy-App bricht durch neue Tabellen | M3 nur additiv, keine Legacy-Queries umstellen |
|
||||||
| Rollen werden global statt tenant-scoped | Rollen ausschliesslich in `tenant_memberships` speichern |
|
| 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 |
|
| Falsche Owner-Zuordnung | Owner per Env-Konfiguration oder manuell dokumentierter Entscheidung setzen |
|
||||||
|
|
||||||
## Empfohlene Reihenfolge
|
## Empfohlene Reihenfolge
|
||||||
@@ -270,24 +270,24 @@ Umgesetzter Umfang:
|
|||||||
1. Migration `0002_saas_identity_tenants.sql` erstellen: erledigt.
|
1. Migration `0002_saas_identity_tenants.sql` erstellen: erledigt.
|
||||||
2. Migration `0003_saas_auth_account_fields.sql` erstellen: erledigt.
|
2. Migration `0003_saas_auth_account_fields.sql` erstellen: erledigt.
|
||||||
3. `scripts/backfill-default-tenant.php` erstellen: erledigt.
|
3. `scripts/backfill-default-tenant.php` erstellen: erledigt.
|
||||||
4. Backfill gegen die Dev-Datenbank ausfuehren: erledigt.
|
4. Backfill gegen die Dev-Datenbank ausführen: erledigt.
|
||||||
5. Kontrollskript fuer Tenant/Participant/Role-Counts schreiben: erledigt.
|
5. Kontrollskript für Tenant/Participant/Role-Counts schreiben: erledigt.
|
||||||
6. Login-/Registrierungsrouten bauen: erledigt.
|
6. Login-/Registrierungsrouten bauen: erledigt.
|
||||||
7. Auth-Flow-Kontrollskript schreiben: erledigt.
|
7. Auth-Flow-Kontrollskript schreiben: erledigt.
|
||||||
8. Zentrale Rollenpruefung und Mandant-Einstellungen bauen: erledigt.
|
8. Zentrale Rollenprüfung und Mandant-Einstellungen bauen: erledigt.
|
||||||
9. Settings-Flow-Kontrollskript schreiben: erledigt.
|
9. Settings-Flow-Kontrollskript schreiben: erledigt.
|
||||||
10. Migration `0004_saas_auth_tokens.sql` erstellen: erledigt.
|
10. Migration `0004_saas_auth_tokens.sql` erstellen: erledigt.
|
||||||
11. Passwort-Reset und E-Mail-Verifikation bauen: erledigt.
|
11. Passwort-Reset und E-Mail-Verifikation bauen: erledigt.
|
||||||
12. Password-/E-Mail-Flow-Kontrollskript schreiben: erledigt.
|
12. Password-/E-Mail-Flow-Kontrollskript schreiben: erledigt.
|
||||||
13. Migration `0005_saas_tenant_resolution.sql` erstellen: erledigt.
|
13. Migration `0005_saas_tenant_resolution.sql` erstellen: erledigt.
|
||||||
14. Mandantenauswahl und zentrale Session-Aufloesung bauen: erledigt.
|
14. Mandantenauswahl und zentrale Session-Auflösung bauen: erledigt.
|
||||||
15. Tenant-Resolution-Kontrollskript schreiben: erledigt.
|
15. Tenant-Resolution-Kontrollskript schreiben: erledigt.
|
||||||
16. Golden-Master und HTTP-Smoke ausfuehren: erledigt.
|
16. Golden-Master und HTTP-Smoke ausführen: erledigt.
|
||||||
17. Mail-Transport-Abstraktion und Mail-Flow-Kontrollskript bauen: erledigt.
|
17. Mail-Transport-Abstraktion und Mail-Flow-Kontrollskript bauen: erledigt.
|
||||||
18. Public-Landingpage mit erstem Hero-Asset vorbereiten: erledigt.
|
18. Public-Landingpage mit erstem Hero-Asset vorbereiten: erledigt.
|
||||||
19. M3-Abschlusscheck dokumentieren und M4-Datenmigration starten: erledigt.
|
19. M3-Abschlusscheck dokumentieren und M4-Datenmigration starten: erledigt.
|
||||||
|
|
||||||
## Uebergabe an M4
|
## Übergabe an M4
|
||||||
|
|
||||||
M4 ist in `docs/m4-data-migration.md` dokumentiert. Der erste M4-Schritt ist
|
M4 ist in `docs/m4-data-migration.md` dokumentiert. Der erste M4-Schritt ist
|
||||||
bewusst additiv:
|
bewusst additiv:
|
||||||
|
|||||||
+39
-39
@@ -2,20 +2,20 @@
|
|||||||
|
|
||||||
Stand: 2026-07-14
|
Stand: 2026-07-14
|
||||||
|
|
||||||
M4 uebernimmt die finanznahen Legacy-Buchungen additiv in das neue
|
M4 übernimmt die finanznahen Legacy-Buchungen additiv in das neue
|
||||||
tenant-sichere Ledger-Modell. Die bestehenden Legacy-Seiten lesen und schreiben
|
tenant-sichere Ledger-Modell. Die bestehenden Legacy-Seiten lesen und schreiben
|
||||||
weiterhin die bisherigen `kl_*`-Tabellen; das Ledger dient zunaechst als
|
weiterhin die bisherigen `kl_*`-Tabellen; das Ledger dient zunächst als
|
||||||
vergleichbare, pruefbare Zielstruktur. Erste App-Abfragen koennen nun ueber
|
vergleichbare, prüfbare Zielstruktur. Erste App-Abfragen können nun über
|
||||||
einen zentralen Ledger-Service gegen `ledger_entries` laufen.
|
einen zentralen Ledger-Service gegen `ledger_entries` laufen.
|
||||||
|
|
||||||
## Ziel
|
## Ziel
|
||||||
|
|
||||||
- `kl_Einzahlungen` nach `ledger_entries` spiegeln.
|
- `kl_Einzahlungen` nach `ledger_entries` spiegeln.
|
||||||
- `kl_Kaffeeverbrauch` nach `ledger_entries` spiegeln.
|
- `kl_Kaffeeverbrauch` nach `ledger_entries` spiegeln.
|
||||||
- Legacy-IDs erhalten, damit Paritaet und spaetere Delta-Migration moeglich
|
- Legacy-IDs erhalten, damit Parität und spätere Delta-Migration möglich
|
||||||
bleiben.
|
bleiben.
|
||||||
- Summen gegen den Golden Master pruefen.
|
- Summen gegen den Golden Master prüfen.
|
||||||
- Keine bestehenden Legacy-Buchungen loeschen oder veraendern.
|
- Keine bestehenden Legacy-Buchungen löschen oder verändern.
|
||||||
|
|
||||||
## Nicht-Ziele
|
## Nicht-Ziele
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ Neue Tabelle:
|
|||||||
|
|
||||||
- `ledger_entries`
|
- `ledger_entries`
|
||||||
|
|
||||||
Ergaenzende Skripte:
|
Ergänzende Skripte:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
scripts/backfill-ledger-entries.php
|
scripts/backfill-ledger-entries.php
|
||||||
@@ -44,20 +44,20 @@ scripts/check-m4-ledger-migration.php
|
|||||||
scripts/check-m4-ledger-service.php
|
scripts/check-m4-ledger-service.php
|
||||||
```
|
```
|
||||||
|
|
||||||
Ergaenzende App-Dateien:
|
Ergänzende App-Dateien:
|
||||||
|
|
||||||
```text
|
```text
|
||||||
app/ledger.php
|
app/ledger.php
|
||||||
ledger-preview.php
|
ledger-preview.php
|
||||||
```
|
```
|
||||||
|
|
||||||
Ausgefuehrter Dev-Stand:
|
Ausgeführter Dev-Stand:
|
||||||
|
|
||||||
- Migration `0006_saas_ledger_entries.sql` wurde angewendet.
|
- Migration `0006_saas_ledger_entries.sql` wurde angewendet.
|
||||||
- 9 Legacy-Einzahlungen wurden als `payment` gespiegelt.
|
- 9 Legacy-Einzahlungen wurden als `payment` gespiegelt.
|
||||||
- 12 Legacy-Kaffeeverbrauch-Zeilen wurden als `consumption` gespiegelt.
|
- 12 Legacy-Kaffeeverbrauch-Zeilen wurden als `consumption` gespiegelt.
|
||||||
- Ein zweiter Backfill-Lauf blieb idempotent und erzeugte keine Dubletten.
|
- Ein zweiter Backfill-Lauf blieb idempotent und erzeugte keine Dubletten.
|
||||||
- `app/ledger.php` stellt zentrale Abfragen fuer Tenant-Summen,
|
- `app/ledger.php` stellt zentrale Abfragen für Tenant-Summen,
|
||||||
Teilnehmer-Summen, einzelne Teilnehmer und letzte Buchungen bereit.
|
Teilnehmer-Summen, einzelne Teilnehmer und letzte Buchungen bereit.
|
||||||
- `ledger-preview.php` zeigt eine read-only App-Vorschau auf Tenant-Summen,
|
- `ledger-preview.php` zeigt eine read-only App-Vorschau auf Tenant-Summen,
|
||||||
aktive Teilnehmer und die letzten Ledger-Buchungen.
|
aktive Teilnehmer und die letzten Ledger-Buchungen.
|
||||||
@@ -109,16 +109,16 @@ ledger_entries.legacy_id = VerbrauchID
|
|||||||
Verbrauch wird negativ gespeichert. Damit ergibt `SUM(amount_cents)` direkt den
|
Verbrauch wird negativ gespeichert. Damit ergibt `SUM(amount_cents)` direkt den
|
||||||
aktuellen Saldo eines Teilnehmers.
|
aktuellen Saldo eines Teilnehmers.
|
||||||
|
|
||||||
## Idempotenz und Aufraeumen
|
## Idempotenz und Aufräumen
|
||||||
|
|
||||||
Das Backfill-Skript nutzt `tenant_id`, `legacy_table` und `legacy_id` als
|
Das Backfill-Skript nutzt `tenant_id`, `legacy_table` und `legacy_id` als
|
||||||
eindeutige Quelle. Wiederholte Laeufe aktualisieren vorhandene Ledger-Zeilen.
|
eindeutige Quelle. Wiederholte Läufe aktualisieren vorhandene Ledger-Zeilen.
|
||||||
|
|
||||||
Fuer den Default-Tenant werden nur solche Legacy-Spiegelungen entfernt, deren
|
Für den Default-Tenant werden nur solche Legacy-Spiegelungen entfernt, deren
|
||||||
urspruengliche Legacy-Zeile nicht mehr existiert. Fachliche Daten werden dabei
|
ursprüngliche Legacy-Zeile nicht mehr existiert. Fachliche Daten werden dabei
|
||||||
nicht aus den `kl_*`-Tabellen geloescht.
|
nicht aus den `kl_*`-Tabellen gelöscht.
|
||||||
|
|
||||||
## Ausfuehrung
|
## Ausführung
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
php scripts/backfill-default-tenant.php
|
php scripts/backfill-default-tenant.php
|
||||||
@@ -133,33 +133,33 @@ Installation aus `.local/` verwendet werden.
|
|||||||
|
|
||||||
## Akzeptanzkriterien
|
## Akzeptanzkriterien
|
||||||
|
|
||||||
- Migration `0006_saas_ledger_entries.sql` laeuft erfolgreich: erfuellt.
|
- Migration `0006_saas_ledger_entries.sql` läuft erfolgreich: erfüllt.
|
||||||
- Jede Legacy-Einzahlung hat genau eine Ledger-Zeile: erfuellt.
|
- Jede Legacy-Einzahlung hat genau eine Ledger-Zeile: erfüllt.
|
||||||
- Jeder Legacy-Kaffeeverbrauch hat genau eine Ledger-Zeile: erfuellt.
|
- Jeder Legacy-Kaffeeverbrauch hat genau eine Ledger-Zeile: erfüllt.
|
||||||
- Legacy-IDs sind je Tenant eindeutig: erfuellt.
|
- Legacy-IDs sind je Tenant eindeutig: erfüllt.
|
||||||
- Einzahlungen sind positiv, Verbrauch ist negativ: erfuellt.
|
- Einzahlungen sind positiv, Verbrauch ist negativ: erfüllt.
|
||||||
- Verbrauch behaelt Strichanzahl und Preis pro Strich: erfuellt.
|
- Verbrauch behält Strichanzahl und Preis pro Strich: erfüllt.
|
||||||
- Web-Striche aus `Eintragsart = 2` bleiben als `source = legacy_web`
|
- Web-Striche aus `Eintragsart = 2` bleiben als `source = legacy_web`
|
||||||
erkennbar: erfuellt.
|
erkennbar: erfüllt.
|
||||||
- Ledger-Summen entsprechen dem Golden Master: erfuellt.
|
- Ledger-Summen entsprechen dem Golden Master: erfüllt.
|
||||||
- Zentrale Ledger-Abfragen liefern dieselben Teilnehmer-Summen wie der Golden
|
- Zentrale Ledger-Abfragen liefern dieselben Teilnehmer-Summen wie der Golden
|
||||||
Master: erfuellt.
|
Master: erfüllt.
|
||||||
- Tenant-Summen, aktive Teilnehmer, Einzelteilnehmer und letzte Buchungen sind
|
- Tenant-Summen, aktive Teilnehmer, Einzelteilnehmer und letzte Buchungen sind
|
||||||
ueber `app/ledger.php` abrufbar: erfuellt.
|
über `app/ledger.php` abrufbar: erfüllt.
|
||||||
- Read-only Ledger-Preview ist im Browser erreichbar: erfuellt.
|
- Read-only Ledger-Preview ist im Browser erreichbar: erfüllt.
|
||||||
|
|
||||||
## Aktueller Pruefstatus
|
## Aktueller Prüfstatus
|
||||||
|
|
||||||
- M4 Ledger-Migration: gruen mit 73 Assertions.
|
- M4 Ledger-Migration: grün mit 73 Assertions.
|
||||||
- M4 Ledger-Service: gruen mit 110 Assertions.
|
- M4 Ledger-Service: grün mit 110 Assertions.
|
||||||
- M3 SaaS-Basis: weiterhin gruen.
|
- M3 SaaS-Basis: weiterhin grün.
|
||||||
- M3 Tenant-Aufloesung: weiterhin gruen.
|
- M3 Tenant-Auflösung: weiterhin grün.
|
||||||
- M3 Passwort/E-Mail: weiterhin gruen.
|
- M3 Passwort/E-Mail: weiterhin grün.
|
||||||
- M3 Auth-Flow: weiterhin gruen.
|
- M3 Auth-Flow: weiterhin grün.
|
||||||
- M3 Settings-Flow: weiterhin gruen.
|
- M3 Settings-Flow: weiterhin grün.
|
||||||
- M3 Mail-Flow: weiterhin gruen.
|
- M3 Mail-Flow: weiterhin grün.
|
||||||
- Golden Master: weiterhin gruen mit 104 Assertions.
|
- Golden Master: weiterhin grün mit 104 Assertions.
|
||||||
- HTTP-Smoke: weiterhin gruen mit 23 geprueften Seiten inklusive
|
- HTTP-Smoke: weiterhin grün mit 23 geprüften Seiten inklusive
|
||||||
`ledger-preview.php`.
|
`ledger-preview.php`.
|
||||||
|
|
||||||
## Noch offen in M4
|
## Noch offen in M4
|
||||||
@@ -167,4 +167,4 @@ Installation aus `.local/` verwendet werden.
|
|||||||
- Tenant-sichere Dashboard-, Strich-, Einzahlungs- und Listenqueries schrittweise
|
- Tenant-sichere Dashboard-, Strich-, Einzahlungs- und Listenqueries schrittweise
|
||||||
von Legacy-Tabellen auf das Ledger umstellen.
|
von Legacy-Tabellen auf das Ledger umstellen.
|
||||||
- Storno-/Reversal-Modell in der UI statt harter Deletes.
|
- Storno-/Reversal-Modell in der UI statt harter Deletes.
|
||||||
- Delta-Strategie fuer den finalen Cutover.
|
- Delta-Strategie für den finalen Cutover.
|
||||||
|
|||||||
+14
-14
@@ -4,13 +4,13 @@ Stand: 2026-07-14
|
|||||||
|
|
||||||
M5 stellt die operativen App-Seiten schrittweise auf das neue tenant-sichere
|
M5 stellt die operativen App-Seiten schrittweise auf das neue tenant-sichere
|
||||||
Modell um. Der Start erfolgt bewusst read-only, damit Summen, Links und
|
Modell um. Der Start erfolgt bewusst read-only, damit Summen, Links und
|
||||||
Darstellung gegen die bestehende Legacy-Oberflaeche vergleichbar bleiben.
|
Darstellung gegen die bestehende Legacy-Oberfläche vergleichbar bleiben.
|
||||||
|
|
||||||
## Ziel
|
## Ziel
|
||||||
|
|
||||||
- Kernseiten aus `app/ledger.php` lesen lassen.
|
- Kernseiten aus `app/ledger.php` lesen lassen.
|
||||||
- Bestehendes Tabellenlayout und Bediengefuehl erhalten.
|
- Bestehendes Tabellenlayout und Bediengefühl erhalten.
|
||||||
- Schreibende Legacy-Flows erst nach stabiler Leseparitaet umstellen.
|
- Schreibende Legacy-Flows erst nach stabiler Leseparität umstellen.
|
||||||
- Tenant-Kontext serverseitig bestimmen, nicht aus Formularfeldern.
|
- Tenant-Kontext serverseitig bestimmen, nicht aus Formularfeldern.
|
||||||
|
|
||||||
## Umgesetzter erster Schritt
|
## Umgesetzter erster Schritt
|
||||||
@@ -23,18 +23,18 @@ kaffeeliste.php
|
|||||||
|
|
||||||
Umgesetzter Umfang:
|
Umgesetzter Umfang:
|
||||||
|
|
||||||
- Die Gesamtuebersicht liest aktive Teilnehmer aus
|
- Die Gesamtübersicht liest aktive Teilnehmer aus
|
||||||
`ledger_fetch_participant_summaries()`.
|
`ledger_fetch_participant_summaries()`.
|
||||||
- Angezeigte Werte bleiben fachlich gleich: aktueller Stand, Gesamtausgabe,
|
- Angezeigte Werte bleiben fachlich gleich: aktueller Stand, Gesamtausgabe,
|
||||||
Gesamtstriche und Gesamteinzahlungen.
|
Gesamtstriche und Gesamteinzahlungen.
|
||||||
- Links zur bestehenden `teilnehmerauswertung.php` bleiben ueber
|
- Links zur bestehenden `teilnehmerauswertung.php` bleiben über
|
||||||
`participants.legacy_mitarbeiter_id` erhalten.
|
`participants.legacy_mitarbeiter_id` erhalten.
|
||||||
- Owner, Admin und Treasurer duerfen die SaaS-Ansicht lesen.
|
- Owner, Admin und Treasurer dürfen die SaaS-Ansicht lesen.
|
||||||
- Der lokale Legacy-/Dev-Admin-Fallback nutzt nur ohne SaaS-Session den
|
- Der lokale Legacy-/Dev-Admin-Fallback nutzt nur ohne SaaS-Session den
|
||||||
Default-Tenant.
|
Default-Tenant.
|
||||||
- Die Sidebar zeigt Legacy-Schreibseiten weiterhin nur fuer Legacy-Admins;
|
- Die Sidebar zeigt Legacy-Schreibseiten weiterhin nur für Legacy-Admins;
|
||||||
Ledger-Leseansichten sind fuer passende SaaS-Rollen sichtbar.
|
Ledger-Leseansichten sind für passende SaaS-Rollen sichtbar.
|
||||||
- Export, letzte Eintraege, CSV-Upload und Info-Mail bleiben noch Legacy-Flows.
|
- Export, letzte Einträge, CSV-Upload und Info-Mail bleiben noch Legacy-Flows.
|
||||||
|
|
||||||
## Noch offen
|
## Noch offen
|
||||||
|
|
||||||
@@ -44,9 +44,9 @@ Umgesetzter Umfang:
|
|||||||
Storno-/Reversal-Strategie vorbereiten.
|
Storno-/Reversal-Strategie vorbereiten.
|
||||||
- Export, Mail und Jahresprozesse bleiben M6-Themen.
|
- Export, Mail und Jahresprozesse bleiben M6-Themen.
|
||||||
|
|
||||||
## Aktueller Pruefstatus
|
## Aktueller Prüfstatus
|
||||||
|
|
||||||
- M4 Ledger-Migration: gruen mit 73 Assertions.
|
- M4 Ledger-Migration: grün mit 73 Assertions.
|
||||||
- M4 Ledger-Service: gruen mit 110 Assertions.
|
- M4 Ledger-Service: grün mit 110 Assertions.
|
||||||
- Golden Master: gruen mit 104 Assertions.
|
- Golden Master: grün mit 104 Assertions.
|
||||||
- HTTP-Smoke: gruen mit 23 geprueften Seiten.
|
- HTTP-Smoke: grün mit 23 geprüften Seiten.
|
||||||
|
|||||||
+151
-151
@@ -3,28 +3,28 @@
|
|||||||
Stand: 2026-07-13
|
Stand: 2026-07-13
|
||||||
|
|
||||||
Dieses Dokument beschreibt den geplanten Umbau der bestehenden Kaffeelisten-App zu
|
Dieses Dokument beschreibt den geplanten Umbau der bestehenden Kaffeelisten-App zu
|
||||||
einer mehrkundenfaehigen SaaS-Anwendung mit oeffentlicher Landingpage,
|
einer mehrkundenfähigen SaaS-Anwendung mit öffentlicher Landingpage,
|
||||||
Kundenregistrierung und geschuetzter App. Die bestehende Bedienlogik und das
|
Kundenregistrierung und geschützter App. Die bestehende Bedienlogik und das
|
||||||
visuelle Grunddesign sollen bewusst erhalten bleiben.
|
visuelle Grunddesign sollen bewusst erhalten bleiben.
|
||||||
|
|
||||||
## Zielbild
|
## Zielbild
|
||||||
|
|
||||||
- Mehrere Kunden koennen eigene Kaffeelisten betreiben.
|
- Mehrere Kunden können eigene Kaffeelisten betreiben.
|
||||||
- Jeder Kunde hat isolierte Daten, Einstellungen, Mitglieder und Buchungen.
|
- Jeder Kunde hat isolierte Daten, Einstellungen, Mitglieder und Buchungen.
|
||||||
- Neue Kunden koennen sich ueber eine oeffentliche Landingpage registrieren.
|
- Neue Kunden können sich über eine öffentliche Landingpage registrieren.
|
||||||
- Die operative App bleibt optisch nah am aktuellen Bestand: Sidebar, Tabellen,
|
- Die operative App bleibt optisch nah am aktuellen Bestand: Sidebar, Tabellen,
|
||||||
schlichte Formulare, HTML5-UP-Anmutung.
|
schlichte Formulare, HTML5-UP-Anmutung.
|
||||||
- Authentifizierung, Rollen, Mandantenkontext und Sicherheitspruefungen werden
|
- Authentifizierung, Rollen, Mandantenkontext und Sicherheitsprüfungen werden
|
||||||
zentralisiert.
|
zentralisiert.
|
||||||
- Finanznahe Vorgaenge werden nachvollziehbar und revisionsfreundlich
|
- Finanznahe Vorgänge werden nachvollziehbar und revisionsfreundlich
|
||||||
gespeichert.
|
gespeichert.
|
||||||
|
|
||||||
## Nicht-Ziele fuer den ersten Umbau
|
## Nicht-Ziele für den ersten Umbau
|
||||||
|
|
||||||
- Kein kompletter Design-Relaunch.
|
- Kein kompletter Design-Relaunch.
|
||||||
- Keine verspielte Marketing-App statt der bestehenden Arbeitsoberflaeche.
|
- Keine verspielte Marketing-App statt der bestehenden Arbeitsoberfläche.
|
||||||
- Kein gleichzeitiger Neubau aller Randmodule, wenn diese fuer den MVP nicht
|
- Kein gleichzeitiger Neubau aller Randmodule, wenn diese für den MVP nicht
|
||||||
benoetigt werden.
|
benötigt werden.
|
||||||
- Kein Dual-Write zwischen Legacy und neuer App als Standardbetrieb.
|
- Kein Dual-Write zwischen Legacy und neuer App als Standardbetrieb.
|
||||||
- Keine Mandanten-ID aus Formularfeldern oder URL-Parametern als alleinige
|
- Keine Mandanten-ID aus Formularfeldern oder URL-Parametern als alleinige
|
||||||
Sicherheitsbasis.
|
Sicherheitsbasis.
|
||||||
@@ -35,12 +35,12 @@ Die aktuelle App ist eine flache PHP/sqlsrv-Legacy-App im Webroot.
|
|||||||
|
|
||||||
Wichtige Bereiche:
|
Wichtige Bereiche:
|
||||||
|
|
||||||
- `index.php`: persoenliches Dashboard.
|
- `index.php`: persönliches Dashboard.
|
||||||
- `stricheintragen.php`: Sammelerfassung von Kaffee-Strichen.
|
- `stricheintragen.php`: Sammelerfassung von Kaffee-Strichen.
|
||||||
- `einzahlung.php`: Sammelerfassung von Einzahlungen.
|
- `einzahlung.php`: Sammelerfassung von Einzahlungen.
|
||||||
- `kaffeeliste.php`: Gesamtuebersicht.
|
- `kaffeeliste.php`: Gesamtübersicht.
|
||||||
- `mitarbeiterverwalten.php`: Mitglieder- und Adminpflege.
|
- `mitarbeiterverwalten.php`: Mitglieder- und Adminpflege.
|
||||||
- `letzteneintraege.php`: Korrektur beziehungsweise Loeschung letzter Buchungen.
|
- `letzteneintraege.php`: Korrektur beziehungsweise Löschung letzter Buchungen.
|
||||||
- `csvupload.php`: Zahlungsimport.
|
- `csvupload.php`: Zahlungsimport.
|
||||||
- `exportKaffeeliste.php`: PDF-/Listenexport.
|
- `exportKaffeeliste.php`: PDF-/Listenexport.
|
||||||
- `mailversenden.php`: Massenmail.
|
- `mailversenden.php`: Massenmail.
|
||||||
@@ -49,7 +49,7 @@ Wichtige Bereiche:
|
|||||||
|
|
||||||
Zentrale technische Beobachtungen:
|
Zentrale technische Beobachtungen:
|
||||||
|
|
||||||
- Authentifizierung haengt an Windows/IIS `AUTH_USER` und LDAP.
|
- Authentifizierung hängt an Windows/IIS `AUTH_USER` und LDAP.
|
||||||
- Die Mailadresse des Nutzers wird in `functionsLDAP.php` ermittelt.
|
- Die Mailadresse des Nutzers wird in `functionsLDAP.php` ermittelt.
|
||||||
- Rollen liegen als Boolean `admin` direkt auf `kl_Mitarbeiter`.
|
- Rollen liegen als Boolean `admin` direkt auf `kl_Mitarbeiter`.
|
||||||
- Datenzugriff findet direkt in den einzelnen PHP-Seiten per `sqlsrv_query`
|
- Datenzugriff findet direkt in den einzelnen PHP-Seiten per `sqlsrv_query`
|
||||||
@@ -66,23 +66,23 @@ mit einem stabilen SaaS-Fundament:
|
|||||||
|
|
||||||
1. Bestand dokumentieren und fachliche Ergebnisse einfrieren.
|
1. Bestand dokumentieren und fachliche Ergebnisse einfrieren.
|
||||||
2. Mandantenmodell, Auth und Rollen sauber aufbauen.
|
2. Mandantenmodell, Auth und Rollen sauber aufbauen.
|
||||||
3. Bestehende Fachlogik schrittweise tenant-sicher uebernehmen.
|
3. Bestehende Fachlogik schrittweise tenant-sicher übernehmen.
|
||||||
4. Landingpage und App-Shell trennen, ohne das App-Design neu zu erfinden.
|
4. Landingpage und App-Shell trennen, ohne das App-Design neu zu erfinden.
|
||||||
|
|
||||||
So bleibt die vertraute Kaffeelisten-Oberflaeche erhalten, waehrend die
|
So bleibt die vertraute Kaffeelisten-Oberfläche erhalten, während die
|
||||||
Datenbasis und Sicherheit SaaS-faehig werden.
|
Datenbasis und Sicherheit SaaS-fähig werden.
|
||||||
|
|
||||||
## Zielarchitektur
|
## Zielarchitektur
|
||||||
|
|
||||||
### Public-Bereich
|
### Public-Bereich
|
||||||
|
|
||||||
Der Public-Bereich ist ohne Login erreichbar und laedt keine Mandantendaten.
|
Der Public-Bereich ist ohne Login erreichbar und lädt keine Mandantendaten.
|
||||||
|
|
||||||
Empfohlene Routen:
|
Empfohlene Routen:
|
||||||
|
|
||||||
- `/`: Landingpage.
|
- `/`: Landingpage.
|
||||||
- `/preise` oder spaeter `/pricing`: optional, falls Tarife eingefuehrt werden.
|
- `/preise` oder später `/pricing`: optional, falls Tarife eingeführt werden.
|
||||||
- `/faq`: oeffentliche FAQ oder FAQ-Auszug.
|
- `/faq`: öffentliche FAQ oder FAQ-Auszug.
|
||||||
- `/registrieren` beziehungsweise aktuell `register.php`: Kundenregistrierung.
|
- `/registrieren` beziehungsweise aktuell `register.php`: Kundenregistrierung.
|
||||||
- `/login` beziehungsweise aktuell `login.php`: Login.
|
- `/login` beziehungsweise aktuell `login.php`: Login.
|
||||||
- `/passwort-vergessen` beziehungsweise aktuell `passwort-vergessen.php`:
|
- `/passwort-vergessen` beziehungsweise aktuell `passwort-vergessen.php`:
|
||||||
@@ -91,16 +91,16 @@ Empfohlene Routen:
|
|||||||
Landingpage-Inhalte:
|
Landingpage-Inhalte:
|
||||||
|
|
||||||
- Hero mit Name `Kaffeeliste` und kurzer Nutzenbeschreibung.
|
- Hero mit Name `Kaffeeliste` und kurzer Nutzenbeschreibung.
|
||||||
- Drei Kernablaeufe: Kaffee nehmen, Strich setzen, bei Bedarf bezahlen.
|
- Drei Kernabläufe: Kaffee nehmen, Strich setzen, bei Bedarf bezahlen.
|
||||||
- Kurzer Blick auf Funktionen: Mitglieder, Guthaben, Einzahlungen, Export,
|
- Kurzer Blick auf Funktionen: Mitglieder, Guthaben, Einzahlungen, Export,
|
||||||
Hinweise.
|
Hinweise.
|
||||||
- App-Screenshot oder Demo-Ansicht im bestehenden Stil.
|
- App-Screenshot oder Demo-Ansicht im bestehenden Stil.
|
||||||
- FAQ-Auszug.
|
- FAQ-Auszug.
|
||||||
- Call-to-Action zu Registrierung und Login.
|
- Call-to-Action zu Registrierung und Login.
|
||||||
|
|
||||||
### Geschuetzte App
|
### Geschützte App
|
||||||
|
|
||||||
Die geschuetzte App bleibt die operative Arbeitsoberflaeche.
|
Die geschützte App bleibt die operative Arbeitsoberfläche.
|
||||||
|
|
||||||
Empfohlene Routen:
|
Empfohlene Routen:
|
||||||
|
|
||||||
@@ -109,8 +109,8 @@ Empfohlene Routen:
|
|||||||
- `/app/striche`: Eigene Striche erfassen, falls erlaubt.
|
- `/app/striche`: Eigene Striche erfassen, falls erlaubt.
|
||||||
- `/app/einzahlungen`: Zahlungen und PayPal-Optionen.
|
- `/app/einzahlungen`: Zahlungen und PayPal-Optionen.
|
||||||
- `/app/mitglieder`: Mitgliederverwaltung.
|
- `/app/mitglieder`: Mitgliederverwaltung.
|
||||||
- `/app/liste`: Gesamtuebersicht.
|
- `/app/liste`: Gesamtübersicht.
|
||||||
- `/app/buchungen`: Letzte Eintraege und Korrekturen.
|
- `/app/buchungen`: Letzte Einträge und Korrekturen.
|
||||||
- `/app/importe`: CSV-Importe.
|
- `/app/importe`: CSV-Importe.
|
||||||
- `/app/export/pdf`: PDF-/Listenexport.
|
- `/app/export/pdf`: PDF-/Listenexport.
|
||||||
- `/app/hinweise`: Hinweise.
|
- `/app/hinweise`: Hinweise.
|
||||||
@@ -118,29 +118,29 @@ Empfohlene Routen:
|
|||||||
|
|
||||||
Die App sollte eine Sidebar behalten, aber besser gruppiert werden:
|
Die App sollte eine Sidebar behalten, aber besser gruppiert werden:
|
||||||
|
|
||||||
- Persoenlich: Meine Kaffeeliste, Namensanpassung, FAQ.
|
- Persönlich: Meine Kaffeeliste, Namensanpassung, FAQ.
|
||||||
- Erfassung: Striche, Einzahlungen.
|
- Erfassung: Striche, Einzahlungen.
|
||||||
- Auswertung: Kaffeeliste, Buchungen, Export.
|
- Auswertung: Kaffeeliste, Buchungen, Export.
|
||||||
- Administration: Mitglieder, Hinweise, Einstellungen, Importe.
|
- Administration: Mitglieder, Hinweise, Einstellungen, Importe.
|
||||||
- Konto: Kundenkonto und Logout. Public-Links wie Login und Registrierung
|
- Konto: Kundenkonto und Logout. Public-Links wie Login und Registrierung
|
||||||
gehoeren nicht in die App-Sidebar.
|
gehören nicht in die App-Sidebar.
|
||||||
|
|
||||||
### Webspace- und Host-Strategie
|
### Webspace- und Host-Strategie
|
||||||
|
|
||||||
Empfohlen fuer den Start:
|
Empfohlen für den Start:
|
||||||
|
|
||||||
- `kaffeeliste.de` oder `www.kaffeeliste.de` fuer Landingpage, Registrierung
|
- `kaffeeliste.de` oder `www.kaffeeliste.de` für Landingpage, Registrierung
|
||||||
und Login.
|
und Login.
|
||||||
- `app.kaffeeliste.de` fuer die geschuetzte App.
|
- `app.kaffeeliste.de` für die geschützte App.
|
||||||
- Keine Wildcard-Subdomains fuer Kunden.
|
- Keine Wildcard-Subdomains für Kunden.
|
||||||
- Mandantenauswahl nach Login ueber Session und `tenant_memberships`.
|
- Mandantenauswahl nach Login über Session und `tenant_memberships`.
|
||||||
- Kundeneigene feste Domains oder Subdomains erst spaeter gezielt einrichten,
|
- Kundeneigene feste Domains oder Subdomains erst später gezielt einrichten,
|
||||||
wenn DNS und Zertifikat pro Domain sauber geprueft sind.
|
wenn DNS und Zertifikat pro Domain sauber geprüft sind.
|
||||||
|
|
||||||
Damit bleibt der Betrieb webspace-tauglich: Fuer den Start reichen zwei feste
|
Damit bleibt der Betrieb webspace-tauglich: Für den Start reichen zwei feste
|
||||||
Hosts mit normalen Let's-Encrypt-Zertifikaten. Die fachliche Tenant-Aufloesung
|
Hosts mit normalen Let's-Encrypt-Zertifikaten. Die fachliche Tenant-Auflösung
|
||||||
ist in M3 vorbereitet; produktive Host-Rewrites, Cookie-Domain und Zertifikats-
|
ist in M3 vorbereitet; produktive Host-Rewrites, Cookie-Domain und Zertifikats-
|
||||||
Details gehoeren zur M8-Betriebshaertung.
|
Details gehören zur M8-Betriebshärtung.
|
||||||
|
|
||||||
## Datenmodell
|
## Datenmodell
|
||||||
|
|
||||||
@@ -218,9 +218,9 @@ Wichtige Modellierungsregeln:
|
|||||||
- `users` sind Login-Konten.
|
- `users` sind Login-Konten.
|
||||||
- `participants` sind Kaffee-Teilnehmer.
|
- `participants` sind Kaffee-Teilnehmer.
|
||||||
- Ein Teilnehmer kann, muss aber nicht, ein Login-Konto haben.
|
- Ein Teilnehmer kann, muss aber nicht, ein Login-Konto haben.
|
||||||
- Rollen gehoeren in `tenant_memberships`, nicht direkt auf Teilnehmer.
|
- Rollen gehören in `tenant_memberships`, nicht direkt auf Teilnehmer.
|
||||||
- Buchungen sollten nicht hart geloescht werden.
|
- Buchungen sollten nicht hart gelöscht werden.
|
||||||
- Korrekturen laufen ueber Storno- oder Reversal-Eintraege.
|
- Korrekturen laufen über Storno- oder Reversal-Einträge.
|
||||||
- Legacy-IDs werden bei Migration gespeichert, damit Ergebnisse vergleichbar
|
- Legacy-IDs werden bei Migration gespeichert, damit Ergebnisse vergleichbar
|
||||||
bleiben.
|
bleiben.
|
||||||
- Geldwerte sollten als Cent-Integer gespeichert werden, nicht als Float.
|
- Geldwerte sollten als Cent-Integer gespeichert werden, nicht als Float.
|
||||||
@@ -229,7 +229,7 @@ Wichtige Modellierungsregeln:
|
|||||||
|
|
||||||
Empfohlene Rollen:
|
Empfohlene Rollen:
|
||||||
|
|
||||||
- `owner`: Kunde verwalten, Billing, Admins, Loeschung, Grundeinstellungen.
|
- `owner`: Kunde verwalten, Billing, Admins, Löschung, Grundeinstellungen.
|
||||||
- `admin`: Mitglieder, Hinweise, fachliche Einstellungen, Auswertungen.
|
- `admin`: Mitglieder, Hinweise, fachliche Einstellungen, Auswertungen.
|
||||||
- `treasurer`: Zahlungen, CSV-Import, Korrekturen, Exporte, Mails.
|
- `treasurer`: Zahlungen, CSV-Import, Korrekturen, Exporte, Mails.
|
||||||
- `member`: eigenes Dashboard, eigene Striche, eigener Anzeigename.
|
- `member`: eigenes Dashboard, eigene Striche, eigener Anzeigename.
|
||||||
@@ -246,22 +246,22 @@ SaaS-Basis:
|
|||||||
- E-Mail-Verifikation.
|
- E-Mail-Verifikation.
|
||||||
- Passwort-Reset.
|
- Passwort-Reset.
|
||||||
- Sichere Session-Cookies.
|
- Sichere Session-Cookies.
|
||||||
- CSRF-Schutz fuer alle schreibenden Aktionen.
|
- CSRF-Schutz für alle schreibenden Aktionen.
|
||||||
- Rate-Limits fuer Login, Registrierung und Passwort-Reset.
|
- Rate-Limits für Login, Registrierung und Passwort-Reset.
|
||||||
- Zentrale Funktionen oder Middleware: `requireLogin`, `requireTenant`,
|
- Zentrale Funktionen oder Middleware: `requireLogin`, `requireTenant`,
|
||||||
`requireRole`, `csrfToken`.
|
`requireRole`, `csrfToken`.
|
||||||
|
|
||||||
Tenant-Aufloesung:
|
Tenant-Auflösung:
|
||||||
|
|
||||||
- Primaer serverseitig aus Subdomain, Custom Domain oder tenantgebundener
|
- Primär serverseitig aus Subdomain, Custom Domain oder tenantgebundener
|
||||||
Auswahl nach Login.
|
Auswahl nach Login.
|
||||||
- Nicht allein aus Hidden Inputs oder frei manipulierbaren IDs.
|
- Nicht allein aus Hidden Inputs oder frei manipulierbaren IDs.
|
||||||
- Jede fachliche Query braucht einen Tenant-Scope.
|
- Jede fachliche Query braucht einen Tenant-Scope.
|
||||||
|
|
||||||
Spaeter moeglich:
|
Später möglich:
|
||||||
|
|
||||||
- LDAP/AD oder SSO pro Kunde als optionaler Identity Provider.
|
- LDAP/AD oder SSO pro Kunde als optionaler Identity Provider.
|
||||||
- MFA fuer Owner/Admins.
|
- MFA für Owner/Admins.
|
||||||
- Row-Level-Security in der Datenbank.
|
- Row-Level-Security in der Datenbank.
|
||||||
|
|
||||||
## Design-Leitplanken
|
## Design-Leitplanken
|
||||||
@@ -270,12 +270,12 @@ Das bestehende Design soll erhalten bleiben.
|
|||||||
|
|
||||||
Beibehalten:
|
Beibehalten:
|
||||||
|
|
||||||
- Gruener Akzent `#38761d`.
|
- Grüner Akzent `#38761d`.
|
||||||
- Weiss/Grau als ruhige Grundflaeche.
|
- Weiß/Grau als ruhige Grundfläche.
|
||||||
- Roboto Slab fuer Ueberschriften.
|
- Roboto Slab für Überschriften.
|
||||||
- Open Sans fuer Fliesstext.
|
- Open Sans für Fließtext.
|
||||||
- Sidebar fuer die geschuetzte App.
|
- Sidebar für die geschützte App.
|
||||||
- Tabellen als primaere Darstellung fuer operative Daten.
|
- Tabellen als primäre Darstellung für operative Daten.
|
||||||
- Schlichte Formularfelder und Buttons.
|
- Schlichte Formularfelder und Buttons.
|
||||||
|
|
||||||
Verbessern ohne Relaunch:
|
Verbessern ohne Relaunch:
|
||||||
@@ -283,38 +283,38 @@ Verbessern ohne Relaunch:
|
|||||||
- Hinweise als wiederverwendbare Komponente statt Inline-Style.
|
- Hinweise als wiederverwendbare Komponente statt Inline-Style.
|
||||||
- Einheitliche Erfolgs-, Fehler- und Warnmeldungen.
|
- Einheitliche Erfolgs-, Fehler- und Warnmeldungen.
|
||||||
- Dashboardwerte als kompakte Statusbereiche.
|
- Dashboardwerte als kompakte Statusbereiche.
|
||||||
- Aktionsleisten ueber Tabellen.
|
- Aktionsleisten über Tabellen.
|
||||||
- Sidebar-Gruppierung und aktive Navigation.
|
- Sidebar-Gruppierung und aktive Navigation.
|
||||||
- FAQ strukturieren, aber Inhalte nicht stark veraendern.
|
- FAQ strukturieren, aber Inhalte nicht stark verändern.
|
||||||
|
|
||||||
Nicht tun:
|
Nicht tun:
|
||||||
|
|
||||||
- Kein komplett neues Farbsystem.
|
- Kein komplett neues Farbsystem.
|
||||||
- Keine dekorative Marketingoptik in der App.
|
- Keine dekorative Marketingoptik in der App.
|
||||||
- Keine App-Tabellen in Kartenlandschaften aufloesen.
|
- Keine App-Tabellen in Kartenlandschaften auflösen.
|
||||||
- Keine Navigationsstruktur, die die heutigen Kernablaeufe versteckt.
|
- Keine Navigationsstruktur, die die heutigen Kernabläufe versteckt.
|
||||||
|
|
||||||
## Meilensteinplan
|
## Meilensteinplan
|
||||||
|
|
||||||
Uebersicht:
|
Übersicht:
|
||||||
|
|
||||||
| Meilenstein | Schwerpunkt | Hauptergebnis |
|
| Meilenstein | Schwerpunkt | Hauptergebnis |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| M0 | Baseline | Bestand, Sicherheit und Designreferenz sind dokumentiert |
|
| M0 | Baseline | Bestand, Sicherheit und Designreferenz sind dokumentiert |
|
||||||
| M1 | Golden Master | Legacy-Ergebnisse sind als Vergleichsbasis eingefroren; HTTP-Smoke prueft sichere Seiten |
|
| M1 | Golden Master | Legacy-Ergebnisse sind als Vergleichsbasis eingefroren; HTTP-Smoke prüft sichere Seiten |
|
||||||
| M2 | Technisches Fundament | Abgeschlossen: Migrationen, Bootstrap, Session, CSRF-Helper und Legacy-Schreibseitenschutz stehen |
|
| M2 | Technisches Fundament | Abgeschlossen: Migrationen, Bootstrap, Session, CSRF-Helper und Legacy-Schreibseitenschutz stehen |
|
||||||
| M3 | SaaS-Basis | Abgeschlossen: Tenants, User, Registrierung, Login, Rollen, Mail-Links und zentrale Mandantenauswahl funktionieren |
|
| M3 | SaaS-Basis | Abgeschlossen: Tenants, User, Registrierung, Login, Rollen, Mail-Links und zentrale Mandantenauswahl funktionieren |
|
||||||
| M4 | Datenmigration | Gestartet: Ledger-Tabelle, Legacy-Backfill, Paritaetscheck, Ledger-Service und Preview sind umgesetzt |
|
| M4 | Datenmigration | Gestartet: Ledger-Tabelle, Legacy-Backfill, Paritätscheck, Ledger-Service und Preview sind umgesetzt |
|
||||||
| M5 | App-Kern | Gestartet: Gesamtuebersicht liest read-only aus dem Ledger |
|
| M5 | App-Kern | Gestartet: Gesamtübersicht liest read-only aus dem Ledger |
|
||||||
| M6 | Betriebsflows | Import, Export, Mail und Jahresprozesse sind auditierbar |
|
| M6 | Betriebsflows | Import, Export, Mail und Jahresprozesse sind auditierbar |
|
||||||
| M7 | Landingpage | Public-Seite und Auth-Seiten sind im gemeinsamen Stil nutzbar; spaetere Ausbaustufen folgen |
|
| M7 | Landingpage | Public-Seite und Auth-Seiten sind im gemeinsamen Stil nutzbar; spätere Ausbaustufen folgen |
|
||||||
| M8 | Haertung | Betrieb, Datenschutz, Monitoring und Isolation sind geprueft |
|
| M8 | Härtung | Betrieb, Datenschutz, Monitoring und Isolation sind geprüft |
|
||||||
| M9 | Cutover | Produktivumstellung ist vorbereitet und Legacy ist read-only |
|
| M9 | Cutover | Produktivumstellung ist vorbereitet und Legacy ist read-only |
|
||||||
|
|
||||||
### M0: Planungs- und Sicherheitsbaseline
|
### M0: Planungs- und Sicherheitsbaseline
|
||||||
|
|
||||||
Ziel:
|
Ziel:
|
||||||
Den aktuellen Zustand verlaesslich dokumentieren, bevor umgebaut wird.
|
Den aktuellen Zustand verlässlich dokumentieren, bevor umgebaut wird.
|
||||||
|
|
||||||
Arbeitsartefakte:
|
Arbeitsartefakte:
|
||||||
|
|
||||||
@@ -331,7 +331,7 @@ Schritte:
|
|||||||
- Tabellen, Spalten, Indizes und Constraints dokumentieren.
|
- Tabellen, Spalten, Indizes und Constraints dokumentieren.
|
||||||
- Bekannte Jobs/Skripte erfassen, zum Beispiel Mailversand und Jahresauswertung.
|
- Bekannte Jobs/Skripte erfassen, zum Beispiel Mailversand und Jahresauswertung.
|
||||||
- Secrets inventarisieren und rotieren, insbesondere hart codierte Zugangsdaten.
|
- Secrets inventarisieren und rotieren, insbesondere hart codierte Zugangsdaten.
|
||||||
- Bestehende Seiten und UI-Zustaende per Screenshots festhalten.
|
- Bestehende Seiten und UI-Zustände per Screenshots festhalten.
|
||||||
- Fachliche Kernregeln dokumentieren: Saldo, Jahreswerte, Preis pro Strich,
|
- Fachliche Kernregeln dokumentieren: Saldo, Jahreswerte, Preis pro Strich,
|
||||||
100-Tage-Listen, CSV-Deduplizierung, PDF-Ausgabe.
|
100-Tage-Listen, CSV-Deduplizierung, PDF-Ausgabe.
|
||||||
|
|
||||||
@@ -342,7 +342,7 @@ Ergebnis:
|
|||||||
- Designreferenz.
|
- Designreferenz.
|
||||||
- Liste kritischer Sicherheitsrisiken.
|
- Liste kritischer Sicherheitsrisiken.
|
||||||
|
|
||||||
Abhaengigkeiten:
|
Abhängigkeiten:
|
||||||
|
|
||||||
- Zugriff auf echte oder anonymisierte Datenbank.
|
- Zugriff auf echte oder anonymisierte Datenbank.
|
||||||
- Kenntnis der Produktivumgebung.
|
- Kenntnis der Produktivumgebung.
|
||||||
@@ -350,7 +350,7 @@ Abhaengigkeiten:
|
|||||||
### M1: Golden-Master-Validierung
|
### M1: Golden-Master-Validierung
|
||||||
|
|
||||||
Ziel:
|
Ziel:
|
||||||
Sicherstellen, dass spaetere neue Berechnungen dieselben Ergebnisse wie der
|
Sicherstellen, dass spätere neue Berechnungen dieselben Ergebnisse wie der
|
||||||
Bestand liefern.
|
Bestand liefern.
|
||||||
|
|
||||||
Schritte:
|
Schritte:
|
||||||
@@ -359,42 +359,42 @@ Schritte:
|
|||||||
Master in der MySQL-Dev-Datenbank.
|
Master in der MySQL-Dev-Datenbank.
|
||||||
- Pro Mitglied berechnen: Gesamteinzahlungen, Gesamtausgaben, Gesamtstriche,
|
- Pro Mitglied berechnen: Gesamteinzahlungen, Gesamtausgaben, Gesamtstriche,
|
||||||
aktueller Stand, Jahreswerte. Erledigt mit `scripts/check-golden-master.php`.
|
aktueller Stand, Jahreswerte. Erledigt mit `scripts/check-golden-master.php`.
|
||||||
- CSV-Importfaelle sammeln: Treffer, Dubletten, unbekannte Namen. Erledigt im
|
- CSV-Importfälle sammeln: Treffer, Dubletten, unbekannte Namen. Erledigt im
|
||||||
Golden-Master-Check.
|
Golden-Master-Check.
|
||||||
- Testfaelle fuer Guthaben, Schulden, Nullsaldo und inaktive Teilnehmer
|
- Testfälle für Guthaben, Schulden, Nullsaldo und inaktive Teilnehmer
|
||||||
anlegen. Erledigt.
|
anlegen. Erledigt.
|
||||||
- Sichere GET-Seiten per HTTP-Smoke pruefen. Erledigt mit
|
- Sichere GET-Seiten per HTTP-Smoke prüfen. Erledigt mit
|
||||||
`scripts/http-smoke.php`.
|
`scripts/http-smoke.php`.
|
||||||
- PDF-/Export-Summen als Referenz sichern. Offen, weil die TCPDF-Kopie im Repo
|
- PDF-/Export-Summen als Referenz sichern. Offen, weil die TCPDF-Kopie im Repo
|
||||||
unvollstaendig ist.
|
unvollständig ist.
|
||||||
|
|
||||||
Ergebnis:
|
Ergebnis:
|
||||||
|
|
||||||
- Golden-Master-Daten.
|
- Golden-Master-Daten.
|
||||||
- Vergleichsqueries oder Vergleichsskript.
|
- Vergleichsqueries oder Vergleichsskript.
|
||||||
- HTTP-Smoke-Test fuer sichere UI-Seiten.
|
- HTTP-Smoke-Test für sichere UI-Seiten.
|
||||||
- Akzeptanzkriterien fuer Migration und neue App.
|
- Akzeptanzkriterien für Migration und neue App.
|
||||||
- Dokumentierte offene Punkte: PDF-Export/TCPDF, PHPMailer-Abhaengigkeit,
|
- Dokumentierte offene Punkte: PDF-Export/TCPDF, PHPMailer-Abhängigkeit,
|
||||||
GET-Nebenwirkungen bei Mailversand und Jahresauswertung.
|
GET-Nebenwirkungen bei Mailversand und Jahresauswertung.
|
||||||
|
|
||||||
Abhaengigkeiten:
|
Abhängigkeiten:
|
||||||
|
|
||||||
- M0 abgeschlossen.
|
- M0 abgeschlossen.
|
||||||
- PDF-/Mail-/Jahresprozesse werden in M6 gezielt neu gestaltet, statt sie in M1
|
- PDF-/Mail-/Jahresprozesse werden in M6 gezielt neu gestaltet, statt sie in M1
|
||||||
per GET-Smoke auszufuehren.
|
per GET-Smoke auszuführen.
|
||||||
|
|
||||||
### M2: Technisches Fundament
|
### M2: Technisches Fundament
|
||||||
|
|
||||||
Ziel:
|
Ziel:
|
||||||
Eine saubere Basis fuer App, Public-Seiten, Auth und Mandanten schaffen.
|
Eine saubere Basis für App, Public-Seiten, Auth und Mandanten schaffen.
|
||||||
|
|
||||||
Schritte:
|
Schritte:
|
||||||
|
|
||||||
- Projektstruktur festlegen: Public-Routes, App-Routes, Views/Templates,
|
- Projektstruktur festlegen: Public-Routes, App-Routes, Views/Templates,
|
||||||
Services/Repositories.
|
Services/Repositories.
|
||||||
- Zentrales Bootstrap fuer Config, DB-Verbindung, Session und Fehlerbehandlung.
|
- Zentrales Bootstrap für Config, DB-Verbindung, Session und Fehlerbehandlung.
|
||||||
Begonnen mit `app/bootstrap.php`.
|
Begonnen mit `app/bootstrap.php`.
|
||||||
- Versionierte Migrationen einfuehren. Begonnen mit
|
- Versionierte Migrationen einführen. Begonnen mit
|
||||||
`database/migrations/0001_legacy_mysql_baseline.sql` und
|
`database/migrations/0001_legacy_mysql_baseline.sql` und
|
||||||
`scripts/migrate.php`.
|
`scripts/migrate.php`.
|
||||||
- Layouts trennen: Public-Layout und App-Layout. Noch offen; Header/Footer
|
- Layouts trennen: Public-Layout und App-Layout. Noch offen; Header/Footer
|
||||||
@@ -405,36 +405,36 @@ Schritte:
|
|||||||
abgesichert: `hinweise.php`, `mitarbeiterverwalten.php`,
|
abgesichert: `hinweise.php`, `mitarbeiterverwalten.php`,
|
||||||
`namenanpassen.php`, `index.php`, `stricheintragen.php`, `einzahlung.php`,
|
`namenanpassen.php`, `index.php`, `stricheintragen.php`, `einzahlung.php`,
|
||||||
`letzteneintraege.php`, `csvupload.php`.
|
`letzteneintraege.php`, `csvupload.php`.
|
||||||
- CSV-Upload ausserhalb des Webroots speichern. In M2 als Legacy-Haertung
|
- CSV-Upload außerhalb des Webroots speichern. In M2 als Legacy-Härtung
|
||||||
umgesetzt: temporaer unter `var/uploads`, Dateityp-/Groessenpruefung und
|
umgesetzt: temporär unter `var/uploads`, Dateityp-/Größenprüfung und
|
||||||
Loeschung nach Verarbeitung.
|
Löschung nach Verarbeitung.
|
||||||
- Konfigurationswerte aus Code in Umgebung oder Settings verschieben.
|
- Konfigurationswerte aus Code in Umgebung oder Settings verschieben.
|
||||||
|
|
||||||
Ergebnis:
|
Ergebnis:
|
||||||
|
|
||||||
- Grundgeruest fuer neue SaaS-App.
|
- Grundgerüst für neue SaaS-App.
|
||||||
- Kein fachlicher Rewrite, aber klare Struktur fuer die Migration.
|
- Kein fachlicher Rewrite, aber klare Struktur für die Migration.
|
||||||
- Dokumentation: `docs/m2-technical-foundation.md`.
|
- Dokumentation: `docs/m2-technical-foundation.md`.
|
||||||
- Status: abgeschlossen fuer den M2-Scope.
|
- Status: abgeschlossen für den M2-Scope.
|
||||||
|
|
||||||
Abhaengigkeiten:
|
Abhängigkeiten:
|
||||||
|
|
||||||
- Entscheidung, ob PHP nativ weitergefuehrt oder ein Framework genutzt wird.
|
- Entscheidung, ob PHP nativ weitergeführt oder ein Framework genutzt wird.
|
||||||
- M2 bleibt bewusst ohne Tenant-/User-/Rollen-Tabellen; diese starten in M3.
|
- M2 bleibt bewusst ohne Tenant-/User-/Rollen-Tabellen; diese starten in M3.
|
||||||
|
|
||||||
### M3: Mandanten, Registrierung und Login
|
### M3: Mandanten, Registrierung und Login
|
||||||
|
|
||||||
Ziel:
|
Ziel:
|
||||||
Mehrkundenfaehigkeit und Kunden-Onboarding technisch aktivieren.
|
Mehrkundenfähigkeit und Kunden-Onboarding technisch aktivieren.
|
||||||
|
|
||||||
Schritte:
|
Schritte:
|
||||||
|
|
||||||
- Tabellen fuer `tenants`, `users`, `tenant_memberships` und
|
- Tabellen für `tenants`, `users`, `tenant_memberships` und
|
||||||
`tenant_settings` anlegen. Vorbereitung dokumentiert in
|
`tenant_settings` anlegen. Vorbereitung dokumentiert in
|
||||||
`docs/m3-saas-basis-vorbereitung.md`: erster Schritt erledigt.
|
`docs/m3-saas-basis-vorbereitung.md`: erster Schritt erledigt.
|
||||||
- Zusaetzlich `participants` als getrennte Kaffee-Teilnehmer-Tabelle anlegen:
|
- Zusätzlich `participants` als getrennte Kaffee-Teilnehmer-Tabelle anlegen:
|
||||||
erledigt.
|
erledigt.
|
||||||
- Default-Tenant fuer den aktuellen Bestand anlegen: erledigt.
|
- Default-Tenant für den aktuellen Bestand anlegen: erledigt.
|
||||||
- Bestehende `kl_Mitarbeiter` idempotent in `participants` spiegeln:
|
- Bestehende `kl_Mitarbeiter` idempotent in `participants` spiegeln:
|
||||||
erledigt.
|
erledigt.
|
||||||
- Registrierung: Tenant + Owner-User + Default-Settings erzeugen: erster
|
- Registrierung: Tenant + Owner-User + Default-Settings erzeugen: erster
|
||||||
@@ -442,10 +442,10 @@ Schritte:
|
|||||||
- Login und Logout bauen: erster Flow erledigt.
|
- Login und Logout bauen: erster Flow erledigt.
|
||||||
- Passwort-Reset und E-Mail-Verifikation bauen: Dev-Flow mit Single-Use-Tokens
|
- Passwort-Reset und E-Mail-Verifikation bauen: Dev-Flow mit Single-Use-Tokens
|
||||||
und Mail-Transport-Abstraktion erledigt.
|
und Mail-Transport-Abstraktion erledigt.
|
||||||
- Tenant-Aufloesung definieren: zentrale App-Domain mit Session-Kontext und
|
- Tenant-Auflösung definieren: zentrale App-Domain mit Session-Kontext und
|
||||||
Mandantenauswahl erledigt; feste Domains vorbereitet, keine Wildcards.
|
Mandantenauswahl erledigt; feste Domains vorbereitet, keine Wildcards.
|
||||||
- Rollenpruefung zentralisieren: erster Owner/Admin-Check erledigt.
|
- Rollenprüfung zentralisieren: erster Owner/Admin-Check erledigt.
|
||||||
- Erste Admin-/Owner-Seite fuer Grundeinstellungen: erledigt.
|
- Erste Admin-/Owner-Seite für Grundeinstellungen: erledigt.
|
||||||
- Erste Public-Landingpage mit CTA zu Login und Registrierung: erledigt.
|
- Erste Public-Landingpage mit CTA zu Login und Registrierung: erledigt.
|
||||||
- Login, Registrierung, Passwort-Reset und E-Mail-Verifikation im Public-Stil:
|
- Login, Registrierung, Passwort-Reset und E-Mail-Verifikation im Public-Stil:
|
||||||
erledigt.
|
erledigt.
|
||||||
@@ -454,51 +454,51 @@ Schritte:
|
|||||||
Ergebnis:
|
Ergebnis:
|
||||||
|
|
||||||
- Ein neuer Kunde kann sich registrieren und in seine eigene App gelangen.
|
- Ein neuer Kunde kann sich registrieren und in seine eigene App gelangen.
|
||||||
- Rollen und Tenant-Kontext sind serverseitig verfuegbar.
|
- Rollen und Tenant-Kontext sind serverseitig verfügbar.
|
||||||
- Reset- und Verifikationslinks koennen im Dev-Modus geloggt und produktiv ueber
|
- Reset- und Verifikationslinks können im Dev-Modus geloggt und produktiv über
|
||||||
einen konfigurierten Mail-Transport versendet werden.
|
einen konfigurierten Mail-Transport versendet werden.
|
||||||
- Status: abgeschlossen fuer den M3-Scope.
|
- Status: abgeschlossen für den M3-Scope.
|
||||||
|
|
||||||
Abhaengigkeiten:
|
Abhängigkeiten:
|
||||||
|
|
||||||
- M2 abgeschlossen.
|
- M2 abgeschlossen.
|
||||||
|
|
||||||
### M4: Migration des fachlichen Kerns
|
### M4: Migration des fachlichen Kerns
|
||||||
|
|
||||||
Ziel:
|
Ziel:
|
||||||
Bestehende Kaffeelisten-Daten tenant-sicher uebernehmen.
|
Bestehende Kaffeelisten-Daten tenant-sicher übernehmen.
|
||||||
|
|
||||||
Schritte:
|
Schritte:
|
||||||
|
|
||||||
- Initialen Tenant fuer den bisherigen Bestand anlegen: erledigt in M3.
|
- Initialen Tenant für den bisherigen Bestand anlegen: erledigt in M3.
|
||||||
- `kl_Mitarbeiter` nach `participants` migrieren: erledigt in M3.
|
- `kl_Mitarbeiter` nach `participants` migrieren: erledigt in M3.
|
||||||
- `admin`-Informationen in `tenant_memberships` oder Admin-Rollen ueberfuehren:
|
- `admin`-Informationen in `tenant_memberships` oder Admin-Rollen überführen:
|
||||||
erledigt in M3.
|
erledigt in M3.
|
||||||
- `kl_config` nach `tenant_settings` migrieren: erledigt in M3.
|
- `kl_config` nach `tenant_settings` migrieren: erledigt in M3.
|
||||||
- `ledger_entries` als tenant-sichere Buchungstabelle anlegen: erledigt.
|
- `ledger_entries` als tenant-sichere Buchungstabelle anlegen: erledigt.
|
||||||
- `kl_Einzahlungen` und `kl_Kaffeeverbrauch` additiv nach `ledger_entries`
|
- `kl_Einzahlungen` und `kl_Kaffeeverbrauch` additiv nach `ledger_entries`
|
||||||
spiegeln: erster Backfill erledigt.
|
spiegeln: erster Backfill erledigt.
|
||||||
- Legacy-IDs speichern: erledigt ueber `legacy_table` und `legacy_id`.
|
- Legacy-IDs speichern: erledigt über `legacy_table` und `legacy_id`.
|
||||||
- Salden gegen Golden-Master vergleichen: Kontrollskript erledigt.
|
- Salden gegen Golden-Master vergleichen: Kontrollskript erledigt.
|
||||||
- Ledger-Service fuer Tenant-Summen, Teilnehmer-Summen und letzte Buchungen:
|
- Ledger-Service für Tenant-Summen, Teilnehmer-Summen und letzte Buchungen:
|
||||||
erledigt.
|
erledigt.
|
||||||
- Read-only Ledger-Preview fuer Browservergleich: erledigt.
|
- Read-only Ledger-Preview für Browservergleich: erledigt.
|
||||||
|
|
||||||
Ergebnis:
|
Ergebnis:
|
||||||
|
|
||||||
- Bestehender Datenbestand kann im neuen Modell abgebildet werden.
|
- Bestehender Datenbestand kann im neuen Modell abgebildet werden.
|
||||||
- Saldenparitaet ist ueber `scripts/check-m4-ledger-migration.php`
|
- Saldenparität ist über `scripts/check-m4-ledger-migration.php`
|
||||||
nachweisbar.
|
nachweisbar.
|
||||||
- Erste App-Abfragen koennen ueber `app/ledger.php` tenant-sicher aus dem neuen
|
- Erste App-Abfragen können über `app/ledger.php` tenant-sicher aus dem neuen
|
||||||
Modell lesen.
|
Modell lesen.
|
||||||
- `ledger-preview.php` zeigt die neue Ledger-Auswertung ohne Schreibzugriffe.
|
- `ledger-preview.php` zeigt die neue Ledger-Auswertung ohne Schreibzugriffe.
|
||||||
- Dokumentation: `docs/m4-data-migration.md`.
|
- Dokumentation: `docs/m4-data-migration.md`.
|
||||||
|
|
||||||
Abhaengigkeiten:
|
Abhängigkeiten:
|
||||||
|
|
||||||
- M1 und M3 abgeschlossen.
|
- M1 und M3 abgeschlossen.
|
||||||
|
|
||||||
### M5: Geschuetzte App-Funktionen
|
### M5: Geschützte App-Funktionen
|
||||||
|
|
||||||
Ziel:
|
Ziel:
|
||||||
Die operativen Kernseiten im neuen Modell bereitstellen.
|
Die operativen Kernseiten im neuen Modell bereitstellen.
|
||||||
@@ -509,9 +509,9 @@ Schritte:
|
|||||||
- Eigene Stricherfassung umsetzen.
|
- Eigene Stricherfassung umsetzen.
|
||||||
- Zahlungs-/PayPal-Bereich umsetzen.
|
- Zahlungs-/PayPal-Bereich umsetzen.
|
||||||
- Mitgliederverwaltung tenant- und rollenbasiert umsetzen.
|
- Mitgliederverwaltung tenant- und rollenbasiert umsetzen.
|
||||||
- Gesamtuebersicht umsetzen: erster read-only Stand in `kaffeeliste.php`
|
- Gesamtübersicht umsetzen: erster read-only Stand in `kaffeeliste.php`
|
||||||
erledigt.
|
erledigt.
|
||||||
- Letzte Eintraege und Korrekturen als Storno statt Delete umsetzen.
|
- Letzte Einträge und Korrekturen als Storno statt Delete umsetzen.
|
||||||
- Hinweise als tenant-spezifische Notices umsetzen.
|
- Hinweise als tenant-spezifische Notices umsetzen.
|
||||||
|
|
||||||
Ergebnis:
|
Ergebnis:
|
||||||
@@ -520,7 +520,7 @@ Ergebnis:
|
|||||||
- App sieht weiterhin nach bestehender Kaffeeliste aus.
|
- App sieht weiterhin nach bestehender Kaffeeliste aus.
|
||||||
- Erster M5-Stand ist in `docs/m5-app-kern.md` dokumentiert.
|
- Erster M5-Stand ist in `docs/m5-app-kern.md` dokumentiert.
|
||||||
|
|
||||||
Abhaengigkeiten:
|
Abhängigkeiten:
|
||||||
|
|
||||||
- M4 abgeschlossen.
|
- M4 abgeschlossen.
|
||||||
|
|
||||||
@@ -531,8 +531,8 @@ Admin- und Treasurer-Flows produktionsreif machen.
|
|||||||
|
|
||||||
Schritte:
|
Schritte:
|
||||||
|
|
||||||
- CSV-Import mit Vorschau, Dublettenpruefung und Audit bauen.
|
- CSV-Import mit Vorschau, Dublettenprüfung und Audit bauen.
|
||||||
- Uploads ausserhalb des Webroots speichern.
|
- Uploads außerhalb des Webroots speichern.
|
||||||
- PDF-/Listenexport aus neuem Datenmodell bauen.
|
- PDF-/Listenexport aus neuem Datenmodell bauen.
|
||||||
- Mailversand als nachvollziehbaren Versandjob mit Dry-Run und Versandlog
|
- Mailversand als nachvollziehbaren Versandjob mit Dry-Run und Versandlog
|
||||||
gestalten.
|
gestalten.
|
||||||
@@ -540,22 +540,22 @@ Schritte:
|
|||||||
|
|
||||||
Ergebnis:
|
Ergebnis:
|
||||||
|
|
||||||
- Kassenverwaltung ist fuer reale Betriebsablaeufe vollstaendig.
|
- Kassenverwaltung ist für reale Betriebsabläufe vollständig.
|
||||||
- Import/Export/Mail sind auditierbar.
|
- Import/Export/Mail sind auditierbar.
|
||||||
|
|
||||||
Abhaengigkeiten:
|
Abhängigkeiten:
|
||||||
|
|
||||||
- M5 fuer die Kernansichten.
|
- M5 für die Kernansichten.
|
||||||
|
|
||||||
### M7: Oeffentliche Landingpage
|
### M7: Öffentliche Landingpage
|
||||||
|
|
||||||
Ziel:
|
Ziel:
|
||||||
Werbliche Einstiegseite und Registrierung verfuegbar machen, ohne die App-Optik
|
Werbliche Einstiegseite und Registrierung verfügbar machen, ohne die App-Optik
|
||||||
zu verwischen.
|
zu verwischen.
|
||||||
|
|
||||||
Schritte:
|
Schritte:
|
||||||
|
|
||||||
- Public-Layout mit bestehender Typografie und gruenem Akzent bauen. Erster
|
- Public-Layout mit bestehender Typografie und grünem Akzent bauen. Erster
|
||||||
Stand als `landing.php` und `assets/css/public.css` erledigt.
|
Stand als `landing.php` und `assets/css/public.css` erledigt.
|
||||||
- Landingpage-Inhalte erstellen. Erster Stand erledigt.
|
- Landingpage-Inhalte erstellen. Erster Stand erledigt.
|
||||||
- Demo-Screenshot oder Demo-Ansicht einbinden.
|
- Demo-Screenshot oder Demo-Ansicht einbinden.
|
||||||
@@ -568,26 +568,26 @@ Schritte:
|
|||||||
|
|
||||||
Ergebnis:
|
Ergebnis:
|
||||||
|
|
||||||
- Interessenten verstehen das Produkt und koennen sich registrieren.
|
- Interessenten verstehen das Produkt und können sich registrieren.
|
||||||
- Bestehende App bleibt optisch eigenstaendig und arbeitsorientiert.
|
- Bestehende App bleibt optisch eigenständig und arbeitsorientiert.
|
||||||
|
|
||||||
Abhaengigkeiten:
|
Abhängigkeiten:
|
||||||
|
|
||||||
- M3 fuer Registrierung.
|
- M3 für Registrierung.
|
||||||
- M5 fuer echte App-Screens oder Demo.
|
- M5 für echte App-Screens oder Demo.
|
||||||
|
|
||||||
### M8: Haertung, Datenschutz und Betrieb
|
### M8: Härtung, Datenschutz und Betrieb
|
||||||
|
|
||||||
Ziel:
|
Ziel:
|
||||||
Die SaaS-App fuer mehrere Kunden sicher betreiben.
|
Die SaaS-App für mehrere Kunden sicher betreiben.
|
||||||
|
|
||||||
Schritte:
|
Schritte:
|
||||||
|
|
||||||
- Backups und Restore-Prozess definieren.
|
- Backups und Restore-Prozess definieren.
|
||||||
- Monitoring und Fehlerlogging einrichten.
|
- Monitoring und Fehlerlogging einrichten.
|
||||||
- Audit-Log fuer Admin-Aktionen pruefen.
|
- Audit-Log für Admin-Aktionen prüfen.
|
||||||
- Datenexport pro Tenant.
|
- Datenexport pro Tenant.
|
||||||
- Loesch-/Anonymisierungsprozess fuer Teilnehmer und Kunden.
|
- Lösch-/Anonymisierungsprozess für Teilnehmer und Kunden.
|
||||||
- Rate-Limits und Security Headers.
|
- Rate-Limits und Security Headers.
|
||||||
- Mandanten-Isolation testen.
|
- Mandanten-Isolation testen.
|
||||||
- Rollenmatrix testen.
|
- Rollenmatrix testen.
|
||||||
@@ -596,7 +596,7 @@ Ergebnis:
|
|||||||
|
|
||||||
- SaaS ist betrieblich und datenschutzseitig belastbarer.
|
- SaaS ist betrieblich und datenschutzseitig belastbarer.
|
||||||
|
|
||||||
Abhaengigkeiten:
|
Abhängigkeiten:
|
||||||
|
|
||||||
- M3 bis M6.
|
- M3 bis M6.
|
||||||
|
|
||||||
@@ -607,10 +607,10 @@ Produktive Umstellung ohne Datenverlust.
|
|||||||
|
|
||||||
Schritte:
|
Schritte:
|
||||||
|
|
||||||
- Legacy fuer Schreibzugriffe sperren.
|
- Legacy für Schreibzugriffe sperren.
|
||||||
- Finalen Delta-Export ziehen.
|
- Finalen Delta-Export ziehen.
|
||||||
- Migration ausfuehren.
|
- Migration ausführen.
|
||||||
- Rowcounts, Salden, PDF-Stichproben und Importhistorie pruefen.
|
- Rowcounts, Salden, PDF-Stichproben und Importhistorie prüfen.
|
||||||
- DNS oder Reverse Proxy umschalten.
|
- DNS oder Reverse Proxy umschalten.
|
||||||
- Legacy 30 bis 90 Tage read-only als Archiv behalten.
|
- Legacy 30 bis 90 Tage read-only als Archiv behalten.
|
||||||
- Rollback-Fenster und Vorgehen dokumentieren.
|
- Rollback-Fenster und Vorgehen dokumentieren.
|
||||||
@@ -618,15 +618,15 @@ Schritte:
|
|||||||
Ergebnis:
|
Ergebnis:
|
||||||
|
|
||||||
- Neuer SaaS-Betrieb ist live.
|
- Neuer SaaS-Betrieb ist live.
|
||||||
- Alter Bestand bleibt fuer Rueckfragen lesbar.
|
- Alter Bestand bleibt für Rückfragen lesbar.
|
||||||
|
|
||||||
Abhaengigkeiten:
|
Abhängigkeiten:
|
||||||
|
|
||||||
- M8 abgeschlossen.
|
- M8 abgeschlossen.
|
||||||
|
|
||||||
## Empfohlene MVP-Reihenfolge
|
## Empfohlene MVP-Reihenfolge
|
||||||
|
|
||||||
Fuer den ersten produktnahen MVP sollten nicht alle Randmodule gleichzeitig
|
Für den ersten produktnahen MVP sollten nicht alle Randmodule gleichzeitig
|
||||||
umgebaut werden.
|
umgebaut werden.
|
||||||
|
|
||||||
MVP-Paket:
|
MVP-Paket:
|
||||||
@@ -634,12 +634,12 @@ MVP-Paket:
|
|||||||
1. Tenant, User, Login, Registrierung.
|
1. Tenant, User, Login, Registrierung.
|
||||||
2. Mail-Links, zentrale Mandantenauswahl und erste Landingpage.
|
2. Mail-Links, zentrale Mandantenauswahl und erste Landingpage.
|
||||||
3. Teilnehmer, Settings, Ledger.
|
3. Teilnehmer, Settings, Ledger.
|
||||||
4. Dashboard, Striche, Einzahlungen, Gesamtuebersicht.
|
4. Dashboard, Striche, Einzahlungen, Gesamtübersicht.
|
||||||
5. Mitgliederverwaltung.
|
5. Mitgliederverwaltung.
|
||||||
6. Hinweise.
|
6. Hinweise.
|
||||||
7. CSV-Import, Export.
|
7. CSV-Import, Export.
|
||||||
|
|
||||||
Spaeter:
|
Später:
|
||||||
|
|
||||||
- Umfrage-Modul.
|
- Umfrage-Modul.
|
||||||
- SSO/LDAP pro Kunde.
|
- SSO/LDAP pro Kunde.
|
||||||
@@ -650,7 +650,7 @@ Spaeter:
|
|||||||
|
|
||||||
## Validierung
|
## Validierung
|
||||||
|
|
||||||
Fachliche Pruefungen:
|
Fachliche Prüfungen:
|
||||||
|
|
||||||
- Saldo je Teilnehmer alt gegen neu.
|
- Saldo je Teilnehmer alt gegen neu.
|
||||||
- Jahreswerte alt gegen neu.
|
- Jahreswerte alt gegen neu.
|
||||||
@@ -659,37 +659,37 @@ Fachliche Pruefungen:
|
|||||||
- Export-Summen alt gegen neu.
|
- Export-Summen alt gegen neu.
|
||||||
- CSV-Import: identische Treffer- und Dublettenlogik.
|
- CSV-Import: identische Treffer- und Dublettenlogik.
|
||||||
|
|
||||||
Sicherheitspruefungen:
|
Sicherheitsprüfungen:
|
||||||
|
|
||||||
- Fremde Tenant-IDs liefern keine Daten.
|
- Fremde Tenant-IDs liefern keine Daten.
|
||||||
- Fremde Teilnehmer-IDs liefern keine Daten.
|
- Fremde Teilnehmer-IDs liefern keine Daten.
|
||||||
- Admin-Funktionen sind ohne Rolle blockiert.
|
- Admin-Funktionen sind ohne Rolle blockiert.
|
||||||
- Alle POST-Aktionen brauchen CSRF.
|
- Alle POST-Aktionen brauchen CSRF.
|
||||||
- Uploads sind nicht direkt ausfuehrbar.
|
- Uploads sind nicht direkt ausführbar.
|
||||||
- Ausgabe von Namen, Mails und Hinweisen ist escaped.
|
- Ausgabe von Namen, Mails und Hinweisen ist escaped.
|
||||||
|
|
||||||
UX-Pruefungen:
|
UX-Prüfungen:
|
||||||
|
|
||||||
- Kernseiten bleiben optisch wiedererkennbar.
|
- Kernseiten bleiben optisch wiedererkennbar.
|
||||||
- Sidebar bleibt fuer App-Nutzer vertraut.
|
- Sidebar bleibt für App-Nutzer vertraut.
|
||||||
- Landingpage zeigt keine App-Adminnavigation.
|
- Landingpage zeigt keine App-Adminnavigation.
|
||||||
- Mobile Darstellung bleibt bedienbar.
|
- Mobile Darstellung bleibt bedienbar.
|
||||||
- Tabellen bleiben lesbar.
|
- Tabellen bleiben lesbar.
|
||||||
|
|
||||||
## Risiken und Gegenmassnahmen
|
## Risiken und Gegenmaßnahmen
|
||||||
|
|
||||||
| Risiko | Gegenmassnahme |
|
| Risiko | Gegenmaßnahme |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Tenant-Leak durch vergessene Query-Filter | Zentrale Repository-/Query-Schicht, Tests mit zwei Tenants |
|
| Tenant-Leak durch vergessene Query-Filter | Zentrale Repository-/Query-Schicht, Tests mit zwei Tenants |
|
||||||
| Falsche Salden nach Migration | Golden-Master-Vergleich vor Cutover |
|
| Falsche Salden nach Migration | Golden-Master-Vergleich vor Cutover |
|
||||||
| Harte Deletes verlieren Audit-Historie | Storno-/Reversal-Modell fuer Buchungen |
|
| Harte Deletes verlieren Audit-Historie | Storno-/Reversal-Modell für Buchungen |
|
||||||
| Login und Teilnehmer werden vermischt | `users` und `participants` strikt trennen |
|
| Login und Teilnehmer werden vermischt | `users` und `participants` strikt trennen |
|
||||||
| Bestehendes Design driftet weg | Designreferenz und App-Komponenten definieren |
|
| Bestehendes Design driftet weg | Designreferenz und App-Komponenten definieren |
|
||||||
| CSV-Upload unsicher | Upload ausserhalb Webroot, Dateityppruefung, Importvorschau |
|
| CSV-Upload unsicher | Upload außerhalb Webroot, Dateitypprüfung, Importvorschau |
|
||||||
| Mailversand nicht nachvollziehbar | Versandlog, Dry-Run, Job-Status |
|
| Mailversand nicht nachvollziehbar | Versandlog, Dry-Run, Job-Status |
|
||||||
| Unvollstaendige Vendor-Kopien fuer PDF/Mail | Dependencies sauber vendoren oder ersetzen, Smoke-Tests danach erweitern |
|
| Unvollständige Vendor-Kopien für PDF/Mail | Dependencies sauber vendoren oder ersetzen, Smoke-Tests danach erweitern |
|
||||||
| AD/LDAP blockiert SaaS-Onboarding | E-Mail/Passwort als Basis, SSO spaeter optional |
|
| AD/LDAP blockiert SaaS-Onboarding | E-Mail/Passwort als Basis, SSO später optional |
|
||||||
| Kein DB-Schema im Repo | Schema exportieren und Migrationen einfuehren |
|
| Kein DB-Schema im Repo | Schema exportieren und Migrationen einführen |
|
||||||
|
|
||||||
## Offene Entscheidungen
|
## Offene Entscheidungen
|
||||||
|
|
||||||
@@ -703,9 +703,9 @@ UX-Pruefungen:
|
|||||||
- Braucht der MVP schon Tarife/Billing oder erstmal nur Registrierung?
|
- Braucht der MVP schon Tarife/Billing oder erstmal nur Registrierung?
|
||||||
- Sollen bestehende Kunden per Einladung oder per Self-Service onboarden?
|
- Sollen bestehende Kunden per Einladung oder per Self-Service onboarden?
|
||||||
|
|
||||||
## Naechster konkreter Arbeitsschritt
|
## Nächster konkreter Arbeitsschritt
|
||||||
|
|
||||||
Als naechstes sollte M0 gestartet werden:
|
Als nächstes sollte M0 gestartet werden:
|
||||||
|
|
||||||
1. Produktiv-/Testdatenbankschema exportieren.
|
1. Produktiv-/Testdatenbankschema exportieren.
|
||||||
2. Screenshot-Referenz der wichtigsten Seiten erstellen.
|
2. Screenshot-Referenz der wichtigsten Seiten erstellen.
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
|
|
||||||
if ($result['ok']) {
|
if ($result['ok']) {
|
||||||
if (!empty($result['already_verified'])) {
|
if (!empty($result['already_verified'])) {
|
||||||
$message = 'Die E-Mail-Adresse ist bereits bestaetigt.';
|
$message = 'Die E-Mail-Adresse ist bereits bestätigt.';
|
||||||
} else {
|
} else {
|
||||||
$message = 'Der Verifizierungslink wurde vorbereitet.';
|
$message = 'Der Verifizierungslink wurde vorbereitet.';
|
||||||
if (saas_should_show_auth_links() && !empty($result['token'])) {
|
if (saas_should_show_auth_links() && !empty($result['token'])) {
|
||||||
@@ -61,7 +61,7 @@ include 'nav.php';
|
|||||||
<p><?php echo saas_html($user['email']); ?></p>
|
<p><?php echo saas_html($user['email']); ?></p>
|
||||||
<ul class="actions">
|
<ul class="actions">
|
||||||
<li><button type="submit">Verifizierungslink vorbereiten</button></li>
|
<li><button type="submit">Verifizierungslink vorbereiten</button></li>
|
||||||
<li><a href="konto.php" class="button alt">Zurueck</a></li>
|
<li><a href="konto.php" class="button alt">Zurück</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ $pdo = app_db_pdo();
|
|||||||
$token = trim((string)($_GET['token'] ?? ''));
|
$token = trim((string)($_GET['token'] ?? ''));
|
||||||
$result = $token !== ''
|
$result = $token !== ''
|
||||||
? saas_verify_email_token($pdo, $token)
|
? saas_verify_email_token($pdo, $token)
|
||||||
: ['ok' => false, 'errors' => ['Der Link ist ungueltig oder abgelaufen.']];
|
: ['ok' => false, 'errors' => ['Der Link ist ungültig oder abgelaufen.']];
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
|
||||||
@@ -32,14 +32,14 @@ $result = $token !== ''
|
|||||||
<div class="public-auth-grid">
|
<div class="public-auth-grid">
|
||||||
<div class="public-auth-copy">
|
<div class="public-auth-copy">
|
||||||
<h1>E-Mail verifizieren</h1>
|
<h1>E-Mail verifizieren</h1>
|
||||||
<p>Bestaetige deine Adresse, damit dein Kundenkonto vollstaendig eingerichtet ist.</p>
|
<p>Bestätige deine Adresse, damit dein Kundenkonto vollständig eingerichtet ist.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="public-panel">
|
<div class="public-panel">
|
||||||
<h2>Status</h2>
|
<h2>Status</h2>
|
||||||
|
|
||||||
<?php if ($result['ok']): ?>
|
<?php if ($result['ok']): ?>
|
||||||
<div class="hint-box success"><p>Die E-Mail-Adresse wurde bestaetigt.</p></div>
|
<div class="hint-box success"><p>Die E-Mail-Adresse wurde bestätigt.</p></div>
|
||||||
<ul class="actions">
|
<ul class="actions">
|
||||||
<li><a href="konto.php" class="button primary">Zum Konto</a></li>
|
<li><a href="konto.php" class="button primary">Zum Konto</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ include 'nav.php';
|
|||||||
<td><?php echo saas_html($user['tenant_name']); ?></td>
|
<td><?php echo saas_html($user['tenant_name']); ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Kundenkuerzel</th>
|
<th>Kundenkürzel</th>
|
||||||
<td><?php echo saas_html($user['tenant_slug']); ?></td>
|
<td><?php echo saas_html($user['tenant_slug']); ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
@@ -51,7 +51,7 @@ include 'nav.php';
|
|||||||
<td><?php echo saas_html($user['role']); ?></td>
|
<td><?php echo saas_html($user['role']); ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>E-Mail bestaetigt</th>
|
<th>E-Mail bestätigt</th>
|
||||||
<td><?php echo $user['email_verified_at'] !== null ? 'ja' : 'nein'; ?></td>
|
<td><?php echo $user['email_verified_at'] !== null ? 'ja' : 'nein'; ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
+3
-3
@@ -19,7 +19,7 @@
|
|||||||
</nav>
|
</nav>
|
||||||
<div class="public-hero-content">
|
<div class="public-hero-content">
|
||||||
<h1>Kaffeeliste</h1>
|
<h1>Kaffeeliste</h1>
|
||||||
<p>Die digitale Kaffeekasse fuer Teams, Bueros und Vereine: Striche, Einzahlungen und offene Betraege bleiben nachvollziehbar an einem Ort.</p>
|
<p>Die digitale Kaffeekasse für Teams, Büros und Vereine: Striche, Einzahlungen und offene Beträge bleiben nachvollziehbar an einem Ort.</p>
|
||||||
<ul class="actions">
|
<ul class="actions">
|
||||||
<li><a href="register.php" class="button primary big">Kundenkonto anlegen</a></li>
|
<li><a href="register.php" class="button primary big">Kundenkonto anlegen</a></li>
|
||||||
<li><a href="login.php" class="button big">Zur App</a></li>
|
<li><a href="login.php" class="button big">Zur App</a></li>
|
||||||
@@ -37,12 +37,12 @@
|
|||||||
<p>Teilnehmer und Admins behalten Verbrauch, Einzahlungen und Salden im Blick.</p>
|
<p>Teilnehmer und Admins behalten Verbrauch, Einzahlungen und Salden im Blick.</p>
|
||||||
</article>
|
</article>
|
||||||
<article class="public-feature">
|
<article class="public-feature">
|
||||||
<h3>Mandantenfaehig</h3>
|
<h3>Mandantenfähig</h3>
|
||||||
<p>Jeder Kunde arbeitet in seinem eigenen Bereich mit eigenen Einstellungen.</p>
|
<p>Jeder Kunde arbeitet in seinem eigenen Bereich mit eigenen Einstellungen.</p>
|
||||||
</article>
|
</article>
|
||||||
<article class="public-feature">
|
<article class="public-feature">
|
||||||
<h3>Webspace-tauglich</h3>
|
<h3>Webspace-tauglich</h3>
|
||||||
<p>Der Start erfolgt ueber eine zentrale App-Adresse mit Login und Mandantenauswahl.</p>
|
<p>Der Start erfolgt über eine zentrale App-Adresse mit Login und Mandantenauswahl.</p>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
+1
-1
@@ -71,7 +71,7 @@ include 'nav.php';
|
|||||||
<div class="hint-box error"><p>Kein Zugriff.</p></div>
|
<div class="hint-box error"><p>Kein Zugriff.</p></div>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<p>
|
<p>
|
||||||
Read-only Vorschau aus <code>ledger_entries</code> fuer
|
Read-only Vorschau aus <code>ledger_entries</code> für
|
||||||
<?php echo saas_html($tenantName); ?>
|
<?php echo saas_html($tenantName); ?>
|
||||||
(<code><?php echo saas_html($tenantSlug); ?></code>).
|
(<code><?php echo saas_html($tenantSlug); ?></code>).
|
||||||
Die bestehenden App-Seiten schreiben weiterhin in die Legacy-Tabellen.
|
Die bestehenden App-Seiten schreiben weiterhin in die Legacy-Tabellen.
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
<div class="public-auth-grid">
|
<div class="public-auth-grid">
|
||||||
<div class="public-auth-copy">
|
<div class="public-auth-copy">
|
||||||
<h1>Login</h1>
|
<h1>Login</h1>
|
||||||
<p>Melde dich mit deinem Kundenkonto an. Wenn du mehreren Mandanten zugeordnet bist, waehlst du danach den passenden Bereich aus.</p>
|
<p>Melde dich mit deinem Kundenkonto an. Wenn du mehreren Mandanten zugeordnet bist, wählst du danach den passenden Bereich aus.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="public-panel">
|
<div class="public-panel">
|
||||||
@@ -86,7 +86,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
<input type="password" name="password" id="password" required>
|
<input type="password" name="password" id="password" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<label for="tenant_slug">Kundenkuerzel</label>
|
<label for="tenant_slug">Kundenkürzel</label>
|
||||||
<input type="text" name="tenant_slug" id="tenant_slug" value="<?php echo saas_html($tenantSlug); ?>" placeholder="optional">
|
<input type="text" name="tenant_slug" id="tenant_slug" value="<?php echo saas_html($tenantSlug); ?>" placeholder="optional">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+3
-3
@@ -19,7 +19,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$identity = $tenantId > 0 ? saas_identity_for_user_tenant($pdo, $pendingUserId, $tenantId) : null;
|
$identity = $tenantId > 0 ? saas_identity_for_user_tenant($pdo, $pendingUserId, $tenantId) : null;
|
||||||
|
|
||||||
if ($identity === null) {
|
if ($identity === null) {
|
||||||
$errors[] = 'Dieser Mandant ist fuer dein Konto nicht verfuegbar.';
|
$errors[] = 'Dieser Mandant ist für dein Konto nicht verfügbar.';
|
||||||
} else {
|
} else {
|
||||||
saas_session_login($identity);
|
saas_session_login($identity);
|
||||||
header('Location: konto.php');
|
header('Location: konto.php');
|
||||||
@@ -34,7 +34,7 @@ include 'nav.php';
|
|||||||
|
|
||||||
<section id="banner">
|
<section id="banner">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<h2>Mandant auswaehlen</h2>
|
<h2>Mandant auswählen</h2>
|
||||||
|
|
||||||
<?php if ($errors !== []): ?>
|
<?php if ($errors !== []): ?>
|
||||||
<div class="hint-box error">
|
<div class="hint-box error">
|
||||||
@@ -45,7 +45,7 @@ include 'nav.php';
|
|||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if ($memberships === []): ?>
|
<?php if ($memberships === []): ?>
|
||||||
<div class="hint-box error"><p>Fuer dieses Konto ist kein aktiver Mandant verfuegbar.</p></div>
|
<div class="hint-box error"><p>Für dieses Konto ist kein aktiver Mandant verfügbar.</p></div>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<form method="post" action="mandant-auswahl.php">
|
<form method="post" action="mandant-auswahl.php">
|
||||||
<?php echo app_csrf_field(); ?>
|
<?php echo app_csrf_field(); ?>
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ include 'nav.php';
|
|||||||
|
|
||||||
<?php if (!$canManageSettings): ?>
|
<?php if (!$canManageSettings): ?>
|
||||||
<?php http_response_code(403); ?>
|
<?php http_response_code(403); ?>
|
||||||
<div class="hint-box error"><p>Du hast keine Berechtigung fuer diese Einstellungen.</p></div>
|
<div class="hint-box error"><p>Du hast keine Berechtigung für diese Einstellungen.</p></div>
|
||||||
<?php elseif ($settings === null): ?>
|
<?php elseif ($settings === null): ?>
|
||||||
<div class="hint-box error"><p>Die Einstellungen konnten nicht geladen werden.</p></div>
|
<div class="hint-box error"><p>Die Einstellungen konnten nicht geladen werden.</p></div>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
@@ -79,7 +79,7 @@ include 'nav.php';
|
|||||||
<input type="text" name="locale" id="locale" value="<?php echo saas_html($settings['locale']); ?>" required>
|
<input type="text" name="locale" id="locale" value="<?php echo saas_html($settings['locale']); ?>" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-12-small">
|
<div class="col-6 col-12-small">
|
||||||
<label for="currency_code">Waehrung</label>
|
<label for="currency_code">Währung</label>
|
||||||
<input type="text" name="currency_code" id="currency_code" value="<?php echo saas_html($settings['currency_code']); ?>" maxlength="3" required>
|
<input type="text" name="currency_code" id="currency_code" value="<?php echo saas_html($settings['currency_code']); ?>" maxlength="3" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-12-small">
|
<div class="col-6 col-12-small">
|
||||||
@@ -109,7 +109,7 @@ include 'nav.php';
|
|||||||
</div>
|
</div>
|
||||||
<ul class="actions">
|
<ul class="actions">
|
||||||
<li><button type="submit">Speichern</button></li>
|
<li><button type="submit">Speichern</button></li>
|
||||||
<li><a href="konto.php" class="button alt">Zurueck</a></li>
|
<li><a href="konto.php" class="button alt">Zurück</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</form>
|
</form>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
<div class="public-auth-grid">
|
<div class="public-auth-grid">
|
||||||
<div class="public-auth-copy">
|
<div class="public-auth-copy">
|
||||||
<h1>Passwort vergessen</h1>
|
<h1>Passwort vergessen</h1>
|
||||||
<p>Fordere einen Link an, um dein Passwort neu zu setzen. Wenn du mehrere Kundenbereiche nutzt, kannst du das Kuerzel optional angeben.</p>
|
<p>Fordere einen Link an, um dein Passwort neu zu setzen. Wenn du mehrere Kundenbereiche nutzt, kannst du das Kürzel optional angeben.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="public-panel">
|
<div class="public-panel">
|
||||||
@@ -62,7 +62,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
<div class="hint-box success">
|
<div class="hint-box success">
|
||||||
<p><?php echo saas_html($message); ?></p>
|
<p><?php echo saas_html($message); ?></p>
|
||||||
<?php if ($resetLink !== null): ?>
|
<?php if ($resetLink !== null): ?>
|
||||||
<p><a href="<?php echo saas_html($resetLink); ?>">Dev-Link zum Zuruecksetzen</a></p>
|
<p><a href="<?php echo saas_html($resetLink); ?>">Dev-Link zum Zurücksetzen</a></p>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
@@ -83,7 +83,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
<input type="email" name="email" id="email" value="<?php echo saas_html($email); ?>" required>
|
<input type="email" name="email" id="email" value="<?php echo saas_html($email); ?>" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<label for="tenant_slug">Kundenkuerzel</label>
|
<label for="tenant_slug">Kundenkürzel</label>
|
||||||
<input type="text" name="tenant_slug" id="tenant_slug" value="<?php echo saas_html($tenantSlug); ?>" placeholder="optional">
|
<input type="text" name="tenant_slug" id="tenant_slug" value="<?php echo saas_html($tenantSlug); ?>" placeholder="optional">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
<!DOCTYPE HTML>
|
<!DOCTYPE HTML>
|
||||||
<html lang="de">
|
<html lang="de">
|
||||||
<head>
|
<head>
|
||||||
<title>Kaffeeliste Passwort zuruecksetzen</title>
|
<title>Kaffeeliste Passwort zurücksetzen</title>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
|
||||||
<link rel="stylesheet" href="assets/css/main.css" />
|
<link rel="stylesheet" href="assets/css/main.css" />
|
||||||
@@ -49,15 +49,15 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
|
|
||||||
<div class="public-auth-grid">
|
<div class="public-auth-grid">
|
||||||
<div class="public-auth-copy">
|
<div class="public-auth-copy">
|
||||||
<h1>Passwort zuruecksetzen</h1>
|
<h1>Passwort zurücksetzen</h1>
|
||||||
<p>Setze ein neues Passwort fuer dein Kaffeeliste-Konto.</p>
|
<p>Setze ein neues Passwort für dein Kaffeeliste-Konto.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="public-panel">
|
<div class="public-panel">
|
||||||
<h2>Neues Passwort</h2>
|
<h2>Neues Passwort</h2>
|
||||||
|
|
||||||
<?php if ($success): ?>
|
<?php if ($success): ?>
|
||||||
<div class="hint-box success"><p>Das Passwort wurde geaendert.</p></div>
|
<div class="hint-box success"><p>Das Passwort wurde geändert.</p></div>
|
||||||
<ul class="actions">
|
<ul class="actions">
|
||||||
<li><a href="login.php" class="button primary">Zum Login</a></li>
|
<li><a href="login.php" class="button primary">Zum Login</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -69,7 +69,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
<?php elseif (!$tokenValid): ?>
|
<?php elseif (!$tokenValid): ?>
|
||||||
<div class="hint-box error"><p>Der Link ist ungueltig oder abgelaufen.</p></div>
|
<div class="hint-box error"><p>Der Link ist ungültig oder abgelaufen.</p></div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php if ($tokenValid): ?>
|
<?php if ($tokenValid): ?>
|
||||||
|
|||||||
+2
-2
@@ -63,7 +63,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
<div class="public-auth-grid">
|
<div class="public-auth-grid">
|
||||||
<div class="public-auth-copy">
|
<div class="public-auth-copy">
|
||||||
<h1>Registrierung</h1>
|
<h1>Registrierung</h1>
|
||||||
<p>Lege einen neuen Kundenbereich an. Danach bist du als Owner angemeldet und kannst die Kaffeeliste fuer dein Team einrichten.</p>
|
<p>Lege einen neuen Kundenbereich an. Danach bist du als Owner angemeldet und kannst die Kaffeeliste für dein Team einrichten.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="public-panel">
|
<div class="public-panel">
|
||||||
@@ -85,7 +85,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
<input type="text" name="tenant_name" id="tenant_name" value="<?php echo saas_html($values['tenant_name']); ?>" required>
|
<input type="text" name="tenant_name" id="tenant_name" value="<?php echo saas_html($values['tenant_name']); ?>" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-12-small">
|
<div class="col-6 col-12-small">
|
||||||
<label for="tenant_slug">Kundenkuerzel</label>
|
<label for="tenant_slug">Kundenkürzel</label>
|
||||||
<input type="text" name="tenant_slug" id="tenant_slug" value="<?php echo saas_html($values['tenant_slug']); ?>" placeholder="kaffeeliste-team" required>
|
<input type="text" name="tenant_slug" id="tenant_slug" value="<?php echo saas_html($values['tenant_slug']); ?>" placeholder="kaffeeliste-team" required>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 col-12-small">
|
<div class="col-6 col-12-small">
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ $checks = [
|
|||||||
[
|
[
|
||||||
'label' => 'Landingpage',
|
'label' => 'Landingpage',
|
||||||
'path' => 'landing.php',
|
'path' => 'landing.php',
|
||||||
'contains' => ['Kaffeeliste', 'Kundenkonto anlegen', 'Mandantenfaehig'],
|
'contains' => ['Kaffeeliste', 'Kundenkonto anlegen', 'Mandantenfähig'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'label' => 'Dashboard',
|
'label' => 'Dashboard',
|
||||||
@@ -53,7 +53,7 @@ $checks = [
|
|||||||
'contains' => ['Mitglieder verwalten', 'PayPal-Name'],
|
'contains' => ['Mitglieder verwalten', 'PayPal-Name'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'label' => 'Letzte Eintraege',
|
'label' => 'Letzte Einträge',
|
||||||
'path' => 'letzteneintraege.php',
|
'path' => 'letzteneintraege.php',
|
||||||
'contains' => ['Letzte 100 Einzahlungen'],
|
'contains' => ['Letzte 100 Einzahlungen'],
|
||||||
],
|
],
|
||||||
@@ -93,14 +93,14 @@ $checks = [
|
|||||||
'contains' => ['Login'],
|
'contains' => ['Login'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'label' => 'Passwort zuruecksetzen Invalid',
|
'label' => 'Passwort zurücksetzen Invalid',
|
||||||
'path' => 'passwort-zuruecksetzen.php',
|
'path' => 'passwort-zuruecksetzen.php',
|
||||||
'contains' => ['Passwort zuruecksetzen', 'ungueltig oder abgelaufen'],
|
'contains' => ['Passwort zurücksetzen', 'ungültig oder abgelaufen'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'label' => 'E-Mail verifizieren Invalid',
|
'label' => 'E-Mail verifizieren Invalid',
|
||||||
'path' => 'email-verifizieren.php',
|
'path' => 'email-verifizieren.php',
|
||||||
'contains' => ['E-Mail verifizieren', 'ungueltig oder abgelaufen'],
|
'contains' => ['E-Mail verifizieren', 'ungültig oder abgelaufen'],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'label' => 'Mandant-Einstellungen Login-Schutz',
|
'label' => 'Mandant-Einstellungen Login-Schutz',
|
||||||
@@ -146,11 +146,11 @@ $knownIssueChecks = [
|
|||||||
$skippedUnsafe = [
|
$skippedUnsafe = [
|
||||||
[
|
[
|
||||||
'path' => 'mailversenden.php',
|
'path' => 'mailversenden.php',
|
||||||
'reason' => 'GET kann bei vollstaendiger PHPMailer-Installation E-Mails versenden.',
|
'reason' => 'GET kann bei vollständiger PHPMailer-Installation E-Mails versenden.',
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'path' => 'jahresauswertung.php',
|
'path' => 'jahresauswertung.php',
|
||||||
'reason' => 'GET kann Jahresbuchungen schreiben und E-Mails versenden; PHPMailer-Abhaengigkeit ist zudem unvollstaendig.',
|
'reason' => 'GET kann Jahresbuchungen schreiben und E-Mails versenden; PHPMailer-Abhängigkeit ist zudem unvollständig.',
|
||||||
],
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -260,7 +260,7 @@ foreach ($knownIssueChecks as $check) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ($response['status'] === 200 && preg_match($issuePattern, $response['body']) !== 1) {
|
if ($response['status'] === 200 && preg_match($issuePattern, $response['body']) !== 1) {
|
||||||
echo "RESOLVED {$label}: bitte in die regulaeren Smoke-Checks aufnehmen.\n";
|
echo "RESOLVED {$label}: bitte in die regulären Smoke-Checks aufnehmen.\n";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -100,8 +100,8 @@ try {
|
|||||||
|
|
||||||
$step = 'insert notices';
|
$step = 'insert notices';
|
||||||
$insertNotice = $pdo->prepare('INSERT INTO kl_hinweise (nachricht, gueltig_bis) VALUES (?, ?)');
|
$insertNotice = $pdo->prepare('INSERT INTO kl_hinweise (nachricht, gueltig_bis) VALUES (?, ?)');
|
||||||
$insertNotice->execute(['[GM] Aktiver Hinweis fuer Golden-Master-Test', $dates['notice_active']]);
|
$insertNotice->execute(['[GM] Aktiver Hinweis für Golden-Master-Test', $dates['notice_active']]);
|
||||||
$insertNotice->execute(['[GM] Abgelaufener Hinweis fuer Golden-Master-Test', $dates['notice_expired']]);
|
$insertNotice->execute(['[GM] Abgelaufener Hinweis für Golden-Master-Test', $dates['notice_expired']]);
|
||||||
|
|
||||||
$metadata = [
|
$metadata = [
|
||||||
'golden_master_seed' => 'seeded',
|
'golden_master_seed' => 'seeded',
|
||||||
|
|||||||
Reference in New Issue
Block a user