Point mcma-backend + mcma-webui at their sloppyslop tips (lyrics, transcoding, admin/storage/maintenance/instance UI, batch metadata, NowPlaying+lyrics). Includes the CORS note in .env.example, TODO/ ignore, and the project CLAUDE.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
5.1 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
What this repo is
mcma-compose is the dev-orchestration superproject for mycoolmusicapp — a self-hosted music
app. It contains no application code of its own: docker-compose.yml, nginx.conf, Makefile, and
.env.example. The actual code lives in two git submodules:
mcma-backend/— Python / FastAPI (async), arq background workers, Alembic migrations.mcma-webui/— TypeScript / React, built with Rsbuild.
Both submodules are pulled from ssh://git@git.ollyhearn.ru:49239 (see .gitmodules). They may be
empty — clone with git clone --recurse-submodules, or run git submodule update --init in an
existing checkout, before you can touch or build app code.
The stack
make up builds and starts six services (see docker-compose.yml):
| Service | Image / context | Role |
|---|---|---|
db |
postgres:16-alpine | PostgreSQL, data in ./data/pgdata |
redis |
redis:7-alpine | arq broker + cache, data in ./data/redisdata |
api |
mcma-backend |
FastAPI via uvicorn --reload |
worker |
mcma-backend |
arq app.workers.arq_worker.WorkerSettings background jobs |
webui |
mcma-webui |
Rsbuild dev server with HMR |
nginx |
nginx:1.27-alpine | single entrypoint, reverse proxy |
Key architectural points that span multiple files:
- nginx is the only public port. It routes
/api/and/health→api:8000, everything else (including the/rsbuild-hmrwebsocket) →webui:3000. The browser never talks to webui directly; HMR is proxied through nginx, which is why compose setsRSBUILD_HMR_CLIENT_PORTtoNGINX_PORT. - The entrypoint is
http://localhost:8881, not:80. Compose maps${NGINX_PORT:-8881}:80(README says:80, but the.env.exampledefault is8881).api:8000is also exposed directly for docs/debugging (/docs). - Source is bind-mounted into
api,worker, andwebui, so edits in the submodules hot-reload with no rebuild. Named-volume mounts (/app/.venv,/app/node_modules) shadow the host dir to preserve the image's installed deps — if you change dependencies you must rebuild (make build). apiandworkershare the same image and both needdb+redishealthy before starting.DATABASE_URL/REDIS_URLare overridden inside compose to use service names (db,redis). The localhost values in.envare only the fallback for host-run processes.- Persistent state and media live under
./data/(gitignored):pgdata,redisdata,media,transcode-cache, andyoutube(drop a yt-dlpcookies.txthere — optional).
Commands
Everything runs inside the containers via the Makefile, which wraps docker compose exec.
The stack must be up (make up) before test/lint/migrate/shell targets work. Run make help
for the full list.
make up # create .env from .env.example, build images, start the whole stack
make build # rebuild images (with cache); needed after dependency changes
make rebuild # rebuild with --no-cache
make down # stop + remove containers
make clean # down -v — DESTROYS db/redis volumes
make logs-api # tail a single service's logs (also logs, logs-webui)
make sh-api # bash into api (also sh-webui, db-shell, redis-cli)
Migrations (Alembic, run in the api container):
make migrate # alembic upgrade head
make makemigration m="add_tracks" # autogenerate a revision
make downgrade # roll back one
Quality — these shell out to the tools inside each container:
make test # test-api (pytest) + test-webui (npm test)
make test-api # pytest — for a single test: make sh-api, then `pytest path::test`
make test-webui # npm test
make lint # ruff check . (api) + npm run lint (webui)
make fmt # ruff format . (api) + npm run format (webui)
There is no dev docker-compose for prod. Prod images are built straight from each submodule's
dockerfiles/Dockerfile.prod:
make prod-build # builds mcma-backend:prod and mcma-webui:prod
Environment
.env is a single combined file at the repo root, created from .env.example by make env /
make up (never committed; it's gitignored). It is injected into api, worker, and webui.
Backend features degrade gracefully when optional keys are unset:
ACOUSTID_API_KEY+MUSICBRAINZ_OWNER_EMAIL— enable AcoustID/MusicBrainz metadata enrichment.YOUTUBE_ENABLED/YOUTUBE_COOKIES_PATH— YouTube Music source via yt-dlp.ALLOW_REGISTRATION(backend) must be kept in sync withPUBLIC_ENABLE_REGISTRATION(frontend).
Working across submodules
When a change touches app behavior, the code is in mcma-backend/ or mcma-webui/ — commit there
first, then the superproject records the new submodule commit. Recent superproject history is mostly
chore: bump mcma-backend/mcma-webui commits that pin updated submodule SHAs.