feat: FASE 1 - Backend Core (modelli, auth, API)

Implementazione completa del backend FastAPI:
- Modelli SQLAlchemy: User, Recipe, RecipeVersion, RecipeTask,
  RecipeSubtask, Measurement, AccessLog, SystemSetting, RecipeVersionAudit
- Schemas Pydantic v2 per tutti i CRUD + statistiche SPC
- Middleware: API Key auth (X-API-Key) con role checking + access logging
- Router: auth, users, recipes, tasks, measurements, files, settings
- Services: auth (bcrypt+secrets), recipe (copy-on-write versioning),
  measurement (auto pass/fail con UTL/UWL/LWL/LTL)
- Alembic env.py con import modelli attivi
- Fix architect review: no double-commit, recipe_id subquery filter,
  user_id in access logs, type annotations corrette

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Adriano
2026-02-07 00:40:50 +01:00
parent 76be6f5ac4
commit d6508e0ae8
28 changed files with 2942 additions and 7 deletions
+65
View File
@@ -0,0 +1,65 @@
"""Pydantic schemas for User operations."""
from datetime import datetime
from typing import Optional
from pydantic import BaseModel, ConfigDict, Field
class UserCreate(BaseModel):
"""Schema for creating a new user."""
username: str = Field(..., min_length=3, max_length=100)
password: str = Field(..., min_length=6, max_length=128)
email: Optional[str] = Field(None, max_length=255)
display_name: str = Field(..., min_length=1, max_length=255)
roles: list[str] = Field(default_factory=list)
is_admin: bool = False
language_pref: str = Field("it", pattern="^(it|en)$")
theme_pref: str = Field("light", pattern="^(light|dark)$")
class UserUpdate(BaseModel):
"""Schema for updating a user (admin)."""
email: Optional[str] = Field(None, max_length=255)
display_name: Optional[str] = Field(None, min_length=1, max_length=255)
roles: Optional[list[str]] = None
is_admin: Optional[bool] = None
active: Optional[bool] = None
language_pref: Optional[str] = Field(None, pattern="^(it|en)$")
theme_pref: Optional[str] = Field(None, pattern="^(light|dark)$")
class UserProfileUpdate(BaseModel):
"""Schema for user self-update (profile)."""
display_name: Optional[str] = Field(None, min_length=1, max_length=255)
language_pref: Optional[str] = Field(None, pattern="^(it|en)$")
theme_pref: Optional[str] = Field(None, pattern="^(light|dark)$")
class UserResponse(BaseModel):
"""Schema for user response."""
model_config = ConfigDict(from_attributes=True)
id: int
username: str
email: Optional[str] = None
display_name: str
roles: list[str]
is_admin: bool
language_pref: str
theme_pref: str
active: bool
created_at: datetime
last_login: Optional[datetime] = None
class LoginRequest(BaseModel):
"""Schema for login request."""
username: str
password: str
class LoginResponse(BaseModel):
"""Schema for login response."""
user: UserResponse
api_key: str
message: str = "Login successful"