1
0
forked from wrenn/wrenn

Add email activation flow and replace is_active with status column

Email signup now creates inactive users who must activate via a 30-minute
email token before signing in. Team creation is deferred to first login
after activation, while OAuth users continue to get teams immediately.

- Replace boolean is_active with status column (inactive/active/disabled/deleted)
- Add POST /v1/auth/activate endpoint with Redis-backed token consumption
- Signup returns message instead of JWT, sends activation email
- Login differentiates error messages by user status
- Add confirm password field to signup form
- Add /activate frontend page that auto-logs in on success
- Handle inactive user cleanup on re-signup (30-min cooldown) and OAuth collision
This commit is contained in:
2026-04-16 04:05:41 +06:00
parent e8a2217247
commit a3f75300a9
18 changed files with 726 additions and 265 deletions

View File

@ -16,6 +16,10 @@ paths:
summary: Create a new account
operationId: signup
tags: [auth]
description: |
Creates an inactive user account and sends an activation email.
The user must activate their account within 30 minutes.
Does not return a JWT — the user must activate first, then sign in.
requestBody:
required: true
content:
@ -24,11 +28,11 @@ paths:
$ref: "#/components/schemas/SignupRequest"
responses:
"201":
description: Account created
description: Account created, activation email sent
content:
application/json:
schema:
$ref: "#/components/schemas/AuthResponse"
$ref: "#/components/schemas/SignupResponse"
"400":
description: Invalid request (bad email, short password)
content:
@ -36,7 +40,39 @@ paths:
schema:
$ref: "#/components/schemas/Error"
"409":
description: Email already registered
description: Email already registered or signup cooldown active
content:
application/json:
schema:
$ref: "#/components/schemas/Error"
/v1/auth/activate:
post:
summary: Activate account via email token
operationId: activate
tags: [auth]
description: |
Consumes the activation token sent via email and activates the user account.
Creates a default team and returns a JWT to log the user in.
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [token]
properties:
token:
type: string
responses:
"200":
description: Account activated, JWT issued
content:
application/json:
schema:
$ref: "#/components/schemas/AuthResponse"
"400":
description: Invalid or expired token
content:
application/json:
schema:
@ -229,7 +265,7 @@ paths:
security:
- bearerAuth: []
description: |
Soft-deletes the account (sets is_active=false, deleted_at=now).
Soft-deletes the account (sets status=deleted, deleted_at=now).
The account is permanently removed after 15 days. Blocked if the user
owns any team that has other members.
requestBody:
@ -2323,6 +2359,13 @@ components:
password:
type: string
SignupResponse:
type: object
properties:
message:
type: string
description: Confirmation message instructing user to check email
AuthResponse:
type: object
properties: