Files
claudetools/api/models/ticket_link.py
Mike Swanson 390b10b32c Complete Phase 6: MSP Work Tracking with Context Recall System
Implements production-ready MSP platform with cross-machine persistent memory for Claude.

API Implementation:
- 130 REST API endpoints across 21 entities
- JWT authentication on all endpoints
- AES-256-GCM encryption for credentials
- Automatic audit logging
- Complete OpenAPI documentation

Database:
- 43 tables in MariaDB (172.16.3.20:3306)
- 42 SQLAlchemy models with modern 2.0 syntax
- Full Alembic migration system
- 99.1% CRUD test pass rate

Context Recall System (Phase 6):
- Cross-machine persistent memory via database
- Automatic context injection via Claude Code hooks
- Automatic context saving after task completion
- 90-95% token reduction with compression utilities
- Relevance scoring with time decay
- Tag-based semantic search
- One-command setup script

Security Features:
- JWT tokens with Argon2 password hashing
- AES-256-GCM encryption for all sensitive data
- Comprehensive audit trail for credentials
- HMAC tamper detection
- Secure configuration management

Test Results:
- Phase 3: 38/38 CRUD tests passing (100%)
- Phase 4: 34/35 core API tests passing (97.1%)
- Phase 5: 62/62 extended API tests passing (100%)
- Phase 6: 10/10 compression tests passing (100%)
- Overall: 144/145 tests passing (99.3%)

Documentation:
- Comprehensive architecture guides
- Setup automation scripts
- API documentation at /api/docs
- Complete test reports
- Troubleshooting guides

Project Status: 95% Complete (Production-Ready)
Phase 7 (optional work context APIs) remains for future enhancement.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-17 06:00:26 -07:00

119 lines
3.8 KiB
Python

"""
Ticket Link model for connecting sessions to external ticketing systems.
This model creates relationships between ClaudeTools sessions and tickets
in external systems like SyncroMSP, Autotask, ConnectWise, etc.
"""
from datetime import datetime
from typing import Optional
from sqlalchemy import CHAR, ForeignKey, Index, String
from sqlalchemy.orm import Mapped, mapped_column, relationship
from sqlalchemy.sql import func
from .base import Base, UUIDMixin
class TicketLink(Base, UUIDMixin):
"""
Links between sessions and external ticketing system tickets.
Creates associations between ClaudeTools work sessions and tickets
in external MSP platforms. Enables automatic time tracking, status
updates, and work documentation in ticketing systems.
Attributes:
id: Unique identifier
session_id: Reference to the ClaudeTools session
client_id: Reference to the client
integration_type: Type of ticketing system (syncro, autotask, connectwise)
ticket_id: External ticket identifier
ticket_number: Human-readable ticket number (e.g., "T12345")
ticket_subject: Subject/title of the ticket
ticket_url: Direct URL to view the ticket
ticket_status: Current status of the ticket
link_type: Type of relationship (related, resolves, documents)
created_at: When the link was created
"""
__tablename__ = "ticket_links"
# Foreign keys
session_id: Mapped[Optional[str]] = mapped_column(
CHAR(36),
ForeignKey("sessions.id", ondelete="CASCADE"),
nullable=True,
doc="ClaudeTools session linked to this ticket",
)
client_id: Mapped[Optional[str]] = mapped_column(
CHAR(36),
ForeignKey("clients.id", ondelete="CASCADE"),
nullable=True,
doc="Client this ticket belongs to",
)
# Ticket information
integration_type: Mapped[str] = mapped_column(
String(100),
nullable=False,
doc="Ticketing system type (syncro, autotask, connectwise)",
)
ticket_id: Mapped[str] = mapped_column(
String(255),
nullable=False,
doc="External ticket identifier",
)
ticket_number: Mapped[Optional[str]] = mapped_column(
String(100),
nullable=True,
doc="Human-readable ticket number (T12345)",
)
ticket_subject: Mapped[Optional[str]] = mapped_column(
String(500),
nullable=True,
doc="Subject/title of the ticket",
)
ticket_url: Mapped[Optional[str]] = mapped_column(
String(500),
nullable=True,
doc="Direct URL to view the ticket",
)
ticket_status: Mapped[Optional[str]] = mapped_column(
String(100),
nullable=True,
doc="Current status of the ticket",
)
# Link metadata
link_type: Mapped[Optional[str]] = mapped_column(
String(50),
nullable=True,
doc="Type of relationship (related, resolves, documents)",
)
created_at: Mapped[datetime] = mapped_column(
nullable=False,
server_default=func.now(),
doc="When the link was created",
)
# Indexes
__table_args__ = (
Index("idx_ticket_session", "session_id"),
Index("idx_ticket_client", "client_id"),
Index("idx_ticket_external", "integration_type", "ticket_id"),
)
# Relationships
# session = relationship("Session", back_populates="ticket_links")
# client = relationship("Client", back_populates="ticket_links")
def __repr__(self) -> str:
"""String representation of the ticket link."""
return (
f"<TicketLink(id={self.id!r}, "
f"type={self.integration_type!r}, "
f"ticket={self.ticket_number or self.ticket_id!r}, "
f"link_type={self.link_type!r})>"
)