feat(views): saved-views backend — table, model, CRUD + reorder API
Per-user named snapshots of the feed's FeedFilters. New saved_views table (migration 0035, unique per user+name, position, is_default) + SavedView model, and a /api/saved-views router (list/create/patch/delete/reorder) gated behind require_human so the shared demo account can't pollute it. Setting is_default clears the flag on the user's other views (one default).
This commit is contained in:
parent
669994cc85
commit
3056734231
4 changed files with 235 additions and 0 deletions
|
|
@ -593,6 +593,28 @@ class PlaylistItem(Base):
|
|||
playlist: Mapped["Playlist"] = relationship(back_populates="items")
|
||||
|
||||
|
||||
class SavedView(Base, TimestampMixin, UpdatedAtMixin):
|
||||
"""A per-user named snapshot of the feed's filter/sort state (a "smart view").
|
||||
|
||||
`filters` is the serialized FeedFilters JSON the frontend applies with one click.
|
||||
`position` orders them in the sidebar (drag-reorder); `is_default` marks the one view
|
||||
applied automatically on load — at most one per user, enforced by the API on set."""
|
||||
|
||||
__tablename__ = "saved_views"
|
||||
__table_args__ = (UniqueConstraint("user_id", "name", name="uq_user_saved_view"),)
|
||||
|
||||
id: Mapped[int] = mapped_column(primary_key=True)
|
||||
user_id: Mapped[int] = mapped_column(
|
||||
ForeignKey("users.id", ondelete="CASCADE"), index=True
|
||||
)
|
||||
name: Mapped[str] = mapped_column(String(80))
|
||||
filters: Mapped[dict] = mapped_column(JSON)
|
||||
position: Mapped[int] = mapped_column(Integer, default=0, server_default="0")
|
||||
is_default: Mapped[bool] = mapped_column(
|
||||
Boolean, default=False, server_default="false"
|
||||
)
|
||||
|
||||
|
||||
class Notification(Base):
|
||||
"""A durable, server-backed per-user notification (the inbox center, phase 1).
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue