M6: Mailversand als nachvollziehbaren Versandjob mit Dry-Run/Log

mailversenden.php hatte keine Zugriffskontrolle, versendete bei jedem
GET-Request sofort echte Mails und nutzte PHPMailer, dessen Quelldateien
im Repo gar nicht vorhanden waren (nur composer.json/Lizenz) - der Aufruf
waere also ohnehin mit Fatal Error abgebrochen. Zusaetzlich waren SMTP-
Host, Absender, PayPal-Link und FAQ-URL fest auf einen Alt-Kunden (AOK)
codiert.

- Ersetzt PHPMailer durch die bestehende saas_send_mail()-Abstraktion aus
  M3 (Transport log/mail je nach APP_MAIL_TRANSPORT) statt eine fehlende
  Abhaengigkeit nachzuvendoren.
- Neue Tabelle outbound_emails protokolliert jeden Versandversuch:
  Mandant, Mitglied, Vorlage, Betreff, Status, Fehler - das Versandlog.
- Formular hat eine standardmaessig aktive Dry-Run-Checkbox; im Dry-Run
  wird nur geloggt, saas_send_mail() nicht aufgerufen.
- Mailtext ist jetzt tenant-generisch (Saldo, optionaler PayPal-Link nur
  wenn der Mandant PayPal aktiviert hat, eigener Dashboard-Link) statt
  hartcodierter Alt-Kunden-Inhalte.
