# Mailversand reparieren + Templates neu gestalten — Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Mailversand für Registrierung und Passwort-vergessen im NestJS-Backend (`myteamwallet_backend`) wieder funktionsfähig machen, das mail-only `nestjs-i18n` Setup entfernen (Texte direkt auf Deutsch), und die zwei Handlebars-Templates in einem zu "TeamWallet" (Grün `#2e7d32`) passenden, hübschen Design neu bauen. **Architecture:** `MailService` (`@nestjs-modules/mailer` + Nodemailer + Handlebars) bleibt die zentrale Versandstelle. Der Bug ist ein totes `return;` vor `sendMail(...)` in beiden Methoden — Fix ist ein reiner Code-Fix, keine Config-Änderung nötig (`.env` ist bereits lokal korrekt befüllt). `nestjs-i18n` wird komplett entfernt, deutsche Texte wandern direkt in die `.hbs`-Templates bzw. als String-Literale in `mail.service.ts`. Die zwei Templates teilen sich ein gemeinsames Handlebars-Block-Partial (`partials/layout.hbs`) für Header/Footer, um Duplikation zu vermeiden. **Tech Stack:** NestJS 9, `@nestjs-modules/mailer` 1.8.1 (Nodemailer 6.8.0), Handlebars 4.7.7, Jest 29 (Unit-Tests), TypeScript 4.8. ## Global Constraints - Nur Deutsch — keine mehrsprachige i18n-Infrastruktur für Mails, keine Sprachdateien. - `nestjs-i18n` wird vollständig aus dem Backend entfernt (Modul, Dependency, `src/i18n/`). - Branding: Akzentfarbe `#2e7d32` (Grün), Textwordmark „TeamWallet" (kein Bild-Logo), Roboto mit Fallback-Stack `Roboto, Helvetica, Arial, sans-serif`, abgerundete Card-Optik (~12px Radius), `max-width: 600px`, Inline-CSS-safe (die `HandlebarsAdapter` inlined `
TeamWallet
{{> @partial-block }}
``` - [ ] **Step 4: `activation.hbs` neu gestalten** Datei `myteamwallet_backend/src/mail/mail-templates/activation.hbs` komplett ersetzen: ```handlebars {{#> layout}}

Hallo{{#if firstName}} {{firstName}}{{/if}},

schön, dass du bei TeamWallet dabei bist! Bestätige deine E-Mail-Adresse, um dein Konto zu aktivieren.

{{actionTitle}}

Falls der Button nicht funktioniert, kopiere diesen Link in deinen Browser:
{{url}}

{{/layout}} ``` - [ ] **Step 5: `reset-password.hbs` neu gestalten** Datei `myteamwallet_backend/src/mail/mail-templates/reset-password.hbs` komplett ersetzen: ```handlebars {{#> layout}}

Hallo{{#if firstName}} {{firstName}}{{/if}},

du hast angefragt, dein TeamWallet-Passwort zurückzusetzen. Klicke auf den Button, um ein neues Passwort zu vergeben.

{{actionTitle}}

Falls du diese Anfrage nicht gestellt hast, kannst du diese E-Mail einfach ignorieren — es wird nichts verändert.

Falls der Button nicht funktioniert, kopiere diesen Link in deinen Browser:
{{url}}

{{/layout}} ``` - [ ] **Step 6: Partials-Verzeichnis in `mail-config.service.ts` registrieren** In `myteamwallet_backend/src/mail/mail-config.service.ts` den `template.options` Block erweitern (`partials.dir` zeigt auf den neuen Ordner, damit `HandlebarsAdapter` die `.hbs` Dateien darin beim Versand automatisch als Partials lädt): ```typescript createMailerOptions(): MailerOptions { return { transport: { host: this.configService.get('mail.host'), port: this.configService.get('mail.port'), ignoreTLS: this.configService.get('mail.ignoreTLS'), secure: this.configService.get('mail.secure'), requireTLS: this.configService.get('mail.requireTLS'), auth: { user: this.configService.get('mail.user'), pass: this.configService.get('mail.password'), }, }, defaults: { from: `"${this.configService.get( 'mail.defaultName', )}" <${this.configService.get('mail.defaultEmail')}>`, }, template: { dir: path.join( this.configService.get('app.workingDirectory'), 'src', 'mail', 'mail-templates', ), adapter: new HandlebarsAdapter(), options: { strict: true, partials: { dir: path.join( this.configService.get('app.workingDirectory'), 'src', 'mail', 'mail-templates', 'partials', ), }, }, }, } as MailerOptions; } ``` - [ ] **Step 7: Test laufen lassen, Erfolg bestätigen** Run: `cd myteamwallet_backend && npx jest mail-templates.spec.ts` Expected: PASS — alle 3 Tests grün. - [ ] **Step 8: Alle Unit-Tests + Build** Run: `cd myteamwallet_backend && npm test && npm run build` Expected: alle Tests grün, Build erfolgreich. - [ ] **Step 9: Commit** ```bash git add myteamwallet_backend/src/mail/mail-config.service.ts myteamwallet_backend/src/mail/mail-templates git commit -m "feat(mail): redesign email templates with TeamWallet branding and shared layout partial" ``` --- ### Task 4: Manuelle Verifikation mit echtem Versand Kein Code-Task — Nachweis, dass Registrierung und Passwort-vergessen tatsächlich E-Mails verschicken (Strato-SMTP, kein lokaler MailDev vorhanden, siehe Spec). **Files:** keine. - [ ] **Step 1: Backend lokal starten** Voraussetzung: lokale MySQL-Instanz läuft (Container `brave_einstein`, Port 3306, bereits aktiv laut `docker ps`), `myteamwallet_backend/.env` unverändert vorhanden. Run: `cd myteamwallet_backend && npm run start:dev` Expected: Server startet ohne Fehler auf Port `3999` (kein Absturz durch die entfernten `nestjs-i18n`-Imports, keine `MailerModule`-Config-Fehler). - [ ] **Step 2: Registrierung auslösen (Aktivierungsmail)** In einem zweiten Terminal, mit einer echten, von dir kontrollierten Test-Adresse: ```bash curl -X POST http://localhost:3999/api/v1/auth/email/register \ -H "Content-Type: application/json" \ -d '{"email":"DEINE-TEST-ADRESSE@example.com","password":"Test1234!","firstName":"Max","lastName":"Mustermann"}' ``` Expected: HTTP 201, und innerhalb kurzer Zeit trifft eine E-Mail „Bestätige deine E-Mail-Adresse" mit grünem TeamWallet-Header, Begrüßung „Hallo Max," und funktionierendem Bestätigungs-Button in der Test-Mailbox ein. - [ ] **Step 3: Passwort-vergessen auslösen** ```bash curl -X POST http://localhost:3999/api/v1/auth/forgot/password \ -H "Content-Type: application/json" \ -d '{"email":"DEINE-TEST-ADRESSE@example.com"}' ``` Expected: HTTP 204/200 (je nach Response des Endpoints), und eine E-Mail „Passwort zurücksetzen" mit gleichem Layout trifft ein. - [ ] **Step 4: Server stoppen** `npm run start:dev` Prozess beenden (Ctrl+C). - [ ] **Step 5: Ergebnis festhalten** Kein Commit nötig — dies ist ein manueller Verifikationsschritt. Falls eine der beiden Mails nicht ankommt, zurück zu systematic-debugging (SMTP-Verbindung, Firewall, Spam-Ordner prüfen) bevor der Task als abgeschlossen gilt. --- ## Self-Review - **Spec coverage:** Bugfix (Task 1), i18n-Entfernung (Task 2), Template-Redesign inkl. Branding/Partial (Task 3), Personalisierung (Task 1), Testing-Strategie laut korrigiertem Spec — Unit-Tests statt e2e/MailDev (Task 1 + 3), manueller Realversand (Task 4) — alles abgedeckt. `.env` explizit als "keine Aktion" markiert (Global Constraints), passend zum korrigierten Spec. - **Placeholder-Scan:** keine TBD/TODO, jeder Step enthält vollständigen Code. - **Typ-Konsistenz:** `MailData<{ hash: string; firstName?: string | null }>` konsistent in `mail.service.ts` (Task 1) und den Aufrufstellen in `auth.service.ts` (Task 1) verwendet; Context-Keys `title`/`year`/`firstName`/`url`/`actionTitle` konsistent zwischen `mail.service.ts` (Task 1) und den Templates (Task 3).