"""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"