Docker Compose¶
Purpose¶
Run the full local stack - MySQL, Redis, backend API, frontend - with one command, for day-to-day application development.
Prerequisites¶
Docker Desktop running. Optionally a .env file at the repo root (copy .env.example) to
override any default below - every default is safe to leave as-is for local development.
Files involved¶
docker-compose.yml (base stack), docker-compose.dev.yml (dev overrides: hot reload, exposed
ports), database/init.sql (mounted read-only into MySQL's entrypoint-init directory).
Services (docker-compose.yml)¶
| Service | Image | Container name | Host port(s) | Purpose |
|---|---|---|---|---|
mysql |
mysql:8.2 |
ecommerce_mysql |
3309:3306 (configurable via MYSQL_HOST_PORT) |
Database |
redis |
redis:7.2-alpine |
ecommerce_redis |
(not published - only reachable from other Compose services) | Cache/session |
api |
built from backend/Dockerfile |
ecommerce_api |
(not published in the base file - only docker-compose.dev.yml exposes 5000:8080) |
Backend |
frontend |
built from frontend/Dockerfile |
ecommerce_frontend |
80:80, 443:443 |
Single external entry point - serves the SPA and proxies /api/* |
adminer |
adminer:latest |
ecommerce_adminer |
8080:8080 |
Database UI - only runs with --profile dev, never starts by default |
Configuration (environment variables, all with safe local defaults)¶
| Variable | Default if unset | Used by |
|---|---|---|
MYSQL_ROOT_PASSWORD |
rootpassword |
mysql |
MYSQL_PASSWORD |
ecommerce_pass |
mysql, api |
MYSQL_HOST_PORT |
3309 |
mysql |
REDIS_PASSWORD |
redispassword |
redis, api |
JWT_SECRET_KEY |
a placeholder string (must be overridden before anything resembling production use) | api |
ASPNETCORE_ENVIRONMENT |
Production |
api |
FRONTEND_URL |
http://localhost |
api (CORS AllowedOrigins) |
EMAIL_PROVIDER / WHATSAPP_PROVIDER / PUSH_PROVIDER |
Simulated |
api - safe no-op providers; set a real provider name + matching *_API_KEY/*_ACCESS_TOKEN in .env to send real notifications |
These fallback defaults only ever apply on a developer's own machine when .env is absent - never
in any Kubernetes environment, which requires an explicitly pre-created Secret with no
fallback (see Kubernetes → Helm).
Volumes¶
| Volume | Mounted at | Purpose |
|---|---|---|
mysql_data |
/var/lib/mysql |
Database files - persists across docker compose down (not down -v) |
redis_data |
/data |
Redis AOF persistence |
api_uploads |
/app/uploads |
Locally-stored file uploads (when FileStorage:Provider=Local) |
./database/init.sql |
/docker-entrypoint-initdb.d/init.sql (read-only) |
One-time schema/seed on first MySQL start |
Networking¶
All services share one bridge network, ecommerce_network. Services reach each other by service
name (Server=mysql;..., redis:6379) - only frontend (80/443) and, in dev mode, api
(5000→8080) and adminer (8080) publish host ports.
Health checks¶
Every service except adminer has a HEALTHCHECK/Compose healthcheck. api and frontend
both depends_on their dependencies with condition: service_healthy - frontend won't even
attempt to start until api reports healthy, and api won't start until mysql/redis do.
Commands¶
# Start (background)
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build
# Start (foreground, dev hot-reload)
docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build
# Status
docker compose ps
# Logs (all services, follow)
docker compose logs -f
# Logs (one service)
docker compose logs -f api
# Stop (keeps volumes/data)
docker compose -f docker-compose.yml -f docker-compose.dev.yml down
# Stop AND delete volumes (MySQL/Redis data gone - only do this deliberately)
docker compose -f docker-compose.yml -f docker-compose.dev.yml down -v
# Rebuild one service after a Dockerfile/dependency change
docker compose build api
docker compose up -d api
# Optional: Adminer DB UI
docker compose --profile dev up -d adminer
Validation / expected result¶
Frontend at http://localhost (or http://localhost:3000 withdocker-compose.dev.yml's Vite
dev server), backend directly at http://localhost:5000 (dev override only).
Troubleshooting¶
Rollback / recovery¶
docker compose down never deletes the named volumes (mysql_data, redis_data,
api_uploads) unless you pass -v explicitly - restarting with up again reattaches to the same
data. To reset to a clean database, down -v then up --build re-runs database/init.sql.
Security considerations¶
docker-compose.override.ymlis gitignored - the intended place for any real local secret override, never committed..envis gitignored (see repository root.gitignore) - never commit a filled-in.env.- The weak fallback passwords above are a deliberate, low-severity local-only convenience -
documented, not hidden, and never reachable outside
docker compose upon your own machine.