mirror of
https://github.com/escalante29/WealthySmart.git
synced 2026-07-17 17:08:47 +02:00
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>
37 lines
937 B
Python
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")),
|
|
}
|