"""Session resolution output model — three deliverables generated on resolve.""" import uuid from datetime import datetime, timezone from typing import Optional, Any from sqlalchemy import String, Text, DateTime, ForeignKey, CheckConstraint, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column, relationship from sqlalchemy.dialects.postgresql import UUID, JSONB from app.core.database import Base class SessionResolutionOutput(Base): """One of three resolution deliverables: PSA ticket notes, KB article, client summary. UNIQUE(session_id, output_type) + upsert so outputs can be regenerated. """ __tablename__ = "session_resolution_outputs" __table_args__ = ( CheckConstraint("output_type IN ('psa_ticket_notes', 'knowledge_base', 'client_summary')", name="ck_session_resolution_outputs_output_type"), CheckConstraint("status IN ('draft', 'approved', 'pushed', 'rejected')", name="ck_session_resolution_outputs_status"), UniqueConstraint("session_id", "output_type", name="uq_session_resolution_session_type"), ) id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) session_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("ai_sessions.id", ondelete="CASCADE"), nullable=False, index=True) account_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("accounts.id", ondelete="CASCADE"), nullable=False, index=True, ) output_type: Mapped[str] = mapped_column(String(30), nullable=False) generated_content: Mapped[str] = mapped_column(Text, nullable=False) structured_data: Mapped[Optional[dict[str, Any]]] = mapped_column(JSONB, nullable=True, comment="For KB: {symptoms, root_cause, steps, tags}") edited_content: Mapped[Optional[str]] = mapped_column(Text, nullable=True) status: Mapped[str] = mapped_column(String(20), nullable=False, default="draft") pushed_to: Mapped[Optional[str]] = mapped_column(String(50), nullable=True) pushed_at: Mapped[Optional[datetime]] = mapped_column(DateTime(timezone=True), nullable=True) pushed_reference: Mapped[Optional[str]] = mapped_column(String(200), nullable=True) generated_by_model: Mapped[str] = mapped_column(String(50), nullable=False) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc)) updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=lambda: datetime.now(timezone.utc), onupdate=lambda: datetime.now(timezone.utc)) # Relationships session = relationship("AISession", foreign_keys="SessionResolutionOutput.session_id", back_populates="resolution_outputs")