- Toast now announces via role="status"/aria-live="polite" by default,
and role="alert"/aria-live="assertive" for errors. Screen readers
previously got nothing when notifications appeared.
- Move playlist-item flex-wrap:wrap from inline style into the
@media (max-width: 768px) block so desktop rows don't wrap controls
when the viewport is intermediate-narrow.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds accessible up/down arrow buttons alongside the existing drag-to-
reorder handle on each playlist item. Touch users (and keyboard users)
now have a reliable way to re-order without relying on HTML5 drag-drop,
which is effectively unusable on mobile. First/last items have the
respective arrow disabled.
Uses the same /reorder API the drag handler uses, so behavior stays
consistent. flex-wrap on the item container prevents control overflow
on narrow screens.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Security fixes:
- Critical: Add ownership checks to assignments PUT/:id and DELETE/:id (IDOR)
- Critical: Add ownership checks to assignments copy-to endpoint for both devices
- High: Validate device ownership when adding to device groups
- High: UUID-validate content ID before LIKE query + scope to owner's playlists
- Low: Handle FK violations gracefully in playlist discard (deleted content/widgets)
- Low: Escape mime_type with esc() in playlist item display (XSS)
Bug fix:
- Device-detail mutation handlers now reload full page to show draft banner
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Schema: add status and published_snapshot columns to playlists table.
Migration snapshots all existing playlists as published (idempotent via schema_migrations).
Devices always receive the published_snapshot, not live playlist_items.
Edits from device-detail/groups auto-publish immediately (display updates instantly).
Edits from playlist detail page go to draft (requires explicit publish).
POST /playlists/:id/publish snapshots and pushes to all devices.
POST /playlists/:id/discard reverts playlist_items from published snapshot.
Content deletion scrubs references from all published snapshots.
Frontend: draft badge in playlist list, prominent yellow banner with publish/discard
buttons on playlist detail and device detail pages.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Users need to see migrated playlists immediately. The toggle still
allows hiding them if desired.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
List view: auto-generated playlists hidden by default with toggle checkbox.
Cards show 'auto' badge and display count. Detail view shows display count
in the header.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
List view: playlist cards with name, description, item count.
Detail view: inline-editable name/description, ordered item list
with thumbnails, duration editing, drag-to-reorder, remove.
Add-item modal: content/widget picker with search and tabs.
All user strings escaped via esc() helper for safe innerHTML.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>