# 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-hmr` websocket) → `webui:3000`. The browser never talks to webui directly; HMR is proxied through nginx, which is why compose sets `RSBUILD_HMR_CLIENT_PORT` to `NGINX_PORT`. - **The entrypoint is `http://localhost:8881`**, not `:80`. Compose maps `${NGINX_PORT:-8881}:80` (README says `:80`, but the `.env.example` default is `8881`). `api:8000` is also exposed directly for docs/debugging (`/docs`). - **Source is bind-mounted** into `api`, `worker`, and `webui`, 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`). - **`api` and `worker` share the same image** and both need `db` + `redis` healthy before starting. - **`DATABASE_URL` / `REDIS_URL` are overridden inside compose** to use service names (`db`, `redis`). The localhost values in `.env` are only the fallback for host-run processes. - **Persistent state and media live under `./data/`** (gitignored): `pgdata`, `redisdata`, `media`, `transcode-cache`, and `youtube` (drop a yt-dlp `cookies.txt` here — 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. ```bash 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): ```bash 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: ```bash 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`: ```bash 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 with `PUBLIC_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.