services: # ============================================ # Nginx HTTPS Reverse Proxy # Enables secure context for microphone/crypto # Access via HTTPS on same ports as HTTP was before # ============================================ nginx: image: nginx:alpine container_name: breakpilot-pwa-nginx ports: - "443:443" # HTTPS Studio v2 (https://macmini/) - "80:80" # HTTP -> HTTPS redirect - "3000:3000" # HTTPS Admin Website (https://macmini:3000/) - "3002:3002" # HTTPS Admin v2 (https://macmini:3002/) - "8091:8091" # HTTPS Voice Service (wss://macmini:8091/) - "8000:8000" # HTTPS Backend API - "8086:8086" # HTTPS Klausur Service - "8089:8089" # HTTPS Edu-Search proxy (edu-search runs on 8088) - "8093:8093" # HTTPS AI Compliance SDK - "8443:8443" # HTTPS Jitsi Meet (https://macmini:8443/) volumes: - ./nginx/conf.d:/etc/nginx/conf.d:ro - vault_certs:/etc/nginx/certs:ro depends_on: vault-agent: condition: service_started studio-v2: condition: service_started voice-service: condition: service_started backend: condition: service_started klausur-service: condition: service_started website: condition: service_started ai-compliance-sdk: condition: service_started admin-v2: condition: service_started jitsi-web: condition: service_started extra_hosts: - "breakpilot-edu-search:host-gateway" networks: - breakpilot-pwa-network restart: unless-stopped # ============================================ # HashiCorp Vault - Secrets Management # Web UI: http://localhost:8200/ui # ============================================ vault: image: hashicorp/vault:1.15 container_name: breakpilot-pwa-vault cap_add: - IPC_LOCK ports: - "8200:8200" environment: - VAULT_DEV_ROOT_TOKEN_ID=${VAULT_DEV_TOKEN:-breakpilot-dev-token} - VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200 - VAULT_ADDR=http://127.0.0.1:8200 volumes: - vault_data:/vault/data healthcheck: test: ["CMD", "vault", "status"] interval: 10s timeout: 5s retries: 3 start_period: 5s networks: - breakpilot-pwa-network restart: unless-stopped # Vault PKI Initialization - runs once to set up PKI and issue initial certs vault-init: image: hashicorp/vault:1.15 container_name: breakpilot-pwa-vault-init environment: - VAULT_ADDR=http://vault:8200 - VAULT_TOKEN=${VAULT_DEV_TOKEN:-breakpilot-dev-token} volumes: - ./vault/init-pki.sh:/init-pki.sh:ro - vault_agent_config:/vault/agent/data - vault_certs:/vault/certs entrypoint: ["/bin/sh", "-c"] command: - | echo "Waiting for Vault to be ready..." until vault status > /dev/null 2>&1; do sleep 1; done echo "Vault is ready. Running PKI initialization..." chmod +x /init-pki.sh /init-pki.sh echo "PKI initialization complete. Exiting." depends_on: vault: condition: service_healthy networks: - breakpilot-pwa-network restart: "no" # Vault Agent - manages certificate renewal for nginx vault-agent: image: hashicorp/vault:1.15 container_name: breakpilot-pwa-vault-agent environment: - VAULT_ADDR=http://vault:8200 volumes: - ./vault/agent/config.hcl:/vault/agent/config.hcl:ro - ./vault/agent/templates:/vault/agent/templates:ro - ./vault/agent/split-certs.sh:/vault/agent/split-certs.sh:ro - vault_agent_config:/vault/agent/data - vault_certs:/vault/certs entrypoint: ["vault", "agent", "-config=/vault/agent/config.hcl"] depends_on: vault: condition: service_healthy vault-init: condition: service_completed_successfully networks: - breakpilot-pwa-network restart: unless-stopped # 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 # Automatic Database Backup (runs daily at 2 AM) backup: image: postgres:16-alpine container_name: breakpilot-pwa-backup volumes: - ./backups:/backups - postgres_data:/var/lib/postgresql/data:ro environment: - PGHOST=postgres - PGUSER=breakpilot - PGPASSWORD=breakpilot123 - PGDATABASE=breakpilot_db entrypoint: ["/bin/sh", "-c"] command: - | echo "Backup service started. Running backup every day at 2 AM..." while true; do # Berechne Sekunden bis 2 Uhr current_hour=$$(date +%H) current_min=$$(date +%M) current_sec=$$(date +%S) if [ $$current_hour -lt 2 ]; then sleep_hours=$$((2 - current_hour - 1)) else sleep_hours=$$((26 - current_hour - 1)) fi sleep_mins=$$((60 - current_min - 1)) sleep_secs=$$((60 - current_sec)) total_sleep=$$((sleep_hours * 3600 + sleep_mins * 60 + sleep_secs)) echo "Next backup in $$total_sleep seconds (at 2:00 AM)" sleep $$total_sleep # Backup erstellen TIMESTAMP=$$(date +"%Y%m%d_%H%M%S") BACKUP_FILE="/backups/breakpilot_$${TIMESTAMP}.sql.gz" echo "Creating backup: $$BACKUP_FILE" pg_dump | gzip > "$$BACKUP_FILE" if [ $$? -eq 0 ]; then echo "✓ Backup completed: $$BACKUP_FILE" # Alte Backups löschen (älter als 30 Tage) find /backups -name "breakpilot_*.sql.gz" -mtime +30 -delete echo "✓ Old backups cleaned up" else echo "✗ Backup failed!" fi done depends_on: postgres: condition: service_healthy networks: - breakpilot-pwa-network restart: unless-stopped profiles: - backup # 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 # Matrix Synapse - Schulkommunikation (E2EE Messenger) # Admin: http://localhost:8008/_synapse/admin synapse: image: matrixdotorg/synapse:latest container_name: breakpilot-pwa-synapse ports: - "8008:8008" # Client-Server API - "8448:8448" # Federation (optional für später) volumes: - synapse_data:/data environment: - SYNAPSE_SERVER_NAME=${MATRIX_SERVER_NAME:-breakpilot.local} - SYNAPSE_REPORT_STATS=no - SYNAPSE_NO_TLS=1 - SYNAPSE_ENABLE_REGISTRATION=no - SYNAPSE_LOG_LEVEL=INFO - UID=1000 - GID=1000 healthcheck: test: ["CMD-SHELL", "curl -fSs http://localhost:8008/health || exit 1"] interval: 30s timeout: 10s retries: 3 start_period: 30s networks: - breakpilot-pwa-network restart: unless-stopped # PostgreSQL für Matrix Synapse (separate DB) synapse-db: image: postgres:16-alpine container_name: breakpilot-pwa-synapse-db environment: POSTGRES_USER: synapse POSTGRES_PASSWORD: ${SYNAPSE_DB_PASSWORD:-synapse_secret_123} POSTGRES_DB: synapse POSTGRES_INITDB_ARGS: "--encoding=UTF8 --lc-collate=C --lc-ctype=C" volumes: - synapse_db_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U synapse -d synapse"] interval: 5s timeout: 5s retries: 5 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/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 # ============================================ # ERPNext - Open Source ERP System # Web UI: http://localhost:8090 # Default: Administrator / admin # ============================================ # MariaDB for ERPNext erpnext-db: image: mariadb:10.6 container_name: breakpilot-pwa-erpnext-db command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --skip-character-set-client-handshake --skip-innodb-read-only-compressed environment: - MYSQL_ROOT_PASSWORD=${ERPNEXT_DB_ROOT_PASSWORD:-changeit123} - MYSQL_DATABASE=erpnext - MYSQL_USER=erpnext - MYSQL_PASSWORD=${ERPNEXT_DB_PASSWORD:-erpnext123} volumes: - erpnext_db_data:/var/lib/mysql networks: - breakpilot-pwa-network restart: unless-stopped healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${ERPNEXT_DB_ROOT_PASSWORD:-changeit123}"] interval: 5s timeout: 5s retries: 10 # Redis Queue for ERPNext erpnext-redis-queue: image: redis:alpine container_name: breakpilot-pwa-erpnext-redis-queue volumes: - erpnext_redis_queue_data:/data networks: - breakpilot-pwa-network restart: unless-stopped # Redis Cache for ERPNext erpnext-redis-cache: image: redis:alpine container_name: breakpilot-pwa-erpnext-redis-cache volumes: - erpnext_redis_cache_data:/data networks: - breakpilot-pwa-network restart: unless-stopped # ERPNext Site Creator (runs once) erpnext-create-site: image: frappe/erpnext:latest container_name: breakpilot-pwa-erpnext-create-site command: - bash - -c - | wait-for-it -t 120 erpnext-db:3306; wait-for-it -t 120 erpnext-redis-cache:6379; wait-for-it -t 120 erpnext-redis-queue:6379; if [[ ! -f sites/erpnext.local/site_config.json ]]; then echo "Creating ERPNext site..."; bench new-site erpnext.local --db-host=erpnext-db --db-port=3306 --admin-password=admin --db-root-password=${ERPNEXT_DB_ROOT_PASSWORD:-changeit123} --install-app erpnext --set-default; echo "Site created successfully!"; else echo "Site already exists, skipping creation."; fi; environment: - DB_HOST=erpnext-db - DB_PORT=3306 - REDIS_CACHE=redis://erpnext-redis-cache:6379 - REDIS_QUEUE=redis://erpnext-redis-queue:6379 - SOCKETIO_PORT=9000 volumes: - erpnext_sites:/home/frappe/frappe-bench/sites - erpnext_logs:/home/frappe/frappe-bench/logs networks: - breakpilot-pwa-network depends_on: erpnext-db: condition: service_healthy erpnext-redis-cache: condition: service_started erpnext-redis-queue: condition: service_started # ERPNext Backend erpnext-backend: image: frappe/erpnext:latest container_name: breakpilot-pwa-erpnext-backend command: - bash - -c - | wait-for-it -t 120 erpnext-db:3306; wait-for-it -t 120 erpnext-redis-cache:6379; wait-for-it -t 120 erpnext-redis-queue:6379; bench serve --port 8000 environment: - DB_HOST=erpnext-db - DB_PORT=3306 - REDIS_CACHE=redis://erpnext-redis-cache:6379 - REDIS_QUEUE=redis://erpnext-redis-queue:6379 - SOCKETIO_PORT=9000 volumes: - erpnext_sites:/home/frappe/frappe-bench/sites - erpnext_logs:/home/frappe/frappe-bench/logs networks: - breakpilot-pwa-network restart: unless-stopped depends_on: erpnext-db: condition: service_healthy erpnext-create-site: condition: service_completed_successfully # ERPNext WebSocket erpnext-websocket: image: frappe/erpnext:latest container_name: breakpilot-pwa-erpnext-websocket command: - bash - -c - | wait-for-it -t 120 erpnext-db:3306; wait-for-it -t 120 erpnext-redis-cache:6379; wait-for-it -t 120 erpnext-redis-queue:6379; bench watch environment: - DB_HOST=erpnext-db - DB_PORT=3306 - REDIS_CACHE=redis://erpnext-redis-cache:6379 - REDIS_QUEUE=redis://erpnext-redis-queue:6379 - SOCKETIO_PORT=9000 volumes: - erpnext_sites:/home/frappe/frappe-bench/sites - erpnext_logs:/home/frappe/frappe-bench/logs networks: - breakpilot-pwa-network restart: unless-stopped depends_on: erpnext-db: condition: service_healthy erpnext-create-site: condition: service_completed_successfully # ERPNext Scheduler erpnext-scheduler: image: frappe/erpnext:latest container_name: breakpilot-pwa-erpnext-scheduler command: - bash - -c - | wait-for-it -t 120 erpnext-db:3306; wait-for-it -t 120 erpnext-redis-cache:6379; wait-for-it -t 120 erpnext-redis-queue:6379; bench schedule environment: - DB_HOST=erpnext-db - DB_PORT=3306 - REDIS_CACHE=redis://erpnext-redis-cache:6379 - REDIS_QUEUE=redis://erpnext-redis-queue:6379 - SOCKETIO_PORT=9000 volumes: - erpnext_sites:/home/frappe/frappe-bench/sites - erpnext_logs:/home/frappe/frappe-bench/logs networks: - breakpilot-pwa-network restart: unless-stopped depends_on: erpnext-db: condition: service_healthy erpnext-create-site: condition: service_completed_successfully # ERPNext Worker (Long) erpnext-worker-long: image: frappe/erpnext:latest container_name: breakpilot-pwa-erpnext-worker-long command: - bash - -c - | wait-for-it -t 120 erpnext-db:3306; wait-for-it -t 120 erpnext-redis-cache:6379; wait-for-it -t 120 erpnext-redis-queue:6379; bench worker --queue long,default,short environment: - DB_HOST=erpnext-db - DB_PORT=3306 - REDIS_CACHE=redis://erpnext-redis-cache:6379 - REDIS_QUEUE=redis://erpnext-redis-queue:6379 - SOCKETIO_PORT=9000 volumes: - erpnext_sites:/home/frappe/frappe-bench/sites - erpnext_logs:/home/frappe/frappe-bench/logs networks: - breakpilot-pwa-network restart: unless-stopped depends_on: erpnext-db: condition: service_healthy erpnext-create-site: condition: service_completed_successfully # ERPNext Worker (Short) erpnext-worker-short: image: frappe/erpnext:latest container_name: breakpilot-pwa-erpnext-worker-short command: - bash - -c - | wait-for-it -t 120 erpnext-db:3306; wait-for-it -t 120 erpnext-redis-cache:6379; wait-for-it -t 120 erpnext-redis-queue:6379; bench worker --queue short,default environment: - DB_HOST=erpnext-db - DB_PORT=3306 - REDIS_CACHE=redis://erpnext-redis-cache:6379 - REDIS_QUEUE=redis://erpnext-redis-queue:6379 - SOCKETIO_PORT=9000 volumes: - erpnext_sites:/home/frappe/frappe-bench/sites - erpnext_logs:/home/frappe/frappe-bench/logs networks: - breakpilot-pwa-network restart: unless-stopped depends_on: erpnext-db: condition: service_healthy erpnext-create-site: condition: service_completed_successfully # ERPNext Frontend (Nginx) erpnext-frontend: image: frappe/erpnext:latest container_name: breakpilot-pwa-erpnext-frontend command: - nginx-entrypoint.sh ports: - "8090:8080" environment: - BACKEND=erpnext-backend:8000 - SOCKETIO=erpnext-websocket:9000 - UPSTREAM_REAL_IP_ADDRESS=127.0.0.1 - UPSTREAM_REAL_IP_HEADER=X-Forwarded-For - UPSTREAM_REAL_IP_RECURSIVE=off - FRAPPE_SITE_NAME_HEADER=erpnext.local volumes: - erpnext_sites:/home/frappe/frappe-bench/sites - erpnext_logs:/home/frappe/frappe-bench/logs networks: - breakpilot-pwa-network restart: unless-stopped depends_on: erpnext-backend: condition: service_started erpnext-websocket: condition: service_started # ============================================ # Breakpilot Drive - Lernspiel (Unity WebGL) # Web UI: http://localhost:3001 # ============================================ breakpilot-drive: build: context: ./breakpilot-drive dockerfile: Dockerfile container_name: breakpilot-pwa-drive ports: - "3001:80" environment: # API Configuration (injected into Unity WebGL) - API_BASE_URL=${GAME_API_URL:-http://localhost:8000/api/game} # Feature Flags - GAME_REQUIRE_AUTH=${GAME_REQUIRE_AUTH:-false} - GAME_ENABLE_LEADERBOARDS=${GAME_ENABLE_LEADERBOARDS:-true} networks: - breakpilot-pwa-network depends_on: - backend healthcheck: test: ["CMD", "wget", "-q", "--spider", "http://localhost:80/health.json"] interval: 30s timeout: 10s retries: 3 restart: unless-stopped profiles: - game # ============================================ # 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 # ============================================ # Gitea - Self-hosted Git Server # Web UI: http://localhost:3003 # SSH: localhost:2222 # Gitea Actions enabled for CI/CD # ============================================ gitea: image: gitea/gitea:1.22-rootless container_name: breakpilot-pwa-gitea extra_hosts: - "macmini:192.168.178.100" environment: - USER_UID=1000 - USER_GID=1000 - GITEA__database__DB_TYPE=postgres - GITEA__database__HOST=postgres:5432 - GITEA__database__NAME=gitea - GITEA__database__USER=breakpilot - GITEA__database__PASSWD=breakpilot123 - GITEA__server__DOMAIN=macmini - GITEA__server__SSH_DOMAIN=macmini - GITEA__server__ROOT_URL=http://macmini:3003/ - GITEA__server__HTTP_PORT=3003 - GITEA__server__SSH_PORT=2222 - GITEA__server__SSH_LISTEN_PORT=2222 - GITEA__actions__ENABLED=true - GITEA__actions__DEFAULT_ACTIONS_URL=https://gitea.com - GITEA__service__DISABLE_REGISTRATION=true - GITEA__service__REQUIRE_SIGNIN_VIEW=false - GITEA__repository__DEFAULT_BRANCH=main - GITEA__log__LEVEL=Info - GITEA__webhook__ALLOWED_HOST_LIST=macmini,192.168.178.100,woodpecker-server,localhost,external volumes: - gitea_data:/var/lib/gitea - gitea_config:/etc/gitea - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro ports: - "3003:3003" - "2222:2222" depends_on: postgres: condition: service_healthy networks: - breakpilot-pwa-network healthcheck: test: ["CMD", "curl", "-f", "http://localhost:3003/api/healthz"] interval: 30s timeout: 10s retries: 3 start_period: 30s restart: unless-stopped # ============================================ # Gitea Actions Runner # Executes CI/CD workflows defined in .gitea/workflows/ # Includes Syft, Grype, Trivy for SBOM generation # ============================================ gitea-runner: image: gitea/act_runner:latest container_name: breakpilot-pwa-gitea-runner environment: - CONFIG_FILE=/config/config.yaml - GITEA_INSTANCE_URL=http://gitea:3003 - GITEA_RUNNER_REGISTRATION_TOKEN=${GITEA_RUNNER_TOKEN:-} - GITEA_RUNNER_NAME=breakpilot-runner - GITEA_RUNNER_LABELS=ubuntu-latest:docker://node:20-bookworm,ubuntu-22.04:docker://ubuntu:22.04,self-hosted:host volumes: - gitea_runner_data:/data - ./gitea/runner-config.yaml:/config/config.yaml:ro - /var/run/docker.sock:/var/run/docker.sock depends_on: gitea: condition: service_healthy networks: - breakpilot-pwa-network restart: unless-stopped # ============================================ # Woodpecker CI - Server # Modern CI/CD with native container support # Web UI: http://localhost:8085 # ============================================ woodpecker-server: image: woodpeckerci/woodpecker-server:v3 container_name: breakpilot-pwa-woodpecker-server ports: - "8090:8000" extra_hosts: - "macmini:192.168.178.100" environment: - WOODPECKER_OPEN=true - WOODPECKER_HOST=http://macmini:8090 - WOODPECKER_ADMIN=pilotadmin,breakpilot_admin # Gitea OAuth Integration - WOODPECKER_GITEA=true - WOODPECKER_GITEA_URL=http://macmini:3003 - WOODPECKER_GITEA_CLIENT=${WOODPECKER_GITEA_CLIENT:-} - WOODPECKER_GITEA_SECRET=${WOODPECKER_GITEA_SECRET:-} # Agent Secret (fuer Agent-Authentifizierung) - WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET:-woodpecker-agent-secret-key} # Database (SQLite fuer einfache Einrichtung) - WOODPECKER_DATABASE_DRIVER=sqlite3 - WOODPECKER_DATABASE_DATASOURCE=/var/lib/woodpecker/woodpecker.sqlite # Logging - WOODPECKER_LOG_LEVEL=info # Trust all repos (allows privileged containers) - WOODPECKER_PLUGINS_PRIVILEGED=true - WOODPECKER_PLUGINS_TRUSTED_CLONE=true volumes: - woodpecker_data:/var/lib/woodpecker depends_on: gitea: condition: service_healthy networks: - breakpilot-pwa-network restart: unless-stopped # ============================================ # Night Scheduler - Nachtabschaltung # Stoppt Services nachts, startet sie morgens # API: http://localhost:8096 # ============================================ night-scheduler: build: ./night-scheduler container_name: breakpilot-pwa-night-scheduler volumes: - /var/run/docker.sock:/var/run/docker.sock - ./night-scheduler/config:/config - ./docker-compose.yml:/app/docker-compose.yml:ro environment: - COMPOSE_PROJECT_NAME=breakpilot-pwa ports: - "8096:8096" networks: - breakpilot-pwa-network restart: unless-stopped healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8096/health"] interval: 30s timeout: 10s retries: 3 start_period: 10s # ============================================ # Woodpecker CI - Agent # Executes pipeline steps in containers # ============================================ woodpecker-agent: image: woodpeckerci/woodpecker-agent:v3 container_name: breakpilot-pwa-woodpecker-agent command: agent environment: - WOODPECKER_SERVER=woodpecker-server:9000 - WOODPECKER_AGENT_SECRET=${WOODPECKER_AGENT_SECRET:-woodpecker-agent-secret-key} - WOODPECKER_MAX_WORKFLOWS=4 - WOODPECKER_LOG_LEVEL=info # Backend für Container-Ausführung - WOODPECKER_BACKEND=docker - DOCKER_HOST=unix:///var/run/docker.sock # Extra hosts für Pipeline-Container (damit sie macmini erreichen) - WOODPECKER_BACKEND_DOCKER_EXTRA_HOSTS=macmini:192.168.178.100,gitea:192.168.178.100 # Nutze das gleiche Netzwerk für Pipeline-Container - WOODPECKER_BACKEND_DOCKER_NETWORK=breakpilot-dev_breakpilot-pwa-network # Docker-Socket für Build-Steps (Host-Docker statt DinD) - WOODPECKER_BACKEND_DOCKER_VOLUMES=/var/run/docker.sock:/var/run/docker.sock volumes: - /var/run/docker.sock:/var/run/docker.sock depends_on: - woodpecker-server networks: - breakpilot-pwa-network restart: unless-stopped volumes: # Woodpecker CI Data woodpecker_data: driver: local # Vault Data vault_data: driver: local # Vault Agent Config (role-id, secret-id, token) vault_agent_config: driver: local # Vault-managed SSL Certificates vault_certs: driver: local breakpilot_pwa_data: driver: local # Embedding Service Model Cache embedding_models: driver: local # Valkey Session Cache valkey_data: driver: local dsms_data: driver: local klausur_uploads: driver: local eh_uploads: driver: local ocr_labeling: driver: local # PaddleOCR Model Cache (persist across container restarts) paddle_models: driver: local # PaddleOCR Service Model Cache (x86_64 emulation) paddleocr_models: driver: local qdrant_data: driver: local minio_data: driver: local synapse_data: driver: local synapse_db_data: driver: local # Jitsi Volumes jitsi_web_config: driver: local jitsi_web_crontabs: driver: local jitsi_transcripts: driver: local jitsi_prosody_config: driver: local jitsi_prosody_plugins: driver: local jitsi_jicofo_config: driver: local jitsi_jvb_config: driver: local # Jibri Recording Volumes jibri_recordings: driver: local # Transcription Worker Volumes transcription_models: driver: local transcription_temp: driver: local # ERPNext Volumes erpnext_db_data: driver: local erpnext_redis_queue_data: driver: local erpnext_redis_cache_data: driver: local erpnext_sites: driver: local erpnext_logs: driver: local # GeoEdu Service Volumes geo_osm_data: driver: local geo_dem_data: driver: local geo_tile_cache: driver: local geo_aoi_bundles: driver: local # Voice Service Volumes (transient sessions only) voice_session_data: driver: local # Gitea Volumes gitea_data: driver: local gitea_config: driver: local gitea_runner_data: driver: local networks: breakpilot-pwa-network: driver: bridge