Files
jungwoo choi f4b75b96a5 feat: Phase 1 - Complete authentication system with JWT
Backend Implementation (FastAPI + MongoDB):
- JWT authentication with access/refresh tokens
- User registration and login endpoints
- Password hashing with bcrypt (fixed 72-byte limit)
- Protected endpoints with JWT middleware
- Token refresh mechanism
- Role-Based Access Control (RBAC) structure
- Pydantic v2 models and async MongoDB with Motor
- API endpoints: /api/auth/register, /api/auth/login, /api/auth/me, /api/auth/refresh

Frontend Implementation (React + TypeScript + Material-UI):
- Login and Register pages with validation
- AuthContext for global authentication state
- API client with Axios interceptors for token refresh
- Protected routes with automatic redirect
- User profile display in navigation
- Logout functionality

Technical Achievements:
- Resolved bcrypt 72-byte limit (replaced passlib with native bcrypt)
- Fixed Pydantic v2 compatibility (PyObjectId, ConfigDict)
- Implemented automatic token refresh on 401 errors
- Created comprehensive test suite for all auth endpoints

Docker & Kubernetes:
- Backend image: yakenator/site11-console-backend:latest
- Frontend image: yakenator/site11-console-frontend:latest
- Deployed to site11-pipeline namespace
- Nginx reverse proxy configuration

Documentation:
- CONSOLE_ARCHITECTURE.md - Complete system architecture
- PHASE1_COMPLETION.md - Detailed completion report
- PROGRESS.md - Updated with Phase 1 status

All authentication endpoints tested and verified working.

🤖 Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-28 16:23:07 +09:00

90 lines
2.6 KiB
Python

from pydantic import BaseModel, EmailStr, Field, ConfigDict
from typing import Optional
class UserRegister(BaseModel):
"""User registration schema"""
email: EmailStr = Field(..., description="User email")
username: str = Field(..., min_length=3, max_length=50, description="Username")
password: str = Field(..., min_length=6, description="Password")
full_name: Optional[str] = Field(None, description="Full name")
model_config = ConfigDict(
json_schema_extra={
"example": {
"email": "user@example.com",
"username": "johndoe",
"password": "securepassword123",
"full_name": "John Doe"
}
}
)
class UserLogin(BaseModel):
"""User login schema"""
username: str = Field(..., description="Username or email")
password: str = Field(..., description="Password")
model_config = ConfigDict(
json_schema_extra={
"example": {
"username": "johndoe",
"password": "securepassword123"
}
}
)
class Token(BaseModel):
"""Token response schema"""
access_token: str = Field(..., description="JWT access token")
refresh_token: Optional[str] = Field(None, description="JWT refresh token")
token_type: str = Field(default="bearer", description="Token type")
model_config = ConfigDict(
json_schema_extra={
"example": {
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer"
}
}
)
class TokenRefresh(BaseModel):
"""Token refresh schema"""
refresh_token: str = Field(..., description="Refresh token")
class UserResponse(BaseModel):
"""User response schema (without password)"""
id: str = Field(..., alias="_id", description="User ID")
email: EmailStr
username: str
full_name: Optional[str] = None
role: str
permissions: list = []
status: str
is_active: bool
created_at: str
last_login_at: Optional[str] = None
model_config = ConfigDict(
populate_by_name=True,
json_schema_extra={
"example": {
"_id": "507f1f77bcf86cd799439011",
"email": "user@example.com",
"username": "johndoe",
"full_name": "John Doe",
"role": "viewer",
"permissions": [],
"status": "active",
"is_active": True,
"created_at": "2024-01-01T00:00:00Z"
}
}
)