Local Stack

The Docker Compose configuration in the repository root starts all Causet services and their infrastructure dependencies. Use this for local development and integration testing.


Start the stack

docker compose up -d

This pulls and starts all containers in detached mode. First run takes longer because images are pulled.


What starts

ContainerPortPurpose
causet-runtime-service8080, 9090Intent processing, rule evaluation, ledger writes
causet-query-service8082Named query execution
causet-projection-workerKafka consumer, projection UPSERT
causet-saas-cloud8085Control plane API
causet-cloud-control-plane3000Web UI
ws-gateway-go8081WebSocket gateway
postgres5432PostgreSQL (causet + projections databases)
redpanda9092, 9644Kafka-compatible broker
redis6379IR artifact cache
minio9000, 9001S3-compatible object store

Startup order

Services wait for their dependencies to become healthy before starting. The order is:

postgres → redpanda → redis → minio
  → causet-saas-cloud
  → causet-runtime-service
  → causet-projection-worker
  → causet-query-service
  → causet-cloud-control-plane
  → ws-gateway-go

On first start, you also need to initialize infrastructure before the application services will work correctly:

# Create Kafka topics
./infra/redpanda/create-topics.sh
 
# Create MinIO bucket
./infra/minio/create-buckets.sh
 
# Initialize PostgreSQL schemas
psql $DATABASE_URL -f infra/postgres/init.sql
psql $DATABASE_URL -f infra/postgres/02-projections-schema.sql

Note: These scripts are idempotent. Running them more than once is safe.


MinIO (local S3)

MinIO runs on port 9000 (API) and 9001 (console). IR artifacts are stored in the causet-artifacts bucket.

Access the MinIO console at http://localhost:9001. Default credentials are in docker-compose.yml (typically minioadmin / minioadmin).

# Verify the bucket exists
mc alias set local http://localhost:9000 minioadmin minioadmin
mc ls local/causet-artifacts

Redpanda (local Kafka)

Redpanda runs on port 9092 (Kafka protocol) and 9644 (admin API). Topics are created by ./infra/redpanda/create-topics.sh.

Required topics:

TopicPurpose
causet.intents.v1Inbound intents (optional, can use HTTP directly)
causet.ledger-events.v1Committed ledger events
causet.projection-events.v1Projection events consumed by projection worker
causet.projection-dlq.v1Dead-letter queue for failed projection handlers
causet.patches.v1State patch events
# List topics
rpk topic list --brokers localhost:9092
 
# Consume from a topic
rpk topic consume causet.ledger-events.v1 --brokers localhost:9092

PostgreSQL

Postgres runs on port 5432. Two databases are used:

  • causet — event store (ledger_events, intent log, entity state)
  • projections — projection tables per tenant
# Connect to causet database
psql postgresql://localhost:5432/causet
 
# Connect to projections database
psql postgresql://localhost:5432/projections
 
# Check that ledger_events table exists
psql postgresql://localhost:5432/causet -c "\dt"

Tenant schemas are created when you deploy a release to a fork. The schema name follows the pattern {platformId}_{applicationId}_{forkId}.


Health checks

Verify each service is healthy:

# Runtime service
curl -s http://localhost:8080/actuator/health | jq .
 
# Query service
curl -s http://localhost:8082/actuator/health | jq .
 
# SaaS / control plane API
curl -s http://localhost:8085/actuator/health | jq .
 
# Projection worker (internal port, check via docker)
docker exec causet-projection-worker curl -s http://localhost:8083/actuator/health

Expected response for a healthy service:

{
  "status": "UP",
  "components": {
    "db": { "status": "UP" },
    "kafka": { "status": "UP" },
    "s3": { "status": "UP" }
  }
}

Tail logs

# All services
docker compose logs -f
 
# Specific service
docker compose logs -f causet-runtime-service
docker compose logs -f causet-projection-worker
 
# Follow projection worker DLQ errors
docker compose logs -f causet-projection-worker | grep -i "dlq\|error\|failed"

Stop the stack

# Stop containers, preserve volumes
docker compose down
 
# Stop and remove all volumes (destroys all data)
docker compose down -v

Common startup issues

Port conflicts

If a port is already in use, Docker Compose will fail to start the conflicting container. Check what’s using the port:

lsof -i :8080
lsof -i :5432

Either stop the conflicting process or edit docker-compose.yml to use a different host port.

Postgres not ready

Services start before Postgres has finished initializing. The compose file uses health checks to gate startup, but if you see connection refused errors in the first 30 seconds, wait and retry.

# Check postgres health
docker inspect postgres --format '{{.State.Health.Status}}'

If Postgres stays unhealthy, check its logs:

docker compose logs postgres

Redpanda topic creation fails

If create-topics.sh returns errors, Redpanda may not be ready yet. Wait 10–15 seconds and retry:

docker compose logs redpanda
./infra/redpanda/create-topics.sh

MinIO bucket missing

If you see S3 errors in service logs, the bucket may not exist. Run:

./infra/minio/create-buckets.sh

Services restart-looping

If a service exits and Docker restarts it repeatedly, check its logs for the error before it exits:

docker compose logs --tail=50 causet-runtime-service

Most common causes: missing environment variable, database unreachable, IR artifact not found on S3.


Reset everything

To start completely fresh:

docker compose down -v
docker compose up -d
./infra/redpanda/create-topics.sh
./infra/minio/create-buckets.sh
psql postgresql://localhost:5432/causet -f infra/postgres/init.sql
psql postgresql://localhost:5432/projections -f infra/postgres/02-projections-schema.sql