"""GET /api/sync/status — sync monitor (cursors + recent runs). Returns the current :class:`SyncState` cursors and the most recent N :class:`SyncRun` audit rows (default 20). Read-only — purely for the operator dashboard. """ from __future__ import annotations from typing import Annotated import sqlalchemy as sa from fastapi import APIRouter, Depends, Query from sqlalchemy.ext.asyncio import AsyncSession from app.api.deps import get_session from app.api.schemas import SyncRunOut, SyncStateOut, SyncStatusOut from app.db.models import SyncRun, SyncState router = APIRouter(prefix="/api/sync", tags=["sync"]) SessionDep = Annotated[AsyncSession, Depends(get_session)] RecentLimitParam = Annotated[int, Query(ge=1, le=200)] @router.get("/status") async def sync_status( session: SessionDep, recent: RecentLimitParam = 20, ) -> SyncStatusOut: """Return sync cursors plus the most recent ``recent`` runs.""" state_rows = ( await session.execute( sa.select(SyncState).order_by( SyncState.entity_type.asc(), sa.nullslast(SyncState.channel.asc()), sa.nullslast(SyncState.scope_id.asc()), ) ) ).scalars().all() states = [SyncStateOut.model_validate(row) for row in state_rows] run_rows = ( await session.execute( sa.select(SyncRun) .order_by(SyncRun.started_at.desc(), SyncRun.run_id.desc()) .limit(recent) ) ).scalars().all() recent_runs = [SyncRunOut.model_validate(row) for row in run_rows] return SyncStatusOut(states=states, recent_runs=recent_runs)