Add system alerts log with nav badge and Admin Alerts tab.
Deploy / lint (push) Successful in 8s
Deploy / test (push) Failing after 1m4s
Deploy / deploy (push) Has been skipped

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:
2026-07-14 13:38:04 +02:00
parent ed82d0a665
commit f59c0c3484
16 changed files with 825 additions and 7 deletions
+2
View File
@@ -13,6 +13,7 @@ from app.models.paper_trade import PaperTrade
from app.models.regime_snapshot import RegimeSnapshot
from app.models.benchmark_price import BenchmarkPrice
from app.models.signal_context_snapshot import SignalContextSnapshot
from app.models.system_event import SystemEvent
__all__ = [
"Ticker",
@@ -32,4 +33,5 @@ __all__ = [
"RegimeSnapshot",
"BenchmarkPrice",
"SignalContextSnapshot",
"SystemEvent",
]
+37
View File
@@ -0,0 +1,37 @@
"""Operational system events (warnings/errors) for the admin UI and top-nav badge."""
from datetime import datetime
from sqlalchemy import DateTime, Index, String, Text
from sqlalchemy.orm import Mapped, mapped_column
from app.database import Base
class SystemEvent(Base):
"""Durable warning/error record (jobs, ingestion, pipelines).
``acknowledged_at`` is set when a user dismisses the nav badge / clears
events — history still shows in Admin → Jobs for the retention window.
"""
__tablename__ = "system_events"
__table_args__ = (
Index("ix_system_events_created_at", "created_at"),
Index("ix_system_events_ack_created", "acknowledged_at", "created_at"),
Index("ix_system_events_dedup_created", "dedup_key", "created_at"),
)
id: Mapped[int] = mapped_column(primary_key=True)
severity: Mapped[str] = mapped_column(String(16), nullable=False) # warning | error
source: Mapped[str] = mapped_column(String(64), nullable=False)
code: Mapped[str] = mapped_column(String(64), nullable=False)
message: Mapped[str] = mapped_column(Text, nullable=False)
symbol: Mapped[str | None] = mapped_column(String(20), nullable=True)
dedup_key: Mapped[str | None] = mapped_column(String(200), nullable=True)
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), default=datetime.utcnow, nullable=False
)
acknowledged_at: Mapped[datetime | None] = mapped_column(
DateTime(timezone=True), nullable=True
)