UI-Focused Routers#
Routers primarily serving the web frontend (ops-db-ui).
Transfer Router#
Path: /api/transfer
Purpose: Data transfer pipeline monitoring and recovery
Key endpoints:
GET /overview- Transfer statistics (uniform funnel + per-kind counts)GET /raw-packages- List packages with paginationWS /ws/overview- Real-time WebSocket updatesGET /failure-history/{operation_type}/{operation_id}- Durable failure trailPOST /operation/{kind}/{id}/reset- Reset one operation of a kind (admin)POST /operation/{kind}/reset-all-failed- Reset all FAILED operations of a kind (admin)POST /raw-data-package/{id}/reconcile- Recompute one package’s state (admin)POST /raw-data-package/reconcile-inconsistent- Reconcile the inconsistent set (admin)POST /data-transfer/{id}/reset- Legacy reset shim (#95-safe, admin)
Authentication: GitHub OAuth (JWT); reset/reconcile actions are admin-gated (ADR-0002)
Example — overview reads the Operation chain, not a paired status column:
The overview does not query a per-stage status column off each artifact. It loads
the packages, bulk-attaches their operation chain by FK (_attach_operations), and
derives the funnel + failure attribution from the operation rows. Failures are
charged latest-step-first and keyed by OperationKind.value + the Operation row id:
@router.get("/api/transfer/overview")
async def get_transfer_overview(db: AsyncSession = Depends(get_async_db)):
# crud.get_transfer_overview:
# - COUNT operations per OperationKind -> operation_counts_by_kind
# - load non-archived RawDataPackages
# - _attach_operations(db, packages): bulk-load the five operation lists
# BY FK (no artifact->operation ORM relationship, no N+1)
# - classify_transferring_step(pkg): place each in the seven-step funnel
# - attribute_failed_package(pkg): charge the failing op,
# operation_type = op.operation_kind.value, operation_id = op.id
return await crud.get_transfer_overview(db)
The WS /ws/overview handler runs outside the per-request Depends chain, so it
pulls its own session from websocket.app.state.async_session_factory instead.
Recovery — uniform reset and reconcile:
# Reset one operation of any kind; {kind} is an OperationKind value
@router.post("/api/transfer/operation/{kind}/{operation_id:int}/reset")
async def reset_operation(kind: OperationKind, operation_id: int, ...):
# status -> PENDING, retry_count++, breadcrumb cache nulled,
# OperationFailureEvent history preserved (ADR-0001)
op = await crud.reset_operation(db, kind, operation_id)
# Reconcile a stale state=FAILED package from its op chain (ADR-0004)
@router.post("/api/transfer/raw-data-package/{package_id:int}/reconcile")
async def reconcile_raw_data_package(package_id: int, ...):
pkg = await crud.reconcile_raw_data_package(db, package_id)
Observing Program Router#
Path: /observing_program
Purpose: Manage observation programs
Key endpoints:
GET /- List programsPOST /- Create programGET /{id}- Get program detailsPUT /{id}- Update program
Sources Router#
Path: /sources
Purpose: Astronomical source catalog queries
Key endpoints:
GET /- List/search sourcesGET /{id}/chip- Source card viewGET /{id}/details- Detailed infoPOST /resolve- Name resolution
Features:
Cone search by coordinates
Name resolution (SIMBAD/NED)
Multiple detail levels
Visibility Router#
Path: /visibility
Purpose: Source visibility calculations
Key endpoints:
GET /{source_id}- Visibility for sourceGET /heatmap- Heatmap dataPOST /precalculate- Trigger precalculation (admin)
Characteristics:
Computationally expensive
Heavily cached
Time-based queries
Next Steps#
Operations-Focused Routers - Operations-focused routers
Endpoint Categories - Full categorization