"""Public request/response models for `/v1/domains` (ADR-0008, ADR-0009). `tenant_id` appears in none of these: it comes from the authenticated key, and accepting it from a body would break the isolation boundary (ADR-0002). """ import uuid from datetime import datetime from pydantic import BaseModel, Field, field_validator from src.application.domains.models import DomainResult # Lowercase alphanumerics plus - and _; the key is embedded in every Qdrant # payload and filtered on as a keyword, so it stays boring on purpose. _DOMAIN_PATTERN = r"^[a-z0-9][a-z0-9_-]*$" class DomainResponse(BaseModel): id: uuid.UUID domain: str display_name: str status: str metadata: dict[str, object] created_at: datetime updated_at: datetime @classmethod def from_result(cls, result: DomainResult) -> "DomainResponse": return cls( id=result.id, domain=result.domain, display_name=result.display_name, status=result.status, metadata=result.metadata, created_at=result.created_at, updated_at=result.updated_at, ) class DomainListResponse(BaseModel): domains: list[DomainResponse] class CreateDomainRequest(BaseModel): domain: str = Field(min_length=1, max_length=80, pattern=_DOMAIN_PATTERN) display_name: str = Field(min_length=1, max_length=200) metadata: dict[str, object] = Field(default_factory=dict) @field_validator("domain") @classmethod def _normalize(cls, value: str) -> str: return value.strip() class UpdateDomainRequest(BaseModel): """`domain` is absent by design — the key is immutable. It is denormalized into every point payload and into `source_files`, so renaming it is a migration rather than an edit (ADR-0009). """ display_name: str = Field(min_length=1, max_length=200)