Appearance
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
| Service | Image / Build | Port | Description |
|---|---|---|---|
postgres | postgis/postgis:16-3.4-alpine | 5434 | PostgreSQL with PostGIS |
redis | redis:7-alpine | 6380 | Redis for job queues |
tileserv | pramsey/pg_tileserv:latest | 7800 | Mapbox Vector Tile (MVT) server backed by PostGIS |
api | api/Dockerfile.dev | 8001 | NestJS API |
frontend | frontend/Dockerfile.dev | 8000 | Vue 3 app |
admin | admin/Dockerfile.dev | 8002 | Admin dashboard |
help | help/Dockerfile.dev | 8003 | User documentation |
docs | docs/Dockerfile.dev | 8004 | Developer documentation |
data-fetching | data-fetching/Dockerfile.dev | — | Data fetch worker |
data-processing | data-processing/Dockerfile.dev | — | Data process worker |
Dependency Graph
postgres ← api ← frontend
← api ← admin
← tileserv
redis ← api
← data-fetching
← data-processing
postgres ← data-fetching
← data-processingThe 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:removeLive Reload
All development containers mount source code as volumes, so changes are reflected immediately:
- API:
./api/srcis mounted — NestJS watch mode picks up changes - Frontend/Admin:
./frontend/srcand./admin/srcare mounted — Vite HMR works - Shared:
./shared/srcis 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_dataData 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 8000Stale containers: If containers behave unexpectedly:
bash
pnpm docker:remove
pnpm docker:upDatabase 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