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 routing engine + BullMQ worker ────────────────────────────── # Built from the gis-ops Valhalla image + Node.js. This container does two # things: processes build-valhalla BullMQ jobs (running valhalla_build_tiles # natively) and serves the resulting tiles via valhalla_service on port 8002. valhalla: build: context: . target: valhalla-worker restart: unless-stopped volumes: - osm_data:/data/osm:ro # PBF files downloaded by the main worker - valhalla_tiles:/data/valhalla # Valhalla config and routing tiles environment: REDIS_HOST: valkey REDIS_PORT: "6379" REDIS_PASSWORD: ${VALKEY_PASSWORD} OSM_DATA_DIR: /data/osm VALHALLA_CONFIG: /data/valhalla/valhalla.json VALHALLA_TILES_DIR: /data/valhalla/valhalla_tiles NODE_ENV: production ports: - "127.0.0.1:8002:8002" # Valhalla HTTP API 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: . target: web 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} VALHALLA_URL: http://valhalla:8002 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 ─────────────────────────────────────────────── worker: build: context: . target: 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 VALHALLA_URL: http://valhalla:8002 NODE_ENV: production volumes: - osm_data:/data/osm # Worker downloads PBF here depends_on: postgres: condition: service_healthy valkey: condition: service_healthy volumes: postgres_data: valkey_data: osm_data: # Shared: worker writes, valhalla reads valhalla_tiles: pmtiles_data: