"""ORM models. One table for now: the per-user cached feed (the last completed search).""" from __future__ import annotations from datetime import datetime from sqlalchemy import JSON, DateTime, Integer, String, func from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column class Base(DeclarativeBase): pass class UserFeed(Base): """The user's last completed search — replayed on load so matches survive navigation. Upserted on each `search_complete`; read by `get_feed`. One row per user (PK = user_id).""" __tablename__ = "user_feed" user_id: Mapped[str] = mapped_column(String, primary_key=True) prefs: Mapped[dict] = mapped_column(JSON, default=dict) # the ScoutPrefs that produced it opportunities: Mapped[list] = mapped_column(JSON, default=list) # the curated deck (with match blocks) sources: Mapped[dict] = mapped_column(JSON, default=dict) # per-board counts engine: Mapped[str] = mapped_column(String, default="") # "opus" | "fallback:…" scanned: Mapped[int] = mapped_column(Integer, default=0) updated_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), server_default=func.now(), onupdate=func.now() )