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.
85 lines
3.2 KiB
YAML
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:
|