feat: add gear provenance models and browser fetcher

This commit is contained in:
ik
2026-09-20 15:50:43 +07:00
parent b0edae98c6
commit 4e9895fbf4
19 changed files with 986 additions and 20 deletions
+55
View File
@@ -69,6 +69,61 @@ class Bait(Base):
kind: Mapped[BaitKind] = mapped_column(Enum(BaitKind))
class TackleItem(Base):
"""Canonical gear item; legacy Bait rows remain source-compatible."""
__tablename__ = "tackle_item"
__table_args__ = (
UniqueConstraint("source_system", "source_external_id"),
CheckConstraint(
"category IN ('bait', 'lure', 'rod', 'reel', 'line', 'hook', 'rig', 'float', 'sinker', 'other')",
name="ck_tackle_item_category",
),
)
id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4)
name: Mapped[str] = mapped_column(String(200))
normalized_name: Mapped[str] = mapped_column(String(200), unique=True)
category: Mapped[str] = mapped_column(String(20))
subcategory: Mapped[str | None] = mapped_column(String(100))
brand: Mapped[str | None] = mapped_column(String(100))
family: Mapped[str | None] = mapped_column(String(100))
unlock_level: Mapped[int | None]
source_system: Mapped[str | None] = mapped_column(String(50))
source_external_id: Mapped[str | None] = mapped_column(String(200))
source_url: Mapped[str | None] = mapped_column(Text)
source_checked_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
raw_payload: Mapped[dict | None] = mapped_column(JSON)
rig_components: Mapped[list["RigComponent"]] = relationship(back_populates="tackle_item")
class Rig(Base):
"""A named rig/setup kept separate from individual tackle items."""
__tablename__ = "rig"
id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4)
name: Mapped[str] = mapped_column(String(200))
normalized_name: Mapped[str] = mapped_column(String(200), unique=True)
source_system: Mapped[str | None] = mapped_column(String(50))
source_external_id: Mapped[str | None] = mapped_column(String(200))
source_url: Mapped[str | None] = mapped_column(Text)
source_checked_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
raw_payload: Mapped[dict | None] = mapped_column(JSON)
components: Mapped[list["RigComponent"]] = relationship(back_populates="rig")
class RigComponent(Base):
__tablename__ = "rig_component"
__table_args__ = (UniqueConstraint("rig_id", "position"),)
id: Mapped[uuid.UUID] = mapped_column(primary_key=True, default=uuid.uuid4)
rig_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("rig.id"))
tackle_item_id: Mapped[uuid.UUID | None] = mapped_column(ForeignKey("tackle_item.id"))
role: Mapped[str] = mapped_column(String(50))
position: Mapped[int] = mapped_column(Integer)
raw_value: Mapped[str | None] = mapped_column(String(200))
rig: Mapped[Rig] = relationship(back_populates="components")
tackle_item: Mapped[TackleItem | None] = relationship(back_populates="rig_components")
class Spot(Base):
__tablename__ = "spot"
__table_args__ = (UniqueConstraint("waterbody_id", "x", "y"),)