"""Admin Health Console router — one aggregate endpoint per page load. A single ``GET /api/v1/admin/health/overview`` feeds the four-panel ``/admin/health`` console. Gated with ``require_admin_read`` so ``management`` / ``auditor`` can browse it (read-only) alongside ``global_admin``. The detail pages each panel links to keep their own finer-grained RBAC. """ from __future__ import annotations from fastapi import APIRouter, Depends, Query, Request from sqlalchemy.ext.asyncio import AsyncSession from app.auth.models import AuthUser from app.core.database import get_db from app.core.dependencies import require_admin_read from app.core.response import success_response from app.domains.health.service import get_health_overview from app.scheduled_jobs.slo_evaluator import evaluate_all_slos router = APIRouter(prefix="/api/v1/admin/health", tags=["admin-health"]) @router.get( "/overview", summary="One-shot aggregate for /admin/health — cron + offboarding + notifications + data health", ) async def health_overview( request: Request, window_days: int = Query(7, ge=1, le=180), current_user: AuthUser = Depends(require_admin_read()), db: AsyncSession = Depends(get_db), ): data = await get_health_overview(db, window_days=window_days) return success_response(data=data, request=request) @router.get( "/slo", summary="SLO status per registered scheduled-job handler (PR-C)", ) async def health_slo( request: Request, window_days: int = Query(7, ge=1, le=180), current_user: AuthUser = Depends(require_admin_read()), db: AsyncSession = Depends(get_db), ): rows = await evaluate_all_slos(db, window_days=window_days) # Surface tier + status histograms so the frontend can render the # KPI strip without a second pass over ``rows``. by_tier = {"P0": 0, "P1": 0, "P2": 0} by_status = {"ok": 0, "warn": 0, "breach": 0, "no_data": 0} breach_handlers: list[str] = [] for row in rows: by_tier[row["tier"]] = by_tier.get(row["tier"], 0) + 1 by_status[row["status"]] = by_status.get(row["status"], 0) + 1 if row["status"] == "breach": breach_handlers.append(row["handler_key"]) return success_response( data={ "window_days": window_days, "by_tier": by_tier, "by_status": by_status, "breach_handlers": breach_handlers, "rows": rows, }, request=request, )