Files
patrickandClaude Sonnet 5 5c2e09b36d feat: admin-triggered password reset for members
Org admins can now trigger a password reset for a member from the
members list dropdown, without ever seeing or setting the password
themselves — POST /api/members/:memberId/reset-password sends the
same reset-link email the self-service /forgot-password flow uses.

Extracted the shared token-generation + email logic into
lib/password-reset.ts so both flows use one implementation. Returns
409 member_has_no_account for members who never accepted their
invitation (no linked login account to reset).

Verified end-to-end on talkhub: admin trigger sends the mail (SMTP
not configured in this test env, confirmed via the mail service's
own log fallback), non-admin gets 403.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0143yYvjesjHndBACoweyK67
2026-09-11 23:52:17 +02:00

2.4 KiB

PROJ-1: Auth (Login/Logout/Session)

Status: Deployed Created: 2026-09-11 (retro-dokumentiert, tatsächlich gebaut in commit 5e6ee2c)

Summary

E-Mail/Passwort-Auth mit JWT-Session für TalkTime. Grundlage für alle geschützten Routen.

Built

  • backend/src/routes/auth.ts — Register/Login, bcrypt-Hash, JWT-Ausgabe, Rate-Limit auf Auth-Endpunkten
  • backend/src/types.d.ts — JWT-Payload-Typisierung (FastifyJWT)
  • frontend/src/components/auth/LoginForm.tsx, RegisterForm.tsx
  • frontend/src/pages/LoginPage.tsx, RegisterPage.tsx
  • frontend/src/lib/auth-context.tsx — Session-State im Frontend
  • frontend/src/routes/ProtectedRoute.tsx — Redirect bei fehlender Session
  • Nachtrag 2026-09-11 (commit bc4d749): Passwort-Reset — backend/src/db/schema.ts (password_reset_tokens-Tabelle, 60min TTL, single-use), POST /api/auth/forgot-password + POST /api/auth/reset-password/:token in backend/src/routes/auth.ts, Mail-Versand über bestehenden services/mail.ts; Frontend: ForgotPasswordForm.tsx/ResetPasswordForm.tsx, ForgotPasswordPage.tsx/ResetPasswordPage.tsx, Link im LoginForm.tsx
  • Nachtrag 2026-09-11 (Admin-Trigger): Reset-Mail-Logik nach backend/src/lib/password-reset.ts extrahiert (sendPasswordResetEmail), genutzt von forgot-password und neu von POST /api/members/:memberId/reset-password (PROJ-3) — Admin kann für ein Mitglied einen Reset auslösen, sieht/setzt aber nie selbst das Passwort. Live verifiziert: Admin löst Reset aus (Mail-Log bestätigt Versandversuch), Non-Admin bekommt 403.

Acceptance Criteria

  • Registrierung mit E-Mail + Passwort, Passwort gehasht (bcrypt, Cost 12)
  • Login liefert JWT, generische Fehlermeldung bei falschen Zugangsdaten (kein User-Enumeration-Leak)
  • Geschützte Frontend-Routen leiten unauthentifizierte Nutzer zum Login um
  • Geschützte Backend-Routen verifizieren JWT via request.jwtVerify()
  • Passwort-Reset per E-Mail-Link, Token läuft nach 60min ab, einmalig verwendbar
  • forgot-password antwortet immer generisch, unabhängig davon ob die E-Mail registriert ist (kein Enumeration-Leak)

Open Items

  • E-Mail-Verification laut PRD P1 noch offen

Notes

Retro-Spec: Feature war bereits produktiv im Code, INDEX.md/Spec wurden nachträglich nachgezogen. Passwort-Reset am 2026-09-11 nachgebaut und getestet auf talkhub-LXC (192.168.66.8).