---
id: T01
parent: S02
milestone: M019
provides: []
requires: []
affects: []
key_files: ["backend/models.py", "backend/auth.py", "backend/schemas.py", "backend/requirements.txt", "alembic/versions/016_add_users_and_invite_codes.py"]
key_decisions: ["24-hour JWT expiry with HS256 using existing app_secret_key", "OAuth2PasswordBearer tokenUrl /api/v1/auth/login for T02 router", "User.creator_id FK uses SET NULL on delete"]
patterns_established: []
drill_down_paths: []
observability_surfaces: []
duration: ""
verification_result: "All slice verification checks pass: model imports OK, auth utility imports OK, schema imports OK, migration file contains users and invite_codes. Additional integration test verified password roundtrip, JWT roundtrip, expired token rejection, and garbage token rejection."
completed_at: 2026-04-03T21:46:54.281Z
blocker_discovered: false
---

# T01: Added User/InviteCode models, Alembic migration 016, auth utilities (bcrypt hashing, JWT, FastAPI dependencies), and Pydantic auth schemas

> Added User/InviteCode models, Alembic migration 016, auth utilities (bcrypt hashing, JWT, FastAPI dependencies), and Pydantic auth schemas

## What Happened
---
id: T01
parent: S02
milestone: M019
key_files:
  - backend/models.py
  - backend/auth.py
  - backend/schemas.py
  - backend/requirements.txt
  - alembic/versions/016_add_users_and_invite_codes.py
key_decisions:
  - 24-hour JWT expiry with HS256 using existing app_secret_key
  - OAuth2PasswordBearer tokenUrl /api/v1/auth/login for T02 router
  - User.creator_id FK uses SET NULL on delete
duration: ""
verification_result: passed
completed_at: 2026-04-03T21:46:54.282Z
blocker_discovered: false
---

# T01: Added User/InviteCode models, Alembic migration 016, auth utilities (bcrypt hashing, JWT, FastAPI dependencies), and Pydantic auth schemas

**Added User/InviteCode models, Alembic migration 016, auth utilities (bcrypt hashing, JWT, FastAPI dependencies), and Pydantic auth schemas**

## What Happened

Added PyJWT and passlib[bcrypt] to requirements.txt. Created UserRole enum and two new models: User (email, hashed_password, display_name, role, creator_id FK, is_active) and InviteCode (code, uses_remaining, created_by FK, expires_at). Added five Pydantic schemas for auth flows. Created backend/auth.py with password hashing, JWT encode/decode, get_current_user dependency, and require_role factory. Wrote Alembic migration 016 creating both tables with constraints and user_role enum.

## Verification

All slice verification checks pass: model imports OK, auth utility imports OK, schema imports OK, migration file contains users and invite_codes. Additional integration test verified password roundtrip, JWT roundtrip, expired token rejection, and garbage token rejection.

## Verification Evidence

| # | Command | Exit Code | Verdict | Duration |
|---|---------|-----------|---------|----------|
| 1 | `cd backend && python -c "from models import User, InviteCode, UserRole; print('Models OK')"` | 0 | ✅ pass | 500ms |
| 2 | `cd backend && python -c "from auth import hash_password, verify_password, create_access_token, decode_access_token; print('Auth OK')"` | 0 | ✅ pass | 500ms |
| 3 | `cd backend && python -c "from schemas import RegisterRequest, LoginRequest, TokenResponse, UserResponse, UpdateProfileRequest; print('Schemas OK')"` | 0 | ✅ pass | 500ms |
| 4 | `grep -l 'users|invite_codes' alembic/versions/016_add_users_and_invite_codes.py` | 0 | ✅ pass | 100ms |
| 5 | `cd backend && python -c "(auth function integration tests)"` | 0 | ✅ pass | 800ms |


## Deviations

Alembic migration written manually (no live DB for autogenerate). Added Boolean import to models.py.

## Known Issues

None.

## Files Created/Modified

- `backend/models.py`
- `backend/auth.py`
- `backend/schemas.py`
- `backend/requirements.txt`
- `alembic/versions/016_add_users_and_invite_codes.py`


## Deviations
Alembic migration written manually (no live DB for autogenerate). Added Boolean import to models.py.

## Known Issues
None.
