services: simstudio: env_file: - path: .env required: false build: context: . dockerfile: docker/app.Dockerfile ports: - '3000:3000' deploy: resources: limits: memory: 8G environment: - NODE_ENV=development - DATABASE_URL=postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@db:5432/${POSTGRES_DB:-simstudio} - BETTER_AUTH_URL=${NEXT_PUBLIC_APP_URL:-http://localhost:3000} - NEXT_PUBLIC_APP_URL=${NEXT_PUBLIC_APP_URL:-http://localhost:3000} - BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET:-dev-secret-at-least-32-characters-long} - ENCRYPTION_KEY=${ENCRYPTION_KEY:-dev-encryption-key-at-least-32-chars} - API_ENCRYPTION_KEY=${API_ENCRYPTION_KEY:-} - INTERNAL_API_SECRET=${INTERNAL_API_SECRET:-dev-internal-api-secret-min-32-chars} - REDIS_URL=${REDIS_URL:-redis://redis:6379} - COPILOT_API_KEY=${COPILOT_API_KEY:-} - MSHIP_SYSPROMPT_OVERRIDE=${MSHIP_SYSPROMPT_OVERRIDE:-} - NEXT_PUBLIC_CHAT_DISABLED=${NEXT_PUBLIC_CHAT_DISABLED:-} - SIM_AGENT_API_URL=${SIM_AGENT_API_URL:-} - OLLAMA_URL=${OLLAMA_URL:-http://localhost:11434} - SOCKET_SERVER_URL=${SOCKET_SERVER_URL:-http://realtime:3002} - NEXT_PUBLIC_SOCKET_URL=${NEXT_PUBLIC_SOCKET_URL:-} depends_on: db: condition: service_healthy redis: condition: service_healthy migrations: condition: service_completed_successfully realtime: condition: service_healthy healthcheck: test: ['CMD', 'curl', '-fsS', 'http://127.0.0.1:3000'] interval: 90s timeout: 5s retries: 3 start_period: 10s realtime: env_file: - path: .env required: false build: context: . dockerfile: docker/realtime.Dockerfile environment: - NODE_ENV=development - DATABASE_URL=postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@db:5432/${POSTGRES_DB:-simstudio} - NEXT_PUBLIC_APP_URL=${NEXT_PUBLIC_APP_URL:-http://localhost:3000} - BETTER_AUTH_URL=${BETTER_AUTH_URL:-http://localhost:3000} - BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET:-dev-secret-at-least-32-characters-long} - INTERNAL_API_SECRET=${INTERNAL_API_SECRET:-dev-internal-api-secret-min-32-chars} - REDIS_URL=${REDIS_URL:-redis://redis:6379} depends_on: db: condition: service_healthy redis: condition: service_healthy restart: unless-stopped ports: - '3002:3002' deploy: resources: limits: memory: 1G healthcheck: test: ['CMD', 'curl', '-fsS', 'http://127.0.0.1:3002/health'] interval: 90s timeout: 5s retries: 3 start_period: 10s migrations: build: context: . dockerfile: docker/db.Dockerfile working_dir: /app/packages/db environment: - DATABASE_URL=postgresql://${POSTGRES_USER:-postgres}:${POSTGRES_PASSWORD:-postgres}@db:5432/${POSTGRES_DB:-simstudio} depends_on: db: condition: service_healthy command: ['bun', 'run', 'db:migrate'] restart: 'no' # Backs pub/sub (live Chat task-status and table events) and the shared caches. # The app falls back to PostgreSQL for storage when REDIS_URL is unset, but the # pub/sub channels have no fallback — without Redis, live status never streams. # Not published to the host: only the app and realtime containers need it, and # binding 6379 would collide with a Redis already running locally. redis: image: redis:7-alpine restart: always healthcheck: test: ['CMD', 'redis-cli', 'ping'] interval: 5s timeout: 5s retries: 5 db: image: pgvector/pgvector:pg17 restart: always ports: - '${POSTGRES_PORT:-5432}:5432' environment: - POSTGRES_USER=${POSTGRES_USER:-postgres} - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-postgres} - POSTGRES_DB=${POSTGRES_DB:-simstudio} volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ['CMD-SHELL', 'pg_isready -U postgres'] interval: 5s timeout: 5s retries: 5 volumes: postgres_data: