The legacy SMARTMUSIC_ prefix dates from when the project was specced
as "smart-music" before being renamed to Minstrel. Hard cutover to
MINSTREL_* across config.go, tests, config.example.yaml, README, and
docker-compose. Also renames SMARTMUSIC_CONFIG in cmd/minstrel/main.go
which was missed in the original audit.
Also seeds Auth.AdminBootstrap.Username = "admin" in Default() so
MINSTREL_DATABASE_URL is the only env var required for a fresh prod
deployment — the bootstrap auto-generates a password and prints it
to stderr. Drops the now-redundant MINSTREL_AUTH_ADMIN_USERNAME=admin
line from the README quickstart and docker-compose.
M1 follow-up from the #363 final review: guards
MINSTREL_BRANDING_APP_NAME and _DESCRIPTION against empty-string
overrides — empty would have shipped <title></title> to share-preview
crawlers.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Slice 1 of M7 #352 added Server.DataDir but left it un-populated —
the playlist cover-collage writer would have used "" as the relative
path root in production, writing to the current working directory.
- Add Storage.DataDir to Config (yaml: storage.data_dir, env:
SMARTMUSIC_STORAGE_DATA_DIR), defaulting to "./data".
- server.New takes the data dir as a parameter; main.go threads it.
- main.go MkdirAll's the directory at startup so the playlist cover
writer doesn't fail on first use with a missing parent.
- config.example.yaml documents the new section.
Existing internal/server/server_test.go constructs Server directly
without server.New, so no test fixture changes needed for that file.
Validates seed_track + optional limit (default cfg.Recommendation.RadioSize,
clamped to RadioSizeMax). Calls recommendation.LoadCandidates +
recommendation.Shuffle. Prepends seed to result. Server seeds a
math/rand source at startup; handlers package threads that as a
func() float64 so tests inject deterministic RNGs.
Mount + server.New gain a RecommendationConfig parameter.
Discriminated-union JSON over three event types: play_started,
play_ended, play_skipped. Auth via existing RequireUser. play_started
returns play_event_id + session_id; the other two return { ok: true }.
Validates ownership: play_ended/play_skipped on another user's row
returns 403. Mount signature now takes EventsConfig and constructs
the playevents.Writer; server.New propagates it through.
Parses --config / SMARTMUSIC_CONFIG, loads YAML config with env overlay,
initializes slog, starts the chi HTTP server, and shuts down cleanly on
SIGINT/SIGTERM.