Files
resolutionflow/backend/app/models/session.py
chihlasm f16a686fb4 feat: add onboarding, branding, and supporting data models, migrations, and schemas
Add onboarding_dismissed and branding columns (logo_data, logo_content_type,
company_display_name) to users and teams models. Create SessionSupportingData
model for attaching text snippets and screenshots to sessions. Add Pydantic
schemas for onboarding status, branding responses, and supporting data CRUD.
Update SessionExport to accept pdf format.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 23:51:42 -04:00

103 lines
4.1 KiB
Python

import uuid
from datetime import datetime, timezone
from typing import Optional, Any, TYPE_CHECKING
from sqlalchemy import String, DateTime, ForeignKey, Boolean, Text
import sqlalchemy as sa
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.dialects.postgresql import UUID, JSONB
from app.core.database import Base
if TYPE_CHECKING:
from app.models.session_share import SessionShare
class Session(Base):
__tablename__ = "sessions"
id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True),
primary_key=True,
default=uuid.uuid4
)
tree_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True),
ForeignKey("trees.id"),
nullable=False,
index=True
)
user_id: Mapped[uuid.UUID] = mapped_column(
UUID(as_uuid=True),
ForeignKey("users.id"),
nullable=False,
index=True
)
tree_snapshot: Mapped[dict[str, Any]] = mapped_column(JSONB, nullable=False)
path_taken: Mapped[list[str]] = mapped_column(JSONB, nullable=False, default=list)
decisions: Mapped[list[dict[str, Any]]] = mapped_column(JSONB, nullable=False, default=list)
custom_steps: Mapped[list[dict[str, Any]]] = mapped_column(JSONB, nullable=False, default=list)
started_at: Mapped[Optional[datetime]] = mapped_column(
DateTime(timezone=True),
nullable=True,
default=lambda: datetime.now(timezone.utc),
index=True
)
completed_at: Mapped[Optional[datetime]] = mapped_column(
DateTime(timezone=True),
nullable=True,
index=True
)
outcome: Mapped[Optional[str]] = mapped_column(String(20), nullable=True, index=True)
outcome_notes: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
ticket_number: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
client_name: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
exported: Mapped[bool] = mapped_column(Boolean, default=False)
session_variables: Mapped[dict[str, Any]] = mapped_column(
JSONB, nullable=False, server_default=sa.text("'{}'::jsonb")
)
scratchpad: Mapped[Optional[str]] = mapped_column(
Text, nullable=True, server_default=sa.text("''")
)
next_steps: Mapped[Optional[str]] = mapped_column(
Text, nullable=True, server_default=sa.text("''")
)
# Prepared sessions (flexible intake)
prepared_by_id: Mapped[Optional[uuid.UUID]] = mapped_column(
UUID(as_uuid=True),
ForeignKey("users.id"),
nullable=True,
index=True
)
assigned_to_id: Mapped[Optional[uuid.UUID]] = mapped_column(
UUID(as_uuid=True),
ForeignKey("users.id"),
nullable=True,
index=True
)
# Relationships
tree: Mapped["Tree"] = relationship("Tree", back_populates="sessions")
user: Mapped["User"] = relationship("User", foreign_keys=[user_id], back_populates="sessions")
prepared_by: Mapped[Optional["User"]] = relationship("User", foreign_keys=[prepared_by_id])
assigned_to: Mapped[Optional["User"]] = relationship("User", foreign_keys=[assigned_to_id])
attachments: Mapped[list["Attachment"]] = relationship("Attachment", back_populates="session")
shares: Mapped[list["SessionShare"]] = relationship("SessionShare", back_populates="session", cascade="all, delete-orphan")
supporting_data = relationship("SessionSupportingData", back_populates="session", cascade="all, delete-orphan", order_by="SessionSupportingData.sort_order")
# PSA ticket link
psa_ticket_id: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
psa_connection_id: Mapped[Optional[uuid.UUID]] = mapped_column(
UUID(as_uuid=True),
ForeignKey("psa_connections.id", ondelete="SET NULL"),
nullable=True,
)
psa_connection = relationship("PsaConnection", foreign_keys=[psa_connection_id])
# Batch tracking (maintenance flows)
batch_id: Mapped[Optional[uuid.UUID]] = mapped_column(
UUID(as_uuid=True), nullable=True, index=True
)
target_label: Mapped[Optional[str]] = mapped_column(
String(255), nullable=True
)