This repository has been archived on 2026-02-15. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
breakpilot-pwa/docker-compose-new-infra.yml
BreakPilot Dev 9fe0a27a60 chore: Add new infrastructure docker-compose draft
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-10 23:26:37 +01:00

1050 lines
36 KiB
YAML

services:
# PostgreSQL Database with PostGIS Extension
# PostGIS is required for geo-service (OSM/Terrain features)
postgres:
image: postgis/postgis:16-3.4-alpine
container_name: breakpilot-pwa-postgres
ports:
- "5432:5432"
environment:
POSTGRES_USER: breakpilot
POSTGRES_PASSWORD: breakpilot123
POSTGRES_DB: breakpilot_db
volumes:
- breakpilot_pwa_data:/var/lib/postgresql/data
- ./geo-service/scripts/init_postgis.sql:/docker-entrypoint-initdb.d/10-init-postgis.sql:ro
healthcheck:
test: ["CMD-SHELL", "pg_isready -U breakpilot -d breakpilot_db"]
interval: 5s
timeout: 5s
retries: 5
networks:
- breakpilot-pwa-network
restart: unless-stopped
# ============================================
# Valkey - Session Cache (Redis-Fork, BSD-3)
# Redis-compatible, 100% Open Source
# ============================================
valkey:
image: valkey/valkey:8-alpine
container_name: breakpilot-pwa-valkey
ports:
- "6379:6379"
volumes:
- valkey_data:/data
command: valkey-server --appendonly yes --maxmemory 256mb --maxmemory-policy allkeys-lru
healthcheck:
test: ["CMD", "valkey-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
networks:
- breakpilot-pwa-network
restart: unless-stopped
# Go Consent Service
consent-service:
build:
context: ./consent-service
dockerfile: Dockerfile
platform: linux/arm64 # Mac Mini Apple Silicon
container_name: breakpilot-pwa-consent-service
ports:
- "8081:8081"
environment:
- DATABASE_URL=postgres://breakpilot:breakpilot123@postgres:5432/breakpilot_db?sslmode=disable
- JWT_SECRET=${JWT_SECRET:-your-super-secret-jwt-key-change-in-production}
- JWT_REFRESH_SECRET=${JWT_REFRESH_SECRET:-your-refresh-secret-key-change-in-production}
- PORT=8081
- ENVIRONMENT=${ENVIRONMENT:-development}
- ALLOWED_ORIGINS=http://localhost:8000,http://backend:8000
# Valkey Session Cache
- VALKEY_URL=${VALKEY_URL:-redis://valkey:6379}
- SESSION_TTL_HOURS=${SESSION_TTL_HOURS:-24}
# E-Mail Konfiguration (Mailpit für Entwicklung)
- SMTP_HOST=${SMTP_HOST:-mailpit}
- SMTP_PORT=${SMTP_PORT:-1025}
- SMTP_USERNAME=${SMTP_USERNAME:-}
- SMTP_PASSWORD=${SMTP_PASSWORD:-}
- SMTP_FROM_NAME=${SMTP_FROM_NAME:-BreakPilot}
- SMTP_FROM_ADDR=${SMTP_FROM_ADDR:-noreply@breakpilot.app}
- FRONTEND_URL=${FRONTEND_URL:-http://localhost:8000}
depends_on:
postgres:
condition: service_healthy
valkey:
condition: service_healthy
mailpit:
condition: service_started
networks:
- breakpilot-pwa-network
restart: unless-stopped
# Python Backend
backend:
build:
context: ./backend
dockerfile: Dockerfile
platform: linux/arm64 # Mac Mini Apple Silicon
container_name: breakpilot-pwa-backend
expose:
- "8000"
environment:
- CONSENT_SERVICE_URL=http://consent-service:8081
- KLAUSUR_SERVICE_URL=http://klausur-service:8086
- TROCR_SERVICE_URL=${TROCR_SERVICE_URL:-http://host.docker.internal:18084}
- CAMUNDA_URL=http://camunda:8080/engine-rest
- DATABASE_URL=postgres://breakpilot:breakpilot123@postgres:5432/breakpilot_db?sslmode=disable
- JWT_SECRET=${JWT_SECRET:-your-super-secret-jwt-key-change-in-production}
- ENVIRONMENT=${ENVIRONMENT:-development}
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
- DEBUG=${DEBUG:-false}
# Alerts Agent (Google Alerts Monitoring)
- ALERTS_AGENT_ENABLED=${ALERTS_AGENT_ENABLED:-true}
# HashiCorp Vault - Secrets Management
- VAULT_ADDR=${VAULT_ADDR:-http://vault:8200}
- VAULT_TOKEN=${VAULT_TOKEN:-breakpilot-dev-token}
- VAULT_SECRETS_PATH=${VAULT_SECRETS_PATH:-breakpilot}
- USE_VAULT_SECRETS=${USE_VAULT_SECRETS:-true}
# Keycloak Authentication (optional - wenn nicht gesetzt wird lokales JWT verwendet)
- KEYCLOAK_SERVER_URL=${KEYCLOAK_SERVER_URL:-}
- KEYCLOAK_REALM=${KEYCLOAK_REALM:-}
- KEYCLOAK_CLIENT_ID=${KEYCLOAK_CLIENT_ID:-}
- KEYCLOAK_CLIENT_SECRET=${KEYCLOAK_CLIENT_SECRET:-}
- KEYCLOAK_VERIFY_SSL=${KEYCLOAK_VERIFY_SSL:-true}
# Valkey Session Cache
- VALKEY_URL=${VALKEY_URL:-redis://valkey:6379}
- SESSION_TTL_HOURS=${SESSION_TTL_HOURS:-24}
# vast.ai GPU Infrastructure
- VAST_API_KEY=${VAST_API_KEY:-}
- VAST_INSTANCE_ID=${VAST_INSTANCE_ID:-}
- CONTROL_API_KEY=${CONTROL_API_KEY:-}
- VAST_AUTO_SHUTDOWN=${VAST_AUTO_SHUTDOWN:-true}
- VAST_AUTO_SHUTDOWN_MINUTES=${VAST_AUTO_SHUTDOWN_MINUTES:-30}
# vLLM Backend
- VLLM_BASE_URL=${VLLM_BASE_URL:-}
- VLLM_ENABLED=${VLLM_ENABLED:-false}
# Ollama Backend (lokal auf Mac Mini - DSGVO-konform)
- OLLAMA_BASE_URL=${OLLAMA_BASE_URL:-http://host.docker.internal:11434}
- OLLAMA_ENABLED=${OLLAMA_ENABLED:-true}
- OLLAMA_DEFAULT_MODEL=${OLLAMA_DEFAULT_MODEL:-qwen2.5:14b}
- OLLAMA_VISION_MODEL=${OLLAMA_VISION_MODEL:-qwen2.5vl:32b}
- OLLAMA_CORRECTION_MODEL=${OLLAMA_CORRECTION_MODEL:-qwen2.5:14b}
- OLLAMA_TIMEOUT=${OLLAMA_TIMEOUT:-180}
# Breakpilot Drive Game API
- GAME_USE_DATABASE=${GAME_USE_DATABASE:-true}
- GAME_REQUIRE_AUTH=${GAME_REQUIRE_AUTH:-false}
- GAME_REQUIRE_BILLING=${GAME_REQUIRE_BILLING:-false}
- GAME_LLM_MODEL=${GAME_LLM_MODEL:-}
# Compliance LLM Provider Configuration
# Options: "anthropic" (cloud) or "self_hosted" (Ollama/local)
- COMPLIANCE_LLM_PROVIDER=${COMPLIANCE_LLM_PROVIDER:-self_hosted}
- SELF_HOSTED_LLM_URL=${SELF_HOSTED_LLM_URL:-http://host.docker.internal:11434}
- SELF_HOSTED_LLM_MODEL=${SELF_HOSTED_LLM_MODEL:-llama3.1:70b}
- COMPLIANCE_LLM_MAX_TOKENS=${COMPLIANCE_LLM_MAX_TOKENS:-4096}
- COMPLIANCE_LLM_TEMPERATURE=${COMPLIANCE_LLM_TEMPERATURE:-0.3}
- COMPLIANCE_LLM_TIMEOUT=${COMPLIANCE_LLM_TIMEOUT:-120}
# E-Mail Konfiguration (Mailpit fuer Entwicklung)
- SMTP_HOST=${SMTP_HOST:-mailpit}
- SMTP_PORT=${SMTP_PORT:-1025}
- SMTP_USERNAME=${SMTP_USERNAME:-}
- SMTP_PASSWORD=${SMTP_PASSWORD:-}
- SMTP_FROM_NAME=${SMTP_FROM_NAME:-BreakPilot}
- SMTP_FROM_ADDR=${SMTP_FROM_ADDR:-noreply@breakpilot.app}
extra_hosts:
- "host.docker.internal:host-gateway"
- "mac-mini:192.168.178.163"
volumes:
# Mount Docker socket for container monitoring (Mac Mini Control)
- /var/run/docker.sock:/var/run/docker.sock:ro
# Mount SBOM files for Security Dashboard
- ./docs/sbom:/app/docs/sbom:ro
# Mount Projekt-Verzeichnis fuer Test-Dashboard (echte Test-Discovery)
- /Users/benjaminadmin/Projekte/breakpilot-pwa:/app/project:ro
depends_on:
- consent-service
- valkey
- mailpit
networks:
- breakpilot-pwa-network
restart: unless-stopped
# Mailpit - Lokaler E-Mail-Server für Entwicklung
# Web UI: http://localhost:8025
# SMTP: localhost:1025
mailpit:
image: axllent/mailpit:latest
container_name: breakpilot-pwa-mailpit
ports:
- "8025:8025" # Web UI
- "1025:1025" # SMTP Server
environment:
- MP_SMTP_AUTH_ACCEPT_ANY=true
- MP_SMTP_AUTH_ALLOW_INSECURE=true
networks:
- breakpilot-pwa-network
restart: unless-stopped
# Go School Service (Klausuren, Noten, Zeugnisse)
school-service:
build:
context: ./school-service
dockerfile: Dockerfile
platform: linux/arm64 # Mac Mini Apple Silicon
container_name: breakpilot-pwa-school-service
ports:
- "8084:8084"
environment:
- DATABASE_URL=postgres://breakpilot:breakpilot123@postgres:5432/breakpilot_db?sslmode=disable
- JWT_SECRET=${JWT_SECRET:-your-super-secret-jwt-key-change-in-production}
- PORT=8084
- ENVIRONMENT=${ENVIRONMENT:-development}
- ALLOWED_ORIGINS=http://localhost:8000,http://backend:8000
- LLM_GATEWAY_URL=http://backend:8000/llm
depends_on:
postgres:
condition: service_healthy
networks:
- breakpilot-pwa-network
restart: unless-stopped
# Embedding Service (ML-heavy operations)
# Handles: embeddings, re-ranking, PDF extraction
# Separated for faster klausur-service builds
embedding-service:
build:
context: ./klausur-service/embedding-service
dockerfile: Dockerfile
platform: linux/arm64 # Mac Mini Apple Silicon
container_name: breakpilot-pwa-embedding-service
ports:
- "8087:8087"
environment:
- EMBEDDING_BACKEND=${EMBEDDING_BACKEND:-local}
- LOCAL_EMBEDDING_MODEL=${LOCAL_EMBEDDING_MODEL:-BAAI/bge-m3}
- LOCAL_RERANKER_MODEL=${LOCAL_RERANKER_MODEL:-BAAI/bge-reranker-v2-m3}
- PDF_EXTRACTION_BACKEND=${PDF_EXTRACTION_BACKEND:-auto}
- OPENAI_API_KEY=${OPENAI_API_KEY:-}
- COHERE_API_KEY=${COHERE_API_KEY:-}
- LOG_LEVEL=${LOG_LEVEL:-INFO}
volumes:
- embedding_models:/root/.cache/huggingface
deploy:
resources:
limits:
memory: 4G
healthcheck:
test: ["CMD", "python", "-c", "import httpx; httpx.get('http://localhost:8087/health').raise_for_status()"]
interval: 30s
timeout: 10s
start_period: 120s
retries: 3
networks:
- breakpilot-pwa-network
restart: unless-stopped
# Klausur-Service (Abitur/Vorabitur Klausurkorrektur)
# React + FastAPI Microservice
# Web UI: http://localhost:8086
klausur-service:
build:
context: ./klausur-service
dockerfile: Dockerfile
platform: linux/arm64 # Native ARM64 - PaddlePaddle 3.3.0 unterstützt ARM64
container_name: breakpilot-pwa-klausur-service
expose:
- "8086"
environment:
- JWT_SECRET=${JWT_SECRET:-your-super-secret-jwt-key-change-in-production}
- BACKEND_URL=http://backend:8000
- SCHOOL_SERVICE_URL=http://school-service:8084
- ENVIRONMENT=${ENVIRONMENT:-development}
# PostgreSQL for OCR Labeling & Metrics
- DATABASE_URL=postgres://breakpilot:breakpilot123@postgres:5432/breakpilot_db
# Embedding Service (ML operations)
- EMBEDDING_SERVICE_URL=http://embedding-service:8087
# BYOEH Configuration
- QDRANT_URL=http://qdrant:6333
- BYOEH_ENCRYPTION_ENABLED=true
- BYOEH_CHUNK_SIZE=1000
- BYOEH_CHUNK_OVERLAP=200
# MinIO Configuration (RAG Document Storage)
- MINIO_ENDPOINT=minio:9000
- MINIO_ACCESS_KEY=${MINIO_ROOT_USER:-breakpilot}
- MINIO_SECRET_KEY=${MINIO_ROOT_PASSWORD:-breakpilot123}
- MINIO_BUCKET=breakpilot-rag
- MINIO_SECURE=false
# Ollama LLM Configuration
- OLLAMA_BASE_URL=${OLLAMA_BASE_URL:-http://host.docker.internal:11434}
- OLLAMA_ENABLED=${OLLAMA_ENABLED:-true}
- OLLAMA_DEFAULT_MODEL=${OLLAMA_DEFAULT_MODEL:-qwen2.5:14b}
- OLLAMA_VISION_MODEL=${OLLAMA_VISION_MODEL:-qwen2.5vl:32b}
- OLLAMA_CORRECTION_MODEL=${OLLAMA_CORRECTION_MODEL:-qwen2.5:14b}
# PaddleOCR Service (x86_64 via Rosetta)
- PADDLEOCR_SERVICE_URL=http://paddleocr-service:8095
# HashiCorp Vault - Anthropic API Key for Loesung E
- VAULT_ADDR=http://vault:8200
- VAULT_TOKEN=${VAULT_DEV_TOKEN:-breakpilot-dev-token}
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
volumes:
- klausur_uploads:/app/uploads
- eh_uploads:/app/eh-uploads
- ocr_labeling:/app/ocr-labeling
- paddle_models:/root/.paddlex # Persist PaddleOCR models across restarts
- ./docs:/app/docs # NIBIS Abitur-Dateien
depends_on:
- backend
- school-service
- embedding-service
- postgres
- qdrant
- minio
- paddleocr-service
- vault
networks:
- breakpilot-pwa-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8086/health"]
interval: 30s
timeout: 30s
retries: 3
start_period: 10s
restart: unless-stopped
# ============================================
# PaddleOCR Service - x86_64 via Rosetta
# Runs in emulation to avoid ARM64 crashes
# ============================================
paddleocr-service:
build:
context: ./paddleocr-service
dockerfile: Dockerfile
platform: linux/amd64 # Force x86_64 emulation via Rosetta
container_name: breakpilot-pwa-paddleocr
expose:
- "8095"
environment:
- PADDLE_PDX_DISABLE_MODEL_SOURCE_CHECK=True
volumes:
- paddleocr_models:/root/.paddlex # Cache PaddleX models
- paddleocr_models:/root/.paddleocr # Cache PaddleOCR 3.x models
networks:
- breakpilot-pwa-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8095/health"]
interval: 30s
timeout: 60s
retries: 5
start_period: 180s # Models need time to load in emulation
restart: unless-stopped
# Qdrant Vector Database (BYOEH - Erwartungshorizont RAG)
# REST API: http://localhost:6333
# gRPC: localhost:6334
qdrant:
image: qdrant/qdrant:v1.12.1
container_name: breakpilot-pwa-qdrant
ports:
- "6333:6333"
- "6334:6334"
volumes:
- qdrant_data:/qdrant/storage
environment:
- QDRANT__SERVICE__GRPC_PORT=6334
healthcheck:
test: ["CMD-SHELL", "bash -c '</dev/tcp/localhost/6333'"]
interval: 10s
timeout: 5s
retries: 3
networks:
- breakpilot-pwa-network
restart: unless-stopped
# Go Billing Service
billing-service:
build:
context: ./billing-service
dockerfile: Dockerfile
platform: linux/arm64 # Mac Mini Apple Silicon
container_name: breakpilot-pwa-billing-service
ports:
- "8083:8083"
environment:
- DATABASE_URL=postgres://breakpilot:breakpilot123@postgres:5432/breakpilot_db?sslmode=disable
- JWT_SECRET=${JWT_SECRET:-your-super-secret-jwt-key-change-in-production}
- PORT=8083
- ENVIRONMENT=${ENVIRONMENT:-development}
- ALLOWED_ORIGINS=http://localhost:8000,http://backend:8000
# Stripe Configuration
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY:-}
- STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET:-}
- STRIPE_PUBLISHABLE_KEY=${STRIPE_PUBLISHABLE_KEY:-}
# URLs
- BILLING_SUCCESS_URL=${BILLING_SUCCESS_URL:-http://localhost:3000/success}
- BILLING_CANCEL_URL=${BILLING_CANCEL_URL:-http://localhost:3000/cancel}
- FRONTEND_URL=${FRONTEND_URL:-http://localhost:8000}
# Trial
- TRIAL_PERIOD_DAYS=${TRIAL_PERIOD_DAYS:-7}
# Internal API
- INTERNAL_API_KEY=${INTERNAL_API_KEY:-internal-service-key-change-in-production}
depends_on:
postgres:
condition: service_healthy
networks:
- breakpilot-pwa-network
restart: unless-stopped
# Website - BreakPilot Landing/Pricing Page (Next.js)
# HTTPS via nginx on port 3000
website:
build:
context: ./website
dockerfile: Dockerfile
args:
- NEXT_PUBLIC_BILLING_API_URL=${NEXT_PUBLIC_BILLING_API_URL:-https://macmini:8083}
- NEXT_PUBLIC_APP_URL=${NEXT_PUBLIC_APP_URL:-https://macmini:8000}
- NEXT_PUBLIC_KLAUSUR_SERVICE_URL=${NEXT_PUBLIC_KLAUSUR_SERVICE_URL:-https://macmini:8086}
- NEXT_PUBLIC_VOICE_SERVICE_URL=${NEXT_PUBLIC_VOICE_SERVICE_URL:-https://macmini:8091}
- NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=${STRIPE_PUBLISHABLE_KEY:-}
platform: linux/arm64 # Mac Mini Apple Silicon
container_name: breakpilot-pwa-website
expose:
- "3000"
environment:
- NODE_ENV=production
- VAST_API_KEY=${VAST_API_KEY:-}
- CONTROL_API_KEY=${CONTROL_API_KEY:-}
- BACKEND_URL=http://backend:8000
- CONSENT_SERVICE_URL=http://consent-service:8081
# Edu-Search Service (for uni-crawler admin)
- EDU_SEARCH_URL=${EDU_SEARCH_URL:-http://breakpilot-edu-search:8086}
- EDU_SEARCH_API_KEY=${EDU_SEARCH_API_KEY:-dev-key}
# Unity AI Bridge (runs on host machine in Unity Editor)
- UNITY_BRIDGE_URL=http://host.docker.internal:8090
# Woodpecker CI/CD Status Widget
- WOODPECKER_URL=${WOODPECKER_URL:-http://woodpecker-server:8000}
- WOODPECKER_TOKEN=${WOODPECKER_TOKEN:-}
depends_on:
- billing-service
- backend
- consent-service
networks:
- breakpilot-pwa-network
restart: unless-stopped
# ============================================
# Studio v2 - Neue Lehrer-Oberfläche
# Next.js auf Port 3001
# ============================================
studio-v2:
build:
context: ./studio-v2
dockerfile: Dockerfile
args:
- NEXT_PUBLIC_VOICE_SERVICE_URL=${NEXT_PUBLIC_VOICE_SERVICE_URL:-https://macmini:8091}
- NEXT_PUBLIC_KLAUSUR_SERVICE_URL=${NEXT_PUBLIC_KLAUSUR_SERVICE_URL:-https://macmini:8086}
platform: linux/arm64 # Mac Mini Apple Silicon
container_name: breakpilot-pwa-studio-v2
# Port 443 wird von nginx HTTPS bereitgestellt (studio-v2 intern auf 3001)
# Port 3004 ist HTTP-only für Mobile Uploads (HSTS-Umgehung)
ports:
- "3004:3001" # HTTP-only port for mobile QR uploads
expose:
- "3001"
environment:
- NODE_ENV=production
- BACKEND_URL=http://backend:8000
depends_on:
- backend
networks:
- breakpilot-pwa-network
restart: unless-stopped
# ============================================
# Admin v2 - Neues Admin-Frontend
# Next.js auf Port 3002
# ============================================
admin-v2:
build:
context: ./admin-v2
dockerfile: Dockerfile
args:
- NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL:-https://macmini:8000}
- NEXT_PUBLIC_OLD_ADMIN_URL=${NEXT_PUBLIC_OLD_ADMIN_URL:-https://macmini:3000/admin}
- NEXT_PUBLIC_SDK_URL=${NEXT_PUBLIC_SDK_URL:-https://macmini:8093}
- NEXT_PUBLIC_KLAUSUR_SERVICE_URL=${NEXT_PUBLIC_KLAUSUR_SERVICE_URL:-/klausur-api}
platform: linux/arm64 # Mac Mini Apple Silicon
container_name: breakpilot-pwa-admin-v2
# Port 3002 wird über nginx proxied (admin-v2:3000 intern)
# Port 3005 ist HTTP-only für Mobile Uploads (HSTS-Umgehung)
ports:
- "3005:3000" # HTTP-only port for mobile QR uploads
expose:
- "3000"
environment:
- NODE_ENV=production
- BACKEND_URL=http://backend:8000
- CONSENT_SERVICE_URL=http://consent-service:8081
- KLAUSUR_SERVICE_URL=http://klausur-service:8086
- SDK_URL=http://ai-compliance-sdk:8090
# Woodpecker CI Status
- WOODPECKER_URL=${WOODPECKER_URL:-http://woodpecker-server:8000}
- WOODPECKER_TOKEN=${WOODPECKER_TOKEN:-}
# Compliance Advisor LLM
- OLLAMA_URL=${OLLAMA_BASE_URL:-http://host.docker.internal:11434}
- COMPLIANCE_LLM_MODEL=${COMPLIANCE_LLM_MODEL:-qwen2.5vl:32b}
volumes:
# Mount Docker socket for Mac Mini monitoring dashboard
- /var/run/docker.sock:/var/run/docker.sock:ro
extra_hosts:
- "host.docker.internal:host-gateway"
depends_on:
- backend
- consent-service
- ai-compliance-sdk
networks:
- breakpilot-pwa-network
restart: unless-stopped
# ============================================
# Developer Portal - Oeffentliches SDK-Dokumentationsportal
# Access: https://macmini:3006/
# ============================================
developer-portal:
build:
context: ./developer-portal
dockerfile: Dockerfile
platform: linux/arm64
container_name: breakpilot-pwa-developer-portal
expose:
- "3000"
environment:
- NODE_ENV=production
networks:
- breakpilot-pwa-network
restart: unless-stopped
# ============================================
# AI Compliance SDK - Multi-Tenant RBAC & LLM Gateway
# Go auf Port 8090 (intern), 8093 (extern)
# CFO Use-Case: Namespace-isolierte KI-Nutzung
# ============================================
ai-compliance-sdk:
build:
context: ./ai-compliance-sdk
dockerfile: Dockerfile
platform: linux/arm64 # Mac Mini Apple Silicon
container_name: breakpilot-pwa-ai-compliance-sdk
# Port 8093 wird über nginx proxied (ai-compliance-sdk:8090 intern)
environment:
- PORT=8090
- ENVIRONMENT=${ENVIRONMENT:-development}
# PostgreSQL for RBAC, Policies, Audit
- DATABASE_URL=postgres://breakpilot:breakpilot123@postgres:5432/breakpilot_db?sslmode=disable
- JWT_SECRET=${JWT_SECRET:-your-super-secret-jwt-key-change-in-production}
# LLM Provider Configuration
- LLM_PROVIDER=${SDK_LLM_PROVIDER:-ollama}
- LLM_FALLBACK_PROVIDER=${SDK_LLM_FALLBACK_PROVIDER:-anthropic}
# Ollama (Mac Mini lokal - DSGVO-konform)
- OLLAMA_URL=${OLLAMA_BASE_URL:-http://host.docker.internal:11434}
- OLLAMA_DEFAULT_MODEL=${OLLAMA_DEFAULT_MODEL:-qwen2.5:14b}
# Anthropic (Cloud-Fallback via Syseleven BSI-Cloud)
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY:-}
- ANTHROPIC_DEFAULT_MODEL=${ANTHROPIC_DEFAULT_MODEL:-claude-sonnet-4-20250514}
# PII Detection & Redaction
- PII_REDACTION_ENABLED=${PII_REDACTION_ENABLED:-true}
- PII_REDACTION_LEVEL=${PII_REDACTION_LEVEL:-strict}
# Audit Trail
- AUDIT_RETENTION_DAYS=${AUDIT_RETENTION_DAYS:-365}
- AUDIT_LOG_PROMPTS=${AUDIT_LOG_PROMPTS:-false}
# CORS
- ALLOWED_ORIGINS=http://localhost:3002,https://macmini:3002,http://admin-v2:3000
extra_hosts:
- "host.docker.internal:host-gateway"
depends_on:
postgres:
condition: service_healthy
networks:
- breakpilot-pwa-network
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8090/health"]
interval: 30s
timeout: 3s
start_period: 10s
retries: 3
restart: unless-stopped
# DSMS Node - Dezentrales Speichersystem (Private IPFS)
dsms-node:
build:
context: ./dsms-node
dockerfile: Dockerfile
container_name: breakpilot-pwa-dsms-node
ports:
- "4001:4001" # Swarm P2P
- "5001:5001" # IPFS API
- "8085:8080" # IPFS Gateway (8085 um Konflikt mit Backend zu vermeiden)
volumes:
- dsms_data:/data/ipfs
environment:
- IPFS_PROFILE=server
networks:
- breakpilot-pwa-network
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "ipfs id > /dev/null 2>&1 || exit 1"]
interval: 30s
timeout: 10s
start_period: 30s
retries: 3
# DSMS Gateway - REST API für DSMS
dsms-gateway:
build:
context: ./dsms-gateway
dockerfile: Dockerfile
container_name: breakpilot-pwa-dsms-gateway
ports:
- "8082:8082"
environment:
- IPFS_API_URL=http://dsms-node:5001
- IPFS_GATEWAY_URL=http://dsms-node:8080
- JWT_SECRET=${JWT_SECRET:-your-super-secret-jwt-key-change-in-production}
depends_on:
dsms-node:
condition: service_healthy
networks:
- breakpilot-pwa-network
restart: unless-stopped
# ============================================
# Jitsi Meet - Videokonferenzen für Schulungen
# Web UI: http://localhost:8443
# ============================================
# Jitsi Web Frontend
jitsi-web:
image: jitsi/web:stable-9823
container_name: breakpilot-pwa-jitsi-web
expose:
- "80"
environment:
- ENABLE_XMPP_WEBSOCKET=1
- ENABLE_COLIBRI_WEBSOCKET=1
- XMPP_DOMAIN=meet.jitsi
- XMPP_BOSH_URL_BASE=http://jitsi-xmpp:5280
- XMPP_MUC_DOMAIN=muc.meet.jitsi
- XMPP_GUEST_DOMAIN=guest.meet.jitsi
- TZ=Europe/Berlin
- PUBLIC_URL=${JITSI_PUBLIC_URL:-https://macmini}
- JICOFO_AUTH_USER=focus
- ENABLE_AUTH=${JITSI_ENABLE_AUTH:-0}
- ENABLE_GUESTS=${JITSI_ENABLE_GUESTS:-1}
- ENABLE_RECORDING=${JITSI_ENABLE_RECORDING:-1}
- ENABLE_LIVESTREAMING=0
- DISABLE_HTTPS=1
# Branding
- APP_NAME=BreakPilot Meet
- NATIVE_APP_NAME=BreakPilot Meet
- PROVIDER_NAME=BreakPilot
volumes:
- jitsi_web_config:/config
- jitsi_web_crontabs:/var/spool/cron/crontabs
- jitsi_transcripts:/usr/share/jitsi-meet/transcripts
networks:
breakpilot-pwa-network:
aliases:
- meet.jitsi
restart: unless-stopped
depends_on:
- jitsi-xmpp
# Prosody XMPP Server
jitsi-xmpp:
image: jitsi/prosody:stable-9823
container_name: breakpilot-pwa-jitsi-xmpp
environment:
- XMPP_DOMAIN=meet.jitsi
- XMPP_AUTH_DOMAIN=auth.meet.jitsi
- XMPP_MUC_DOMAIN=muc.meet.jitsi
- XMPP_INTERNAL_MUC_DOMAIN=internal-muc.meet.jitsi
- XMPP_GUEST_DOMAIN=guest.meet.jitsi
- XMPP_RECORDER_DOMAIN=recorder.meet.jitsi
- XMPP_CROSS_DOMAIN=true
- TZ=Europe/Berlin
- JICOFO_AUTH_USER=focus
- JICOFO_AUTH_PASSWORD=${JITSI_JICOFO_AUTH_PASSWORD:-jicofo_secret_123}
- JVB_AUTH_USER=jvb
- JVB_AUTH_PASSWORD=${JITSI_JVB_AUTH_PASSWORD:-jvb_secret_123}
- JIGASI_XMPP_USER=jigasi
- JIGASI_XMPP_PASSWORD=${JITSI_JIGASI_XMPP_PASSWORD:-jigasi_secret_123}
- JIBRI_XMPP_USER=jibri
- JIBRI_XMPP_PASSWORD=${JITSI_JIBRI_XMPP_PASSWORD:-jibri_secret_123}
- JIBRI_RECORDER_USER=recorder
- JIBRI_RECORDER_PASSWORD=${JITSI_JIBRI_RECORDER_PASSWORD:-recorder_secret_123}
- LOG_LEVEL=info
- PUBLIC_URL=${JITSI_PUBLIC_URL:-https://macmini}
- ENABLE_AUTH=${JITSI_ENABLE_AUTH:-0}
- ENABLE_GUESTS=${JITSI_ENABLE_GUESTS:-1}
volumes:
- jitsi_prosody_config:/config
- jitsi_prosody_plugins:/prosody-plugins-custom
networks:
breakpilot-pwa-network:
aliases:
- xmpp.meet.jitsi
restart: unless-stopped
# Jicofo - Jitsi Conference Focus
jitsi-jicofo:
image: jitsi/jicofo:stable-9823
container_name: breakpilot-pwa-jitsi-jicofo
environment:
- XMPP_DOMAIN=meet.jitsi
- XMPP_AUTH_DOMAIN=auth.meet.jitsi
- XMPP_MUC_DOMAIN=muc.meet.jitsi
- XMPP_INTERNAL_MUC_DOMAIN=internal-muc.meet.jitsi
- XMPP_SERVER=jitsi-xmpp
- JICOFO_AUTH_USER=focus
- JICOFO_AUTH_PASSWORD=${JITSI_JICOFO_AUTH_PASSWORD:-jicofo_secret_123}
- TZ=Europe/Berlin
- ENABLE_AUTH=${JITSI_ENABLE_AUTH:-0}
- AUTH_TYPE=internal
- ENABLE_AUTO_OWNER=${JITSI_ENABLE_AUTO_OWNER:-1}
volumes:
- jitsi_jicofo_config:/config
networks:
- breakpilot-pwa-network
restart: unless-stopped
depends_on:
- jitsi-xmpp
# JVB - Jitsi Videobridge (WebRTC SFU)
jitsi-jvb:
image: jitsi/jvb:stable-9823
container_name: breakpilot-pwa-jitsi-jvb
ports:
- "10000:10000/udp" # Video/Audio RTP
- "8080:8080" # Colibri REST API (internal)
environment:
- XMPP_DOMAIN=meet.jitsi
- XMPP_AUTH_DOMAIN=auth.meet.jitsi
- XMPP_INTERNAL_MUC_DOMAIN=internal-muc.meet.jitsi
- XMPP_SERVER=jitsi-xmpp
- JVB_AUTH_USER=jvb
- JVB_AUTH_PASSWORD=${JITSI_JVB_AUTH_PASSWORD:-jvb_secret_123}
- JVB_PORT=10000
- JVB_STUN_SERVERS=meet-jit-si-turnrelay.jitsi.net:443
- TZ=Europe/Berlin
- PUBLIC_URL=${JITSI_PUBLIC_URL:-https://macmini}
- COLIBRI_REST_ENABLED=true
- ENABLE_COLIBRI_WEBSOCKET=1
volumes:
- jitsi_jvb_config:/config
networks:
- breakpilot-pwa-network
restart: unless-stopped
depends_on:
- jitsi-xmpp
# ============================================
# Jibri - Jitsi Recording Service
# Recordings werden zu MinIO hochgeladen
# ============================================
jibri:
build:
context: ./docker/jibri
dockerfile: Dockerfile
container_name: breakpilot-pwa-jibri
environment:
- XMPP_DOMAIN=meet.jitsi
- XMPP_AUTH_DOMAIN=auth.meet.jitsi
- XMPP_INTERNAL_MUC_DOMAIN=internal-muc.meet.jitsi
- XMPP_RECORDER_DOMAIN=recorder.meet.jitsi
- XMPP_SERVER=jitsi-xmpp
- XMPP_MUC_DOMAIN=muc.meet.jitsi
- JIBRI_XMPP_USER=jibri
- JIBRI_XMPP_PASSWORD=${JITSI_JIBRI_XMPP_PASSWORD:-jibri_secret_123}
- JIBRI_RECORDER_USER=recorder
- JIBRI_RECORDER_PASSWORD=${JITSI_JIBRI_RECORDER_PASSWORD:-recorder_secret_123}
- JIBRI_BREWERY_MUC=jibribrewery
- JIBRI_RECORDING_DIR=/recordings
- JIBRI_FINALIZE_SCRIPT=/config/finalize.sh
- TZ=Europe/Berlin
# X11 Display Konfiguration (Xvfb)
- DISPLAY=:0
- RESOLUTION=1920x1080x24
# Optional: VNC fuer Debugging (Port 5900)
# - VNC_PASSWORD=debug123
# MinIO Upload Konfiguration
- MINIO_ENDPOINT=minio:9000
- MINIO_ACCESS_KEY=${MINIO_ROOT_USER}
- MINIO_SECRET_KEY=${MINIO_ROOT_PASSWORD}
- MINIO_BUCKET=breakpilot-recordings
# Backend Webhook (wird nach Upload aufgerufen)
- BACKEND_WEBHOOK_URL=http://backend:8000/api/recordings/webhook
volumes:
- jibri_recordings:/recordings
- /dev/shm:/dev/shm
shm_size: '2gb'
cap_add:
- SYS_ADMIN
- NET_BIND_SERVICE
networks:
- breakpilot-pwa-network
restart: unless-stopped
depends_on:
- jitsi-xmpp
- minio
profiles:
- recording
# ============================================
# Transcription Worker - Whisper + pyannote
# Verarbeitet Recordings asynchron
# ============================================
transcription-worker:
build:
context: ./backend
dockerfile: Dockerfile.worker
container_name: breakpilot-pwa-transcription-worker
environment:
- DATABASE_URL=postgres://breakpilot:breakpilot123@postgres:5432/breakpilot_db?sslmode=disable
- REDIS_URL=redis://valkey:6379/1
- WHISPER_MODEL=${WHISPER_MODEL:-large-v3}
- WHISPER_DEVICE=${WHISPER_DEVICE:-cpu}
- WHISPER_COMPUTE_TYPE=${WHISPER_COMPUTE_TYPE:-int8}
# pyannote.audio Token (HuggingFace)
- PYANNOTE_AUTH_TOKEN=${PYANNOTE_AUTH_TOKEN:-}
# MinIO Storage
- MINIO_ENDPOINT=${MINIO_ENDPOINT:-minio:9000}
- MINIO_ACCESS_KEY=${MINIO_ROOT_USER:-breakpilot}
- MINIO_SECRET_KEY=${MINIO_ROOT_PASSWORD:-breakpilot123}
- MINIO_BUCKET=breakpilot-recordings
- MINIO_SECURE=false
- TZ=Europe/Berlin
volumes:
- transcription_models:/root/.cache/huggingface
- transcription_temp:/tmp/transcriptions
deploy:
resources:
limits:
memory: 8G
reservations:
memory: 4G
networks:
- breakpilot-pwa-network
restart: unless-stopped
depends_on:
postgres:
condition: service_healthy
valkey:
condition: service_healthy
minio:
condition: service_started
profiles:
- recording
# ============================================
# Camunda 7 - BPMN Workflow Engine
# Web UI: http://localhost:8089/camunda
# REST API: http://localhost:8089/engine-rest
# License: Apache 2.0 (kommerziell nutzbar)
# ============================================
camunda:
image: camunda/camunda-bpm-platform:7.21.0
container_name: breakpilot-pwa-camunda
ports:
- "8089:8080"
environment:
- DB_DRIVER=org.postgresql.Driver
- DB_URL=jdbc:postgresql://postgres:5432/breakpilot_db
- DB_USERNAME=breakpilot
- DB_PASSWORD=${POSTGRES_PASSWORD:-breakpilot123}
- DB_VALIDATE_ON_BORROW=true
- WAIT_FOR=postgres:5432
- CAMUNDA_BPM_ADMIN_USER_ID=admin
- CAMUNDA_BPM_ADMIN_USER_PASSWORD=${CAMUNDA_ADMIN_PASSWORD:-admin123}
depends_on:
postgres:
condition: service_healthy
networks:
- breakpilot-pwa-network
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:8080/camunda/api/engine || exit 1"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s
restart: unless-stopped
profiles:
- bpmn
# ============================================
# GeoEdu Service - Self-Hosted OSM + Terrain
# DSGVO-konforme Erdkunde-Lernplattform
# Web UI: http://localhost:8088
# ============================================
geo-service:
build:
context: ./geo-service
dockerfile: Dockerfile
platform: linux/arm64 # Mac Mini Apple Silicon
container_name: breakpilot-pwa-geo-service
ports:
- "8088:8088"
environment:
- PORT=8088
- ENVIRONMENT=${ENVIRONMENT:-development}
- JWT_SECRET=${JWT_SECRET:-your-super-secret-jwt-key}
# PostgreSQL (PostGIS fuer OSM-Daten)
- DATABASE_URL=postgresql+asyncpg://breakpilot:breakpilot123@postgres:5432/breakpilot_db
# MinIO (AOI Bundles, generierte Assets)
- MINIO_ENDPOINT=minio:9000
- MINIO_ACCESS_KEY=${MINIO_ROOT_USER:-breakpilot}
- MINIO_SECRET_KEY=${MINIO_ROOT_PASSWORD:-breakpilot123}
- MINIO_BUCKET=breakpilot-geo
- MINIO_SECURE=false
# Ollama (Lernstationen generieren)
- OLLAMA_BASE_URL=${OLLAMA_BASE_URL:-http://host.docker.internal:11434}
- OLLAMA_MODEL=${OLLAMA_DEFAULT_MODEL:-qwen2.5:14b}
# Tile Server Config
- TILE_CACHE_DIR=/app/cache/tiles
- DEM_CACHE_DIR=/app/cache/dem
- MAX_AOI_SIZE_KM2=4
volumes:
- geo_osm_data:/app/data/osm
- geo_dem_data:/app/data/dem
- geo_tile_cache:/app/cache/tiles
- geo_aoi_bundles:/app/bundles
extra_hosts:
- "host.docker.internal:host-gateway"
depends_on:
postgres:
condition: service_healthy
minio:
condition: service_started
networks:
- breakpilot-pwa-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8088/health"]
interval: 30s
timeout: 10s
start_period: 60s
retries: 3
restart: unless-stopped
# ============================================
# Voice Service - PersonaPlex + TaskOrchestrator
# Voice-First Interface fuer Breakpilot
# DSGVO-konform: Keine Audio-Persistenz
# Web UI: http://localhost:8091
# ============================================
voice-service:
build:
context: ./voice-service
dockerfile: Dockerfile
platform: linux/arm64 # Mac Mini Apple Silicon
container_name: breakpilot-pwa-voice-service
# Port 8091 wird von nginx HTTPS bereitgestellt (wss://macmini:8091)
expose:
- "8091"
environment:
- PORT=8091
- DATABASE_URL=postgresql+asyncpg://breakpilot:breakpilot123@postgres:5432/breakpilot_db
- VALKEY_URL=redis://valkey:6379/2
- PERSONAPLEX_ENABLED=${PERSONAPLEX_ENABLED:-false}
- PERSONAPLEX_WS_URL=${PERSONAPLEX_WS_URL:-ws://host.docker.internal:8998}
- ORCHESTRATOR_ENABLED=true
- FALLBACK_LLM_PROVIDER=${FALLBACK_LLM_PROVIDER:-ollama}
- OLLAMA_BASE_URL=http://host.docker.internal:11434
- OLLAMA_VOICE_MODEL=qwen2.5:32b
- BQAS_JUDGE_MODEL=qwen2.5:14b
- KLAUSUR_SERVICE_URL=http://klausur-service:8086
- ENCRYPTION_ENABLED=true
- AUDIO_PERSISTENCE=false
- AUDIO_SAMPLE_RATE=24000
- ENVIRONMENT=${ENVIRONMENT:-development}
- JWT_SECRET=${JWT_SECRET:-your-super-secret-jwt-key-change-in-production}
volumes:
- voice_session_data:/app/data/sessions
extra_hosts:
- "host.docker.internal:host-gateway"
depends_on:
postgres:
condition: service_healthy
valkey:
condition: service_healthy
networks:
- breakpilot-pwa-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8091/health"]
interval: 30s
timeout: 10s
start_period: 60s
retries: 3
restart: unless-stopped
# ============================================
# MkDocs Documentation
# Web UI: http://localhost:8009
# Material Theme with German language support
# ============================================
docs:
build:
context: .
dockerfile: docs-src/Dockerfile
platform: linux/arm64 # Mac Mini Apple Silicon
container_name: breakpilot-pwa-docs
ports:
- "8009:80"
networks:
- breakpilot-pwa-network
restart: unless-stopped
healthcheck:
test: ["CMD", "wget", "-q", "--spider", "http://127.0.0.1:80/"]
interval: 30s
timeout: 10s
retries: 3
volumes:
breakpilot_pwa_data:
# Embedding Service Model Cache
embedding_models:
# Valkey Session Cache
valkey_data:
dsms_data:
klausur_uploads:
eh_uploads:
ocr_labeling:
# PaddleOCR Model Cache (persist across container restarts)
paddle_models:
# PaddleOCR Service Model Cache (x86_64 emulation)
paddleocr_models:
qdrant_data:
# Jitsi Volumes
jitsi_web_config:
jitsi_web_crontabs:
jitsi_transcripts:
jitsi_prosody_config:
jitsi_prosody_plugins:
jitsi_jicofo_config:
jitsi_jvb_config:
# Jibri Recording Volumes
jibri_recordings:
# Transcription Worker Volumes
transcription_models:
transcription_temp:
# GeoEdu Service Volumes
geo_osm_data:
geo_dem_data:
geo_tile_cache:
geo_aoi_bundles:
# Voice Service Volumes (transient sessions only)
voice_session_data:
networks:
breakpilot-pwa-network:
driver: bridge