"""Health check endpoints: /health (root) and /api/v1/health.""" from __future__ import annotations import logging from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy import text from sqlalchemy.ext.asyncio import AsyncSession from app import __version__ from app.core.db import get_db logger = logging.getLogger(__name__) router = APIRouter(tags=["health"]) async def _check_db(db: AsyncSession) -> bool: """Run SELECT 1 to verify the database connection is alive.""" try: result = await db.execute(text("SELECT 1")) result.scalar_one() return True except Exception as e: logger.error("Database health check failed: %s", e) return False @router.get( "/health", summary="Healthcheck (used by Coolify + Kubernetes)", ) async def health( db: AsyncSession = Depends(get_db), ) -> dict: """Returns 200 if the API and DB are healthy, 503 if the DB is down.""" db_ok = await _check_db(db) if not db_ok: raise HTTPException( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail={"status": "error", "db": "down"}, ) return { "status": "ok", "db": "ok", "version": __version__, } @router.get( "/api/v1/health", summary="Versioned healthcheck (for clients that hit /api/v1/*)", ) async def api_v1_health( db: AsyncSession = Depends(get_db), ) -> dict: """Same as /health but under the /api/v1 prefix for versioned routing.""" db_ok = await _check_db(db) if not db_ok: raise HTTPException( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail={"status": "error", "db": "down"}, ) return { "status": "ok", "db": "ok", "version": __version__, }