Files
hold-slayer/docker-compose.yaml
Robert Helewka 4a3c14d4af
All checks were successful
CVE Scan & Docker Build / security-scan (push) Successful in 45s
CVE Scan & Docker Build / build-and-push (push) Successful in 1m53s
docs: add Claude AI assistant rules and configuration
Add comprehensive rule documentation for AI-assisted development covering
authentication surfaces, outbound-call safety invariants, and other project
conventions to guide Claude's understanding of critical system behaviors.
2026-07-28 19:01:38 -04:00

85 lines
3.2 KiB
YAML

# Local Hold Slayer stack: the single app image + its own PostgreSQL.
#
# Hold Slayer is ONE FastAPI process exposing REST/WS/MCP and serving its built
# SvelteKit dashboard at "/" — no separate web/nginx service (the Dockerfile's
# node stage builds the dashboard into the image).
#
# Auth is Casdoor SSO (owner-only). Because the published port binds the app to
# 0.0.0.0, dev-owner mode (CASDOOR_ENABLED=false) is intentionally REFUSED at
# startup here — that mode is loopback-only. So the stack expects the CASDOOR_*
# + OWNER_NAME vars set (see .env.compose.example). MCP/CLI clients then use an
# owner-minted PAT.
#
# cp .env.compose.example .env
# # fill in CASDOOR_* + OWNER_NAME (+ HS_DB_PASSWORD)
# docker compose up --build
services:
db:
image: postgres:17
environment:
POSTGRES_USER: ${HS_DB_USER:-holdslayer}
POSTGRES_PASSWORD: ${HS_DB_PASSWORD:?set HS_DB_PASSWORD in .env}
POSTGRES_DB: ${HS_DB_NAME:-holdslayer}
volumes:
- hs_pgdata:/var/lib/postgresql/data
# json-file + Alloy docker-socket discovery is the estate pattern; no
# syslog driver / 514xx listener (which would block container creation when
# the listener is absent). See ouranos Rosalind/Virgo logging convention.
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${HS_DB_USER:-holdslayer} -d ${HS_DB_NAME:-holdslayer}"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
app:
build: .
depends_on:
db:
condition: service_healthy
environment:
# Migrations run in the app's own init_db() on boot; it just needs to
# reach the db service. asyncpg URL points at the compose service name.
DATABASE_URL: postgresql+asyncpg://${HS_DB_USER:-holdslayer}:${HS_DB_PASSWORD}@db:5432/${HS_DB_NAME:-holdslayer}
HOST: "0.0.0.0"
PORT: "21081"
# Mock SIP: this stack is a dev/local deploy, not a real trunk. /health
# honestly reports engine=mock as "degraded". Flip to false + fill the
# SIP_TRUNK_* vars for a real-trunk deploy.
USE_MOCK_SIP: ${USE_MOCK_SIP:-true}
# --- Auth: Casdoor SSO (owner-only) ---
CASDOOR_ENABLED: ${CASDOOR_ENABLED:-true}
CASDOOR_ENDPOINT: ${CASDOOR_ENDPOINT:-https://id.ouranos.helu.ca}
CASDOOR_CLIENT_ID: ${CASDOOR_CLIENT_ID}
CASDOOR_CLIENT_SECRET: ${CASDOOR_CLIENT_SECRET}
CASDOOR_ORG_NAME: ${CASDOOR_ORG_NAME:-heluca}
CASDOOR_APP_NAME: ${CASDOOR_APP_NAME:-hold-slayer}
OWNER_NAME: ${OWNER_NAME:?set OWNER_NAME (the owner's Casdoor username)}
PUBLIC_BASE_URL: ${PUBLIC_BASE_URL:-}
ports:
- "${HS_APP_PORT:-21081}:21081"
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
healthcheck:
# /health returns 200 even when "degraded" (mock engine / unregistered
# trunk) — so a 200 means the process is up and serving, which is the
# right liveness signal for a mock-SIP dev stack.
test: ["CMD", "curl", "-f", "http://localhost:21081/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
restart: unless-stopped
volumes:
hs_pgdata: