from __future__ import annotations from datetime import datetime, timezone from uuid import uuid4 from sqlalchemy import JSON, DateTime, Float, Integer, String, Text from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column def _utcnow() -> datetime: return datetime.now(timezone.utc) class Base(DeclarativeBase): pass class AuditLog(Base): __tablename__ = "audit_logs" id: Mapped[str] = mapped_column( String(36), primary_key=True, default=lambda: str(uuid4()) ) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, index=True ) method: Mapped[str] = mapped_column(String(12), index=True) path: Mapped[str] = mapped_column(String(300), index=True) query_string: Mapped[str] = mapped_column(String(1000), default="") status_code: Mapped[int] = mapped_column(Integer, index=True) duration_ms: Mapped[float] = mapped_column(Float) trace_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True) span_id: Mapped[str | None] = mapped_column(String(16), nullable=True, index=True) client_ip: Mapped[str | None] = mapped_column(String(120), nullable=True) user_agent: Mapped[str | None] = mapped_column(Text, nullable=True) details: Mapped[dict] = mapped_column(JSON, default=dict) class ForecastRun(Base): __tablename__ = "forecast_runs" id: Mapped[str] = mapped_column( String(36), primary_key=True, default=lambda: str(uuid4()) ) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, index=True ) horizon_days: Mapped[int] = mapped_column(Integer) point_count: Mapped[int] = mapped_column(Integer) trigger_source: Mapped[str] = mapped_column(String(64), index=True) trace_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True) span_id: Mapped[str | None] = mapped_column(String(16), nullable=True, index=True) payload: Mapped[list[dict]] = mapped_column(JSON, default=list) class RankingRun(Base): __tablename__ = "ranking_runs" id: Mapped[str] = mapped_column( String(36), primary_key=True, default=lambda: str(uuid4()) ) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, index=True ) top_n: Mapped[int] = mapped_column(Integer) item_count: Mapped[int] = mapped_column(Integer) trigger_source: Mapped[str] = mapped_column(String(64), index=True) trace_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True) span_id: Mapped[str | None] = mapped_column(String(16), nullable=True, index=True) payload: Mapped[list[dict]] = mapped_column(JSON, default=list) class RecommendationRun(Base): __tablename__ = "recommendation_runs" id: Mapped[str] = mapped_column( String(36), primary_key=True, default=lambda: str(uuid4()) ) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), default=_utcnow, index=True ) item_count: Mapped[int] = mapped_column(Integer) trigger_source: Mapped[str] = mapped_column(String(64), index=True) trace_id: Mapped[str | None] = mapped_column(String(32), nullable=True, index=True) span_id: Mapped[str | None] = mapped_column(String(16), nullable=True, index=True) payload: Mapped[list[dict]] = mapped_column(JSON, default=list)