"""Nexus — Health Check Endpoint External monitoring endpoint for Shell health_monitor.sh and Supervisor. Security: Only returns minimal status ("ok") for external probes. Detailed health diagnostics require admin JWT auth via /health/detail. """ import logging from fastapi import APIRouter, Depends from fastapi.responses import PlainTextResponse from sqlalchemy import text from server.api.auth_jwt import get_current_admin from server.domain.models import Admin from server.infrastructure.database.session import AsyncSessionLocal from server.infrastructure.redis.client import get_redis from server.api.websocket import manager as ws_manager logger = logging.getLogger("nexus.health") router = APIRouter() @router.get("/health", response_class=PlainTextResponse) async def health_check(): """Minimal health check — used by Shell health_monitor.sh (Layer 3 guardian). Returns plain-text "ok" — no JSON, no backend fingerprint. health_monitor.sh discards response body (curl -sf > /dev/null), so this is purely for HTTP status code. """ return "ok" @router.get("/health/detail") async def health_detail(admin: Admin = Depends(get_current_admin)): """Detailed health diagnostics — requires admin JWT authentication. Returns Redis/MySQL/WebSocket status for admin dashboard use. """ checks = {"python": "ok"} # Redis check try: redis = get_redis() await redis.ping() checks["redis"] = "ok" except Exception as e: logger.error(f"Redis health check failed: {e}") checks["redis"] = "unavailable" # MySQL check try: async with AsyncSessionLocal() as session: await session.execute(text("SELECT 1")) checks["mysql"] = "ok" except Exception as e: logger.error(f"MySQL health check failed: {e}") checks["mysql"] = "error" # WebSocket connections count try: checks["websocket_clients"] = await ws_manager.global_client_count() except Exception: checks["websocket_clients"] = ws_manager.client_count return {"status": "ok", "checks": checks}