"""Theme & layout engine DTOs — Phase 11.3.""" from __future__ import annotations from datetime import datetime from uuid import UUID from pydantic import BaseModel, ConfigDict, Field from app.models.types import ( DirectionMode, LayoutKind, LayoutStatus, LayoutVersionStatus, ThemeStatus, ThemeVersionStatus, ) from app.schemas.common import ORMBase _FORBID = ConfigDict(extra="forbid") # --- Themes --- class ExperienceThemeCreate(BaseModel): model_config = _FORBID workspace_id: UUID code: str = Field(max_length=50) name: str = Field(max_length=255) description: str | None = None status: ThemeStatus = ThemeStatus.DRAFT direction_mode: DirectionMode = DirectionMode.BOTH category: str | None = Field(default=None, max_length=100) tags: list[str] | None = None metadata_json: dict | None = None class ExperienceThemeUpdate(BaseModel): model_config = _FORBID name: str | None = Field(default=None, max_length=255) description: str | None = None status: ThemeStatus | None = None direction_mode: DirectionMode | None = None category: str | None = Field(default=None, max_length=100) tags: list[str] | None = None metadata_json: dict | None = None version: int = Field(ge=1) class ExperienceThemeRead(ORMBase): id: UUID tenant_id: UUID workspace_id: UUID code: str name: str description: str | None status: ThemeStatus direction_mode: DirectionMode category: str | None tags: list | None latest_version_number: int published_version_id: UUID | None is_system: bool metadata_json: dict | None version: int is_deleted: bool created_by: str | None updated_by: str | None created_at: datetime updated_at: datetime class ExperienceThemeListResponse(BaseModel): items: list[ExperienceThemeRead] total: int page: int page_size: int # --- Theme Versions --- class ExperienceThemeVersionCreate(BaseModel): model_config = _FORBID workspace_id: UUID theme_id: UUID tokens: dict | None = None brand_shell: dict | None = None direction_mode: DirectionMode | None = None changelog: str | None = None metadata_json: dict | None = None class ExperienceThemeVersionUpdate(BaseModel): model_config = _FORBID tokens: dict | None = None brand_shell: dict | None = None direction_mode: DirectionMode | None = None changelog: str | None = None metadata_json: dict | None = None version: int = Field(ge=1) class ExperienceThemeVersionRead(ORMBase): id: UUID tenant_id: UUID workspace_id: UUID theme_id: UUID version_number: int status: ThemeVersionStatus tokens: dict | None brand_shell: dict | None direction_mode: DirectionMode | None changelog: str | None is_immutable: bool published_at: datetime | None retired_at: datetime | None metadata_json: dict | None version: int is_deleted: bool created_by: str | None updated_by: str | None created_at: datetime updated_at: datetime class ExperienceThemeVersionListResponse(BaseModel): items: list[ExperienceThemeVersionRead] total: int page: int page_size: int # --- Layouts --- class ExperienceLayoutCreate(BaseModel): model_config = _FORBID workspace_id: UUID code: str = Field(max_length=50) name: str = Field(max_length=255) description: str | None = None kind: LayoutKind = LayoutKind.PAGE_SHELL status: LayoutStatus = LayoutStatus.DRAFT direction_mode: DirectionMode = DirectionMode.BOTH category: str | None = Field(default=None, max_length=100) tags: list[str] | None = None metadata_json: dict | None = None class ExperienceLayoutUpdate(BaseModel): model_config = _FORBID name: str | None = Field(default=None, max_length=255) description: str | None = None kind: LayoutKind | None = None status: LayoutStatus | None = None direction_mode: DirectionMode | None = None category: str | None = Field(default=None, max_length=100) tags: list[str] | None = None metadata_json: dict | None = None version: int = Field(ge=1) class ExperienceLayoutRead(ORMBase): id: UUID tenant_id: UUID workspace_id: UUID code: str name: str description: str | None kind: LayoutKind status: LayoutStatus direction_mode: DirectionMode category: str | None tags: list | None latest_version_number: int published_version_id: UUID | None is_system: bool metadata_json: dict | None version: int is_deleted: bool created_by: str | None updated_by: str | None created_at: datetime updated_at: datetime class ExperienceLayoutListResponse(BaseModel): items: list[ExperienceLayoutRead] total: int page: int page_size: int # --- Layout Versions --- class ExperienceLayoutVersionCreate(BaseModel): model_config = _FORBID workspace_id: UUID layout_id: UUID regions: list[dict] | None = None structure_shell: dict | None = None changelog: str | None = None metadata_json: dict | None = None class ExperienceLayoutVersionUpdate(BaseModel): model_config = _FORBID regions: list[dict] | None = None structure_shell: dict | None = None changelog: str | None = None metadata_json: dict | None = None version: int = Field(ge=1) class ExperienceLayoutVersionRead(ORMBase): id: UUID tenant_id: UUID workspace_id: UUID layout_id: UUID version_number: int status: LayoutVersionStatus regions: list | None structure_shell: dict | None changelog: str | None is_immutable: bool published_at: datetime | None retired_at: datetime | None metadata_json: dict | None version: int is_deleted: bool created_by: str | None updated_by: str | None created_at: datetime updated_at: datetime class ExperienceLayoutVersionListResponse(BaseModel): items: list[ExperienceLayoutVersionRead] total: int page: int page_size: int # --- Site Theme Bindings --- class SiteThemeBindingCreate(BaseModel): model_config = _FORBID workspace_id: UUID site_id: UUID theme_id: UUID theme_version_id: UUID metadata_json: dict | None = None class SiteThemeBindingUpdate(BaseModel): model_config = _FORBID metadata_json: dict | None = None version: int = Field(ge=1) class SiteThemeBindingRead(ORMBase): id: UUID tenant_id: UUID workspace_id: UUID site_id: UUID theme_id: UUID theme_version_id: UUID is_active: bool metadata_json: dict | None version: int is_deleted: bool created_by: str | None updated_by: str | None created_at: datetime updated_at: datetime class SiteThemeBindingListResponse(BaseModel): items: list[SiteThemeBindingRead] total: int page: int page_size: int # --- Page Layout Bindings --- class PageLayoutBindingCreate(BaseModel): model_config = _FORBID workspace_id: UUID site_id: UUID page_id: UUID layout_id: UUID layout_version_id: UUID metadata_json: dict | None = None class PageLayoutBindingUpdate(BaseModel): model_config = _FORBID metadata_json: dict | None = None version: int = Field(ge=1) class PageLayoutBindingRead(ORMBase): id: UUID tenant_id: UUID workspace_id: UUID site_id: UUID page_id: UUID layout_id: UUID layout_version_id: UUID is_active: bool metadata_json: dict | None version: int is_deleted: bool created_by: str | None updated_by: str | None created_at: datetime updated_at: datetime class PageLayoutBindingListResponse(BaseModel): items: list[PageLayoutBindingRead] total: int page: int page_size: int