Database Migrations:
- Alembic configuration and env.py
- Initial schema migration (001_initial_schema.py) with all 25 entities
- Support for all 7 MVPs + authentication + compliance
- Ready to run: alembic upgrade head
Authentication System:
- Registration/login endpoints with Argon2 password hashing
- JWT token generation and refresh token rotation
- Account lockout protection (5 failed attempts)
- Token refresh with automatic rotation
- Logout with token invalidation
- Audit logging for all auth events
- Pydantic schemas for validation
- Email-based account enumeration prevention
Frontend Scaffolding:
Web (Next.js 14):
- TypeScript configuration
- Next.js App Router setup
- Tailwind CSS configured
- API client setup (Axios + React Query)
- Zustand for state management
- Directory structure for all 7 MVPs
- Layout and navigation stubs
- Responsive design ready
Mobile (React Native/Expo):
- Expo 51+ configuration
- TypeScript setup
- Expo Router for navigation
- Tab-based navigation structure
- All 7 MVP screens scaffolded
- iOS and Android support
- Accessibility components ready
Project Status:
- Backend: 85% complete (foundation + auth + migrations)
- Web: 10% complete (scaffolding only)
- Mobile: 10% complete (scaffolding only)
- Tests: Not yet implemented
All code follows OpenSpec standards and design system guidelines.
Job ID: MTAD-IMPL-2025-11-18-CL
🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
88 lines
1.9 KiB
Python
88 lines
1.9 KiB
Python
"""Authentication schemas. Job ID: MTAD-IMPL-2025-11-18-CL"""
|
|
|
|
from pydantic import BaseModel, EmailStr, Field
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
|
|
|
|
class UserRegisterRequest(BaseModel):
|
|
"""User registration request."""
|
|
email: EmailStr
|
|
password: str = Field(..., min_length=8, max_length=128)
|
|
display_name: str = Field(..., min_length=2, max_length=255)
|
|
|
|
|
|
class UserRegisterResponse(BaseModel):
|
|
"""User registration response."""
|
|
id: str
|
|
email: str
|
|
display_name: str
|
|
created_at: datetime
|
|
|
|
|
|
class UserLoginRequest(BaseModel):
|
|
"""User login request."""
|
|
email: EmailStr
|
|
password: str
|
|
|
|
|
|
class TokenResponse(BaseModel):
|
|
"""Token response."""
|
|
access_token: str
|
|
refresh_token: str
|
|
token_type: str = "bearer"
|
|
expires_in: int = 900 # 15 minutes
|
|
|
|
|
|
class RefreshTokenRequest(BaseModel):
|
|
"""Refresh token request."""
|
|
refresh_token: str
|
|
|
|
|
|
class UserResponse(BaseModel):
|
|
"""User response."""
|
|
id: str
|
|
email: str
|
|
email_verified: bool
|
|
mfa_enabled: bool
|
|
created_at: datetime
|
|
|
|
|
|
class ProfileResponse(BaseModel):
|
|
"""User profile response."""
|
|
id: str
|
|
user_id: str
|
|
display_name: str
|
|
pseudonym: Optional[str] = None
|
|
pronouns: Optional[str] = None
|
|
bio: Optional[str] = None
|
|
avatar_url: Optional[str] = None
|
|
|
|
|
|
class PasswordResetRequest(BaseModel):
|
|
"""Password reset request."""
|
|
email: EmailStr
|
|
|
|
|
|
class PasswordResetConfirm(BaseModel):
|
|
"""Password reset confirmation."""
|
|
token: str
|
|
new_password: str = Field(..., min_length=8, max_length=128)
|
|
|
|
|
|
class MFASetupResponse(BaseModel):
|
|
"""MFA setup response with QR code."""
|
|
secret: str
|
|
qr_code: str
|
|
backup_codes: list[str]
|
|
|
|
|
|
class MFAVerifyRequest(BaseModel):
|
|
"""MFA verification request."""
|
|
code: str = Field(..., min_length=6, max_length=6)
|
|
|
|
|
|
class ErrorResponse(BaseModel):
|
|
"""Error response."""
|
|
detail: str
|
|
status_code: int
|