Files
suaveplan/docker/README.md
2026-05-27 23:29:53 +01:00

6.4 KiB

@suaveplan/docker

Docker Compose infrastructure for the genesis monorepo. Three stacks cover every stage of the development lifecycle.


Stacks

docker-compose.dev.yml — Development

Persistent local services with named volumes. Ports are offset into the 8000 range so they do not collide with app servers running on the typical 3000/4000 range. Intended to run continuously while developing; data survives container restarts.

docker-compose.test.yml — Integration Tests

Ephemeral, no volumes. Ports are in the 7000 range, distinct from the dev stack so both can run simultaneously. Started automatically by CI and by the integration test suite's global setup; torn down after the run.

docker-compose.testbed.yml — Testbed Staging

Fully isolated on a private Docker network (testbed-net). Services communicate by service name only — no host ports are exposed for the backing services. Includes a testbed app container (built from apps/testbed) and a Caddy reverse proxy on host ports 3200/3201. Used for full E2E staging runs before graduation.


Port Table

Service Dev host port Test host port Testbed
SurrealDB (WS) 8001 7004 internal only
Redis 8002 7005 internal only
PostgreSQL 8003 7006 internal only
Mailpit SMTP 8004 7007 internal only
Mailpit Web UI 8005 7008 internal only
Typesense 8006 7009 internal only
Garage S3 API 8900 7010 internal only
Garage S3 Admin 8902 7011 internal only
Caddy HTTP — — 3200
Caddy HTTPS — — 3201

Starting and Stopping

Development stack

# From repo root
bun run --filter=@suaveplan/docker dev:up
bun run --filter=@suaveplan/docker dev:down

# Or directly from docker/
docker compose -f docker-compose.dev.yml up -d
docker compose -f docker-compose.dev.yml down

Integration-test stack

bun run --filter=@suaveplan/docker test:up
bun run --filter=@suaveplan/docker test:down

# Or directly
docker compose -f docker-compose.test.yml up -d
docker compose -f docker-compose.test.yml down

Testbed staging stack

bun run --filter=@suaveplan/docker testbed:up    # builds apps/testbed first
bun run --filter=@suaveplan/docker testbed:down

# Or directly
docker compose -f docker-compose.testbed.yml up --build -d
docker compose -f docker-compose.testbed.yml down

Health Verification

After starting a stack, verify individual services are healthy:

# SurrealDB
curl -sf http://localhost:8001/health && echo "surreal OK"

# Redis
redis-cli -p 8002 ping          # expect PONG

# PostgreSQL
pg_isready -h localhost -p 8003 -U postgres

# Mailpit Web UI
curl -sf http://localhost:8005/api/v1/messages && echo "mailpit OK"

# Typesense
curl -sf "http://localhost:8006/health" -H "X-TYPESENSE-API-KEY: test" && echo "typesense OK"

# Garage S3
curl -sf http://localhost:8900 && echo "garage OK"

For Docker-native health status:

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

Environment Variable Bridge

The env-bridge pattern lets you point test fixtures at services you are already running locally — for example, a managed SurrealDB instance — instead of starting a Docker container. A fixture only enters passthrough mode when all of its required variables are set and non-empty. If any variable in a group is missing or empty, the fixture spins up its own container.

Setup

cp docker/.env.example docker/.env
# Edit docker/.env — fill in only the groups you want to bypass

The .env file is gitignored. Never commit real credentials.

Variable Reference

Fixture Required variables
SurrealDB SURREALDB_URL, SURREALDB_USERNAME, SURREALDB_PASSWORD
Redis REDIS_URL
PostgreSQL POSTGRES_URL
Mailpit MAILPIT_SMTP_URL, MAILPIT_API_URL
Typesense TYPESENSE_URL, TYPESENSE_API_KEY
Garage S3 GARAGE_S3_ENDPOINT, GARAGE_S3_ADMIN_ENDPOINT, GARAGE_S3_ACCESS_KEY_ID, GARAGE_S3_SECRET_ACCESS_KEY

Default values (dev stack)

Variable Default
SURREALDB_URL ws://localhost:8001
SURREALDB_USERNAME root
SURREALDB_PASSWORD root
REDIS_URL redis://localhost:8002
POSTGRES_URL postgresql://postgres:postgres@localhost:8003/postgres
MAILPIT_SMTP_URL smtp://localhost:8004
MAILPIT_API_URL http://localhost:8005
TYPESENSE_URL http://localhost:8006
TYPESENSE_API_KEY test
GARAGE_S3_ENDPOINT http://localhost:8900
GARAGE_S3_ADMIN_ENDPOINT http://localhost:8902

Garage S3 — Key Retrieval After First Run

Garage generates a root key on first startup. The access key ID and secret are not set via environment variables — you must retrieve them after the first run:

# 1. Start the dev stack
docker compose -f docker-compose.dev.yml up -d garage-s3

# 2. Create a layout (single-node, zone z1, 1 GB capacity)
docker compose -f docker-compose.dev.yml exec garage-s3 \
  /garage layout assign -z z1 -c 1G $(
    /garage node id 2>/dev/null | awk '{print $1}'
  )
docker compose -f docker-compose.dev.yml exec garage-s3 \
  /garage layout apply --version 1

# 3. Create a key
docker compose -f docker-compose.dev.yml exec garage-s3 \
  /garage key create my-key

# 4. Copy the key ID and secret into docker/.env
GARAGE_S3_ACCESS_KEY_ID=<key-id>
GARAGE_S3_SECRET_ACCESS_KEY=<secret>

Refer to the Garage documentation for full setup instructions.


Testbed Staging Environment

The testbed stack builds apps/testbed locally and wires every service on the internal testbed-net network. Caddy proxies inbound traffic from localhost:3200 to testbed:3000.

# Build and start
docker compose -f docker-compose.testbed.yml up --build -d

# Follow testbed app logs
docker compose -f docker-compose.testbed.yml logs -f testbed

# Run Playwright E2E against the staging URL
PLAYWRIGHT_BASE_URL=http://localhost:3200 bunx turbo test:e2e --filter=@suaveplan/testbed

# Tear down
docker compose -f docker-compose.testbed.yml down

The testbed service reads all connection strings from its environment block (defined in docker-compose.testbed.yml) and does not rely on .env. Service-to-service communication uses Docker DNS names (surrealdb, redis, etc.).