Files
stackpilot/backend/main.py
menzeljandClaude Fable 5 34cb215266 Phase 24: Design System v2 — analytics-style UI (0.30.0)
- New /api/dashboard/funnel (5-stage stack health, 30s TTL cache) and
  /api/dashboard/summary (containers, daily uptime jsonl, ops activity)
- Token system (tokens.css + Tailwind sp-* aliases); legacy bg/card/accent
  remapped onto the tokens; Schibsted Grotesk bundled via fontsource
- TopNav pill navigation + AppShell replace the sidebar layout (off-canvas
  drawer below 1024px); central display-weight page titles
- Dashboard redesign: FunnelChart (gradient/hatch SVG waterfall), container
  count card with per-host bars + Insights chip, UptimeChart, OpsGrid,
  AiPromptBar; 30/7-day range selector; host sections retained below
- Stacks page honours ?q= / ?filter= deep links + new status-filter select

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 10:54:06 +00:00

105 lines
2.7 KiB
Python

"""StackPilot backend — FastAPI application entry point."""
from __future__ import annotations
import asyncio
import logging
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from sqlmodel import Session
from config import settings
from database import engine, init_db
from docker_client import DockerError
from routers import (
agents,
audit,
auth,
backups,
containers,
dashboard,
destinations,
editor,
files,
images,
networks,
ports,
schedules,
secrets,
settings as settings_router,
stacks,
system,
templates,
volumes,
ws,
)
from services import schedule_service, update_service
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("stackpilot")
@asynccontextmanager
async def lifespan(app: FastAPI):
init_db()
# Register stacks that already exist on disk.
try:
with Session(engine) as session:
stacks.sync_discovered_stacks(session)
except Exception as exc: # noqa: BLE001
logger.warning("Stack discovery failed: %s", exc)
update_task = asyncio.create_task(update_service.background_loop())
schedule_task = asyncio.create_task(schedule_service.scheduler_loop())
logger.info("StackPilot backend ready on port %s", settings.PORT)
yield
update_task.cancel()
schedule_task.cancel()
app = FastAPI(title="StackPilot", version="0.30.0", lifespan=lifespan)
app.add_middleware(
CORSMiddleware,
allow_origins=settings.CORS_ORIGINS,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.exception_handler(DockerError)
async def docker_error_handler(_request: Request, exc: DockerError):
return JSONResponse(
status_code=502,
content={"error": exc.error, "detail": exc.detail},
)
app.include_router(auth.router)
app.include_router(stacks.router)
app.include_router(secrets.router)
app.include_router(containers.router)
app.include_router(dashboard.router)
app.include_router(system.router)
app.include_router(volumes.router)
app.include_router(editor.router)
app.include_router(files.router)
app.include_router(images.router)
app.include_router(ports.router)
app.include_router(templates.router)
app.include_router(audit.router)
app.include_router(settings_router.router)
app.include_router(backups.router)
app.include_router(destinations.router)
app.include_router(schedules.router)
app.include_router(networks.router)
app.include_router(agents.router)
app.include_router(ws.router)
@app.get("/api/health")
def health() -> dict:
return {"status": "ok"}