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>
103 lines
4.1 KiB
Python
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
|
|
)
|