Files
erp-nutzfahrzeuge/backend/app/schemas/user.py
T
Leopoldadmin d89304845a feat(T01): auth + user management + RBAC + base frontend + i18n
- Backend: FastAPI, JWT auth (HS256), bcrypt, RBAC middleware
- User CRUD (admin-only), soft-delete, pagination
- Pydantic BaseSettings config, async SQLAlchemy 2.0
- 50 backend tests, 88% coverage
- Frontend: Next.js 14 App Router, Tailwind, design tokens
- Login page, auth context, API client with auto-refresh
- i18n: next-intl, DE/EN (31 keys each)
- 6 base UI components (Button, Input, Card, Table, Modal, Toast)
- 12 frontend tests, npm build success
2026-07-14 11:51:32 +02:00

81 lines
2.1 KiB
Python

"""Pydantic schemas for user-related request and response bodies."""
import uuid
from datetime import datetime
from typing import Literal, Optional
from pydantic import BaseModel, ConfigDict, EmailStr, Field
class LoginRequest(BaseModel):
"""POST /api/v1/auth/login request body."""
email: EmailStr
password: str = Field(..., min_length=1)
class TokenResponse(BaseModel):
"""JWT token pair returned after login or refresh."""
access_token: str
refresh_token: str
token_type: str = "bearer"
expires_in: int = Field(..., description="Access token TTL in seconds")
class RefreshRequest(BaseModel):
"""POST /api/v1/auth/refresh request body."""
refresh_token: str
class UserBase(BaseModel):
"""Base user fields shared across schemas."""
email: EmailStr
full_name: str = Field(..., min_length=1, max_length=200)
role: Literal["admin", "verkaeufer", "buchhaltung"] = "verkaeufer"
language: str = Field(default="de", max_length=5)
class UserCreate(UserBase):
"""POST /api/v1/users request body."""
password: str = Field(..., min_length=8, max_length=128)
class UserUpdate(BaseModel):
"""PUT /api/v1/users/:id request body (all fields optional)."""
email: Optional[EmailStr] = None
full_name: Optional[str] = Field(None, min_length=1, max_length=200)
role: Optional[Literal["admin", "verkaeufer", "buchhaltung"]] = None
language: Optional[str] = Field(None, max_length=5)
is_active: Optional[bool] = None
class UserResponse(BaseModel):
"""User response schema (never exposes password_hash)."""
model_config = ConfigDict(from_attributes=True)
id: uuid.UUID
email: str
full_name: str
role: str
language: str
is_active: bool
created_at: Optional[datetime] = None
updated_at: Optional[datetime] = None
class UserListResponse(BaseModel):
"""Paginated user list response."""
items: list[UserResponse]
total: int
page: int
page_size: int
class ErrorResponse(BaseModel):
"""Standard error response format."""
error: dict
class HealthResponse(BaseModel):
"""Health check response."""
status: str = "ok"