-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Feature: Implement POST /api/v1/auth/signup — User Registration Endpoint
Problem
FluentMeet has no way for new users to register. There is no signup endpoint, no user creation logic, no password hashing, and no email verification flow. Without this, the platform cannot onboard any users and every subsequent authenticated feature (meetings, profiles, settings) remains inaccessible.
Proposed Solution
Implement the POST /api/v1/auth/signup endpoint that accepts user credentials and language preferences, validates the input, hashes the password, persists the user to the database, and triggers an account verification email via Kafka. The new user account starts in an unverified state (is_verified=False) and cannot access protected endpoints until the verification link is clicked.
User Stories
- As a new user, I want to register with my email, password, and language preferences in a single request, so I can get started with FluentMeet quickly.
- As a new user, I want to receive a verification email immediately after signing up, so I know my registration was successful and can activate my account.
- As a developer, I want the signup endpoint to reject duplicate email addresses with a clear error, so users are not confused when they try to register with an email that already exists.
- As a security engineer, I want passwords to be hashed with bcrypt before storage and never logged or returned in any response, so user credentials are protected even in the event of a database breach.
Acceptance Criteria
POST /api/v1/auth/signupaccepts the following JSON body:{ "email": "user@example.com", "password": "MyStr0ngP@ss!", "full_name": "Ada Lovelace", "speaking_language": "en", "listening_language": "fr" }- Input validation (enforced by Pydantic):
email— valid email format; required.password— minimum 8 characters; required.speaking_languageandlistening_language— valid BCP-47 language codes (e.g.,"en","fr","de"); default to"en"if omitted.full_name— optional string, max 255 characters; stripped of leading/trailing whitespace.
- If
emailalready exists in the database, the endpoint returns409 Conflictusing the standard error schema:{ "status": "error", "code": "EMAIL_ALREADY_REGISTERED", "message": "An account with this email already exists.", "details": [] } - The user's password is hashed with bcrypt (via
passlib) before being stored. The plaintext password is never persisted or logged. - A new
Userrecord is created in PostgreSQL withis_active=True,is_verified=False, anddeleted_at=None. - On successful creation, a message is published to the
notifications.emailKafka topic to trigger a verification email (see Email Service issue):{ "to": "user@example.com", "subject": "Verify your FluentMeet account", "template": "verification", "data": { "full_name": "Ada Lovelace", "verification_link": "https://..." } } - The endpoint returns
201 Createdwith the new user's public profile:{ "id": 1, "email": "user@example.com", "full_name": "Ada Lovelace", "speaking_language": "en", "listening_language": "fr", "is_active": true, "is_verified": false, "created_at": "2026-03-14T12:00:00Z" } - The password,
hashed_password, and any internal fields are never included in the response. - The endpoint is rate-limited to 10 requests/minute per IP (see Security & Rate Limiting issue).
- Unit and integration tests cover: successful signup, duplicate email conflict, validation errors, and Kafka message publication.
Proposed Technical Details
- Router:
app/api/v1/endpoints/auth.py— newPOST /signuproute. - Schema:
UserCreate(already inapp/schemas/user.py) —email,password(min 8 chars),full_name,speaking_language,listening_language. - CRUD:
app/crud/user.py—create_user(db, user_in)function; checks for existing email, hashes password viapasslib.context.CryptContext(schemes=["bcrypt"]), inserts record. - Email Trigger:
EmailProducerService.send_email(...)called after successful DB commit; failure to publish to Kafka should not roll back the user creation — it should be logged and retried separately. - Verification Token: A
VerificationTokenrecord is created alongside the user and its value embedded in the verification link (/api/v1/auth/verify-email?token=<uuid>). Token expires after 24 hours. - New/Modified Files:
app/api/v1/endpoints/auth.py[NEW]app/crud/user.py[NEW]app/models/verification_token.py[NEW]app/schemas/auth.py—SignupResponse[NEW]app/api/v1/api.py— register auth router [MODIFY]- Alembic migration for
verification_tokenstable [NEW]
Tasks
- Create
app/crud/user.pywithget_user_by_emailandcreate_userfunctions. - Implement
VerificationTokenSQLAlchemy model inapp/models/verification_token.py. - Generate and apply Alembic migration for
verification_tokenstable. - Implement
POST /api/v1/auth/signupinapp/api/v1/endpoints/auth.py. - Add
ConflictExceptionwith codeEMAIL_ALREADY_REGISTEREDto the signup CRUD logic. - Integrate
EmailProducerServiceto publish verification email after user creation. - Apply
@limiter.limit("10/minute")rate limit decorator to the signup route. - Register the auth router in
app/api/v1/api.py. - Write unit tests for
create_userCRUD (mock DB session). - Write integration tests for the full signup flow (duplicate email, validation errors, successful
201).
Open Questions/Considerations
- Should signup be open to everyone (public), or should we support invite-only registration (requiring a valid invite token)?
- What should happen if the Kafka email publish fails at signup time — silent retry, or notify the user that the verification email will be delayed?
- Should the verification token be a UUID or a signed JWT (which avoids a database lookup on verification)?
- Should we enforce a minimum password strength policy beyond the 8-character minimum (e.g., require numbers and symbols)?