import uuid import enum from datetime import datetime from sqlalchemy import String, DateTime, Boolean, Text, BigInteger, Float, Integer, ForeignKey from sqlalchemy import Enum as SAEnum from sqlalchemy.orm import Mapped, mapped_column from sqlalchemy.dialects.postgresql import UUID, JSONB from app.database import Base class MediaAssetType(str, enum.Enum): thumbnail = "thumbnail" still = "still" turntable = "turntable" stl_low = "stl_low" stl_high = "stl_high" gltf_geometry = "gltf_geometry" # DEPRECATED: use usd_master — viewer GLB auto-generated as part of USD pipeline gltf_production = "gltf_production" # DEPRECATED: use usd_master — high-quality production GLB superseded by USD master blend_production = "blend_production" usd_master = "usd_master" class MediaAsset(Base): __tablename__ = "media_assets" id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) tenant_id: Mapped[uuid.UUID | None] = mapped_column( UUID(as_uuid=True), ForeignKey("tenants.id", ondelete="CASCADE"), nullable=True, index=True ) product_id: Mapped[uuid.UUID | None] = mapped_column( UUID(as_uuid=True), ForeignKey("products.id", ondelete="CASCADE"), nullable=True, index=True ) cad_file_id: Mapped[uuid.UUID | None] = mapped_column( UUID(as_uuid=True), ForeignKey("cad_files.id", ondelete="SET NULL"), nullable=True ) order_line_id: Mapped[uuid.UUID | None] = mapped_column( UUID(as_uuid=True), ForeignKey("order_lines.id", ondelete="SET NULL"), nullable=True, index=True ) workflow_run_id: Mapped[uuid.UUID | None] = mapped_column( UUID(as_uuid=True), ForeignKey("workflow_runs.id", ondelete="SET NULL"), nullable=True ) asset_type: Mapped[MediaAssetType] = mapped_column( SAEnum(MediaAssetType, name="media_asset_type"), nullable=False ) storage_key: Mapped[str] = mapped_column(Text, nullable=False) file_size_bytes: Mapped[int | None] = mapped_column(BigInteger, nullable=True) mime_type: Mapped[str | None] = mapped_column(String(100), nullable=True) width: Mapped[int | None] = mapped_column(Integer, nullable=True) height: Mapped[int | None] = mapped_column(Integer, nullable=True) duration_s: Mapped[float | None] = mapped_column(Float, nullable=True) render_config: Mapped[dict | None] = mapped_column(JSONB, nullable=True) is_archived: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, nullable=False)