From 2ec340c64b98c8b24d8e942f7b670069d3a7e87d Mon Sep 17 00:00:00 2001 From: Sharang Parnerkar Date: Wed, 25 Feb 2026 10:43:04 +0100 Subject: [PATCH] feat: add Coolify deployment configuration Add docker-compose.coolify.yml (8 services), .env.coolify.example, and Gitea Action workflow for Coolify API deployment. Removes core-health-check and docs. Adds Traefik labels for *.breakpilot.ai domain routing with Let's Encrypt SSL. Co-Authored-By: Claude Opus 4.6 --- .env.coolify.example | 57 ++++++ .gitea/workflows/deploy-coolify.yml | 32 ++++ docker-compose.coolify.yml | 257 ++++++++++++++++++++++++++++ 3 files changed, 346 insertions(+) create mode 100644 .env.coolify.example create mode 100644 .gitea/workflows/deploy-coolify.yml create mode 100644 docker-compose.coolify.yml diff --git a/.env.coolify.example b/.env.coolify.example new file mode 100644 index 0000000..f5074de --- /dev/null +++ b/.env.coolify.example @@ -0,0 +1,57 @@ +# ========================================================= +# BreakPilot Compliance — Coolify Environment Variables +# ========================================================= +# Copy these into Coolify's environment variable UI +# for the breakpilot-compliance Docker Compose resource. +# ========================================================= + +# --- Database (shared with Core) --- +POSTGRES_USER=breakpilot +POSTGRES_PASSWORD=CHANGE_ME_SAME_AS_CORE +POSTGRES_DB=breakpilot_db + +# --- Security --- +JWT_SECRET=CHANGE_ME_SAME_AS_CORE + +# --- MinIO (from Core) --- +MINIO_ROOT_USER=breakpilot +MINIO_ROOT_PASSWORD=CHANGE_ME_SAME_AS_CORE + +# --- Session --- +SESSION_TTL_HOURS=24 + +# --- SMTP (Real mail server) --- +SMTP_HOST=smtp.example.com +SMTP_PORT=587 +SMTP_USERNAME=compliance@breakpilot.ai +SMTP_PASSWORD=CHANGE_ME_SMTP_PASSWORD +SMTP_FROM_NAME=BreakPilot Compliance +SMTP_FROM_ADDR=compliance@breakpilot.ai + +# --- LLM Configuration --- +COMPLIANCE_LLM_PROVIDER=anthropic +SELF_HOSTED_LLM_URL= +SELF_HOSTED_LLM_MODEL= +COMPLIANCE_LLM_MAX_TOKENS=4096 +COMPLIANCE_LLM_TEMPERATURE=0.3 +COMPLIANCE_LLM_TIMEOUT=120 +ANTHROPIC_API_KEY=CHANGE_ME_ANTHROPIC_KEY +ANTHROPIC_DEFAULT_MODEL=claude-sonnet-4-5-20250929 + +# --- Ollama (optional) --- +OLLAMA_URL= +OLLAMA_DEFAULT_MODEL= +COMPLIANCE_LLM_MODEL= + +# --- LLM Fallback --- +LLM_FALLBACK_PROVIDER= + +# --- PII & Audit --- +PII_REDACTION_ENABLED=true +PII_REDACTION_LEVEL=standard +AUDIT_RETENTION_DAYS=365 +AUDIT_LOG_PROMPTS=true + +# --- Frontend URLs (build args) --- +NEXT_PUBLIC_API_URL=https://api-compliance.breakpilot.ai +NEXT_PUBLIC_SDK_URL=https://sdk.breakpilot.ai diff --git a/.gitea/workflows/deploy-coolify.yml b/.gitea/workflows/deploy-coolify.yml new file mode 100644 index 0000000..4949666 --- /dev/null +++ b/.gitea/workflows/deploy-coolify.yml @@ -0,0 +1,32 @@ +name: Deploy to Coolify + +on: + push: + branches: + - coolify + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Wait for Core deployment + run: | + echo "Waiting 30s for Core services to stabilize..." + sleep 30 + + - name: Deploy via Coolify API + run: | + echo "Deploying breakpilot-compliance to Coolify..." + HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \ + -X POST \ + -H "Authorization: Bearer ${{ secrets.COOLIFY_API_TOKEN }}" \ + -H "Content-Type: application/json" \ + -d '{"uuid": "${{ secrets.COOLIFY_RESOURCE_UUID }}", "force_rebuild": true}' \ + "${{ secrets.COOLIFY_BASE_URL }}/api/v1/deploy") + + echo "HTTP Status: $HTTP_STATUS" + if [ "$HTTP_STATUS" -ne 200 ] && [ "$HTTP_STATUS" -ne 201 ]; then + echo "Deployment failed with status $HTTP_STATUS" + exit 1 + fi + echo "Deployment triggered successfully!" diff --git a/docker-compose.coolify.yml b/docker-compose.coolify.yml new file mode 100644 index 0000000..b6ed2d8 --- /dev/null +++ b/docker-compose.coolify.yml @@ -0,0 +1,257 @@ +# ========================================================= +# BreakPilot Compliance — Compliance SDK Platform (Coolify) +# ========================================================= +# Requires: breakpilot-core must be running +# Deployed via Coolify. SSL termination handled by Traefik. +# ========================================================= + +networks: + breakpilot-network: + external: true + name: breakpilot-network + +volumes: + dsms_data: + +services: + + # ========================================================= + # FRONTEND + # ========================================================= + admin-compliance: + build: + context: ./admin-compliance + dockerfile: Dockerfile + args: + NEXT_PUBLIC_API_URL: ${NEXT_PUBLIC_API_URL:-https://api-compliance.breakpilot.ai} + NEXT_PUBLIC_SDK_URL: ${NEXT_PUBLIC_SDK_URL:-https://sdk.breakpilot.ai} + container_name: bp-compliance-admin + expose: + - "3000" + environment: + NODE_ENV: production + BACKEND_URL: http://backend-compliance:8002 + CONSENT_SERVICE_URL: http://bp-core-consent-service:8081 + SDK_URL: http://ai-compliance-sdk:8090 + OLLAMA_URL: ${OLLAMA_URL:-} + COMPLIANCE_LLM_MODEL: ${COMPLIANCE_LLM_MODEL:-} + depends_on: + backend-compliance: + condition: service_started + labels: + - "traefik.enable=true" + - "traefik.http.routers.admin-compliance.rule=Host(`admin-compliance.breakpilot.ai`)" + - "traefik.http.routers.admin-compliance.entrypoints=https" + - "traefik.http.routers.admin-compliance.tls=true" + - "traefik.http.routers.admin-compliance.tls.certresolver=letsencrypt" + - "traefik.http.services.admin-compliance.loadbalancer.server.port=3000" + restart: unless-stopped + networks: + - breakpilot-network + + developer-portal: + build: + context: ./developer-portal + dockerfile: Dockerfile + container_name: bp-compliance-developer-portal + expose: + - "3000" + environment: + NODE_ENV: production + labels: + - "traefik.enable=true" + - "traefik.http.routers.developer-portal.rule=Host(`developer.breakpilot.ai`)" + - "traefik.http.routers.developer-portal.entrypoints=https" + - "traefik.http.routers.developer-portal.tls=true" + - "traefik.http.routers.developer-portal.tls.certresolver=letsencrypt" + - "traefik.http.services.developer-portal.loadbalancer.server.port=3000" + restart: unless-stopped + networks: + - breakpilot-network + + # ========================================================= + # BACKEND + # ========================================================= + backend-compliance: + build: + context: ./backend-compliance + dockerfile: Dockerfile + container_name: bp-compliance-backend + expose: + - "8002" + environment: + PORT: 8002 + DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@bp-core-postgres:5432/${POSTGRES_DB}?options=-csearch_path%3Dcompliance,core,public + JWT_SECRET: ${JWT_SECRET} + ENVIRONMENT: production + CONSENT_SERVICE_URL: http://bp-core-consent-service:8081 + VALKEY_URL: redis://bp-core-valkey:6379/0 + SESSION_TTL_HOURS: ${SESSION_TTL_HOURS:-24} + COMPLIANCE_LLM_PROVIDER: ${COMPLIANCE_LLM_PROVIDER:-anthropic} + SELF_HOSTED_LLM_URL: ${SELF_HOSTED_LLM_URL:-} + SELF_HOSTED_LLM_MODEL: ${SELF_HOSTED_LLM_MODEL:-} + COMPLIANCE_LLM_MAX_TOKENS: ${COMPLIANCE_LLM_MAX_TOKENS:-4096} + COMPLIANCE_LLM_TEMPERATURE: ${COMPLIANCE_LLM_TEMPERATURE:-0.3} + COMPLIANCE_LLM_TIMEOUT: ${COMPLIANCE_LLM_TIMEOUT:-120} + ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-} + SMTP_HOST: ${SMTP_HOST} + SMTP_PORT: ${SMTP_PORT:-587} + SMTP_USERNAME: ${SMTP_USERNAME} + SMTP_PASSWORD: ${SMTP_PASSWORD} + SMTP_FROM_NAME: ${SMTP_FROM_NAME:-BreakPilot Compliance} + SMTP_FROM_ADDR: ${SMTP_FROM_ADDR:-compliance@breakpilot.ai} + RAG_SERVICE_URL: http://bp-core-rag-service:8097 + labels: + - "traefik.enable=true" + - "traefik.http.routers.backend-compliance.rule=Host(`api-compliance.breakpilot.ai`)" + - "traefik.http.routers.backend-compliance.entrypoints=https" + - "traefik.http.routers.backend-compliance.tls=true" + - "traefik.http.routers.backend-compliance.tls.certresolver=letsencrypt" + - "traefik.http.services.backend-compliance.loadbalancer.server.port=8002" + restart: unless-stopped + networks: + - breakpilot-network + + # ========================================================= + # SDK SERVICES + # ========================================================= + ai-compliance-sdk: + build: + context: ./ai-compliance-sdk + dockerfile: Dockerfile + container_name: bp-compliance-ai-sdk + expose: + - "8090" + environment: + PORT: 8090 + ENVIRONMENT: production + DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@bp-core-postgres:5432/${POSTGRES_DB} + JWT_SECRET: ${JWT_SECRET} + LLM_PROVIDER: ${COMPLIANCE_LLM_PROVIDER:-anthropic} + LLM_FALLBACK_PROVIDER: ${LLM_FALLBACK_PROVIDER:-} + OLLAMA_URL: ${OLLAMA_URL:-} + OLLAMA_DEFAULT_MODEL: ${OLLAMA_DEFAULT_MODEL:-} + ANTHROPIC_API_KEY: ${ANTHROPIC_API_KEY:-} + ANTHROPIC_DEFAULT_MODEL: ${ANTHROPIC_DEFAULT_MODEL:-claude-sonnet-4-5-20250929} + PII_REDACTION_ENABLED: ${PII_REDACTION_ENABLED:-true} + PII_REDACTION_LEVEL: ${PII_REDACTION_LEVEL:-standard} + AUDIT_RETENTION_DAYS: ${AUDIT_RETENTION_DAYS:-365} + AUDIT_LOG_PROMPTS: ${AUDIT_LOG_PROMPTS:-true} + ALLOWED_ORIGINS: "*" + TTS_SERVICE_URL: http://compliance-tts-service:8095 + QDRANT_HOST: bp-core-qdrant + QDRANT_PORT: "6333" + healthcheck: + test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:8090/health"] + interval: 30s + timeout: 3s + start_period: 10s + retries: 3 + labels: + - "traefik.enable=true" + - "traefik.http.routers.ai-sdk.rule=Host(`sdk.breakpilot.ai`)" + - "traefik.http.routers.ai-sdk.entrypoints=https" + - "traefik.http.routers.ai-sdk.tls=true" + - "traefik.http.routers.ai-sdk.tls.certresolver=letsencrypt" + - "traefik.http.services.ai-sdk.loadbalancer.server.port=8090" + restart: unless-stopped + networks: + - breakpilot-network + + # ========================================================= + # TTS SERVICE (Piper TTS + FFmpeg) + # ========================================================= + compliance-tts-service: + build: + context: ./compliance-tts-service + dockerfile: Dockerfile + container_name: bp-compliance-tts + expose: + - "8095" + environment: + MINIO_ENDPOINT: bp-core-minio:9000 + MINIO_ACCESS_KEY: ${MINIO_ROOT_USER} + MINIO_SECRET_KEY: ${MINIO_ROOT_PASSWORD} + PIPER_MODEL_PATH: /app/models/de_DE-thorsten-high.onnx + healthcheck: + test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8095/health')"] + interval: 30s + timeout: 10s + start_period: 60s + retries: 3 + restart: unless-stopped + networks: + - breakpilot-network + + # ========================================================= + # DATA SOVEREIGNTY + # ========================================================= + dsms-node: + build: + context: ./dsms-node + dockerfile: Dockerfile + container_name: bp-compliance-dsms-node + expose: + - "4001" + - "5001" + - "8080" + volumes: + - dsms_data:/data/ipfs + environment: + IPFS_PROFILE: server + healthcheck: + test: ["CMD-SHELL", "ipfs id"] + interval: 30s + timeout: 10s + start_period: 30s + retries: 3 + restart: unless-stopped + networks: + - breakpilot-network + + dsms-gateway: + build: + context: ./dsms-gateway + dockerfile: Dockerfile + container_name: bp-compliance-dsms-gateway + expose: + - "8082" + environment: + IPFS_API_URL: http://dsms-node:5001 + IPFS_GATEWAY_URL: http://dsms-node:8080 + JWT_SECRET: ${JWT_SECRET} + depends_on: + dsms-node: + condition: service_healthy + restart: unless-stopped + networks: + - breakpilot-network + + # ========================================================= + # DOCUMENT CRAWLER & AUTO-ONBOARDING + # ========================================================= + document-crawler: + build: + context: ./document-crawler + dockerfile: Dockerfile + container_name: bp-compliance-document-crawler + expose: + - "8098" + environment: + PORT: 8098 + DATABASE_URL: postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@bp-core-postgres:5432/${POSTGRES_DB} + LLM_GATEWAY_URL: http://ai-compliance-sdk:8090 + DSMS_GATEWAY_URL: http://dsms-gateway:8082 + CRAWL_BASE_PATH: /data/crawl + MAX_FILE_SIZE_MB: 50 + volumes: + - /tmp/breakpilot-crawl-data:/data/crawl:ro + healthcheck: + test: ["CMD", "curl", "-f", "http://127.0.0.1:8098/health"] + interval: 30s + timeout: 10s + start_period: 15s + retries: 3 + restart: unless-stopped + networks: + - breakpilot-network