1
0
Files
record-shop/docs/superpowers/specs/2026-09-04-navidrome-link-design.md

2.6 KiB

Replace In-App Player with Navidrome Deep Link — Design Spec

Date: 2026-09-04 Status: Approved design, pending implementation Parent: docs/superpowers/specs/2026-09-03-wave1-hygiene-listening-design.md (supersedes its "Mini player" section)

Purpose

The built-in album player (global audio element + mini-bar) is removed. Listening happens in the user's Navidrome web UI; the item page links directly to the matched album there. Rationale: Navidrome's player is better than ours, and the in-app player added a global-audio architecture for a preview-quality experience.

Removals

  • web/src/player/ (PlayerContext, MiniBar) and their tests; PlayerProvider/MiniBar wiring in web/src/App.tsx
  • Backend stream/tracks/played routes (server/src/routes/streamRoutes.ts) and their tests
  • api methods getAlbumTracks, markPlayed, streamUrl; types Track, AlbumTracks; ItemPage's usePlayer/load wiring and media mocks
  • Media-prototype mocks in web/test/item.test.tsx (no audio element remains)

Changes

  • GET /api/collection/:id detailmatchedAlbum gains webUrl: string: the Navidrome album URL built server-side as <subsonic_url>/app/#/album/<subsonicId> (trailing slashes stripped from the configured base; null-safe — matchedAlbum stays null when unmatched, and when no Subsonic config exists webUrl is still constructed from the stored URL only if the album row exists; unmatched → null either way).
  • Item page — the ▶ Play album button becomes an anchor "Listen in Navidrome ↗" (target="_blank" rel="noreferrer"), shown whenever matchedAlbum != null (regardless of rip status — the album exists in Navidrome if it matched).
  • "Last played X ago" stays. Stamping now comes solely from library sync reading the server's recently-played list (getAlbumList2?type=recent, opportunistic played/playedAt field). No in-app stamping.

Unchanged

Stats, loans, rip queue, export/backup, sync, matching, all plan-1/2 APIs except the removed routes.

Error handling

No new failure modes. The link is a static anchor; a wrong Subsonic URL produces a broken link the same way a wrong URL breaks sync — surfaced by Settings, not the item page.

Testing

  • Backend: detail test asserts matchedAlbum.webUrl (http://n.local/app/#/album/<subsonicId>); stream tests deleted with the routes
  • Web: item tests assert the link (href + target) replaces the player tests; api.test drops the removed methods; player/minibar test files deleted

Manual device checklist

  • Link opens Navidrome's album page from the phone (PWA → browser tab)