Skip to content

Local Docker Compose Stack

Local development uses Docker only for infrastructure dependencies. The backend (Go) and frontend (Expo) run on the host so that hot reload and IDE tooling work without container overhead.

The stack is defined in docker-compose.dev.yml at the repository root.

Services

Service Image Port(s) Purpose Profile
postgres kartoza/postgis:15-3.3 5432 Primary database (Postgres 15 + PostGIS 3.3) default
redis redis:7-alpine 6379 Cache, queues, presence, pub/sub default
minio minio/minio:latest 9000, 9001 S3-compatible object storage (9001 is the web console) default
photon rtuszik/photon-docker:2.2.0 2322 Self-hosted geocoder default
pgadmin dpage/pgadmin4:latest 5050 Postgres web UI — login admin@local.dev / admin tools
redis-commander rediscommander/redis-commander:latest 8081 Redis web UI tools

Default credentials for the local stack (intentionally weak — they never leave your machine):

  • Postgres: tomoda / tomoda123, database tomoda
  • MinIO: root user tomoda, root password tomoda123

Redis Commander port clash

redis-commander exposes port 8081, which is the same port the Expo dev server uses for the web frontend. If you run both at once you'll see a bind conflict. Either skip the tools profile or remap one of the ports.

Starting the stack

The repo ships two entry points:

This is what you run day to day. It:

  1. Brings up only postgres, redis, minio, and photon from the dev compose file (no tools profile, no application containers).
  2. Waits a few seconds, then runs database migrations (task db:migrate).
  3. Regenerates Swagger docs (task gen:docs).
  4. Attempts to pull secrets from GCP Secret Manager (see Secrets). If gcloud is not authenticated, falls back to hard-coded local defaults.
  5. Starts the backend with Air for hot reload (backend && air) on :8080.

You then start the frontend in a second terminal:

task dev:frontend

Just the infra services

If you want to run the backend yourself (e.g. attach a debugger) but still need Postgres/Redis/etc, you can bring up just the dependencies:

docker-compose -f docker-compose.dev.yml up -d postgres redis minio photon

This is what task dev does internally before invoking Air.

Including the GUI tools

docker-compose -f docker-compose.dev.yml --profile tools up -d

This brings up pgAdmin (http://localhost:5050) and Redis Commander (http://localhost:8081).

Volumes & persistence

Each stateful service has a named volume that survives docker-compose down:

  • postgres_tomoda_data/var/lib/postgresql/data
  • redis_tomoda_data/var/lib/redis
  • minio_tomoda_data/data
  • photon_data/photon/data (Photon index — the first download takes several minutes)

To wipe everything and start fresh — most commonly to reset a corrupted database or test migrations from scratch:

task docker:clean    # docker-compose down -v --remove-orphans
task docker:up       # bring everything back up
task db:migrate      # re-run migrations on the empty database
task db:test:setup   # (optional) re-seed test users / events

Or in one shot:

task db:reset

Network

All services share the tomoda-network bridge network so they can talk to each other by service name. The host reaches them through the published ports listed above (localhost:5432, localhost:6379, etc.).

Photon first-run

The Photon container downloads its geocoding index on first start. The default REGION=canada (smallest index — overridable via the PHOTON_REGION env var) takes a few minutes. The healthcheck has a 300-second start_period to account for this. See Photon for how to switch to the multilingual GCS-hosted index for testing Japanese/Chinese queries.

Health checks

Every service defines a Compose-level healthcheck. The most useful one in practice:

docker-compose -f docker-compose.dev.yml ps

A service stuck on (health: starting) for more than a few minutes (other than photon on first launch) usually means something is wrong — check docker-compose logs <service>.