services: # ─── PostgreSQL + PostGIS ────────────────────────────────────────────────── postgres: image: postgis/postgis:16-3.4 restart: unless-stopped environment: POSTGRES_DB: fifteenmin POSTGRES_USER: app POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - postgres_data:/var/lib/postgresql/data - ./infra/schema.sql:/docker-entrypoint-initdb.d/01-schema.sql:ro healthcheck: test: ["CMD-SHELL", "pg_isready -U app -d fifteenmin"] interval: 10s timeout: 5s retries: 10 start_period: 30s # ─── Valkey ─────────────────────────────────────────────────────────────── valkey: image: valkey/valkey:8-alpine restart: unless-stopped command: valkey-server --appendonly yes --requirepass ${VALKEY_PASSWORD} volumes: - valkey_data:/data healthcheck: test: ["CMD", "valkey-cli", "-a", "${VALKEY_PASSWORD}", "ping"] interval: 10s timeout: 5s retries: 5 # ─── Valhalla road tile-builder + road routing queue ────────────────────── # Builds road-only per-city tile directories (walking/cycling/driving). # Also serves on-demand routing requests from the web app + pipeline worker # via the BullMQ 'routing' queue using @valhallajs/valhallajs Actor pool. # No HTTP server — all routing goes through BullMQ. valhalla: build: context: . dockerfile: Dockerfile.valhalla-worker restart: unless-stopped volumes: - osm_data:/data/osm:ro - valhalla_tiles:/data/valhalla environment: REDIS_HOST: valkey REDIS_PORT: "6379" REDIS_PASSWORD: ${VALKEY_PASSWORD} VALHALLA_QUEUE_NAME: valhalla VALHALLA_TILES_BASE: /data/valhalla/tiles VALHALLA_DATA_DIR: /data/valhalla OSM_DATA_DIR: /data/osm NODE_ENV: production depends_on: valkey: condition: service_healthy # ─── Valhalla transit tile-builder + transit routing queue ──────────────── # Builds transit per-city tile directories (GTFS multimodal routing). # Also serves transit isochrone requests via the 'routing-transit' queue. # No HTTP server — all routing goes through BullMQ. valhalla-transit: build: context: . dockerfile: Dockerfile.valhalla-worker restart: unless-stopped volumes: - osm_data:/data/osm:ro - valhalla_tiles_transit:/data/valhalla environment: REDIS_HOST: valkey REDIS_PORT: "6379" REDIS_PASSWORD: ${VALKEY_PASSWORD} VALHALLA_QUEUE_NAME: valhalla-transit VALHALLA_TILES_BASE: /data/valhalla/tiles VALHALLA_DATA_DIR: /data/valhalla VALHALLA_INCLUDE_TRANSIT: "true" OSM_DATA_DIR: /data/osm NODE_ENV: production CONNECT_INFO_TOKEN: ${CONNECT_INFO_TOKEN:-} depends_on: valkey: condition: service_healthy # ─── Protomaps tile server ───────────────────────────────────────────────── tiles: image: ghcr.io/protomaps/go-pmtiles:latest restart: unless-stopped volumes: - pmtiles_data:/data command: serve /data --cors "*" ports: - "127.0.0.1:8080:8080" # ─── Next.js web application ─────────────────────────────────────────────── web: build: context: . dockerfile: Dockerfile restart: unless-stopped ports: - "3000:3000" environment: DATABASE_URL: postgres://app:${POSTGRES_PASSWORD}@postgres:5432/fifteenmin REDIS_HOST: valkey REDIS_PORT: "6379" REDIS_PASSWORD: ${VALKEY_PASSWORD} ADMIN_PASSWORD_HASH: ${ADMIN_PASSWORD_HASH} ADMIN_JWT_SECRET: ${ADMIN_JWT_SECRET} NODE_ENV: production depends_on: postgres: condition: service_healthy valkey: condition: service_healthy # ─── BullMQ pipeline worker ─────────────────────────────────────────────── # Pure pipeline: download, extract, grid, scoring — no Valhalla knowledge. # Routing requests are dispatched via BullMQ to the valhalla containers. worker: build: context: . dockerfile: Dockerfile.worker restart: unless-stopped environment: DATABASE_URL: postgres://app:${POSTGRES_PASSWORD}@postgres:5432/fifteenmin REDIS_HOST: valkey REDIS_PORT: "6379" REDIS_PASSWORD: ${VALKEY_PASSWORD} OSM_DATA_DIR: /data/osm LUA_SCRIPT: /app/infra/osm2pgsql.lua NODE_ENV: production CONNECT_INFO_TOKEN: ${CONNECT_INFO_TOKEN:-} volumes: - osm_data:/data/osm depends_on: postgres: condition: service_healthy valkey: condition: service_healthy volumes: postgres_data: valkey_data: osm_data: # Shared: worker writes PBF files, valhalla containers read valhalla_tiles: # Road-only per-city tiles + Actor pool data valhalla_tiles_transit: # Transit per-city tiles + GTFS data + Actor pool data pmtiles_data: