Files
WealthySmart/backend/app/api/v1/endpoints/sync_status.py
Carlos Escalante 7dfe2da2a9 OpenAPI type codegen with CI drift gate (plan 3.4, ARCH-16, FE-14)
Every dict-returning route the SPA consumes now declares a response
model (auth, bulk, sync-status, notifications). api-types.gen.ts is
generated from app.openapi() via openapi-typescript, and the 22 hand-
written read interfaces in api.ts are now aliases onto the generated
schemas — backend schema drift becomes a typecheck failure, and CI
regenerates the file and fails the deploy if it's stale. The aliasing
immediately caught two real drifts: RecurringItemType was missing
SAVINGS, and raw_charges (untyped JSON column) is now explicitly
shaped at the boundary.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 07:53:00 -06:00

37 lines
937 B
Python

from fastapi import APIRouter, Depends
from pydantic import BaseModel
from sqlmodel import Session
from app.auth import get_current_user
from app.db import get_session
from app.services.sync_status import compute_sync_status
router = APIRouter(prefix="/sync-status", tags=["sync-status"])
class SyncSourceStatus(BaseModel):
key: str
label: str
description: str
last_received: str | None
age_days: float | None
warn_after_days: float
status: str # 'ok' | 'warning' | 'never'
class SyncStatusResponse(BaseModel):
sources: list[SyncSourceStatus]
warnings: int
@router.get("/", response_model=SyncStatusResponse)
def sync_status(
session: Session = Depends(get_session),
_user: str = Depends(get_current_user),
):
sources = compute_sync_status(session)
return {
"sources": sources,
"warnings": sum(1 for s in sources if s["status"] in ("warning", "never")),
}