from datetime import datetime from typing import Optional from pydantic import BaseModel, Field, field_validator # === Request 스키마 === class CategoryCreate(BaseModel): """카테고리 생성 요청 (F-007)""" name: str = Field(..., min_length=1, max_length=50) color: str = Field("#6B7280", pattern=r"^#[0-9A-Fa-f]{6}$") @field_validator("name") @classmethod def name_not_blank(cls, v: str) -> str: v = v.strip() if not v: raise ValueError("카테고리 이름은 공백만으로 구성할 수 없습니다") return v class CategoryUpdate(BaseModel): """카테고리 수정 요청 (F-009) - Partial Update""" name: Optional[str] = Field(None, min_length=1, max_length=50) color: Optional[str] = Field(None, pattern=r"^#[0-9A-Fa-f]{6}$") order: Optional[int] = Field(None, ge=0) @field_validator("name") @classmethod def name_not_blank(cls, v: Optional[str]) -> Optional[str]: if v is not None: v = v.strip() if not v: raise ValueError("카테고리 이름은 공백만으로 구성할 수 없습니다") return v # === Response 스키마 === class CategoryResponse(BaseModel): """카테고리 응답 (F-008)""" id: str name: str color: str order: int todo_count: int = 0 created_at: datetime