- Zugriffskontrolle ergaenzt (owner/admin/treasurer + Legacy-Fallback).
- http-smoke.php: mailversenden.php ist jetzt reguel</EOF>
This commit is contained in:
2026-07-15 16:13:38 +02:00
parent 81dfff51a0
commit d5195e7f9f
6 changed files with 286 additions and 117 deletions
+52 -2
View File
@@ -99,10 +99,60 @@ Live getestet: gültiges zweiseitiges PDF (58&nbsp;KB) mit korrektem
stichprobenartig verifiziert (unkomprimierte Testausgabe), Vieltrinker-/
Wenigtrinker-Aufteilung stimmt mit den Ledger-Daten überein.
## Mailversand
Umgesetzte Dateien:
```text
database/migrations/0009_saas_outbound_emails.sql
app/saas-mail.php (Vorlage + Versandlog)
mailversenden.php
scripts/http-smoke.php
```
Ziel: Nachvollziehbarer Versandjob mit Dry-Run und Versandlog statt
sofortigem, ungeprüftem Versand.
Umfang:
- `mailversenden.php` hatte zuvor keine Zugriffskontrolle, versendete auf
jeden GET-Request sofort echte E-Mails und nutzte PHPMailer, dessen
Quelldateien im Repo gar nicht vorhanden sind (nur `composer.json` und
Lizenzdateien) der Aufruf wäre also ohnehin mit einem Fatal Error
abgebrochen. Zusätzlich waren SMTP-Host, Absender, PayPal-Link und
FAQ-URL fest auf einen einzelnen Alt-Kunden (AOK) codiert.
- Statt PHPMailer zu vendoren, nutzt der Versand jetzt die in M3 bereits
gebaute Mail-Abstraktion (`saas_send_mail()`), die je nach
`APP_MAIL_TRANSPORT` entweder wirklich per `mail()` verschickt oder
(Standard im Dev-Modus) in `var/mail` protokolliert. Damit entfällt die
fehlende Abhängigkeit vollständig, und "Dry-Run" beziehungsweise
"Log" sind bereits strukturell dieselbe Mechanik.
- Neue Tabelle `outbound_emails` protokolliert jeden Versandversuch:
Mandant, Mitglied, Vorlage, Betreff, Status (`dry_run`/`sent`/`failed`),
Zeitpunkt, Fehlermeldung. Das ist das im Plan geforderte Versandlog.
- Echter zweistufiger Schutz: Das Formular hat eine standardmäßig aktive
"Dry-Run"-Checkbox. Im Dry-Run wird für jeden Empfänger ein Log-Eintrag
geschrieben, aber `saas_send_mail()` nicht aufgerufen. Erst mit
deaktivierter Checkbox wird wirklich versendet.
- Der Mailtext ist jetzt tenant-generisch (`saas_render_balance_mail_body()`):
Saldo, optionaler PayPal-Link nur wenn der Mandant PayPal aktiviert hat,
Link zum eigenen Dashboard über `saas_app_url()`. Keine hartcodierten
Alt-Kunden-Inhalte mehr.
- Zugriffskontrolle ergänzt (owner/admin/treasurer + Legacy-Fallback).
- `scripts/http-smoke.php`: `mailversenden.php` ist jetzt ein regulärer
Check statt eines übersprungenen unsicheren GET-Aufrufs, da GET keine
Seiteneffekte mehr hat.
Live getestet: GET zeigt nur das Formular (kein Versand), Dry-Run
protokolliert alle aktiven Mitglieder ohne `var/mail`-Dateien zu erzeugen,
Live-Versand erzeugt für jeden Empfänger eine Log-Datei mit korrekt
personalisiertem Inhalt (Guthaben- und Schuldenfall geprüft), Versandlog in
der UI zeigt die Einträge. Testdaten anschließend entfernt.
## Prüfstatus
- Golden Master: grün mit 104 Assertions.
- M4 Ledger-Migration: grün mit 73 Assertions.
- M4 Ledger-Service: grün mit 115 Assertions.
- HTTP-Smoke: grün mit 24 geprüften Seiten (PDF-Export jetzt regulär statt
bekannter offener Punkt).
- HTTP-Smoke: grün mit 25 geprüften Seiten (PDF-Export und Mailversand
jetzt regulär statt bekannter offener Punkte).
+7 -2
View File
@@ -306,7 +306,7 @@ Nicht tun:
| M3 | SaaS-Basis | Abgeschlossen: Tenants, User, Registrierung, Login, Rollen, Mail-Links und zentrale Mandantenauswahl funktionieren |
| M4 | Datenmigration | Gestartet: Ledger-Tabelle, Legacy-Backfill, Paritätscheck, Ledger-Service und Preview sind umgesetzt |
| M5 | App-Kern | Weit fortgeschritten: Kernseiten lesen und schreiben tenant-sicher gegen das Ledger, inklusive Hinweise und rollenbasiertem Zugang; offen ist ein eigener Zahlungs-Screen |
| M6 | Betriebsflows | Gestartet: CSV-Import und PDF-Export stehen; Mail und Jahresprozesse offen |
| M6 | Betriebsflows | Weit fortgeschritten: CSV-Import, PDF-Export und Mailversand stehen; Jahresprozesse offen |
| M7 | Landingpage | Public-Seite und Auth-Seiten sind im gemeinsamen Stil nutzbar; spätere Ausbaustufen folgen |
| M8 | Härtung | Betrieb, Datenschutz, Monitoring und Isolation sind geprüft |
| M9 | Cutover | Produktivumstellung ist vorbereitet und Legacy ist read-only |
@@ -579,7 +579,12 @@ Schritte:
Zugriffskontrolle; das ist behoben, die Seite liest jetzt tenant-sicher
aus dem Ledger.
- Mailversand als nachvollziehbaren Versandjob mit Dry-Run und Versandlog
gestalten.
gestalten: erledigt. `mailversenden.php` versendete zuvor ungeprüft bei
jedem GET-Request echte Mails über PHPMailer (dessen Quelldateien im Repo
gar nicht vorhanden waren) mit fest codierten Alt-Kunden-Inhalten (SMTP,
PayPal-Link, FAQ-URL). Ersetzt durch die bestehende `saas_send_mail()`-
Abstraktion aus M3, eine neue `outbound_emails`-Tabelle als Versandlog
und eine standardmäßig aktive Dry-Run-Option.
- Jahresauswertung beziehungsweise Jahresbuchungen tenant-sicher abbilden.
Ergebnis: