"""Request and response shapes for templates and the shipped catalog.""" import uuid from typing import Any from pydantic import BaseModel from app.authoring.schema import AuthoringTemplate class TemplateSummary(BaseModel): id: uuid.UUID # The blueprint id from the config (e.g. "onboarding-basis"): stable across # installs, where the row id is not. Anything that wants to offer ONE known # blueprint (the profile page's "write about yourself") finds it by this. config_id: str name: str version: str description: str = "" class TemplateDetail(TemplateSummary): config: dict[str, Any] # The editable source. Serialized server-side because the frontend has # no YAML library and must not gain one. yaml: str class CatalogSummary(BaseModel): """A blueprint on disk. `id` is the config id, NOT a row id — a catalog entry has no row until someone adds it.""" id: str name: str description: str # How many skeleton sections the blueprint carries hints for. sections: int # Whether a template with this config id already exists, so the UI can # offer "View" instead of a second "Add". added: bool class CatalogDetail(CatalogSummary): yaml: str class TemplateImportRequest(BaseModel): yaml: str class TemplateBuildRequest(BaseModel): """A template assembled by the form builder. The config is the same schema a pasted YAML parses into, so both paths get one validation guarantee — the frontend has no YAML library and must not gain one, so it sends the structured config instead of serializing it.""" # The row to update, or null to create a new template. Kept separate from # the config id (a stable slug) so renaming the display name never forks # the row. template_id: uuid.UUID | None = None config: AuthoringTemplate