Docker Compose (Local Development)

Local development setup with dev.compose.yaml, environment variables, and common gotchas

Docker Compose — Local Development

Quick Start

# Start all services
docker compose -f dev.compose.yaml up -d

# View logs
docker compose -f dev.compose.yaml logs -f

# Rebuild a specific service
docker compose -f dev.compose.yaml build backend

# Stop all services
docker compose -f dev.compose.yaml down

dev.compose.yaml

The dev.compose.yaml file at the project root defines all services for local development:

services:
  postgres:
    image: postgres:15
    ports: ["5433:5432"]
    environment:
      POSTGRES_USER: appuser
      POSTGRES_PASSWORD: appsecret
      POSTGRES_DB: appdb

  redis:
    image: redis:latest
    ports: ["6372:6379"]

  backend:
    build: ./backend
    ports: ["8000:8000"]
    volumes:
      - ./backend:/api
      - ./common:/opt/common
    depends_on: [postgres, redis]

  survey-service:
    build: ./survey-service
    ports: ["8001:8000"]
    volumes:
      - ./survey-service:/api
      - ./common:/opt/common
    depends_on: [postgres, redis]

Environment Variables

Shared variables go in the project root .env:

ENVIRONMENT=development
HOST_MAIN_DOMAIN=mquad.local
NOTIFICATION_SERVICE_TOKEN=dev-token
S3_ENDPOINT_URL=http://minio:9000
S3_ACCESS_KEY=mquadadmin
S3_SECRET_KEY=mquadadmin123
S3_BUCKET_NAME=mquad-media

Service-specific variables go in <service>/.env.

Port Mappings (Local)

Host PortContainer PortService
54335432PostgreSQL
63726379Redis
80008000Backend
10231025Fake SMTP (SMTP)
10838025Fake SMTP (Web UI)

Common Gotchas

1. sys.path.insert for common/ module

Every service's api/__init__.py must include this before any from common.* imports:

import sys
sys.path.insert(0, "/opt/common")

Forgetting this causes ModuleNotFoundError: No module named 'common'.

2. Celery Queue Configuration

Each Celery worker must listen to its specific queue. Without queue separation, tasks may be picked up by the wrong worker:

backend-worker:
  command: celery -A api.infrastructure.messaging.celery_worker worker -Q backend_celery

notification-worker:
  command: celery -A api.celery worker -Q notification

3. Redis Port

Redis is exposed on host port 6372 (not 6379) to avoid conflicts with local Redis instances.

4. Alembic Migrations

Before using the backend service for the first time:

cd backend && uv run alembic upgrade head

For services using create_all (analytics-service), tables are created automatically on startup.