diff --git a/docs/superpowers/specs/2026-05-03-m7-track-actions-menu-design.md b/docs/superpowers/specs/2026-05-03-m7-track-actions-menu-design.md index 4141baff..ba2d5d56 100644 --- a/docs/superpowers/specs/2026-05-03-m7-track-actions-menu-design.md +++ b/docs/superpowers/specs/2026-05-03-m7-track-actions-menu-design.md @@ -20,7 +20,7 @@ Per-track kebab menu wherever `` or the `` track display is - "Like / Unlike" and "Hide / Unhide" entries duplicate functionality already on the row (heart and eye icon buttons). Reason: keyboard discoverability — once the kebab is focused, arrow-keys reach every action; mouse users still get one-tap heart/eye on the row. - "Add to playlist…" reserves the menu slot but the submenu of playlists is wired in #352, not here. The slot renders as disabled with a tooltip "Coming with playlists" until #352 ships. - "Go to artist" is single-target (`track.artistId`); compilation/feature artists aren't modeled in the schema today and that's a schema problem to solve before this entry needs a submenu. -- "Remove from library" is admin-only — gated client-side by `currentUser.is_admin`, server-side by the existing `auth.RequireAdmin()` middleware on the new `/api/admin/tracks/{id}` route. New backend endpoint deletes the track row, removes the file from disk (or via Lidarr for Lidarr-managed tracks), and cascades album → artist tidy-up if either becomes empty. +- "Remove from library" is admin-only — gated client-side by `currentUser.is_admin`, server-side by `auth.RequireAdmin()` on the new `/api/admin/tracks/{id}` route. The endpoint always deletes the file from disk via `os.Remove` (not via Lidarr, which is album-granular and has no per-track delete) plus the DB row, then cascades album → artist tidy-up. For Lidarr-managed tracks the operator chooses whether Lidarr should look for a replacement (default — no extra action; Lidarr's monitoring re-imports on next scan) or the track should be unmonitored (server calls `Lidarr.UnmonitorTrack(mbid)` to flip `monitored: false`). The `?unmonitor=true` query param drives this — unset / `false` = replace, `true` = unmonitor. - Keyboard accessibility: kebab is `