from datetime import datetime, timezone from sqlalchemy import Boolean, DateTime, Integer, String, Text, UniqueConstraint from sqlalchemy.orm import Mapped, mapped_column from app.db.base import Base def utcnow(): return datetime.now(timezone.utc) class ModelProfile(Base): __tablename__ = "model_profiles" id: Mapped[int] = mapped_column(Integer, primary_key=True) profile_type: Mapped[str] = mapped_column(String(32), index=True) model_name: Mapped[str] = mapped_column(String(255)) endpoint: Mapped[str] = mapped_column(String(1024)) capabilities_json: Mapped[str] = mapped_column(Text, default="{}") created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow) class ProviderConfig(Base): __tablename__ = "provider_configs" __table_args__ = (UniqueConstraint("profile_type"),) id: Mapped[int] = mapped_column(Integer, primary_key=True) profile_type: Mapped[str] = mapped_column(String(32), index=True) model_name: Mapped[str] = mapped_column(String(255)) endpoint: Mapped[str] = mapped_column(String(1024)) chat_path: Mapped[str] = mapped_column(String(255), default="/chat/completions") models_path: Mapped[str] = mapped_column(String(255), default="/models") auth_type: Mapped[str] = mapped_column(String(32), default="none") api_key: Mapped[str] = mapped_column(Text, default="") auth_header: Mapped[str] = mapped_column(String(255), default="Authorization") auth_prefix: Mapped[str] = mapped_column(String(255), default="Bearer") verify_ssl: Mapped[bool] = mapped_column(Boolean, default=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow) updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow) class User(Base): __tablename__ = "users" id: Mapped[int] = mapped_column(Integer, primary_key=True) username: Mapped[str] = mapped_column(String(64), unique=True, index=True) password_hash: Mapped[str] = mapped_column(String(255)) is_active: Mapped[bool] = mapped_column(default=True) is_admin: Mapped[bool] = mapped_column(default=False) token_version: Mapped[int] = mapped_column(Integer, default=0) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow) class RevokedToken(Base): __tablename__ = "revoked_tokens" id: Mapped[int] = mapped_column(Integer, primary_key=True) token_digest: Mapped[str] = mapped_column(String(64), unique=True, index=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow) class RefreshToken(Base): # ponytail: retain rotation history for replay detection; add scheduled expiry cleanup when table growth matters. __tablename__ = "refresh_tokens" id: Mapped[int] = mapped_column(Integer, primary_key=True) user_id: Mapped[int] = mapped_column(Integer, index=True) family_id: Mapped[str] = mapped_column(String(36), index=True) token_digest: Mapped[str] = mapped_column(String(64), unique=True, index=True) token_version: Mapped[int] = mapped_column(Integer) expires_at: Mapped[int] = mapped_column(Integer) consumed_at: Mapped[int | None] = mapped_column(Integer, nullable=True) idempotency_key: Mapped[str | None] = mapped_column(String(128), nullable=True) replacement_digest: Mapped[str | None] = mapped_column(String(64), nullable=True) access_expires_at: Mapped[int | None] = mapped_column(Integer, nullable=True) revoked_at: Mapped[int | None] = mapped_column(Integer, nullable=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow) class TestRun(Base): __tablename__ = "test_runs" id: Mapped[int] = mapped_column(Integer, primary_key=True) run_type: Mapped[str] = mapped_column(String(32), index=True) status: Mapped[str] = mapped_column(String(32), index=True) profile: Mapped[str] = mapped_column(String(32), default="smoke") selected_count: Mapped[int] = mapped_column(Integer, default=0) idempotency_key: Mapped[str | None] = mapped_column(String(128), unique=True, nullable=True) request_fingerprint: Mapped[str] = mapped_column(String(128), default="") completed_count: Mapped[int] = mapped_column(Integer, default=0) error_count: Mapped[int] = mapped_column(Integer, default=0) summary_json: Mapped[str] = mapped_column(Text, default="{}") capabilities_json: Mapped[str | None] = mapped_column(Text, nullable=True) created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow) updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow) class TestResult(Base): __tablename__ = "test_results" __table_args__ = ( UniqueConstraint("run_id", "execution_id", name="uq_test_results_run_execution"), ) id: Mapped[int] = mapped_column(Integer, primary_key=True) run_id: Mapped[int] = mapped_column(Integer, index=True) execution_id: Mapped[str] = mapped_column(String(128), index=True) case_kind: Mapped[str] = mapped_column(String(32), index=True) interaction_mode: Mapped[str] = mapped_column(String(32), index=True) execution_status: Mapped[str] = mapped_column(String(32), index=True) verdict: Mapped[str | None] = mapped_column(String(32), index=True, nullable=True) model_response: Mapped[str] = mapped_column(Text, default="") judge_result_json: Mapped[str] = mapped_column(Text, default="{}") error_message: Mapped[str] = mapped_column(Text, default="") audit_context_json: Mapped[str] = mapped_column(Text, default="{}") created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), default=utcnow)