TorbatYar/backend/services/experience/app/schemas/publishing.py
Mortezakoohjani 203671a7bf feat(experience): ship Experience Platform phases 11.0-11.10
Add the experience service with sites through analytics/AI hooks, migrations through 0011, and phase docs/manifests marking the track complete.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-27 11:43:10 +03:30

323 lines
8.3 KiB
Python

"""Publishing / SEO / PWA DTOs — Phase 11.7."""
from __future__ import annotations
from datetime import datetime
from uuid import UUID
from pydantic import BaseModel, ConfigDict, Field
from app.models.types import (
DomainEdgeStatus,
PublishReleaseStatus,
PublishTarget,
PwaStatus,
RobotsStatus,
SeoStatus,
SeoTarget,
SitemapStatus,
)
from app.schemas.common import ORMBase
_FORBID = ConfigDict(extra="forbid")
class PublishReleaseCreate(BaseModel):
model_config = _FORBID
workspace_id: UUID
target_type: PublishTarget
target_id: UUID
notes: str | None = None
metadata_json: dict | None = None
class PublishReleaseUpdate(BaseModel):
model_config = _FORBID
status: PublishReleaseStatus | None = None
notes: str | None = None
error_message: str | None = None
metadata_json: dict | None = None
version: int = Field(ge=1)
class PublishReleaseRead(ORMBase):
id: UUID
tenant_id: UUID
workspace_id: UUID
target_type: PublishTarget
target_id: UUID
status: PublishReleaseStatus
notes: str | None
error_message: str | None
completed_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 PublishReleaseListResponse(BaseModel):
items: list[PublishReleaseRead]
total: int
page: int
page_size: int
class DomainEdgeBindingCreate(BaseModel):
model_config = _FORBID
workspace_id: UUID
site_id: UUID
site_domain_id: UUID
dns_status_ref: str | None = Field(default=None, max_length=255)
ssl_cert_ref: str | None = Field(default=None, max_length=255)
edge_map_ref: str | None = Field(default=None, max_length=255)
status: DomainEdgeStatus = DomainEdgeStatus.PENDING
metadata_json: dict | None = None
class DomainEdgeBindingUpdate(BaseModel):
model_config = _FORBID
status: DomainEdgeStatus | None = None
dns_status_ref: str | None = Field(default=None, max_length=255)
ssl_cert_ref: str | None = Field(default=None, max_length=255)
edge_map_ref: str | None = Field(default=None, max_length=255)
metadata_json: dict | None = None
version: int = Field(ge=1)
class DomainEdgeBindingRead(ORMBase):
id: UUID
tenant_id: UUID
workspace_id: UUID
site_id: UUID
site_domain_id: UUID
host: str
status: DomainEdgeStatus
dns_status_ref: str | None
ssl_cert_ref: str | None
edge_map_ref: str | 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 DomainEdgeBindingListResponse(BaseModel):
items: list[DomainEdgeBindingRead]
total: int
page: int
page_size: int
class SeoMetadataUpsert(BaseModel):
model_config = _FORBID
workspace_id: UUID
target_type: SeoTarget
target_id: UUID
status: SeoStatus = SeoStatus.DRAFT
title: str | None = Field(default=None, max_length=255)
description: str | None = None
canonical_url: str | None = Field(default=None, max_length=500)
robots_directive: str | None = Field(default=None, max_length=100)
og_json: dict | None = None
metadata_json: dict | None = None
version: int | None = Field(default=None, ge=1)
class SeoMetadataUpdate(BaseModel):
model_config = _FORBID
status: SeoStatus | None = None
title: str | None = Field(default=None, max_length=255)
description: str | None = None
canonical_url: str | None = Field(default=None, max_length=500)
robots_directive: str | None = Field(default=None, max_length=100)
og_json: dict | None = None
metadata_json: dict | None = None
version: int = Field(ge=1)
class SeoMetadataRead(ORMBase):
id: UUID
tenant_id: UUID
workspace_id: UUID
target_type: SeoTarget
target_id: UUID
status: SeoStatus
title: str | None
description: str | None
canonical_url: str | None
robots_directive: str | None
og_json: dict | 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 SeoMetadataListResponse(BaseModel):
items: list[SeoMetadataRead]
total: int
page: int
page_size: int
class SitemapShellUpsert(BaseModel):
model_config = _FORBID
workspace_id: UUID
site_id: UUID
status: SitemapStatus = SitemapStatus.DRAFT
entries_json: dict | None = None
storage_file_ref: str | None = Field(default=None, max_length=255)
metadata_json: dict | None = None
version: int | None = Field(default=None, ge=1)
class SitemapShellUpdate(BaseModel):
model_config = _FORBID
status: SitemapStatus | None = None
entries_json: dict | None = None
storage_file_ref: str | None = Field(default=None, max_length=255)
metadata_json: dict | None = None
version: int = Field(ge=1)
class SitemapShellRead(ORMBase):
id: UUID
tenant_id: UUID
workspace_id: UUID
site_id: UUID
status: SitemapStatus
entries_json: dict | None
storage_file_ref: str | 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 SitemapShellListResponse(BaseModel):
items: list[SitemapShellRead]
total: int
page: int
page_size: int
class RobotsShellUpsert(BaseModel):
model_config = _FORBID
workspace_id: UUID
site_id: UUID
status: RobotsStatus = RobotsStatus.DRAFT
content_text: str | None = None
rules_json: dict | None = None
metadata_json: dict | None = None
version: int | None = Field(default=None, ge=1)
class RobotsShellUpdate(BaseModel):
model_config = _FORBID
status: RobotsStatus | None = None
content_text: str | None = None
rules_json: dict | None = None
metadata_json: dict | None = None
version: int = Field(ge=1)
class RobotsShellRead(ORMBase):
id: UUID
tenant_id: UUID
workspace_id: UUID
site_id: UUID
status: RobotsStatus
content_text: str | None
rules_json: dict | 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 RobotsShellListResponse(BaseModel):
items: list[RobotsShellRead]
total: int
page: int
page_size: int
class PwaManifestUpsert(BaseModel):
model_config = _FORBID
workspace_id: UUID
site_id: UUID
status: PwaStatus = PwaStatus.DRAFT
name: str | None = Field(default=None, max_length=255)
short_name: str | None = Field(default=None, max_length=100)
start_url: str | None = Field(default=None, max_length=500)
manifest_json: dict | None = None
service_worker_ref: str | None = Field(default=None, max_length=255)
metadata_json: dict | None = None
version: int | None = Field(default=None, ge=1)
class PwaManifestUpdate(BaseModel):
model_config = _FORBID
status: PwaStatus | None = None
name: str | None = Field(default=None, max_length=255)
short_name: str | None = Field(default=None, max_length=100)
start_url: str | None = Field(default=None, max_length=500)
manifest_json: dict | None = None
service_worker_ref: str | None = Field(default=None, max_length=255)
metadata_json: dict | None = None
version: int = Field(ge=1)
class PwaManifestRead(ORMBase):
id: UUID
tenant_id: UUID
workspace_id: UUID
site_id: UUID
status: PwaStatus
name: str | None
short_name: str | None
start_url: str | None
manifest_json: dict | None
service_worker_ref: str | 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 PwaManifestListResponse(BaseModel):
items: list[PwaManifestRead]
total: int
page: int
page_size: int