Ryan Malloy 50c80596d0 Add comprehensive Docker deployment and file upload functionality
Features Added:
• Docker containerization with multi-stage Python 3.12 build
• Caddy reverse proxy integration with automatic SSL
• File upload interface for .claude.json imports with preview
• Comprehensive hook system with 39+ hook types across 9 categories
• Complete documentation system with Docker and import guides

Technical Improvements:
• Enhanced database models with hook tracking capabilities
• Robust file validation and error handling for uploads
• Production-ready Docker compose configuration
• Health checks and resource limits for containers
• Database initialization scripts for containerized deployments

Documentation:
• Docker Deployment Guide with troubleshooting
• Data Import Guide with step-by-step instructions
• Updated Getting Started guide with new features
• Enhanced documentation index with responsive grid layout

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-11 08:02:09 -06:00

225 lines
10 KiB
Python

"""
Comprehensive hook tracking models for Claude Code sessions.
"""
from datetime import datetime
from typing import Optional, Dict, Any
from sqlalchemy import Column, Integer, String, Text, DateTime, ForeignKey, Boolean, Float, JSON
from sqlalchemy.orm import relationship
from app.models.base import Base
class HookEvent(Base):
"""
Base model for all hook events with common fields.
"""
__tablename__ = "hook_events"
id = Column(Integer, primary_key=True, index=True)
session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True)
hook_type = Column(String(50), nullable=False, index=True)
timestamp = Column(DateTime, nullable=False, default=datetime.utcnow, index=True)
data = Column(JSON, nullable=True) # Flexible JSON data for hook-specific information
# Relationships
session = relationship("Session", back_populates="hook_events")
def __repr__(self):
return f"<HookEvent(id={self.id}, type={self.hook_type}, session={self.session_id})>"
class ToolError(Base):
"""Track failed tool calls with error details."""
__tablename__ = "tool_errors"
id = Column(Integer, primary_key=True, index=True)
session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True)
tool_name = Column(String(100), nullable=False, index=True)
error_type = Column(String(100), nullable=False, index=True)
error_message = Column(Text, nullable=False)
stack_trace = Column(Text, nullable=True)
parameters = Column(JSON, nullable=True)
timestamp = Column(DateTime, nullable=False, default=datetime.utcnow, index=True)
session = relationship("Session")
def __repr__(self):
return f"<ToolError(id={self.id}, tool={self.tool_name}, error={self.error_type})>"
class WaitingPeriodNew(Base):
"""Track periods when Claude is thinking vs actively working."""
__tablename__ = "waiting_periods_new"
id = Column(Integer, primary_key=True, index=True)
session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True)
start_time = Column(DateTime, nullable=False, default=datetime.utcnow, index=True)
end_time = Column(DateTime, nullable=True)
duration_ms = Column(Integer, nullable=True)
reason = Column(String(100), nullable=True, index=True) # thinking, processing, waiting_for_input
context = Column(Text, nullable=True) # What was happening when waiting started
session = relationship("Session")
def __repr__(self):
return f"<WaitingPeriodNew(id={self.id}, reason={self.reason}, duration={self.duration_ms}ms)>"
class PerformanceMetric(Base):
"""Monitor system performance during development."""
__tablename__ = "performance_metrics"
id = Column(Integer, primary_key=True, index=True)
session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True)
metric_type = Column(String(50), nullable=False, index=True) # memory, cpu, disk
value = Column(Float, nullable=False)
unit = Column(String(20), nullable=False) # MB, %, seconds
threshold_exceeded = Column(Boolean, default=False)
timestamp = Column(DateTime, nullable=False, default=datetime.utcnow, index=True)
session = relationship("Session")
def __repr__(self):
return f"<PerformanceMetric(id={self.id}, type={self.metric_type}, value={self.value}{self.unit})>"
class CodeQualityEvent(Base):
"""Track code quality analysis, linting, and testing."""
__tablename__ = "code_quality_events"
id = Column(Integer, primary_key=True, index=True)
session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True)
event_type = Column(String(50), nullable=False, index=True) # lint, format, test, build, analysis
file_path = Column(Text, nullable=True)
tool_name = Column(String(100), nullable=True) # eslint, prettier, pytest, etc.
status = Column(String(20), nullable=False, index=True) # success, warning, error
issues_count = Column(Integer, default=0)
details = Column(JSON, nullable=True) # Specific issues, test results, etc.
duration_ms = Column(Integer, nullable=True)
timestamp = Column(DateTime, nullable=False, default=datetime.utcnow, index=True)
session = relationship("Session")
def __repr__(self):
return f"<CodeQualityEvent(id={self.id}, type={self.event_type}, status={self.status})>"
class WorkflowEvent(Base):
"""Track development workflow patterns."""
__tablename__ = "workflow_events"
id = Column(Integer, primary_key=True, index=True)
session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True)
event_type = Column(String(50), nullable=False, index=True) # context_switch, search_query, browser_tab, etc.
description = Column(Text, nullable=True)
event_metadata = Column(JSON, nullable=True) # Event-specific data
source = Column(String(100), nullable=True) # Where the event came from
duration_ms = Column(Integer, nullable=True) # For events with duration
timestamp = Column(DateTime, nullable=False, default=datetime.utcnow, index=True)
session = relationship("Session")
def __repr__(self):
return f"<WorkflowEvent(id={self.id}, type={self.event_type})>"
class LearningEvent(Base):
"""Track learning sessions and knowledge acquisition."""
__tablename__ = "learning_events"
id = Column(Integer, primary_key=True, index=True)
session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True)
event_type = Column(String(50), nullable=False, index=True) # tutorial, documentation, experimentation
topic = Column(String(200), nullable=True, index=True) # What was being learned
resource_url = Column(Text, nullable=True) # Documentation URL, tutorial link
confidence_before = Column(Integer, nullable=True) # 1-10 scale
confidence_after = Column(Integer, nullable=True) # 1-10 scale
notes = Column(Text, nullable=True)
duration_ms = Column(Integer, nullable=True)
timestamp = Column(DateTime, nullable=False, default=datetime.utcnow, index=True)
session = relationship("Session")
def __repr__(self):
return f"<LearningEvent(id={self.id}, topic={self.topic})>"
class EnvironmentEvent(Base):
"""Track environment and configuration changes."""
__tablename__ = "environment_events"
id = Column(Integer, primary_key=True, index=True)
session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True)
event_type = Column(String(50), nullable=False, index=True) # env_change, config_update, security_scan
environment = Column(String(50), nullable=True, index=True) # dev, staging, prod
config_file = Column(Text, nullable=True)
changes = Column(JSON, nullable=True) # What changed
impact_level = Column(String(20), nullable=True) # low, medium, high, critical
timestamp = Column(DateTime, nullable=False, default=datetime.utcnow, index=True)
session = relationship("Session")
def __repr__(self):
return f"<EnvironmentEvent(id={self.id}, type={self.event_type}, env={self.environment})>"
class CollaborationEvent(Base):
"""Track collaboration and external interactions."""
__tablename__ = "collaboration_events"
id = Column(Integer, primary_key=True, index=True)
session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True)
event_type = Column(String(50), nullable=False, index=True) # external_resource, ai_question, review_request
interaction_type = Column(String(50), nullable=True) # documentation, stackoverflow, api_docs
query_or_topic = Column(Text, nullable=True)
resource_url = Column(Text, nullable=True)
response_quality = Column(Integer, nullable=True) # 1-5 rating
time_to_resolution = Column(Integer, nullable=True) # minutes
event_metadata = Column(JSON, nullable=True)
timestamp = Column(DateTime, nullable=False, default=datetime.utcnow, index=True)
session = relationship("Session")
def __repr__(self):
return f"<CollaborationEvent(id={self.id}, type={self.event_type})>"
class ProjectIntelligence(Base):
"""Track high-level project development patterns."""
__tablename__ = "project_intelligence"
id = Column(Integer, primary_key=True, index=True)
session_id = Column(String, ForeignKey("sessions.id"), nullable=False, index=True)
event_type = Column(String(50), nullable=False, index=True) # refactor, feature_flag, debugging_session
scope = Column(String(20), nullable=True, index=True) # small, medium, large
complexity = Column(String(20), nullable=True, index=True) # low, medium, high
start_time = Column(DateTime, nullable=False, default=datetime.utcnow)
end_time = Column(DateTime, nullable=True)
duration_minutes = Column(Integer, nullable=True)
files_affected = Column(JSON, nullable=True) # List of file paths
outcome = Column(String(20), nullable=True) # success, partial, failed, abandoned
notes = Column(Text, nullable=True)
timestamp = Column(DateTime, nullable=False, default=datetime.utcnow, index=True)
session = relationship("Session")
def __repr__(self):
return f"<ProjectIntelligence(id={self.id}, type={self.event_type}, scope={self.scope})>"
# Add hook_events relationship to Session model
def add_hook_relationships():
"""Add hook event relationships to the Session model."""
from app.models.session import Session
Session.hook_events = relationship("HookEvent", back_populates="session", cascade="all, delete-orphan")
Session.tool_errors = relationship("ToolError", cascade="all, delete-orphan")
Session.waiting_periods_new = relationship("WaitingPeriodNew", cascade="all, delete-orphan")
Session.performance_metrics = relationship("PerformanceMetric", cascade="all, delete-orphan")
Session.code_quality_events = relationship("CodeQualityEvent", cascade="all, delete-orphan")
Session.workflow_events = relationship("WorkflowEvent", cascade="all, delete-orphan")
Session.learning_events = relationship("LearningEvent", cascade="all, delete-orphan")
Session.environment_events = relationship("EnvironmentEvent", cascade="all, delete-orphan")
Session.collaboration_events = relationship("CollaborationEvent", cascade="all, delete-orphan")
Session.project_intelligence = relationship("ProjectIntelligence", cascade="all, delete-orphan")