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:
@@ -0,0 +1,85 @@
|
||||
"""Pydantic schemas for RecipeTask and RecipeSubtask operations."""
|
||||
from typing import Any, Optional
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field
|
||||
|
||||
|
||||
class SubtaskCreate(BaseModel):
|
||||
"""Schema for creating a subtask."""
|
||||
marker_number: int = Field(..., ge=1)
|
||||
description: str = Field(..., min_length=1, max_length=500)
|
||||
measurement_type: Optional[str] = Field(None, max_length=100)
|
||||
nominal: Optional[float] = None
|
||||
utl: Optional[float] = None
|
||||
uwl: Optional[float] = None
|
||||
lwl: Optional[float] = None
|
||||
ltl: Optional[float] = None
|
||||
unit: str = Field("mm", max_length=20)
|
||||
|
||||
|
||||
class SubtaskUpdate(BaseModel):
|
||||
"""Schema for updating a subtask."""
|
||||
description: Optional[str] = Field(None, min_length=1, max_length=500)
|
||||
measurement_type: Optional[str] = Field(None, max_length=100)
|
||||
nominal: Optional[float] = None
|
||||
utl: Optional[float] = None
|
||||
uwl: Optional[float] = None
|
||||
lwl: Optional[float] = None
|
||||
ltl: Optional[float] = None
|
||||
unit: Optional[str] = Field(None, max_length=20)
|
||||
|
||||
|
||||
class SubtaskResponse(BaseModel):
|
||||
"""Schema for subtask response."""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
task_id: int
|
||||
marker_number: int
|
||||
description: str
|
||||
measurement_type: Optional[str] = None
|
||||
nominal: Optional[float] = None
|
||||
utl: Optional[float] = None
|
||||
uwl: Optional[float] = None
|
||||
lwl: Optional[float] = None
|
||||
ltl: Optional[float] = None
|
||||
unit: str
|
||||
|
||||
|
||||
class TaskCreate(BaseModel):
|
||||
"""Schema for creating a task."""
|
||||
title: str = Field(..., min_length=1, max_length=255)
|
||||
directive: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
file_type: Optional[str] = Field(None, pattern="^(image|pdf)$")
|
||||
annotations_json: Optional[dict[str, Any]] = None
|
||||
subtasks: list[SubtaskCreate] = []
|
||||
|
||||
|
||||
class TaskUpdate(BaseModel):
|
||||
"""Schema for updating a task."""
|
||||
title: Optional[str] = Field(None, min_length=1, max_length=255)
|
||||
directive: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
annotations_json: Optional[dict[str, Any]] = None
|
||||
|
||||
|
||||
class TaskResponse(BaseModel):
|
||||
"""Schema for task response."""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
id: int
|
||||
version_id: int
|
||||
order_index: int
|
||||
title: str
|
||||
directive: Optional[str] = None
|
||||
description: Optional[str] = None
|
||||
file_path: Optional[str] = None
|
||||
file_type: Optional[str] = None
|
||||
annotations_json: Optional[dict[str, Any]] = None
|
||||
subtasks: list[SubtaskResponse] = []
|
||||
|
||||
|
||||
class TaskReorderRequest(BaseModel):
|
||||
"""Schema for reordering tasks."""
|
||||
task_ids: list[int] = Field(..., min_length=1)
|
||||
Reference in New Issue
Block a user