# Docker development stack ## Quick start 1. Copy the environment template (only required if you want to override defaults): ```sh cp .env.docker .env ``` The stack already reads `.env.docker` via `env_file`, so copying is optional unless you need custom values. 2. Start the stack: ```sh docker compose up -d ``` 3. When you need to run migrations or any workflow that requires the bundled MySQL, activate the `migration` profile: ```sh docker compose --profile migration up -d box-mysql ``` MySQL stays behind this profile so the default stack keeps the scope limited. The APIs already point to `box-mysql` via `MYSQL_URL`, so start the profile before or next to the main stack when migrations are required. 4. Stop and remove containers/volumes: ```sh docker compose down ``` ## Useful helpers - Stream a service log: `docker compose logs -f box-mgnt-api` - Enter the Mongo shell to confirm the replica set: `docker compose exec box-mongodb mongosh --eval 'rs.status()'` - Rebuild an API image after code changes: `docker compose build box-mgnt-api` ## Stack summary - `box-redis`, `box-rabbitmq`, `box-mongodb`, and `box-mysql` use named volumes (`redis_data`, `rabbitmq_data`, `mongo_data`, `mysql_data`). MySQL is only provisioned when you activate the `migration` profile. - Mongo runs `mongod --replSet rs0 --bind_ip_all` plus `docker/mongo/init-repl.js`, which initializes `rs0` exactly once and ensures `box_admin`/`box_stats` exist. - Each API reads `.env.docker` via `env_file`, then sets host/port/DB overrides for container-specific behavior. - One user-defined network (`box-network`) keeps all containers connected while ports stay consistent with the Nest apps (`3300`, `3301`, `3302`). ## Smoke test checklist - `curl -fsSL http://localhost:3300/api/v1/health` (box-mgnt-api) returns HTTP 200/JSON. - `curl -fsSL http://localhost:3301/api/v1/health` (box-app-api) returns HTTP 200/JSON. - `curl -fsSL http://localhost:3302/api/v1/health` (box-stats-api) returns HTTP 200/JSON. - `docker compose exec box-mongodb mongosh --quiet --eval 'rs.status().ok'` prints `1`.