from pydantic import BaseModel, ConfigDict, Field from datetime import datetime, date from typing import Optional, List, Literal from app.schemas.task_comment import TaskCommentResponse from app.schemas.project_task_assignment import TaskAssignmentResponse TaskStatus = Literal["pending", "in_progress", "completed", "blocked", "review", "on_hold"] TaskPriority = Literal["none", "low", "medium", "high"] class ProjectTaskCreate(BaseModel): model_config = ConfigDict(extra="forbid") title: str = Field(min_length=1, max_length=255) description: Optional[str] = Field(None, max_length=5000) status: TaskStatus = "pending" priority: TaskPriority = "medium" due_date: Optional[date] = None person_id: Optional[int] = None sort_order: int = 0 parent_task_id: Optional[int] = None class ProjectTaskUpdate(BaseModel): model_config = ConfigDict(extra="forbid") title: Optional[str] = Field(None, min_length=1, max_length=255) description: Optional[str] = Field(None, max_length=5000) status: Optional[TaskStatus] = None priority: Optional[TaskPriority] = None due_date: Optional[date] = None person_id: Optional[int] = None sort_order: Optional[int] = None version: Optional[int] = None # For optimistic locking class ProjectTaskResponse(BaseModel): id: int project_id: int parent_task_id: Optional[int] = None title: str description: Optional[str] status: str priority: str due_date: Optional[date] person_id: Optional[int] sort_order: int version: int = 1 created_at: datetime updated_at: datetime subtasks: List["ProjectTaskResponse"] = [] comments: List[TaskCommentResponse] = [] assignments: List[TaskAssignmentResponse] = [] model_config = ConfigDict(from_attributes=True) ProjectTaskResponse.model_rebuild()