Add an email-based "forgot password" flow:
- PasswordResetToken model (stores only a SHA-256 hash, single-use, TTL)
and migration 27 for the password_reset_tokens table.
- POST /api/auth/forgot-password — generic response (no account
enumeration), 60s throttle, emails a one-time reset link via the
existing EmailChannel as a background task.
- GET /api/auth/reset-password/validate — token validity check for the UI.
- POST /api/auth/reset-password — validates the token, enforces the
password policy, sets the new password, clears lock state, invalidates
outstanding tokens and terminates all sessions.
- Configurable link lifetime via PASSWORD_RESET_TOKEN_EXPIRE_MINUTES (30m).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>