Add system alerts log with nav badge and Admin Alerts tab.
Persist job and ingestion warnings/errors for 7 days, surface a dismissible top-nav badge, treat stale OHLCV as a warning (e.g. ticker renames), and show market bar age on the ticker freshness chip.
This commit is contained in:
+49
-1
@@ -6,7 +6,7 @@ All endpoints require admin role.
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.dependencies import get_db, require_admin
|
||||
from app.dependencies import get_db, require_access, require_admin
|
||||
from app.models.user import User
|
||||
from app.schemas.admin import (
|
||||
ActivationConfigUpdate,
|
||||
@@ -29,6 +29,7 @@ from app.schemas.common import APIEnvelope
|
||||
from app.services import admin_service
|
||||
from app.services import alert_service
|
||||
from app.services import sentiment_provider_service
|
||||
from app.services import system_event_service
|
||||
from app.services import ticker_universe_service
|
||||
|
||||
router = APIRouter(tags=["admin"])
|
||||
@@ -403,3 +404,50 @@ async def toggle_job(
|
||||
status="success",
|
||||
data={"key": setting.key, "value": setting.value},
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# System events (operational warnings / errors)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@router.get("/admin/system-events", response_model=APIEnvelope)
|
||||
async def list_system_events(
|
||||
days: int = Query(7, ge=1, le=30),
|
||||
severity: str | None = Query(None, description="warning | error"),
|
||||
unacknowledged_only: bool = Query(False),
|
||||
_user: User = Depends(require_access),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""List recent system events (default last 7 days)."""
|
||||
rows = await system_event_service.list_events(
|
||||
db,
|
||||
days=days,
|
||||
severity=severity,
|
||||
unacknowledged_only=unacknowledged_only,
|
||||
)
|
||||
return APIEnvelope(
|
||||
status="success",
|
||||
data=[system_event_service.event_to_dict(r) for r in rows],
|
||||
)
|
||||
|
||||
|
||||
@router.get("/admin/system-events/summary", response_model=APIEnvelope)
|
||||
async def system_events_summary(
|
||||
days: int = Query(7, ge=1, le=30),
|
||||
_user: User = Depends(require_access),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""Badge counts for the top nav."""
|
||||
data = await system_event_service.summary(db, days=days)
|
||||
return APIEnvelope(status="success", data=data)
|
||||
|
||||
|
||||
@router.post("/admin/system-events/acknowledge", response_model=APIEnvelope)
|
||||
async def acknowledge_system_events(
|
||||
days: int = Query(7, ge=1, le=30),
|
||||
_user: User = Depends(require_access),
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""Dismiss unacknowledged events in the lookback window (clears the badge)."""
|
||||
count = await system_event_service.acknowledge_all(db, days=days)
|
||||
return APIEnvelope(status="success", data={"acknowledged": count})
|
||||
|
||||
Reference in New Issue
Block a user