services: db: image: postgres:18 container_name: postgres__open-wearables environment: POSTGRES_DB: open-wearables POSTGRES_USER: open-wearables POSTGRES_PASSWORD: open-wearables ports: - "${DB_PORT:-5432}:5432" healthcheck: test: ["CMD-SHELL", "pg_isready -U open-wearables -d open-wearables"] interval: 5s timeout: 5s retries: 5 volumes: - postgres_data:/var/lib/postgresql - ./backend/scripts/init/create-svix-db.sql:/docker-entrypoint-initdb.d/create-svix-db.sql:ro app: build: context: ./backend dockerfile: Dockerfile container_name: backend__open-wearables image: open-wearables-platform:latest pull_policy: never command: scripts/start/app.sh env_file: - ./backend/config/.env environment: - DB_HOST=db - REDIS_HOST=redis # Keeps root-owned __pycache__ out of the mounted extensions - PYTHONPYCACHEPREFIX=/tmp/pycache ports: - "${API_PORT:-8000}:8000" depends_on: db: condition: service_healthy redis: condition: service_started volumes: - ./extensions:/root_project/extensions develop: watch: - action: sync path: ./backend/app target: /root_project/app - action: sync+restart path: ./backend/migrations target: /root_project/migrations - action: sync+restart path: ./backend/config/.env target: /root_project/config/.env - action: sync path: ./backend/scripts target: /root_project/scripts - action: sync path: ./backend/tests target: /root_project/tests - action: rebuild path: ./backend/uv.lock restart: on-failure celery-worker: container_name: celery-worker__open-wearables image: open-wearables-platform:latest pull_policy: never command: scripts/start/worker.sh env_file: - ./backend/config/.env environment: - DB_HOST=db - REDIS_HOST=redis - PYTHONPYCACHEPREFIX=/tmp/pycache depends_on: - redis - db - app volumes: - ./extensions:/root_project/extensions develop: watch: - action: sync+restart path: ./backend/app target: /root_project/app - action: sync path: ./backend/scripts target: /root_project/scripts celery-beat: container_name: celery-beat__open-wearables image: open-wearables-platform:latest pull_policy: never command: scripts/start/beat.sh env_file: - ./backend/config/.env environment: - DB_HOST=db - REDIS_HOST=redis - PYTHONPYCACHEPREFIX=/tmp/pycache depends_on: - redis - db - app volumes: - ./extensions:/root_project/extensions develop: watch: - action: sync+restart path: ./backend/app target: /root_project/app - action: sync path: ./backend/scripts target: /root_project/scripts flower: container_name: flower__open-wearables image: open-wearables-platform:latest pull_policy: never command: scripts/start/flower.sh env_file: - ./backend/config/.env environment: - DB_HOST=db - REDIS_HOST=redis - PYTHONPYCACHEPREFIX=/tmp/pycache ports: - "${FLOWER_PORT:-5555}:5555" depends_on: - redis - db - app volumes: - ./extensions:/root_project/extensions develop: watch: - action: sync path: ./backend target: /root_project ignore: - .venv/ redis: container_name: redis__open-wearables image: redis:8 entrypoint: - sh - -c - | # Seed AOF from an existing RDB before enabling it, otherwise Redis boots # empty and ignores dump.rdb. Skipped once appendonlydir exists. if [ ! -d /data/appendonlydir ] && [ -f /data/dump.rdb ]; then redis-server --daemonize no & RPID=$$! until redis-cli ping >/dev/null 2>&1; do sleep 0.2; done redis-cli CONFIG SET appendonly yes sleep 1 until redis-cli INFO persistence | grep -q 'aof_rewrite_in_progress:0'; do sleep 0.2; done redis-cli SHUTDOWN NOSAVE wait "$$RPID" 2>/dev/null fi exec redis-server --appendonly yes --appendfsync everysec ports: - "${REDIS_PORT:-6379}:6379" volumes: - redis_data:/data svix-server: container_name: svix-server__open-wearables image: svix/svix-server:v1.101.0 entrypoint: - sh - -c - | : "$${SVIX_JWT_SECRET:=$$SECRET_KEY}" export SVIX_JWT_SECRET exec svix-server "$$@" - -- command: ["--run-migrations"] env_file: - ./backend/config/.env environment: SVIX_DB_DSN: "postgresql://${DB_USER:-open-wearables}:${DB_PASSWORD:-open-wearables}@${DB_HOST:-db}:${DB_PORT:-5432}/svix" SVIX_QUEUE_TYPE: "redis" SVIX_REDIS_DSN: "redis://redis:6379/1" SVIX_CACHE_TYPE: "redis" ports: - "${SVIX_PORT:-8071}:8071" depends_on: db: condition: service_healthy redis: condition: service_started healthcheck: test: ["CMD", "svix-server", "healthcheck", "http://localhost:8071"] interval: 5s timeout: 3s retries: 20 start_period: 10s restart: on-failure frontend: build: context: ./frontend dockerfile: Dockerfile.dev container_name: frontend__open-wearables image: open-wearables-frontend:dev pull_policy: never env_file: # .env.example supplies the defaults; .env overrides it when present. - ./frontend/.env.example - path: ./frontend/.env required: false environment: # The server's own hop to the API stays inside the network; VITE_API_URL # from the env file is the address a browser or phone dials. - API_URL=http://app:8000 ports: - "${FRONTEND_PORT:-3000}:3000" depends_on: - app develop: watch: - action: sync path: ./frontend/src target: /app/src - action: sync path: ./frontend/static target: /app/static - action: rebuild path: ./frontend/package.json - action: rebuild path: ./frontend/bun.lock - action: rebuild path: ./frontend/vite.config.ts restart: on-failure volumes: postgres_data: redis_data: