Initial commit: breakpilot-core - Shared Infrastructure
Docker Compose with 24+ services: - PostgreSQL (PostGIS), Valkey, MinIO, Qdrant - Vault (PKI/TLS), Nginx (Reverse Proxy) - Backend Core API, Consent Service, Billing Service - RAG Service, Embedding Service - Gitea, Woodpecker CI/CD - Night Scheduler, Health Aggregator - Jitsi (Web/XMPP/JVB/Jicofo), Mailpit Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
13
scripts/Dockerfile.health
Normal file
13
scripts/Dockerfile.health
Normal file
@@ -0,0 +1,13 @@
|
||||
FROM python:3.11-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN pip install --no-cache-dir fastapi uvicorn httpx
|
||||
|
||||
COPY health_aggregator.py .
|
||||
|
||||
ENV PORT=8099
|
||||
|
||||
EXPOSE ${PORT}
|
||||
|
||||
CMD ["sh", "-c", "uvicorn health_aggregator:app --host 0.0.0.0 --port ${PORT}"]
|
||||
91
scripts/health-check.sh
Normal file
91
scripts/health-check.sh
Normal file
@@ -0,0 +1,91 @@
|
||||
#!/bin/bash
|
||||
# =========================================================
|
||||
# BreakPilot — Health Check for All Projects
|
||||
# =========================================================
|
||||
|
||||
GREEN='\033[0;32m'
|
||||
RED='\033[0;31m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
check_service() {
|
||||
local name=$1
|
||||
local url=$2
|
||||
local timeout=${3:-5}
|
||||
|
||||
if curl -sf --max-time $timeout "$url" > /dev/null 2>&1; then
|
||||
echo -e " ${GREEN}✓${NC} $name"
|
||||
return 0
|
||||
else
|
||||
echo -e " ${RED}✗${NC} $name ($url)"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
echo "========================================="
|
||||
echo " BreakPilot Health Check"
|
||||
echo "========================================="
|
||||
|
||||
TOTAL=0
|
||||
OK=0
|
||||
|
||||
echo ""
|
||||
echo "CORE Infrastructure:"
|
||||
for svc in \
|
||||
"Health Aggregator|http://127.0.0.1:8099/health" \
|
||||
"PostgreSQL|http://127.0.0.1:8099/health" \
|
||||
"Backend Core|http://127.0.0.1:8000/health|10" \
|
||||
"Embedding Service|http://127.0.0.1:8087/health|10" \
|
||||
"RAG Service|http://127.0.0.1:8097/health|10" \
|
||||
"Consent Service|http://127.0.0.1:8081/health|5" \
|
||||
"Gitea|http://127.0.0.1:3003/api/healthz" \
|
||||
"Mailpit|http://127.0.0.1:8025/" \
|
||||
; do
|
||||
IFS='|' read -r name url timeout <<< "$svc"
|
||||
TOTAL=$((TOTAL + 1))
|
||||
if check_service "$name" "$url" "$timeout"; then
|
||||
OK=$((OK + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "LEHRER Platform:"
|
||||
for svc in \
|
||||
"Studio v2|https://127.0.0.1/|5" \
|
||||
"Admin Lehrer|https://127.0.0.1:3002/|5" \
|
||||
"Backend Lehrer|https://127.0.0.1:8001/health|10" \
|
||||
"Klausur Service|https://127.0.0.1:8086/health|10" \
|
||||
"Voice Service|https://127.0.0.1:8091/health|5" \
|
||||
"Website|https://127.0.0.1:3000/|5" \
|
||||
; do
|
||||
IFS='|' read -r name url timeout <<< "$svc"
|
||||
TOTAL=$((TOTAL + 1))
|
||||
if check_service "$name" "$url" "$timeout"; then
|
||||
OK=$((OK + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "COMPLIANCE Platform:"
|
||||
for svc in \
|
||||
"Admin Compliance|https://127.0.0.1:3007/|5" \
|
||||
"Backend Compliance|https://127.0.0.1:8002/health|10" \
|
||||
"AI Compliance SDK|https://127.0.0.1:8093/health|10" \
|
||||
"Developer Portal|https://127.0.0.1:3006/|5" \
|
||||
; do
|
||||
IFS='|' read -r name url timeout <<< "$svc"
|
||||
TOTAL=$((TOTAL + 1))
|
||||
if check_service "$name" "$url" "$timeout"; then
|
||||
OK=$((OK + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "========================================="
|
||||
echo -e " Result: ${OK}/${TOTAL} services healthy"
|
||||
if [ $OK -eq $TOTAL ]; then
|
||||
echo -e " ${GREEN}All services are up!${NC}"
|
||||
else
|
||||
echo -e " ${RED}$((TOTAL - OK)) services are down${NC}"
|
||||
fi
|
||||
echo "========================================="
|
||||
169
scripts/health_aggregator.py
Normal file
169
scripts/health_aggregator.py
Normal file
@@ -0,0 +1,169 @@
|
||||
"""
|
||||
BreakPilot Health Aggregator Service
|
||||
|
||||
Checks TCP connectivity to all configured services and exposes
|
||||
aggregate health status via a FastAPI HTTP interface.
|
||||
|
||||
Configuration via environment variables:
|
||||
CHECK_SERVICES - comma-separated "host:port" pairs
|
||||
e.g. "postgres:5432,redis:6379,api:3000"
|
||||
CHECK_TIMEOUT - per-service TCP timeout in seconds (default: 3)
|
||||
CACHE_TTL - seconds to cache results (default: 10)
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
import time
|
||||
from typing import Any
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.responses import JSONResponse
|
||||
|
||||
app = FastAPI(title="BreakPilot Health Aggregator")
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Configuration
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
CHECK_TIMEOUT: float = float(os.environ.get("CHECK_TIMEOUT", "3"))
|
||||
CACHE_TTL: float = float(os.environ.get("CACHE_TTL", "10"))
|
||||
|
||||
|
||||
def _parse_services() -> list[dict[str, Any]]:
|
||||
"""Parse CHECK_SERVICES env var into a list of {host, port} dicts."""
|
||||
raw = os.environ.get("CHECK_SERVICES", "")
|
||||
services: list[dict[str, Any]] = []
|
||||
for entry in raw.split(","):
|
||||
entry = entry.strip()
|
||||
if not entry:
|
||||
continue
|
||||
if ":" not in entry:
|
||||
continue
|
||||
host, port_str = entry.rsplit(":", 1)
|
||||
try:
|
||||
port = int(port_str)
|
||||
except ValueError:
|
||||
continue
|
||||
services.append({"host": host, "port": port})
|
||||
return services
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# In-memory cache
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_cache: dict[str, Any] = {
|
||||
"timestamp": 0.0,
|
||||
"results": [],
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# TCP health check
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
async def _check_service(host: str, port: int) -> dict[str, Any]:
|
||||
"""Attempt a TCP connection to host:port and return status + timing."""
|
||||
start = time.monotonic()
|
||||
try:
|
||||
_, writer = await asyncio.wait_for(
|
||||
asyncio.open_connection(host, port),
|
||||
timeout=CHECK_TIMEOUT,
|
||||
)
|
||||
elapsed_ms = round((time.monotonic() - start) * 1000, 2)
|
||||
writer.close()
|
||||
await writer.wait_closed()
|
||||
return {
|
||||
"service": f"{host}:{port}",
|
||||
"status": "up",
|
||||
"response_time_ms": elapsed_ms,
|
||||
}
|
||||
except (OSError, asyncio.TimeoutError) as exc:
|
||||
elapsed_ms = round((time.monotonic() - start) * 1000, 2)
|
||||
return {
|
||||
"service": f"{host}:{port}",
|
||||
"status": "down",
|
||||
"response_time_ms": elapsed_ms,
|
||||
"error": str(exc) or type(exc).__name__,
|
||||
}
|
||||
|
||||
|
||||
async def _check_all() -> list[dict[str, Any]]:
|
||||
"""Check every configured service concurrently, with caching."""
|
||||
now = time.monotonic()
|
||||
|
||||
if _cache["results"] and (now - _cache["timestamp"]) < CACHE_TTL:
|
||||
return _cache["results"]
|
||||
|
||||
services = _parse_services()
|
||||
if not services:
|
||||
return []
|
||||
|
||||
tasks = [_check_service(s["host"], s["port"]) for s in services]
|
||||
results = await asyncio.gather(*tasks)
|
||||
|
||||
_cache["timestamp"] = time.monotonic()
|
||||
_cache["results"] = list(results)
|
||||
|
||||
return _cache["results"]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Routes
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
async def health():
|
||||
"""Aggregate health endpoint.
|
||||
|
||||
Returns 200 when all services are reachable, 503 otherwise.
|
||||
"""
|
||||
results = await _check_all()
|
||||
|
||||
all_up = all(r["status"] == "up" for r in results)
|
||||
total = len(results)
|
||||
healthy = sum(1 for r in results if r["status"] == "up")
|
||||
|
||||
body = {
|
||||
"status": "healthy" if all_up else "degraded",
|
||||
"services_total": total,
|
||||
"services_healthy": healthy,
|
||||
}
|
||||
|
||||
if not results:
|
||||
body["status"] = "no_services_configured"
|
||||
return JSONResponse(content=body, status_code=200)
|
||||
|
||||
status_code = 200 if all_up else 503
|
||||
return JSONResponse(content=body, status_code=status_code)
|
||||
|
||||
|
||||
@app.get("/health/details")
|
||||
async def health_details():
|
||||
"""Detailed per-service health information.
|
||||
|
||||
Returns 200 when all services are reachable, 503 otherwise.
|
||||
"""
|
||||
results = await _check_all()
|
||||
|
||||
all_up = all(r["status"] == "up" for r in results)
|
||||
total = len(results)
|
||||
healthy = sum(1 for r in results if r["status"] == "up")
|
||||
|
||||
body = {
|
||||
"status": "healthy" if all_up else "degraded",
|
||||
"services_total": total,
|
||||
"services_healthy": healthy,
|
||||
"services": results,
|
||||
}
|
||||
|
||||
if not results:
|
||||
body["status"] = "no_services_configured"
|
||||
return JSONResponse(content=body, status_code=200)
|
||||
|
||||
status_code = 200 if all_up else 503
|
||||
return JSONResponse(content=body, status_code=status_code)
|
||||
135
scripts/init-schemas.sql
Normal file
135
scripts/init-schemas.sql
Normal file
@@ -0,0 +1,135 @@
|
||||
-- BreakPilot Schema-Separation
|
||||
-- Erstellt 3 getrennte Schemas für Core, Lehrer und Compliance
|
||||
-- Wird beim ersten Start von postgres ausgeführt
|
||||
|
||||
-- Schemas erstellen
|
||||
CREATE SCHEMA IF NOT EXISTS core;
|
||||
CREATE SCHEMA IF NOT EXISTS lehrer;
|
||||
CREATE SCHEMA IF NOT EXISTS compliance;
|
||||
|
||||
-- Berechtigungen für breakpilot User
|
||||
GRANT ALL ON SCHEMA core TO breakpilot;
|
||||
GRANT ALL ON SCHEMA lehrer TO breakpilot;
|
||||
GRANT ALL ON SCHEMA compliance TO breakpilot;
|
||||
|
||||
-- Default search_path für den breakpilot User
|
||||
ALTER ROLE breakpilot SET search_path TO public, core, lehrer, compliance;
|
||||
|
||||
-- =============================================
|
||||
-- TABELLEN-MIGRATION: public -> core Schema
|
||||
-- =============================================
|
||||
-- Hinweis: Wird nur ausgeführt wenn Tabellen in public existieren
|
||||
-- Bei Neuinstallation werden Tabellen direkt im richtigen Schema erstellt
|
||||
|
||||
DO $$
|
||||
BEGIN
|
||||
-- Core-Tabellen verschieben (falls vorhanden)
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'users') THEN
|
||||
ALTER TABLE public.users SET SCHEMA core;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'sessions') THEN
|
||||
ALTER TABLE public.sessions SET SCHEMA core;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'consent_records') THEN
|
||||
ALTER TABLE public.consent_records SET SCHEMA core;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'notifications') THEN
|
||||
ALTER TABLE public.notifications SET SCHEMA core;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'email_templates') THEN
|
||||
ALTER TABLE public.email_templates SET SCHEMA core;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'billing_customers') THEN
|
||||
ALTER TABLE public.billing_customers SET SCHEMA core;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'billing_subscriptions') THEN
|
||||
ALTER TABLE public.billing_subscriptions SET SCHEMA core;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'billing_invoices') THEN
|
||||
ALTER TABLE public.billing_invoices SET SCHEMA core;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'rbac_roles') THEN
|
||||
ALTER TABLE public.rbac_roles SET SCHEMA core;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'rbac_permissions') THEN
|
||||
ALTER TABLE public.rbac_permissions SET SCHEMA core;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'rbac_role_permissions') THEN
|
||||
ALTER TABLE public.rbac_role_permissions SET SCHEMA core;
|
||||
END IF;
|
||||
|
||||
-- Lehrer-Tabellen verschieben (falls vorhanden)
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'classrooms') THEN
|
||||
ALTER TABLE public.classrooms SET SCHEMA lehrer;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'learning_units') THEN
|
||||
ALTER TABLE public.learning_units SET SCHEMA lehrer;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'klausuren') THEN
|
||||
ALTER TABLE public.klausuren SET SCHEMA lehrer;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'corrections') THEN
|
||||
ALTER TABLE public.corrections SET SCHEMA lehrer;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'worksheets') THEN
|
||||
ALTER TABLE public.worksheets SET SCHEMA lehrer;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'certificates') THEN
|
||||
ALTER TABLE public.certificates SET SCHEMA lehrer;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'letters') THEN
|
||||
ALTER TABLE public.letters SET SCHEMA lehrer;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'meetings') THEN
|
||||
ALTER TABLE public.meetings SET SCHEMA lehrer;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'messenger_contacts') THEN
|
||||
ALTER TABLE public.messenger_contacts SET SCHEMA lehrer;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'messenger_conversations') THEN
|
||||
ALTER TABLE public.messenger_conversations SET SCHEMA lehrer;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'messenger_messages') THEN
|
||||
ALTER TABLE public.messenger_messages SET SCHEMA lehrer;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'vocab_sessions') THEN
|
||||
ALTER TABLE public.vocab_sessions SET SCHEMA lehrer;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'game_sessions') THEN
|
||||
ALTER TABLE public.game_sessions SET SCHEMA lehrer;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'game_scores') THEN
|
||||
ALTER TABLE public.game_scores SET SCHEMA lehrer;
|
||||
END IF;
|
||||
|
||||
-- Compliance-Tabellen verschieben (falls vorhanden)
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'compliance_risks') THEN
|
||||
ALTER TABLE public.compliance_risks SET SCHEMA compliance;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'compliance_controls') THEN
|
||||
ALTER TABLE public.compliance_controls SET SCHEMA compliance;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'compliance_requirements') THEN
|
||||
ALTER TABLE public.compliance_requirements SET SCHEMA compliance;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'compliance_evidence') THEN
|
||||
ALTER TABLE public.compliance_evidence SET SCHEMA compliance;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'dsr_requests') THEN
|
||||
ALTER TABLE public.dsr_requests SET SCHEMA compliance;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'sdk_tenants') THEN
|
||||
ALTER TABLE public.sdk_tenants SET SCHEMA compliance;
|
||||
END IF;
|
||||
IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'sdk_audit_logs') THEN
|
||||
ALTER TABLE public.sdk_audit_logs SET SCHEMA compliance;
|
||||
END IF;
|
||||
|
||||
RAISE NOTICE 'Schema migration complete.';
|
||||
END $$;
|
||||
|
||||
-- Cross-Schema Views für häufige Lookups
|
||||
CREATE OR REPLACE VIEW compliance.v_users AS SELECT * FROM core.users;
|
||||
CREATE OR REPLACE VIEW lehrer.v_users AS SELECT * FROM core.users;
|
||||
CREATE OR REPLACE VIEW lehrer.v_consent_records AS SELECT * FROM core.consent_records;
|
||||
CREATE OR REPLACE VIEW compliance.v_consent_records AS SELECT * FROM core.consent_records;
|
||||
84
scripts/start-all.sh
Normal file
84
scripts/start-all.sh
Normal file
@@ -0,0 +1,84 @@
|
||||
#!/bin/bash
|
||||
# =========================================================
|
||||
# BreakPilot — Start All Projects
|
||||
# =========================================================
|
||||
# Usage: ./start-all.sh [--core-only] [--no-compliance]
|
||||
# =========================================================
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
LEHRER_ROOT="$(dirname "$PROJECT_ROOT")/breakpilot-lehrer"
|
||||
COMPLIANCE_ROOT="$(dirname "$PROJECT_ROOT")/breakpilot-compliance"
|
||||
|
||||
DOCKER="/usr/local/bin/docker"
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
|
||||
echo -e "${GREEN}=========================================${NC}"
|
||||
echo -e "${GREEN} BreakPilot — Starting All Projects${NC}"
|
||||
echo -e "${GREEN}=========================================${NC}"
|
||||
|
||||
# Phase 1: Core
|
||||
echo -e "\n${YELLOW}[1/3] Starting Core Infrastructure...${NC}"
|
||||
$DOCKER compose -f "$PROJECT_ROOT/docker-compose.yml" up -d
|
||||
echo -e "${GREEN}Core started. Waiting for health check...${NC}"
|
||||
|
||||
# Wait for health aggregator
|
||||
MAX_WAIT=120
|
||||
WAITED=0
|
||||
until curl -sf http://127.0.0.1:8099/health > /dev/null 2>&1; do
|
||||
sleep 5
|
||||
WAITED=$((WAITED + 5))
|
||||
if [ $WAITED -ge $MAX_WAIT ]; then
|
||||
echo -e "${RED}Core health check timeout after ${MAX_WAIT}s${NC}"
|
||||
echo "Check: $DOCKER compose -f $PROJECT_ROOT/docker-compose.yml logs"
|
||||
exit 1
|
||||
fi
|
||||
echo " Waiting for core... (${WAITED}s/${MAX_WAIT}s)"
|
||||
done
|
||||
echo -e "${GREEN}Core is healthy!${NC}"
|
||||
|
||||
if [ "$1" = "--core-only" ]; then
|
||||
echo -e "\n${GREEN}Done (core-only mode).${NC}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Phase 2: Lehrer
|
||||
if [ -f "$LEHRER_ROOT/docker-compose.yml" ]; then
|
||||
echo -e "\n${YELLOW}[2/3] Starting Lehrer Platform...${NC}"
|
||||
$DOCKER compose -f "$LEHRER_ROOT/docker-compose.yml" up -d
|
||||
echo -e "${GREEN}Lehrer platform started.${NC}"
|
||||
else
|
||||
echo -e "\n${YELLOW}[2/3] Skipping Lehrer (not found: $LEHRER_ROOT)${NC}"
|
||||
fi
|
||||
|
||||
# Phase 3: Compliance
|
||||
if [ "$1" = "--no-compliance" ]; then
|
||||
echo -e "\n${YELLOW}[3/3] Skipping Compliance (--no-compliance flag)${NC}"
|
||||
elif [ -f "$COMPLIANCE_ROOT/docker-compose.yml" ]; then
|
||||
echo -e "\n${YELLOW}[3/3] Starting Compliance Platform...${NC}"
|
||||
$DOCKER compose -f "$COMPLIANCE_ROOT/docker-compose.yml" up -d
|
||||
echo -e "${GREEN}Compliance platform started.${NC}"
|
||||
else
|
||||
echo -e "\n${YELLOW}[3/3] Skipping Compliance (not found: $COMPLIANCE_ROOT)${NC}"
|
||||
fi
|
||||
|
||||
echo -e "\n${GREEN}=========================================${NC}"
|
||||
echo -e "${GREEN} All Projects Started!${NC}"
|
||||
echo -e "${GREEN}=========================================${NC}"
|
||||
echo ""
|
||||
echo "URLs:"
|
||||
echo " Core Health: http://macmini:8099/health"
|
||||
echo " Studio v2: https://macmini/"
|
||||
echo " Admin Lehrer: https://macmini:3002/"
|
||||
echo " Admin Compliance: https://macmini:3007/"
|
||||
echo " Backend Core: https://macmini:8000/"
|
||||
echo " Backend Lehrer: https://macmini:8001/"
|
||||
echo " Backend Compliance:https://macmini:8002/"
|
||||
echo " RAG Service: https://macmini:8097/"
|
||||
Reference in New Issue
Block a user