Files
headquarter/apps/api/src/main.py
T
alex 4201326467 fix: remove legacy config APIs
Remove stale ToolConfig and ConfigFolder backend/frontend surfaces after the ConfigProfile refactor. Drop dead routers, schemas, model exports, frontend routes, clients, pages, and tests; keep ToolType API compatibility for existing interface/is_builtin response shape.

Quality gates: backend LSP diagnostics passed; backend py_compile passed; backend ruff passed; frontend ToolWorkshopPage test passed. Frontend typecheck blocked by unrelated missing xterm-addon-serialize types.
2026-06-03 12:40:47 +02:00

134 lines
4.4 KiB
Python

import logging
import os
from fastapi import FastAPI, Request
from fastapi.exceptions import RequestValidationError
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from fastapi.staticfiles import StaticFiles
from src.api.auth import router as auth_router
from src.api.dashboard import router as dashboard_router
from src.api.git_repositories import router as git_repositories_router
from src.api.health import router as health_router
from src.api.projects import router as projects_router
from src.api.ssh_keys import router as ssh_keys_router
from src.api.terminal import router as terminal_router
from src.api.instance_proxy import router as instance_proxy_router
from src.api.config_profiles import router as config_profiles_router
from src.api.tool_instances import router as tool_instances_router
from src.api.tool_types import router as tool_types_router
from src.api.user_config import router as user_config_router
from src.api.users import router as users_router
from src.config import Settings
from src.database import init_database
from src.logging_config import (
ExceptionLoggingMiddleware,
RequestLoggingMiddleware,
configure_logging,
)
from src.seeds.builtin_tool_types import seed_builtin_tool_types
# Configure logging early
log_level = os.getenv("LOG_LEVEL", "INFO").upper()
configure_logging(level=getattr(logging, log_level, logging.INFO))
logger = logging.getLogger(__name__)
settings = Settings()
app = FastAPI(title="Headquarter API")
# Configure CORS - must be before other middleware
# Build allowed origins list including web and api domains
cors_origins = [settings.web_base_url]
if settings.api_base_url != settings.web_base_url:
cors_origins.append(settings.api_base_url)
logger.info("CORS configured with origins: %s", cors_origins)
app.add_middleware(
CORSMiddleware,
allow_origins=cors_origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.add_middleware(RequestLoggingMiddleware)
app.add_middleware(ExceptionLoggingMiddleware)
def _sanitize_validation_errors(errors):
"""Convert validation errors to JSON-safe format."""
sanitized = []
for error in errors:
safe_error = {
"type": error.get("type"),
"loc": error.get("loc"),
"msg": error.get("msg"),
"input": str(error.get("input"))
if error.get("input") is not None
else None,
}
# Convert ctx to safe format
ctx = error.get("ctx")
if ctx:
safe_ctx = {}
for key, value in ctx.items():
if isinstance(value, Exception):
safe_ctx[key] = str(value)
elif isinstance(value, (str, int, float, bool, type(None))):
safe_ctx[key] = value
else:
safe_ctx[key] = str(value)
safe_error["ctx"] = safe_ctx
sanitized.append(safe_error)
return sanitized
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
"""Log validation errors and return detailed response."""
errors = exc.errors()
logger.warning(
"Validation error for %s %s: %s",
request.method,
request.url.path,
errors,
)
safe_errors = _sanitize_validation_errors(errors)
return JSONResponse(
status_code=422,
content={"detail": safe_errors},
)
@app.on_event("startup")
async def on_startup():
logger.info("Starting up Headquarter API...")
# Initialize database (run migrations)
db_ready = await init_database()
if not db_ready:
logger.error("Database initialization failed. Shutting down.")
import sys
sys.exit(1)
# Seed built-in data
await seed_builtin_tool_types()
logger.info("Startup complete.")
app.include_router(health_router)
app.include_router(auth_router)
app.include_router(dashboard_router)
app.include_router(projects_router)
app.include_router(users_router)
app.include_router(ssh_keys_router)
app.include_router(git_repositories_router)
app.include_router(user_config_router)
app.include_router(tool_types_router)
app.include_router(config_profiles_router)
app.include_router(tool_instances_router)
app.include_router(instance_proxy_router)
app.include_router(terminal_router)
app.mount("/uploads", StaticFiles(directory="uploads"), name="uploads")