Skip to content

Docker

The project uses Docker Compose to orchestrate all services for local development. Each package has a Dockerfile.dev for development and a Dockerfile for production builds.

Services

ServiceImage / BuildPortDescription
postgrespostgis/postgis:16-3.4-alpine5434PostgreSQL with PostGIS
redisredis:7-alpine6380Redis for job queues
tileservpramsey/pg_tileserv:latest7800Mapbox Vector Tile (MVT) server backed by PostGIS
apiapi/Dockerfile.dev8001NestJS API
frontendfrontend/Dockerfile.dev8000Vue 3 app
adminadmin/Dockerfile.dev8002Admin dashboard
helphelp/Dockerfile.dev8003User documentation
docsdocs/Dockerfile.dev8004Developer documentation
data-fetchingdata-fetching/Dockerfile.devData fetch worker
data-processingdata-processing/Dockerfile.devData process worker

Dependency Graph

postgres ← api ← frontend
         ← api ← admin
         ← tileserv
redis    ← api
         ← data-fetching
         ← data-processing
postgres ← data-fetching
         ← data-processing

The api, tileserv, data-fetching, and data-processing services wait for postgres (and api / workers also wait for redis) healthchecks before starting.

tileserv connects to PostgreSQL as the dedicated tileserv SELECT-only role created in migration 1700000000017-CreateTileFunctions. The Vite dev server (and the production frontend nginx) proxy /tiles/* to it — see Tile Serving.

Commands

bash
# Start all services
pnpm docker:up

# Start specific services
docker compose up -d postgres redis api frontend

# View logs
pnpm docker:logs

# View logs for a specific service
docker compose logs -f api

# Stop all services
pnpm docker:down

# Full cleanup (remove volumes, images)
pnpm docker:remove

Live Reload

All development containers mount source code as volumes, so changes are reflected immediately:

  • API: ./api/src is mounted — NestJS watch mode picks up changes
  • Frontend/Admin: ./frontend/src and ./admin/src are mounted — Vite HMR works
  • Shared: ./shared/src is mounted in API, admin, and data pipeline containers
  • Docs/Help: Full directories are mounted — VitePress HMR works

Node modules and build caches are excluded from mounts to avoid conflicts.

Database

PostgreSQL runs with PostGIS on port 5434 (mapped from container's 5432). Default credentials:

  • User: gis
  • Password: gis_secret
  • Database: gis_data

Connect with any PostgreSQL client:

bash
psql -h localhost -p 5434 -U gis -d gis_data

Data is persisted in the postgres_data Docker volume. Use pnpm docker:remove to wipe it.

Production Dockerfiles

Production builds use multi-stage Dockerfiles:

  • API: Node build stage → Node runtime (runs node dist/main)
  • Frontend/Admin: Node build stage → nginx:alpine (serves static files)
  • Help/Docs: Node build stage → nginx:alpine (serves VitePress output)

All nginx configurations use template substitution for the port (via envsubst).

Troubleshooting

Port conflicts: If ports are in use, check for running processes:

bash
lsof -i :8000  # Check what's using port 8000

Stale containers: If containers behave unexpectedly:

bash
pnpm docker:remove
pnpm docker:up

Database issues: If migrations fail, you may need to recreate the database:

bash
docker compose down -v  # Removes volumes
docker compose up -d postgres
pnpm migration:run
pnpm seed:admin