feat(02-03): password reset flow, force-change interceptor, MailModule

- MailModule with SMTP transport configured from ENV variables
- MailService for password reset and welcome emails (plain text, i18n)
- Password reset flow: request-reset (public), reset-password (token-based)
- Change password for logged-in users with current password verification
- Admin reset password endpoint (ADMIN/SUPER_ADMIN only, D-03)
- ForcePasswordChangeInterceptor blocks all routes except change-password,
  logout, me when mustChangePassword=true (D-06, Pitfall 5)
- Frontend: reset-password request page, token reset page, change-password page
- Forgot password link added to login page
- MailHog service added to docker-compose.dev.yml for dev email testing
- SMTP env vars added to docker-compose.yml (defaults to MailHog)
- Complete DE/EN i18n coverage for reset and change password flows
- SUS packages installed: @nestjs-modules/mailer, nodemailer, ldapts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-18 13:48:23 +02:00
parent eaaa9adfa5
commit ac617f4fe5
20 changed files with 4216 additions and 12 deletions
+30
View File
@@ -23,12 +23,42 @@
"password": "Passwort",
"rememberMe": "Angemeldet bleiben",
"submit": "Anmelden",
"forgotPassword": "Passwort vergessen?",
"error": {
"invalidCredentials": "Benutzername oder Passwort ungueltig",
"networkError": "Verbindungsfehler. Bitte versuchen Sie es erneut."
},
"branding": {
"tagline": "Modulare Workflow-Plattform fuer Ihr Unternehmen"
},
"resetPassword": {
"title": "Passwort zuruecksetzen",
"email": "E-Mail-Adresse",
"submit": "Link senden",
"success": "Falls ein Konto mit dieser E-Mail existiert, wurde ein Link zum Zuruecksetzen gesendet.",
"backToLogin": "Zurueck zur Anmeldung",
"newPasswordTitle": "Neues Passwort festlegen",
"newPassword": "Neues Passwort",
"confirmPassword": "Passwort bestaetigen",
"submitReset": "Passwort zuruecksetzen",
"resetSuccess": "Ihr Passwort wurde erfolgreich zurueckgesetzt.",
"redirecting": "Sie werden in wenigen Sekunden zur Anmeldung weitergeleitet...",
"tokenExpired": "Der Link zum Zuruecksetzen ist abgelaufen. Bitte fordern Sie einen neuen an.",
"tokenUsed": "Dieser Link wurde bereits verwendet. Bitte fordern Sie einen neuen an.",
"tokenInvalid": "Der Link zum Zuruecksetzen ist ungueltig.",
"passwordMismatch": "Die Passwoerter stimmen nicht ueberein."
},
"changePassword": {
"title": "Passwort aendern",
"currentPassword": "Aktuelles Passwort",
"newPassword": "Neues Passwort",
"confirmPassword": "Neues Passwort bestaetigen",
"submit": "Passwort aendern",
"success": "Ihr Passwort wurde erfolgreich geaendert.",
"forceChangeNotice": "Aus Sicherheitsgruenden muessen Sie Ihr Passwort aendern, bevor Sie fortfahren koennen.",
"wrongCurrentPassword": "Das aktuelle Passwort ist falsch.",
"networkError": "Verbindungsfehler. Bitte versuchen Sie es erneut.",
"passwordMismatch": "Die Passwoerter stimmen nicht ueberein."
}
},
"header": {