Captures the brainstorming outcome for fixing the broken mail dispatch, removing the mail-only nestjs-i18n setup in favor of hardcoded German copy, and redesigning the registration/forgot-password email templates.
7.5 KiB
7.5 KiB
Mailversand reparieren + Templates neu gestalten
Status: approved Datum: 2026-07-31
Kontext
Backend: NestJS (myteamwallet_backend), basierend auf nestjs-boilerplate. Mailversand über
@nestjs-modules/mailer (Nodemailer) mit Handlebars-Templates. E-Mails werden für zwei Flows
verschickt: Registrierung (Bestätigungsmail) und Passwort vergessen.
Der Mailversand funktioniert aktuell nicht, aus zwei unabhängigen Gründen:
src/mail/mail.service.ts— sowohluserSignUp()als auchforgotPassword()haben ein totesreturn;als erste Anweisung, noch vor dem eigentlichenmailerService.sendMail(...)Aufruf. Der Versand-Code wird nie erreicht..envexistiert lokal nicht mehr im Arbeitsverzeichnis (im Commit1d4546d "styling"wurde die Datei korrekt aus dem Git-Tracking entfernt und zu.gitignorehinzugefügt — das war bereits vor diesem Spec erledigt). Ohne.envsind alleMAIL_*/DATABASE_*/etc. Umgebungsvariablenundefined, die App kann so nicht sinnvoll laufen.
Zusätzlich bestehende Baustellen, die in diesem Zug mit erledigt werden:
- E-Mail-Templates (
activation.hbs,reset-password.hbs) sind unverändertes, unstyled Boilerplate aus demnestjs-boilerplateScaffold (graue Kopfzeile, generischer Button, kein Branding). - Die E-Mail-Texte laufen aktuell über
nestjs-i18n, das ausschließlich für diese zwei Mails genutzt wird und nur eineen-Locale hat, obwohl das Produkt (myteamwallet.de) deutschsprachig ist. Entscheidung (siehe unten):nestjs-i18nkomplett entfernen, Texte direkt auf Deutsch im Code/Template.
Das Frontend (myteamwallet_frontend_modern, das aktuell aktiv gebaute/deployte Frontend laut
Dockerfile) hat kein fertiges Bild-Logo — nur generische Angular-Default-Icons. Als Markenfarbe
dient das dort verwendete Grün #2e7d32 (Material theme-color), Schriftart Roboto,
Wordmark-Schreibweise „TeamWallet".
Entscheidungen aus dem Brainstorming
- SMTP-Zugangsdaten: das alte, aus der Git-Historie wiederhergestellte Strato-Passwort wird vorerst weiterverwendet (keine sofortige Rotation im Rahmen dieser Änderung).
- Sprachen: nur Deutsch. Keine mehrsprachige i18n-Infrastruktur für Mails.
- i18n-Mechanismus: kein Sprachdatei-System — deutsche Texte direkt im Code/Template.
nestjs-i18nwird komplett entfernt (Modul-Registrierung,src/i18n/, Dependency,I18n-Nutzung inmail.service.ts), da es im Backend ausschließlich für die zwei Mails verwendet wurde. - Branding: Grün
#2e7d32(ausmyteamwallet_frontend_modern), Textwordmark „TeamWallet" (kein Bild-Logo), Roboto mit System-Font-Fallback, abgerundete Card-Optik passend zum „fintech-lite" Look der App. - Personalisierung: Anrede mit Vornamen („Hallo Max,"), da
firstNamean beiden Aufrufstellen imAuthServicebereits verfügbar ist.
Architektur / Komponenten
1. Bugfix mail.service.ts
- Die zwei toten
return;Statements entfernen (vorsendMailinuserSignUp()undforgotPassword()). I18n/I18nRequestScopeServiceConstructor-Injection entfernen.- Betreffzeilen als deutsche String-Literale direkt im Service (
'E-Mail bestätigen','Passwort zurücksetzen'). MailData<T>Interface (src/mail/interfaces/mail-data.interface.ts) bleibt strukturell gleich ({ to: string; data: T }),Twird pro Aufruf umfirstName?: stringerweitert:MailData<{ hash: string; firstName?: string }>.
2. Aufrufstellen auth.service.ts
register():dto.firstNamezusätzlich inmailData.datadurchreichen.forgotPassword():user.firstNamezusätzlich inmailData.datadurchreichen.- Keine Änderung an Kontrollfluss, Fehlerbehandlung oder DB-Zugriffen — nur die zusätzliche Datenübergabe.
3. i18n-Entfernung
app.module.ts:I18nModule.forRootAsync(...)Import und Registrierung entfernen (HeaderResolver-Import ebenfalls, falls sonst ungenutzt).src/i18n/Ordner komplett löschen (nur von Mails genutzt, siehe Analyse).nestjs-i18nDependency auspackage.jsonentfernen (npm uninstall, damit Lockfile konsistent bleibt).app.config.tsFelderfallbackLanguage/headerLanguage(APP_FALLBACK_LANGUAGE,APP_HEADER_LANGUAGE) werden mit entfernt: geprüft, sie werden ausschließlich inapp.module.tsfürI18nModulegelesen (kein anderer Konsument im Code) — würden sonst toten Config-Code hinterlassen.
4. Templates
- Neues Handlebars-Partial
src/mail/mail-templates/partials/layout-header.hbsundlayout-footer.hbs(oder ein kombinierteslayout.hbs, falls das mit demHandlebarsAdaptersauberer registrierbar ist) — gemeinsamer Rahmen: Header mit „TeamWallet"-Wordmark auf grünem/hellem Grund, Footer mit Kontakt-/Legal-Hinweis (z. B. „Diese E-Mail wurde automatisch von TeamWallet verschickt."). activation.hbs: nutzt das Layout, Inhalt: Begrüßung mit{{firstName}}(Fallback ohne Namen falls nicht vorhanden), kurzer Erklärtext, grüner CTA-Button „E-Mail bestätigen" →{{url}}.reset-password.hbs: nutzt das Layout, Inhalt: Begrüßung, Erklärtext, grüner CTA-Button „Passwort zurücksetzen" →{{url}}, Hinweis auf zeitliche Begrenzung des Links und dass die Mail ignoriert werden kann, falls nicht selbst angefragt.- Styling-Konstanten: Akzent
#2e7d32, Radius ~12px auf Card-Container,max-width: 600px, Inline-CSS (kein externes Stylesheet — E-Mail-Client-Kompatibilität), tabellenbasiertes Layout wie bisher (kein MJML — unnötige Build-Komplexität für zwei Templates), Roboto mit Fallback-Stack (Roboto, Helvetica, Arial, sans-serif, da Web-Fonts in vielen Mail-Clients nicht geladen werden). - Kontext-Variablen, die
mail.service.tsan Handlebars übergibt:app_name("TeamWallet"),firstName,url, ggf.yearfürs Footer-Copyright — Rest (Texte, Button-Label, Titel) fest im Template.
5. .env wiederherstellen
- Lokale, nicht getrackte
.envDatei neu anlegen (Datei existiert nicht mehr im Working Tree, ist aber in.gitignore) mit den ausgit show 7df5611:.envwiederhergestellten Werten (DB-, Mail-, JWT- und App-Konfiguration wie zuvor). - Kein Commit dieser Datei — bleibt lokal/untracked, wie vom User entschieden.
Fehlerbehandlung
- Kein Verhaltensunterschied zu heute beabsichtigt:
mailerService.sendMail(...)wirft bei SMTP-Fehlern eine Exception, die aktuell nicht speziell abgefangen wird (weder vorher noch nachher) — das bleibt so, ist außerhalb des Scopes dieser Änderung. Falls beim Testen ein SMTP- Fehler auftritt (z. B. Strato blockiert alte/rotierte Zugangsdaten), wird das separat besprochen statt stillschweigend Fehlerbehandlung hinzuzufügen.
Testing
- Bestehenden e2e-Test
test/user/auth.e2e-spec.ts(Confirm-Email-Flow über MailDev-artige HTTP-Inbox-API) laufen lassen und verifizieren, dass er jetzt grün ist (war zuvor durch den Bug automatisch rot). - Neuer e2e-Test für den Forgot-Password-Mail-Flow, analog zum bestehenden Confirm-Email-Test:
Passwort-vergessen anfragen, Mail über MailDev-Inbox abrufen, Hash extrahieren, gegen
/api/v1/auth/reset/passwordverifizieren. - Kein Unit-Test-Aufbau für
MailServicevorgesehen (kein bestehendes Muster im Repo für Mail-Unit-Tests, e2e deckt das Verhalten ausreichend ab) — YAGNI.
Out of Scope
- Rotation der SMTP-Zugangsdaten (User macht das ggf. später selbst).
- Mehrsprachigkeit / weitere Locales.
- Redesign der Frontend-Flows, die auf
/confirm-email/:hashbzw./password-change/:hashlinken. - MJML- oder Build-Pipeline-Einführung für Templates.