Files
resolutionflow/backend/app/models/session_resolution_output.py
chihlasm c9798514a9 feat: add SessionResolutionOutput model and register all 4 branching models
Introduces the session_resolution_outputs table for the three resolve
deliverables (psa_ticket_notes, knowledge_base, client_summary) with
UNIQUE(session_id, output_type) for safe upsert on regeneration.
Also registers SessionBranch, ForkPoint, SessionHandoff, and
SessionResolutionOutput in models/__init__.py so Alembic and the app
pick them up automatically.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 08:23:48 +00:00

40 lines
2.4 KiB
Python

"""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)
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")