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

134 lines
4.9 KiB
Python

"""
Dashboard web interface routes.
"""
from fastapi import APIRouter, Request, Depends
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
from sqlalchemy.ext.asyncio import AsyncSession
from app.database.connection import get_db
dashboard_router = APIRouter()
templates = Jinja2Templates(directory="app/dashboard/templates")
@dashboard_router.get("/dashboard", response_class=HTMLResponse)
async def dashboard_home(request: Request, db: AsyncSession = Depends(get_db)):
"""Main dashboard page."""
return templates.TemplateResponse("dashboard.html", {
"request": request,
"title": "Claude Code Project Tracker"
})
@dashboard_router.get("/dashboard/projects", response_class=HTMLResponse)
async def dashboard_projects(request: Request, db: AsyncSession = Depends(get_db)):
"""Projects overview page."""
return templates.TemplateResponse("projects.html", {
"request": request,
"title": "Projects - Claude Code Tracker"
})
@dashboard_router.get("/dashboard/analytics", response_class=HTMLResponse)
async def dashboard_analytics(request: Request, db: AsyncSession = Depends(get_db)):
"""Analytics and insights page."""
return templates.TemplateResponse("analytics.html", {
"request": request,
"title": "Analytics - Claude Code Tracker"
})
@dashboard_router.get("/dashboard/conversations", response_class=HTMLResponse)
async def dashboard_conversations(request: Request, db: AsyncSession = Depends(get_db)):
"""Conversation search and history page."""
return templates.TemplateResponse("conversations.html", {
"request": request,
"title": "Conversations - Claude Code Tracker"
})
@dashboard_router.get("/dashboard/import", response_class=HTMLResponse)
async def dashboard_import(request: Request, db: AsyncSession = Depends(get_db)):
"""Data import page."""
return templates.TemplateResponse("import.html", {
"request": request,
"title": "Import Data - Claude Code Tracker"
})
@dashboard_router.get("/dashboard/projects/{project_id}/timeline", response_class=HTMLResponse)
async def dashboard_project_timeline(request: Request, project_id: int, db: AsyncSession = Depends(get_db)):
"""Project timeline page."""
return templates.TemplateResponse("project_timeline.html", {
"request": request,
"title": f"Timeline - Project {project_id}",
"project_id": project_id
})
@dashboard_router.get("/dashboard/projects/{project_id}/stats", response_class=HTMLResponse)
async def dashboard_project_stats(request: Request, project_id: int, db: AsyncSession = Depends(get_db)):
"""Project statistics page."""
return templates.TemplateResponse("project_stats.html", {
"request": request,
"title": f"Statistics - Project {project_id}",
"project_id": project_id
})
@dashboard_router.get("/dashboard/docs", response_class=HTMLResponse)
async def dashboard_docs(request: Request, db: AsyncSession = Depends(get_db)):
"""Documentation overview page."""
return templates.TemplateResponse("docs/index.html", {
"request": request,
"title": "Documentation - Claude Code Tracker"
})
@dashboard_router.get("/dashboard/docs/{section}", response_class=HTMLResponse)
async def dashboard_docs_section(request: Request, section: str, db: AsyncSession = Depends(get_db)):
"""Documentation section pages."""
# Map section names to templates and titles
sections = {
"getting-started": {
"template": "docs/getting-started.html",
"title": "Getting Started - Claude Code Tracker"
},
"data-import": {
"template": "docs/data-import.html",
"title": "Data Import Guide - Claude Code Tracker"
},
"docker-deployment": {
"template": "docs/docker-deployment.html",
"title": "Docker Deployment Guide - Claude Code Tracker"
},
"hook-setup": {
"template": "docs/hook-setup.html",
"title": "Hook Setup Guide - Claude Code Tracker"
},
"hook-reference": {
"template": "docs/hook-reference.html",
"title": "Complete Hook Reference - Claude Code Tracker"
},
"api-reference": {
"template": "docs/api-reference.html",
"title": "API Reference - Claude Code Tracker"
},
"faq": {
"template": "docs/faq.html",
"title": "FAQ - Claude Code Tracker"
}
}
if section not in sections:
from fastapi import HTTPException
raise HTTPException(status_code=404, detail=f"Documentation section '{section}' not found")
section_info = sections[section]
return templates.TemplateResponse(section_info["template"], {
"request": request,
"title": section_info["title"],
"section": section
})