Files
photoanalyzer/photo_pipeline/models/albums.py

50 lines
2.0 KiB
Python

"""Album naming proposal persistence (US03-03).
One current proposal row per album label (the US03-01 identity). The row records
what was proposed, from which evidence version and model/prompt version, the user's
edit, the approval state, and an optimistic ``version`` that every edit/approval
must present so stale browser state cannot overwrite a newer decision.
Approval records intent only — no rename happens here (that is Phase D).
"""
from __future__ import annotations
from datetime import datetime
from sqlalchemy import DateTime, Float, Integer, String, func
from sqlalchemy.orm import Mapped, mapped_column
from photo_pipeline.db import Base
class AlbumProposal(Base):
__tablename__ = "album_proposals"
id: Mapped[str] = mapped_column(String, primary_key=True)
album: Mapped[str] = mapped_column(String, nullable=False, unique=True, index=True)
proposed_name: Mapped[str | None] = mapped_column(String)
final_name: Mapped[str | None] = mapped_column(String)
rationale: Mapped[str | None] = mapped_column(String)
confidence: Mapped[float | None] = mapped_column(Float)
# pending | proposed | edited | approved | error
status: Mapped[str] = mapped_column(String, nullable=False, default="pending")
error_code: Mapped[str | None] = mapped_column(String)
error_message: Mapped[str | None] = mapped_column(String)
evidence_version: Mapped[str | None] = mapped_column(String)
model: Mapped[str | None] = mapped_column(String)
prompt_version: Mapped[str | None] = mapped_column(String)
raw_response: Mapped[str | None] = mapped_column(String)
version: Mapped[int] = mapped_column(Integer, nullable=False, default=1)
approved_at: Mapped[datetime | None] = mapped_column(DateTime(timezone=True))
created_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), nullable=False, server_default=func.now()
)
updated_at: Mapped[datetime] = mapped_column(
DateTime(timezone=True), nullable=False, server_default=func.now(), onupdate=func.now()
)