DESCRIPTION
apps/api/src/auth/auth.service.ts only implements login and register — there is no way for a user who forgets their password to recover their account, no way to change the email on file, and no way for an admin to deactivate a compromised or fraudulent account. This epic closes the account-lifecycle gap using Supabase Auth's existing primitives, and logs every lifecycle event the same way the rest of the platform already does via AuditService.
GOAL
Users can recover a forgotten password and change their email through a real flow; admins can deactivate/reactivate an account; every auth lifecycle event (reset requested, reset completed, email changed, deactivated, reactivated) is audit-logged; and auth endpoints are rate-limited against abuse.
REQUIREMENTS
POST /auth/forgot-password — triggers Supabase's resetPasswordForEmail recovery flow (never reveal whether an email exists).
POST /auth/reset-password — completes the reset using the Supabase recovery token, sets the new password.
POST /auth/change-email (authenticated) — starts Supabase's email-change confirmation flow.
PATCH /users/:id/deactivate and PATCH /users/:id/reactivate (admin only, mirroring the admin-only pattern already used in UsersService.setRole) — soft-disable/enable an account (block login while deactivated).
- Emit an audit event for every lifecycle action above via the existing
AuditService.emit() pattern (see apps/api/src/audit/), the same way other modules already do.
- Basic rate limiting on
login, forgot-password, and register to prevent credential-stuffing/abuse (reuse @nestjs/throttler if already present, or add it scoped to these endpoints only).
ACCEPTANCE CRITERIA
- Forgot/reset-password flow works end-to-end against a local Supabase instance (or mocked
SupabaseService, per apps/api/src/**/*.service.spec.ts), including the "don't leak whether the email exists" behavior.
- Deactivated users cannot log in; reactivation restores access; both are admin-only and audited.
- Every new endpoint has a unit test mocking
SupabaseService — no real VELAR database or credentials required.
npm run build, npm run lint, npm run test pass in apps/api with NO VELAR credentials.
docs/BACKEND.md updated with the new endpoints and the audit events they emit.
NOTES
Relevant files: apps/api/src/auth/auth.service.ts, apps/api/src/auth/auth.controller.ts, apps/api/src/users/users.service.ts, apps/api/src/users/users.controller.ts, apps/api/src/audit/audit.service.ts (reuse, don't reinvent), packages/types/src/ (add request/response types for the new endpoints). Do not touch supabase/migrations/ schema beyond what Supabase Auth already provides — no new tables required for this scope. EXTEND auth/users, don't rewrite existing login/register logic (docs/AGENTS.md §3).
No VELAR credentials required: verifiable locally with a mocked SupabaseService — no real database, passwords, or service_role key.
Difficulty: Advanced
Priority: High
PR REQUIREMENTS
- Ship this as a single pull request — do not split into stacked/sequential PRs.
- Your PR description must include
Closes #<this-issue-number> (this issue's GitHub number) so merging auto-closes it.
CAMPAIGN REQUIREMENTS (FWC26)
To be eligible for the reward on this issue, the contributor must:
DESCRIPTION
apps/api/src/auth/auth.service.tsonly implementsloginandregister— there is no way for a user who forgets their password to recover their account, no way to change the email on file, and no way for an admin to deactivate a compromised or fraudulent account. This epic closes the account-lifecycle gap using Supabase Auth's existing primitives, and logs every lifecycle event the same way the rest of the platform already does viaAuditService.GOAL
Users can recover a forgotten password and change their email through a real flow; admins can deactivate/reactivate an account; every auth lifecycle event (reset requested, reset completed, email changed, deactivated, reactivated) is audit-logged; and auth endpoints are rate-limited against abuse.
REQUIREMENTS
POST /auth/forgot-password— triggers Supabase'sresetPasswordForEmailrecovery flow (never reveal whether an email exists).POST /auth/reset-password— completes the reset using the Supabase recovery token, sets the new password.POST /auth/change-email(authenticated) — starts Supabase's email-change confirmation flow.PATCH /users/:id/deactivateandPATCH /users/:id/reactivate(admin only, mirroring theadmin-only pattern already used inUsersService.setRole) — soft-disable/enable an account (block login while deactivated).AuditService.emit()pattern (seeapps/api/src/audit/), the same way other modules already do.login,forgot-password, andregisterto prevent credential-stuffing/abuse (reuse@nestjs/throttlerif already present, or add it scoped to these endpoints only).ACCEPTANCE CRITERIA
SupabaseService, perapps/api/src/**/*.service.spec.ts), including the "don't leak whether the email exists" behavior.SupabaseService— no real VELAR database or credentials required.npm run build,npm run lint,npm run testpass inapps/apiwith NO VELAR credentials.docs/BACKEND.mdupdated with the new endpoints and the audit events they emit.NOTES
Relevant files:
apps/api/src/auth/auth.service.ts,apps/api/src/auth/auth.controller.ts,apps/api/src/users/users.service.ts,apps/api/src/users/users.controller.ts,apps/api/src/audit/audit.service.ts(reuse, don't reinvent),packages/types/src/(add request/response types for the new endpoints). Do not touchsupabase/migrations/schema beyond what Supabase Auth already provides — no new tables required for this scope. EXTENDauth/users, don't rewrite existing login/register logic (docs/AGENTS.md§3).No VELAR credentials required: verifiable locally with a mocked
SupabaseService— no real database, passwords, orservice_rolekey.Difficulty: Advanced
Priority: High
PR REQUIREMENTS
Closes #<this-issue-number>(this issue's GitHub number) so merging auto-closes it.CAMPAIGN REQUIREMENTS (FWC26)
To be eligible for the reward on this issue, the contributor must: