#!/bin/bash set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" echo "=== ModComms Deployment ===" echo "Working directory: $SCRIPT_DIR" # --- Check prerequisites --- echo "" echo "[Prerequisites] Checking required tools..." check_command() { if ! command -v "$1" &> /dev/null; then echo "Error: $1 is not installed" exit 1 fi echo " ✓ $1" } check_command git check_command node check_command npm check_command docker # --- Load deployment configuration --- if [ -f .env.deploy ]; then source .env.deploy echo " ✓ .env.deploy loaded" else echo "" echo "Error: .env.deploy not found" echo "Create it from the template:" echo " cp .env.deploy.example .env.deploy" echo " nano .env.deploy" exit 1 fi # Validate required variables require_var() { local var_name="$1" local value="${!var_name}" if [ -z "$value" ] || [[ "$value" == *"your_"* ]]; then echo "" echo "Error: ${var_name} is not configured in .env.deploy" exit 1 fi echo " ✓ ${var_name}" } echo "" echo "[Config] Validating required variables..." require_var FRONTEND_DEPLOY_DIR require_var GEMINI_API_KEY require_var AZURE_TENANT_ID require_var AZURE_CLIENT_ID require_var VITE_BACKEND_URL require_var VITE_AZURE_REDIRECT_URI # Set defaults COMPOSE_PROJECT_NAME="${COMPOSE_PROJECT_NAME:-modcomms}" BACKEND_PORT="${BACKEND_PORT:-8000}" POSTGRES_PORT="${POSTGRES_PORT:-5432}" POSTGRES_USER="${POSTGRES_USER:-modcomms}" POSTGRES_PASSWORD="${POSTGRES_PASSWORD:-modcomms_dev}" POSTGRES_DB="${POSTGRES_DB:-modcomms}" VITE_BASE_PATH="${VITE_BASE_PATH:-/}" DISABLE_AUTH="${DISABLE_AUTH:-false}" CORS_ORIGINS="${CORS_ORIGINS:-}" echo " Environment: ${COMPOSE_PROJECT_NAME} (backend:${BACKEND_PORT}, postgres:${POSTGRES_PORT})" # --- Generate .env (docker compose) --- cat > .env << EOF # Auto-generated by deploy.sh — do not edit manually # Edit .env.deploy instead and re-run deploy.sh COMPOSE_PROJECT_NAME=${COMPOSE_PROJECT_NAME} BACKEND_PORT=${BACKEND_PORT} POSTGRES_PORT=${POSTGRES_PORT} POSTGRES_USER=${POSTGRES_USER} POSTGRES_PASSWORD=${POSTGRES_PASSWORD} POSTGRES_DB=${POSTGRES_DB} EOF echo " ✓ .env created for docker compose" # --- Generate backend/.env --- echo "" echo "[Config] Generating backend/.env..." cat > backend/.env << EOF # Auto-generated by deploy.sh — do not edit manually # Edit .env.deploy instead and re-run deploy.sh GEMINI_API_KEY=${GEMINI_API_KEY} CORS_ORIGINS=${CORS_ORIGINS} HOST=0.0.0.0 PORT=${BACKEND_PORT} AZURE_TENANT_ID=${AZURE_TENANT_ID} AZURE_CLIENT_ID=${AZURE_CLIENT_ID} DISABLE_AUTH=${DISABLE_AUTH} MAILGUN_API_URL=${MAILGUN_API_URL} MAILGUN_API_KEY=${MAILGUN_API_KEY} MAILGUN_FROM=${MAILGUN_FROM} SUPPORT_EMAIL=${SUPPORT_EMAIL} LLAMA_CLOUD_API_KEY=${LLAMA_CLOUD_API_KEY} EOF echo " ✓ backend/.env generated" # --- Generate frontend/.env.local --- echo "" echo "[Config] Generating frontend/.env.local..." cat > frontend/.env.local << EOF # Auto-generated by deploy.sh — do not edit manually # Edit .env.deploy instead and re-run deploy.sh VITE_BASE_PATH=${VITE_BASE_PATH} VITE_BACKEND_URL=${VITE_BACKEND_URL} VITE_AZURE_CLIENT_ID=${AZURE_CLIENT_ID} VITE_AZURE_TENANT_ID=${AZURE_TENANT_ID} VITE_AZURE_REDIRECT_URI=${VITE_AZURE_REDIRECT_URI} EOF echo " ✓ frontend/.env.local generated" # --- 1. Pull latest code --- echo "" echo "[1/6] Updating code..." if [ -d .git ]; then if git remote -v | grep -q origin; then git checkout -- frontend/package-lock.json 2>/dev/null || true git pull || echo "Warning: git pull failed, continuing with local code" else echo " No remote configured, skipping git pull" fi else echo " Not a git repository, skipping git pull" fi # --- 2. Build frontend --- echo "" echo "[2/6] Building frontend..." cd frontend npm install npm run build cd "$SCRIPT_DIR" # --- 3. Deploy frontend to Apache --- echo "" echo "[3/6] Deploying frontend to ${FRONTEND_DEPLOY_DIR}..." sudo mkdir -p "$FRONTEND_DEPLOY_DIR" if [ -n "$FRONTEND_DEPLOY_DIR" ] && [ -d "$FRONTEND_DEPLOY_DIR" ]; then sudo find "$FRONTEND_DEPLOY_DIR" -mindepth 1 -delete 2>/dev/null || true fi sudo cp -r frontend/dist/* "$FRONTEND_DEPLOY_DIR/" sudo chown -R www-data:www-data "$FRONTEND_DEPLOY_DIR" echo " ✓ Frontend deployed" # --- 4. Build containers and run database migrations --- echo "" echo "[4/6] Building containers..." docker compose build echo " Starting PostgreSQL..." docker compose up -d postgres echo " Waiting for PostgreSQL to be ready..." for i in {1..30}; do if docker compose exec -T postgres pg_isready -U "${POSTGRES_USER}" -d "${POSTGRES_DB}" > /dev/null 2>&1; then echo " ✓ PostgreSQL is ready" break fi if [ $i -eq 30 ]; then echo " Error: PostgreSQL failed to start" docker compose logs postgres exit 1 fi sleep 1 done # --- 5. Run database migrations --- echo "" echo "[5/6] Running database migrations..." if docker compose run --rm backend alembic upgrade head; then echo " ✓ Database migrations complete" else echo " Error: Database migrations failed" exit 1 fi # --- 6. Start backend service --- echo "" echo "[6/6] Starting backend service..." docker compose up -d --force-recreate backend echo " Waiting for backend to be healthy..." for i in {1..30}; do if curl -sf "http://localhost:${BACKEND_PORT}/health" > /dev/null 2>&1; then echo " ✓ Backend is healthy" break fi if [ $i -eq 30 ]; then echo " Warning: Backend health check timed out" fi sleep 1 done # --- Summary --- echo "" echo "=========================================" echo " Deployment Complete!" echo "=========================================" echo "" echo "Environment: ${COMPOSE_PROJECT_NAME}" echo "Frontend: ${FRONTEND_DEPLOY_DIR}" echo "Backend: http://localhost:${BACKEND_PORT}" echo "" docker compose ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}" echo "" echo "Health check:" curl -s "http://localhost:${BACKEND_PORT}/health" && echo "" || echo "Warning: Backend not responding"