# 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/`](./docs):

- [Server spec](./docs/smart-music-server-spec.md) — current implementation focus.
- [Client spec](./docs/smart-music-client-spec.md) — 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:embed`s it into the
final binary. The resulting container serves the SPA from `/` alongside the
API surfaces. No separate static-file server is required.
