# Docker Development Workflow Guide to developing Changemaker Lite V2 using Docker containers for consistent, reproducible development environments. ## Overview Docker-based development provides: - **Consistency:** Same environment across all developer machines - **Isolation:** Services don't interfere with host system - **Production Parity:** Dev environment matches production - **Easy Reset:** Rebuild containers for clean state This guide covers Docker development workflows, from basic container operations to advanced debugging techniques. ## Docker vs Local Development ### When to Use Docker **Advantages:** - Consistent Node.js/PostgreSQL/Redis versions - No need to install services on host machine - Easy onboarding for new developers - Production-like environment - Volume mounts still support hot reload **Disadvantages:** - Slightly slower hot reload (especially macOS/Windows) - More complex debugging setup - Volume mount performance overhead - Larger disk space usage ### When to Use Local npm **Advantages:** - Faster hot reload (native file system) - Direct access to Node.js processes - Simpler debugging (VSCode attach) - Better performance on macOS/Windows **Disadvantages:** - Must install Node.js, PostgreSQL, Redis locally - Version inconsistencies between developers - Host system configuration required ### Hybrid Approach (Recommended) Run databases in Docker, API/Admin locally: ```bash # Docker: Databases only docker compose up -d v2-postgres redis mailhog # Local: Development servers cd api && npm run dev cd admin && npm run dev ``` This combines benefits of both approaches. ## Starting Development Services ### Full Docker Development Start all development services: ```bash # Core services (API, Admin, Databases) docker compose up -d api admin v2-postgres redis # Optional: MailHog for email testing docker compose up -d mailhog # Optional: Media API docker compose up -d media-api ``` **Verify services started:** ```bash docker compose ps ``` **Expected output:** ``` NAME STATUS PORTS api running 0.0.0.0:4000->4000/tcp admin running 0.0.0.0:3000->3000/tcp v2-postgres running 0.0.0.0:5433->5432/tcp redis running 0.0.0.0:6379->6379/tcp mailhog running 0.0.0.0:1025->1025/tcp, 0.0.0.0:8025->8025/tcp ``` ### Selective Service Start Start only what you need: ```bash # Just databases (for local npm development) docker compose up -d v2-postgres redis # Just API (admin running locally) docker compose up -d api v2-postgres redis # Just Admin (API running locally) docker compose up -d admin ``` ### Start with Monitoring Stack Enable monitoring services: ```bash # Start with monitoring profile docker compose --profile monitoring up -d # Or specific monitoring services docker compose up -d prometheus grafana ``` ## Watching Logs ### View Service Logs Real-time log streaming: ```bash # All services docker compose logs -f # Specific service docker compose logs -f api # Multiple services docker compose logs -f api admin # Last 100 lines, then follow docker compose logs -f --tail=100 api ``` **Log output example (API):** ``` api | Server running on port 4000 api | Database connected api | Redis connected api | BullMQ worker started api | GET /api/users 200 45ms ``` **Log output example (Admin):** ``` admin | VITE v5.x.x ready in 500 ms admin | ➜ Local: http://localhost:3000/ admin | ➜ Network: http://172.18.0.5:3000/ ``` ### Filter Logs Use grep to filter log output: ```bash # Show only errors docker compose logs -f api | grep ERROR # Show only database queries docker compose logs -f api | grep "SELECT\|INSERT\|UPDATE\|DELETE" # Show only HTTP requests docker compose logs -f api | grep "GET\|POST\|PUT\|DELETE" ``` ### Export Logs Save logs to file: ```bash # All services docker compose logs > logs.txt # Specific service with timestamps docker compose logs -t api > api-logs.txt # Last 24 hours docker compose logs --since 24h > recent-logs.txt ``` ## Executing Commands in Containers ### Using docker compose exec Run commands inside running containers: ```bash # General syntax docker compose exec # Examples: docker compose exec api npm run type-check docker compose exec admin npm run lint docker compose exec v2-postgres psql -U changemaker_v2 -d changemaker_v2_db ``` ### Common API Commands ```bash # Type-check docker compose exec api npm run type-check # Prisma migrate docker compose exec api npx prisma migrate dev --name add_field # Prisma Studio docker compose exec api npx prisma studio # Seed database docker compose exec api npx prisma db seed # Drizzle push (Media API) docker compose exec api npx drizzle-kit push # Node REPL docker compose exec api node # Shell access docker compose exec api sh ``` ### Common Admin Commands ```bash # Type-check docker compose exec admin npm run type-check # Build docker compose exec admin npm run build # Lint docker compose exec admin npm run lint # Shell access docker compose exec admin sh ``` ### Database Commands ```bash # PostgreSQL shell docker compose exec v2-postgres psql -U changemaker_v2 -d changemaker_v2_db # Run SQL query docker compose exec v2-postgres psql -U changemaker_v2 -d changemaker_v2_db -c "SELECT COUNT(*) FROM users;" # Dump database docker compose exec v2-postgres pg_dump -U changemaker_v2 changemaker_v2_db > backup.sql # Restore database cat backup.sql | docker compose exec -T v2-postgres psql -U changemaker_v2 changemaker_v2_db ``` ### Redis Commands ```bash # Redis CLI docker compose exec redis redis-cli -a your_redis_password # Ping docker compose exec redis redis-cli -a your_redis_password ping # Get all keys docker compose exec redis redis-cli -a your_redis_password KEYS '*' # Monitor commands docker compose exec redis redis-cli -a your_redis_password MONITOR ``` ## Hot Reload in Containers ### How Volume Mounts Enable Hot Reload Docker Compose volume mounts sync code between host and container: ```yaml # docker-compose.yml api: volumes: - ./api:/app # Syncs code changes - /app/node_modules # Preserves container's node_modules - /app/dist # Preserves build output ``` **When you edit a file on host:** 1. File change detected by host file system 2. Change synced to container via volume mount 3. `tsx watch` (API) or Vite (Admin) detects change 4. Service restarts (API) or HMR updates (Admin) ### API Hot Reload API uses `tsx watch` for auto-restart: ```bash # Start API in Docker docker compose up -d api # Watch logs docker compose logs -f api # Edit file: api/src/modules/auth/auth.service.ts # Logs show: # api | File changed: src/modules/auth/auth.service.ts # api | Restarting server... # api | Server running on port 4000 ``` **What triggers reload:** - `.ts` file changes in `src/` - Schema changes (after Prisma migrate) **What does NOT trigger reload:** - `.env` changes (restart container manually) - `package.json` changes (rebuild container) ### Admin Hot Reload (Vite HMR) Admin uses Vite Hot Module Replacement: ```bash # Start Admin in Docker docker compose up -d admin # Watch logs docker compose logs -f admin # Edit file: admin/src/pages/UsersPage.tsx # Logs show: # admin | 10:30:45 AM [vite] hmr update /src/pages/UsersPage.tsx # Browser updates WITHOUT full reload ``` **HMR behavior:** - Component changes: Updates component only - CSS changes: Updates styles instantly - Store changes: May require full reload ### Performance Considerations **Linux:** Volume mounts are native, excellent performance. **macOS/Windows:** Volume mounts use virtualization layer, slower performance. **Optimization for macOS/Windows:** 1. **Use delegated volume mounts** (docker-compose.yml): ```yaml api: volumes: - ./api:/app:delegated # Slightly better performance ``` 2. **Reduce watched files** (.dockerignore): ``` node_modules dist coverage .git *.log ``` 3. **Use local development** for intensive work: ```bash # Stop Docker services docker compose stop api admin # Run locally cd api && npm run dev cd admin && npm run dev ``` ## Database Operations ### Running Migrations in Docker ```bash # Create migration docker compose exec api npx prisma migrate dev --name add_user_field # Apply migrations (production) docker compose exec api npx prisma migrate deploy # Check migration status docker compose exec api npx prisma migrate status ``` ### Seeding Database ```bash # Run seed script docker compose exec api npx prisma db seed # Or run custom script docker compose exec api npx tsx prisma/custom-seed.ts ``` ### Resetting Database **WARNING: Deletes all data!** ```bash # Reset and re-seed docker compose exec api npx prisma migrate reset # Confirm when prompted: # ⚠️ All data will be lost. Continue? [y/N]: y ``` ### Prisma Studio in Docker ```bash # Start Prisma Studio docker compose exec api npx prisma studio # Access at http://localhost:5555 ``` **Note:** Port forwarding must be configured (already set in docker-compose.yml). ### Manual Database Access ```bash # Open PostgreSQL shell docker compose exec v2-postgres psql -U changemaker_v2 -d changemaker_v2_db # Run queries changemaker_v2_db=# SELECT * FROM users; changemaker_v2_db=# \dt -- List tables changemaker_v2_db=# \q -- Exit ``` ## Rebuilding Containers ### When to Rebuild Rebuild containers when: - `package.json` dependencies change - `Dockerfile` changes - Base image needs update - Container is in corrupted state ### Rebuild Commands ```bash # Rebuild all services docker compose build # Rebuild specific service docker compose build api # Rebuild without cache (clean build) docker compose build --no-cache api # Rebuild and restart docker compose up -d --build api ``` ### Full Rebuild Workflow ```bash # 1. Stop services docker compose down # 2. Rebuild (no cache) docker compose build --no-cache # 3. Start services docker compose up -d # 4. Verify docker compose ps docker compose logs -f api admin ``` ### After Package Changes When `package.json` changes (new dependencies): ```bash # Option 1: Rebuild container docker compose build --no-cache api docker compose restart api # Option 2: Install in running container docker compose exec api npm install docker compose restart api # Option 3: Remove and recreate docker compose rm -sf api docker compose up -d api ``` ## Cleaning Up ### Stop Services ```bash # Stop all services docker compose stop # Stop specific service docker compose stop api # Stop and remove containers docker compose down ``` ### Remove Containers ```bash # Remove containers (keeps volumes) docker compose down # Remove containers and volumes (DELETES DATA) docker compose down -v # Remove containers, volumes, and images docker compose down -v --rmi all ``` ### Clean Docker System ```bash # Remove stopped containers docker container prune # Remove unused images docker image prune # Remove unused volumes docker volume prune # Remove everything (DANGEROUS) docker system prune -a --volumes ``` ### Clean Project Volumes ```bash # List project volumes docker volume ls | grep changemaker # Remove specific volume docker volume rm changemaker-lite_v2-postgres-data # Remove all project volumes (DELETES DATABASE) docker compose down -v ``` ### Reset Development Environment Complete reset (deletes all data): ```bash # 1. Stop and remove everything docker compose down -v --rmi all # 2. Clean Docker system docker system prune -a --volumes -f # 3. Rebuild from scratch docker compose build --no-cache # 4. Start services docker compose up -d # 5. Run migrations docker compose exec api npx prisma migrate deploy docker compose exec api npx prisma db seed ``` ## Debugging in Docker ### Attach to Running Container ```bash # Get shell in running container docker compose exec api sh # Or bash (if available) docker compose exec api bash # Inside container: # - Explore file system # - Run commands # - Check environment variables ``` ### Inspect Container ```bash # View container details docker inspect api # View container environment variables docker inspect api | grep -A 20 "Env" # View container mounts docker inspect api | grep -A 50 "Mounts" ``` ### VSCode Remote Containers Install "Remote - Containers" extension, then: 1. Open Command Palette (Cmd+Shift+P / Ctrl+Shift+P) 2. Select "Remote-Containers: Attach to Running Container" 3. Choose `api` or `admin` container 4. VSCode opens new window attached to container 5. Open `/app` folder in container 6. Set breakpoints and debug normally ### Debug Logs Enable verbose logging: ```bash # API with debug logs docker compose exec api npm run dev -- --inspect # Watch logs with timestamp docker compose logs -f -t api # Filter errors only docker compose logs -f api 2>&1 | grep -i error ``` ### Network Debugging ```bash # Test container connectivity docker compose exec api ping v2-postgres docker compose exec api ping redis # Check listening ports docker compose exec api netstat -tuln # Test API from inside container docker compose exec api wget -O- http://localhost:4000/health ``` ### Performance Debugging ```bash # Container stats docker stats # Specific service stats docker stats api admin # Container resource limits docker inspect api | grep -A 10 "Memory\|Cpu" ``` ## Advanced Workflows ### Multi-Stage Development Run different service combinations: ```bash # Frontend development (local Admin, Docker API) docker compose up -d api v2-postgres redis cd admin && npm run dev # Backend development (local API, Docker Admin) docker compose up -d admin v2-postgres redis cd api && npm run dev # Full-stack (everything in Docker) docker compose up -d api admin v2-postgres redis ``` ### Custom Docker Compose Files Create `docker-compose.dev.yml` for dev overrides: ```yaml # docker-compose.dev.yml services: api: command: npm run dev -- --inspect=0.0.0.0:9229 ports: - "9229:9229" # Debug port environment: - LOG_LEVEL=debug ``` **Usage:** ```bash # Use both files docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d # Or set COMPOSE_FILE env var export COMPOSE_FILE=docker-compose.yml:docker-compose.dev.yml docker compose up -d ``` ### Docker Profiles for Optional Services Start monitoring stack: ```bash # With monitoring services docker compose --profile monitoring up -d # Without monitoring (default) docker compose up -d ``` **Monitoring services:** - Prometheus (port 9090) - Grafana (port 3001) - Alertmanager (port 9093) - cAdvisor (port 8080) ### Build Arguments Pass build-time arguments: ```bash # Build with Node.js version argument docker compose build --build-arg NODE_VERSION=20.11.0 api # Set in docker-compose.yml services: api: build: context: ./api args: - NODE_VERSION=${NODE_VERSION:-20} ``` ### Health Checks Check service health: ```bash # View health status docker compose ps # Inspect health check docker inspect --format='{{json .State.Health}}' api | jq # Wait for healthy docker compose up -d api docker compose exec api sh -c 'while ! wget -q -O- http://localhost:4000/health; do sleep 1; done' ``` ## Troubleshooting ### Container Exits Immediately **Problem:** Container starts then stops. **Solution:** ```bash # Check logs for errors docker compose logs api # Common causes: # 1. Missing .env file # 2. Database connection failed # 3. Syntax error in code # 4. Port already in use # Start with interactive mode to see error docker compose run --rm api npm run dev ``` ### Volume Mount Not Working **Problem:** Code changes don't appear in container. **Solution:** ```bash # Check volume mounts docker inspect api | grep -A 20 "Mounts" # Verify volume path docker compose exec api ls -la /app # Recreate container docker compose rm -sf api docker compose up -d api ``` ### Permission Errors **Problem:** Permission denied errors in container. **Solution:** ```bash # Check file ownership docker compose exec api ls -la /app # Fix permissions on host sudo chown -R $(whoami):$(whoami) ./api # Or run container as current user (docker-compose.yml) services: api: user: "${UID}:${GID}" ``` ### Port Conflicts **Problem:** Port already in use. **Solution:** ```bash # Find process using port lsof -ti:4000 | xargs kill -9 # Or change port in docker-compose.yml services: api: ports: - "4002:4000" # Host:Container # Or use .env API_PORT=4002 ``` ### Database Connection Failed **Problem:** API cannot connect to PostgreSQL. **Solution:** ```bash # Check database is running docker compose ps v2-postgres # Check database logs docker compose logs v2-postgres # Test connection docker compose exec api sh -c 'wget -qO- http://v2-postgres:5432 || echo "Not reachable"' # Verify DATABASE_URL docker compose exec api sh -c 'echo $DATABASE_URL' # Restart database docker compose restart v2-postgres ``` ### Out of Disk Space **Problem:** No space left on device. **Solution:** ```bash # Check Docker disk usage docker system df # Remove unused images docker image prune -a # Remove unused volumes docker volume prune # Remove build cache docker builder prune # Full cleanup docker system prune -a --volumes ``` ### Container Running Out of Memory **Problem:** Container crashes with OOM. **Solution:** ```bash # Check container stats docker stats api # Increase Docker memory limit (Docker Desktop → Preferences → Resources) # Or set memory limit in docker-compose.yml services: api: mem_limit: 2g memswap_limit: 2g ``` ### Slow Performance on macOS/Windows **Problem:** Slow hot reload, high CPU usage. **Solution:** 1. **Use delegated volume mounts:** ```yaml services: api: volumes: - ./api:/app:delegated ``` 2. **Reduce file watching:** ```javascript // vite.config.ts export default { server: { watch: { ignored: ['**/node_modules/**', '**/dist/**'] } } } ``` 3. **Switch to local development:** ```bash docker compose up -d v2-postgres redis cd api && npm run dev cd admin && npm run dev ``` ## Best Practices ### Development Workflow 1. **Start services in background:** ```bash docker compose up -d api admin ``` 2. **Watch logs in separate terminal:** ```bash docker compose logs -f api admin ``` 3. **Make code changes:** - Hot reload picks up changes automatically 4. **Type-check before commit:** ```bash docker compose exec api npm run type-check docker compose exec admin npm run type-check ``` 5. **Stop services when done:** ```bash docker compose stop ``` ### Container Naming Use meaningful service names in docker-compose.yml: ```yaml services: api: # Not "backend" or "server" admin: # Not "frontend" or "ui" v2-postgres: # Not "db" (version-specific) redis: # Standard name ``` ### Environment Variables 1. **Use .env file** (not docker-compose.yml): ```bash # .env API_PORT=4000 ADMIN_PORT=3000 ``` 2. **Reference in docker-compose.yml:** ```yaml services: api: environment: - API_PORT=${API_PORT} ``` 3. **Don't commit .env** (use .env.example). ### Volume Management 1. **Named volumes for data:** ```yaml volumes: v2-postgres-data: # Persistent database ``` 2. **Bind mounts for code:** ```yaml volumes: - ./api:/app # Live code sync ``` 3. **Anonymous volumes for dependencies:** ```yaml volumes: - /app/node_modules # Isolate from host ``` ### Log Management 1. **Use log rotation:** ```yaml services: api: logging: driver: "json-file" options: max-size: "10m" max-file: "3" ``` 2. **Filter logs with grep:** ```bash docker compose logs -f api | grep ERROR ``` 3. **Export logs for analysis:** ```bash docker compose logs > debug-logs.txt ``` ## Quick Reference ### Essential Commands ```bash # Start docker compose up -d api admin # Stop docker compose stop # Restart docker compose restart api # Logs docker compose logs -f api # Execute command docker compose exec api npm run type-check # Shell access docker compose exec api sh # Rebuild docker compose build --no-cache api # Clean up docker compose down -v ``` ### Service Health Checks ```bash # Check status docker compose ps # Test API curl http://localhost:4000/health # Test Admin curl http://localhost:3000 # Test database docker compose exec v2-postgres psql -U changemaker_v2 -d changemaker_v2_db -c "SELECT 1" # Test Redis docker compose exec redis redis-cli -a password ping ``` ### Quick Reset ```bash # Full reset (DELETES DATA) docker compose down -v docker compose build --no-cache docker compose up -d docker compose exec api npx prisma migrate deploy docker compose exec api npx prisma db seed ``` ## Related Documentation - **Setup:** [Local Development Setup](local-setup.md) - **Commands:** [NPM Commands Reference](npm-commands.md) - **Database:** [Migrations Guide](migrations.md) - **Debugging:** [Debugging Guide](debugging.md) - **Deployment:** [Docker Compose Deployment](../deployment/docker-compose.md) ## Summary You now know: - ✅ When to use Docker vs local development - ✅ How to start and stop services - ✅ How to watch and filter logs - ✅ How to execute commands in containers - ✅ How hot reload works with volume mounts - ✅ How to perform database operations in Docker - ✅ How to rebuild and clean up containers - ✅ How to debug containerized services - ✅ Advanced workflows and best practices **Quick Start:** ```bash docker compose up -d api admin v2-postgres redis docker compose logs -f api admin # Make changes → Hot reload! docker compose exec api npm run type-check docker compose stop ```