bvandeusen c331168d3b feat(api): /api/playlists* handlers for M7 #352 slice 1
9 handlers covering create / get / list / update / delete / append /
remove / reorder / cover. Permissions enforced in the service layer
(ErrForbidden -> 403 not_authorized) so the handler is a thin
HTTP-shape adapter. /cover serves the cached collage from disk via
http.ServeFile; 404 when cover_path is nil.

Server gained a DataDir field so the playlists service can find the
collage cache; api.Mount picks up two new params (playlistsSvc and
dataDir). The stale TestRoutesRegisteredInMount Mount() call in
library_test.go was missing the tracks.Service argument added by an
earlier slice — fixed in passing.

Wire codes follow the project's existing nested errorBody envelope:
not_found, not_authorized, unauthenticated, bad_request, server_error.
The plan called for a flat envelope, but the api package's writeErr
already produces {"error":{"code":"...","message":"..."}} and
deviating here would break every existing client.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 11:10:21 -04:00
2026-04-19 15:14:56 +00:00
2026-04-18 17:33:35 +00:00

Minstrel

Self-hosted music server with OpenSubsonic compatibility plus an extended API for server-side smart shuffle, a dual-like model (general + contextual), session-aware radio, ListenBrainz scrobble/similarity, and Lidarr integration. Go + Postgres, packaged as a Docker container.

State and intelligence belong on the server, not the client.

Specs

Authoritative v1 scope lives under docs/:

  • Server spec — current implementation focus.
  • Client spec — Flutter companion app; work starts once the server reaches its Subsonic-compatible baseline.

Development workflow

  • Day-to-day work happens on the dev branch (or feature branches merged into dev).
  • main is protected — changes land only via pull request from dev.
  • Production builds are cut by tagging a release (v*) off main.

CI / container image

Forgejo Actions handles:

  • Tests on push to dev and on PRs into main.
  • Container image build + push to the Forgejo registry on merge to main (:main) and on v* tags (:<version>).

Task and milestone tracking: Fable (Minstrel project, id 12).

Development

Minstrel has two concurrent dev processes:

  1. Backend: docker compose up — starts Postgres and Minstrel on :4533.
  2. Frontend: cd web && npm install && npm run dev — Vite dev server on :5173 with HMR.

The Vite dev server proxies /api/* and /rest/* to the backend on :4533, so session cookies work correctly when the SPA is loaded from the Vite origin.

Production build

docker build -t minstrel . runs the SvelteKit build inside a node stage, copies the output into the golang stage, and //go:embeds it into the final binary. The resulting container serves the SPA from / alongside the API surfaces. No separate static-file server is required.

S
Description
Self-hosted music server with OpenSubsonic compatibility, server-side smart shuffle, dual-like model, session-aware radio, and Lidarr integration. Go + Postgres.
Readme MIT 63 MiB
Languages
Go 39.2%
Kotlin 25%
Dart 14.2%
TypeScript 12%
Svelte 9.3%
Other 0.1%