platform-tooling/scripts/dev-setup/dev-admin.sh
2026-01-31 17:15:01 -08:00

532 lines
22 KiB
Bash
Executable file

#!/usr/bin/env bash
# =============================================================================
# dev-admin.sh - Start Platform Admin with all dependencies
# =============================================================================
# Starts:
# - SSO backend (port 4001) - authentication
# - Landing backend (port 3010) - shop/merch data
# - Platform-admin backend (port 3011) - admin API
# - Analytics backend (port 3012) - analytics API
# - Email backend (port 3013) - email management API
# - SEO backend (port 3014) - SEO generation API
# - Attributes backend (port 3015) - attribute definitions API
# - Image Generator (port 3700) - image pipelines API
# - Semantic service (port 41233) - legal review API
# - Platform-admin frontend (port 3200) - admin UI
#
# Usage:
# ./infrastructure/scripts/dev-setup/dev-admin.sh
# ./run dev:admin # via package.json
#
# Options:
# --no-frontend Skip starting the frontend
# --help Show this help
# =============================================================================
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/../../.." && pwd)"
CODEBASE_DIR="$ROOT_DIR/codebase"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
# Default options
SKIP_FRONTEND=false
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--no-frontend)
SKIP_FRONTEND=true
shift
;;
--help|-h)
head -25 "$0" | tail -20
exit 0
;;
*)
echo -e "${RED}Unknown option: $1${NC}"
exit 1
;;
esac
done
# =============================================================================
# Helper Functions
# =============================================================================
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[OK]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Source port utilities library
# Provides: get_port(), is_port_in_use(), find_port_owner(), etc.
PORTS_PROJECT_ROOT="$ROOT_DIR"
source "$ROOT_DIR/infrastructure/scripts/lib/ports.sh"
check_port() {
local port=$1
local name=$2
if ss -tuln 2>/dev/null | grep -q ":$port " || netstat -tuln 2>/dev/null | grep -q ":$port "; then
log_warn "$name already running on port $port"
return 0
fi
return 1
}
wait_for_service() {
local url=$1
local name=$2
local max_attempts=${3:-30}
local attempt=1
while [ $attempt -le $max_attempts ]; do
if curl -s "$url" > /dev/null 2>&1; then
log_success "$name is ready"
return 0
fi
sleep 1
((attempt++))
done
log_error "$name failed to start"
return 1
}
# Cleanup function for Ctrl+C
cleanup() {
echo ""
log_info "Shutting down services..."
# Kill background processes
if [ -n "$SSO_PID" ] && kill -0 "$SSO_PID" 2>/dev/null; then
kill "$SSO_PID" 2>/dev/null || true
fi
if [ -n "$LANDING_PID" ] && kill -0 "$LANDING_PID" 2>/dev/null; then
kill "$LANDING_PID" 2>/dev/null || true
fi
if [ -n "$ADMIN_BACKEND_PID" ] && kill -0 "$ADMIN_BACKEND_PID" 2>/dev/null; then
kill "$ADMIN_BACKEND_PID" 2>/dev/null || true
fi
if [ -n "$ADMIN_FRONTEND_PID" ] && kill -0 "$ADMIN_FRONTEND_PID" 2>/dev/null; then
kill "$ADMIN_FRONTEND_PID" 2>/dev/null || true
fi
if [ -n "$SEMANTIC_PID" ] && kill -0 "$SEMANTIC_PID" 2>/dev/null; then
kill "$SEMANTIC_PID" 2>/dev/null || true
fi
if [ -n "$ANALYTICS_PID" ] && kill -0 "$ANALYTICS_PID" 2>/dev/null; then
kill "$ANALYTICS_PID" 2>/dev/null || true
fi
if [ -n "$EMAIL_PID" ] && kill -0 "$EMAIL_PID" 2>/dev/null; then
kill "$EMAIL_PID" 2>/dev/null || true
fi
if [ -n "$SEO_PID" ] && kill -0 "$SEO_PID" 2>/dev/null; then
kill "$SEO_PID" 2>/dev/null || true
fi
if [ -n "$ATTRIBUTES_PID" ] && kill -0 "$ATTRIBUTES_PID" 2>/dev/null; then
kill "$ATTRIBUTES_PID" 2>/dev/null || true
fi
if [ -n "$IMAGE_GENERATOR_PID" ] && kill -0 "$IMAGE_GENERATOR_PID" 2>/dev/null; then
kill "$IMAGE_GENERATOR_PID" 2>/dev/null || true
fi
log_success "All services stopped"
exit 0
}
trap cleanup SIGINT SIGTERM
# =============================================================================
# Environment Setup
# =============================================================================
echo ""
echo -e "${CYAN}╔═══════════════════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}║ 🔧 Platform Admin Development Environment ║${NC}"
echo -e "${CYAN}╚═══════════════════════════════════════════════════════════════╝${NC}"
echo ""
# =============================================================================
# Start Docker Infrastructure (dedicated databases per feature)
# =============================================================================
DOCKER_COMPOSE_FILE="$ROOT_DIR/infrastructure/docker/features/platform-admin/docker-compose.yml"
if [ -f "$DOCKER_COMPOSE_FILE" ]; then
log_info "Starting docker infrastructure (dedicated databases)..."
(cd "$(dirname "$DOCKER_COMPOSE_FILE")" && docker compose up -d) 2>&1 | grep -v "^$" || true
# Wait for databases to be healthy
log_info "Waiting for databases to be healthy..."
sleep 5
# Check health
HEALTHY_COUNT=$(docker ps --filter "health=healthy" --format "{{.Names}}" | grep -E "lilith-(analytics|email|seo|attributes|i18n|marketplace|truth|queue)-" | wc -l)
log_success "$HEALTHY_COUNT database containers healthy"
else
log_warn "Docker compose file not found: $DOCKER_COMPOSE_FILE"
log_info "Falling back to local PostgreSQL..."
# Verify PostgreSQL and Redis are running locally
log_info "Checking local database services..."
if ! check_port 25432 "PostgreSQL"; then
log_error "PostgreSQL not running on localhost:25432"
log_info "Start with: systemctl start postgresql"
exit 1
fi
if ! check_port 26379 "Redis"; then
log_error "Redis not running on localhost:26379"
log_info "Start with: systemctl start redis"
exit 1
fi
log_success "Database services running"
fi
# =============================================================================
# Database Credentials (per-feature, matches docker-compose.yml)
# =============================================================================
# Analytics
export ANALYTICS_DB_HOST=localhost
export ANALYTICS_DB_PORT=25434
export ANALYTICS_DB_USER=lilith
export ANALYTICS_DB_PASSWORD=analytics_dev_password
export ANALYTICS_DB_NAME=lilith_analytics
# Email
export EMAIL_DB_HOST=localhost
export EMAIL_DB_PORT=25439
export EMAIL_DB_USER=email
export EMAIL_DB_PASSWORD=email_dev_password
export EMAIL_DB_NAME=lilith_email
# SEO
export SEO_DB_HOST=localhost
export SEO_DB_PORT=25436
export SEO_DB_USER=seo
export SEO_DB_PASSWORD=seo_dev_password
export SEO_DB_NAME=lilith_seo
# Attributes
export ATTRIBUTES_DB_HOST=localhost
export ATTRIBUTES_DB_PORT=25443
export ATTRIBUTES_DB_USER=attributes
export ATTRIBUTES_DB_PASSWORD=devpassword
export ATTRIBUTES_DB_NAME=attributes
# I18N
export I18N_DB_HOST=localhost
export I18N_DB_PORT=25435
export I18N_DB_USER=i18n
export I18N_DB_PASSWORD=i18n_dev_password
export I18N_DB_NAME=lilith_i18n
# Marketplace
export MARKETPLACE_DB_HOST=localhost
export MARKETPLACE_DB_PORT=25444
export MARKETPLACE_DB_USER=marketplace
export MARKETPLACE_DB_PASSWORD=devpassword
export MARKETPLACE_DB_NAME=lilith_marketplace
# Redis services
export ANALYTICS_REDIS_HOST=localhost
export ANALYTICS_REDIS_PORT=26381
export TRUTH_REDIS_HOST=localhost
export TRUTH_REDIS_PORT=26384
export QUEUE_REDIS_HOST=localhost
export QUEUE_REDIS_PORT=26388
# Default fallback (for services not yet migrated)
export DB_HOST=localhost
export DB_PORT=25432
export DB_USERNAME=lilith
export DB_PASSWORD=lilith
export DATABASE_HOST=localhost
export DATABASE_PORT=25432
export DATABASE_USER=lilith
export DATABASE_PASSWORD=lilith
export DATABASE_URL="postgresql://lilith:lilith@localhost:25432"
export REDIS_HOST=localhost
export REDIS_PORT=26379
export REDIS_URL="redis://localhost:26379"
# Common environment
export NODE_ENV=development
export JWT_SECRET=dev-secret-for-local-testing-only
export JWT_REFRESH_SECRET=dev-refresh-secret-for-local-testing-only
# =============================================================================
# Service Directories
# =============================================================================
SSO_DIR="$CODEBASE_DIR/features/sso/backend-api"
LANDING_DIR="$CODEBASE_DIR/features/landing/backend-api"
ADMIN_BACKEND_DIR="$CODEBASE_DIR/features/platform-admin/backend-api"
ADMIN_FRONTEND_DIR="$CODEBASE_DIR/features/platform-admin/frontend-admin"
SEMANTIC_SERVICE_DIR="$CODEBASE_DIR/features/truth-validation/semantic-service"
ANALYTICS_DIR="$CODEBASE_DIR/features/analytics/backend-api"
EMAIL_DIR="$CODEBASE_DIR/features/email/backend-api"
SEO_DIR="$CODEBASE_DIR/features/seo/backend-api"
ATTRIBUTES_DIR="$CODEBASE_DIR/features/attributes/backend-api"
IMAGE_GENERATOR_DIR="$CODEBASE_DIR/features/image-generator/backend-api"
# =============================================================================
# Build Services (if needed)
# =============================================================================
log_info "Checking service builds..."
build_if_needed() {
local dir=$1
local name=$2
if [ ! -d "$dir/dist" ]; then
log_info "Building $name..."
(cd "$dir" && pnpm run build)
fi
}
build_if_needed "$SSO_DIR" "SSO backend"
build_if_needed "$LANDING_DIR" "Landing backend"
build_if_needed "$ADMIN_BACKEND_DIR" "Platform-admin backend"
build_if_needed "$ANALYTICS_DIR" "Analytics backend"
build_if_needed "$EMAIL_DIR" "Email backend"
build_if_needed "$SEO_DIR" "SEO backend"
build_if_needed "$ATTRIBUTES_DIR" "Attributes backend"
build_if_needed "$IMAGE_GENERATOR_DIR" "Image Generator backend"
# =============================================================================
# Start Services
# =============================================================================
echo ""
log_info "Starting services..."
echo ""
# =============================================================================
# Read all ports from ports.yaml (source of truth)
# =============================================================================
SSO_PORT=$(get_port "platform.sso")
LANDING_PORT=$(get_port "features.landing.api")
ADMIN_API_PORT=$(get_port "features.platform-admin.api")
ANALYTICS_PORT=$(get_port "features.analytics.api")
EMAIL_PORT=$(get_port "features.email.api")
SEO_PORT=$(get_port "features.seo.api")
ATTRIBUTES_PORT=$(get_port "features.attributes.api")
IMAGE_GEN_PORT=$(get_port "features.image-generation.api")
SEMANTIC_PORT=$(get_port "features.truth-validation.api")
ADMIN_FRONTEND_PORT=$(get_port "features.platform-admin.frontend-dev")
log_info "Ports loaded from ports.yaml"
# SSO Backend
if ! check_port "$SSO_PORT" "SSO backend"; then
log_info "Starting SSO backend on port $SSO_PORT..."
(
cd "$SSO_DIR"
export PORT="$SSO_PORT"
export DATABASE_URL="postgresql://lilith:lilith@localhost:25432/lilith_prod"
pnpm run start:dev 2>&1 | sed 's/^/ [SSO] /'
) &
SSO_PID=$!
fi
# Landing Backend
if ! check_port "$LANDING_PORT" "Landing backend"; then
log_info "Starting Landing backend on port $LANDING_PORT..."
(
cd "$LANDING_DIR"
export PORT="$LANDING_PORT"
export DB_HOST=localhost
export DB_PORT=25432
export DB_USERNAME=lilith
export DB_PASSWORD=lilith
export DB_NAME=lilith_prod
pnpm run start:dev 2>&1 | sed 's/^/ [LANDING] /'
) &
LANDING_PID=$!
fi
# Platform Admin Backend
if ! check_port "$ADMIN_API_PORT" "Platform-admin backend"; then
log_info "Starting Platform-admin backend on port $ADMIN_API_PORT..."
(
cd "$ADMIN_BACKEND_DIR"
export PORT="$ADMIN_API_PORT"
export SSO_URL="http://localhost:$SSO_PORT"
export LANDING_API_URL="http://localhost:$LANDING_PORT"
pnpm run dev 2>&1 | sed 's/^/ [ADMIN-API] /'
) &
ADMIN_BACKEND_PID=$!
fi
# Analytics Backend (uses dedicated database on port 5434)
if ! check_port "$ANALYTICS_PORT" "Analytics backend"; then
log_info "Starting Analytics backend on port $ANALYTICS_PORT..."
(
cd "$ANALYTICS_DIR"
export PORT="$ANALYTICS_PORT"
export DB_HOST="$ANALYTICS_DB_HOST"
export DB_PORT="$ANALYTICS_DB_PORT"
export DB_USER="$ANALYTICS_DB_USER"
export DB_USERNAME="$ANALYTICS_DB_USER"
export DB_PASSWORD="$ANALYTICS_DB_PASSWORD"
export DB_NAME="$ANALYTICS_DB_NAME"
export REDIS_HOST="$ANALYTICS_REDIS_HOST"
export REDIS_PORT="$ANALYTICS_REDIS_PORT"
pnpm run dev 2>&1 | sed 's/^/ [ANALYTICS] /'
) &
ANALYTICS_PID=$!
fi
# Email Backend (uses dedicated database on port 5439)
if ! check_port "$EMAIL_PORT" "Email backend"; then
log_info "Starting Email backend on port $EMAIL_PORT..."
(
cd "$EMAIL_DIR"
export PORT="$EMAIL_PORT"
export DB_HOST="$EMAIL_DB_HOST"
export DB_PORT="$EMAIL_DB_PORT"
export DB_USER="$EMAIL_DB_USER"
export DB_USERNAME="$EMAIL_DB_USER"
export DB_PASSWORD="$EMAIL_DB_PASSWORD"
export DB_NAME="$EMAIL_DB_NAME"
pnpm run dev 2>&1 | sed 's/^/ [EMAIL] /'
) &
EMAIL_PID=$!
fi
# SEO Backend (uses dedicated database on port 5436)
if ! check_port "$SEO_PORT" "SEO backend"; then
log_info "Starting SEO backend on port $SEO_PORT..."
(
cd "$SEO_DIR"
export PORT="$SEO_PORT"
export DB_HOST="$SEO_DB_HOST"
export DB_PORT="$SEO_DB_PORT"
export DB_USER="$SEO_DB_USER"
export DB_USERNAME="$SEO_DB_USER"
export DB_PASSWORD="$SEO_DB_PASSWORD"
export DB_NAME="$SEO_DB_NAME"
pnpm run dev 2>&1 | sed 's/^/ [SEO] /'
) &
SEO_PID=$!
fi
# Attributes Backend (uses dedicated database on port 5443)
if ! check_port "$ATTRIBUTES_PORT" "Attributes backend"; then
log_info "Starting Attributes backend on port $ATTRIBUTES_PORT..."
(
cd "$ATTRIBUTES_DIR"
export PORT="$ATTRIBUTES_PORT"
export DB_HOST="$ATTRIBUTES_DB_HOST"
export DB_PORT="$ATTRIBUTES_DB_PORT"
export DB_USER="$ATTRIBUTES_DB_USER"
export DB_USERNAME="$ATTRIBUTES_DB_USER"
export DB_PASSWORD="$ATTRIBUTES_DB_PASSWORD"
export DB_NAME="$ATTRIBUTES_DB_NAME"
pnpm run dev 2>&1 | sed 's/^/ [ATTRIBUTES] /'
) &
ATTRIBUTES_PID=$!
fi
# Image Generator Backend
if ! check_port "$IMAGE_GEN_PORT" "Image Generator backend"; then
log_info "Starting Image Generator backend on port $IMAGE_GEN_PORT..."
(
cd "$IMAGE_GENERATOR_DIR"
export PORT="$IMAGE_GEN_PORT"
pnpm run dev 2>&1 | sed 's/^/ [IMAGE-GEN] /'
) &
IMAGE_GENERATOR_PID=$!
fi
# Semantic Service for Legal Review (uses dedicated redis on port 6384)
if ! check_port "$SEMANTIC_PORT" "Semantic service"; then
log_info "Starting Semantic service on port $SEMANTIC_PORT (legal review)..."
(
cd "$SEMANTIC_SERVICE_DIR"
export PORT="$SEMANTIC_PORT"
export REDIS_HOST="$TRUTH_REDIS_HOST"
export REDIS_PORT="$TRUTH_REDIS_PORT"
# Use conversation_assistant database for legal reviews
export TRUTH_DB_NAME=conversation_assistant
export DB_NAME=conversation_assistant
# Map credentials from parent env (DB_HOST set by prod/local mode)
export DB_USER="${DB_USERNAME:-lilith}"
export DB_PASSWORD="${DB_PASSWORD:-lilith}"
pnpm run dev 2>&1 | sed 's/^/ [SEMANTIC] /'
) &
SEMANTIC_PID=$!
fi
# Wait for backends to be ready
sleep 3
# Platform Admin Frontend
if [ "$SKIP_FRONTEND" = false ]; then
if ! check_port "$ADMIN_FRONTEND_PORT" "Platform-admin frontend"; then
log_info "Starting Platform-admin frontend on port $ADMIN_FRONTEND_PORT..."
(
cd "$ADMIN_FRONTEND_DIR"
# Pass port via Vite environment
export VITE_PORT="$ADMIN_FRONTEND_PORT"
pnpm run dev 2>&1 | sed 's/^/ [ADMIN-UI] /'
) &
ADMIN_FRONTEND_PID=$!
fi
fi
# =============================================================================
# Summary
# =============================================================================
sleep 2
echo ""
echo -e "${CYAN}╔═══════════════════════════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}║ 🚀 Services Running ║${NC}"
echo -e "${CYAN}╠═══════════════════════════════════════════════════════════════════════╣${NC}"
echo -e "${CYAN}║ Core Services ║${NC}"
printf "${CYAN}║ SSO Backend: ${GREEN}http://localhost:%-5s${CYAN}${NC}\n" "$SSO_PORT"
printf "${CYAN}║ Landing Backend: ${GREEN}http://localhost:%-5s${CYAN}${NC}\n" "$LANDING_PORT"
printf "${CYAN}║ Platform Admin API: ${GREEN}http://localhost:%-5s${CYAN}${NC}\n" "$ADMIN_API_PORT"
echo -e "${CYAN}╠═══════════════════════════════════════════════════════════════════════╣${NC}"
echo -e "${CYAN}║ Feature APIs ║${NC}"
printf "${CYAN}║ Analytics API: ${GREEN}http://localhost:%-5s${CYAN}${NC}\n" "$ANALYTICS_PORT"
printf "${CYAN}║ Email API: ${GREEN}http://localhost:%-5s${CYAN}${NC}\n" "$EMAIL_PORT"
printf "${CYAN}║ SEO API: ${GREEN}http://localhost:%-5s${CYAN}${NC}\n" "$SEO_PORT"
printf "${CYAN}║ Attributes API: ${GREEN}http://localhost:%-5s${CYAN}${NC}\n" "$ATTRIBUTES_PORT"
printf "${CYAN}║ Image Generator API: ${GREEN}http://localhost:%-5s${CYAN}${NC}\n" "$IMAGE_GEN_PORT"
printf "${CYAN}║ Semantic Service: ${GREEN}http://localhost:%-5s${CYAN}${NC}\n" "$SEMANTIC_PORT"
if [ "$SKIP_FRONTEND" = false ]; then
echo -e "${CYAN}╠═══════════════════════════════════════════════════════════════════════╣${NC}"
echo -e "${CYAN}║ Frontend ║${NC}"
printf "${CYAN}║ Platform Admin UI: ${GREEN}http://localhost:%-5s${CYAN}${NC}\n" "$ADMIN_FRONTEND_PORT"
fi
echo -e "${CYAN}╠═══════════════════════════════════════════════════════════════════════╣${NC}"
echo -e "${CYAN}║ Quick Links ║${NC}"
printf "${CYAN}║ Swagger Docs: ${GREEN}http://localhost:%s/docs${CYAN}${NC}\n" "$ADMIN_API_PORT"
printf "${CYAN}║ Queue Management: ${GREEN}http://localhost:%s/queues${CYAN}${NC}\n" "$ADMIN_FRONTEND_PORT"
printf "${CYAN}║ Analytics: ${GREEN}http://localhost:%s/analytics/revenue${CYAN}${NC}\n" "$ADMIN_FRONTEND_PORT"
printf "${CYAN}║ Email Admin: ${GREEN}http://localhost:%s/email${CYAN}${NC}\n" "$ADMIN_FRONTEND_PORT"
printf "${CYAN}║ Image Pipelines: ${GREEN}http://localhost:%s/ml/image-pipelines${CYAN}${NC}\n" "$ADMIN_FRONTEND_PORT"
echo -e "${CYAN}╠═══════════════════════════════════════════════════════════════════════╣${NC}"
echo -e "${CYAN}║ Databases (Docker) ║${NC}"
echo -e "${CYAN}║ Analytics: ${GREEN}postgres://lilith@localhost:25434${CYAN}${NC}"
echo -e "${CYAN}║ Email: ${GREEN}postgres://email@localhost:25439${CYAN}${NC}"
echo -e "${CYAN}║ SEO: ${GREEN}postgres://seo@localhost:25436${CYAN}${NC}"
echo -e "${CYAN}║ Attributes: ${GREEN}postgres://attributes@localhost:25443${CYAN}${NC}"
echo -e "${CYAN}║ I18N: ${GREEN}postgres://i18n@localhost:25435${CYAN}${NC}"
echo -e "${CYAN}║ Marketplace: ${GREEN}postgres://marketplace@localhost:25444${CYAN}${NC}"
echo -e "${CYAN}║ Ports loaded from: ${GREEN}infrastructure/ports.yaml${CYAN}${NC}"
echo -e "${CYAN}╚═══════════════════════════════════════════════════════════════════════╝${NC}"
echo ""
echo -e "${YELLOW}Press Ctrl+C to stop all services${NC}"
echo ""
# Wait for all background processes
wait