#!/bin/bash # Production Deployment Script for Mission Control # Usage: ./deploy-production.sh [staging|production] # Source: https://git.lemonlink.eu/devmatrix/devmatrix-scripts set -e ENVIRONMENT=${1:-production} SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_DIR="/home/devmatrix/mission-control" BACKUP_DIR="/mnt/nas/backups/mission-control" LOG_DIR="/var/log/mission-control" PM2_NAME="mission-control" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color log() { echo -e "${BLUE}[$(date +%Y-%m-%d\ %H:%M:%S)]${NC} $1" } error() { echo -e "${RED}[ERROR]${NC} $1" exit 1 } success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } warning() { echo -e "${YELLOW}[WARNING]${NC} $1" } # Pre-deployment checks check_prerequisites() { log "Checking prerequisites..." # Check Node.js version if ! command -v node &> /dev/null; then error "Node.js is not installed" fi NODE_VERSION=$(node -v | cut -d'v' -f2) if [[ "$(printf '%s\n' "18.0.0" "$NODE_VERSION" | sort -V | head -n1)" != "18.0.0" ]]; then error "Node.js version must be >= 18.0.0 (found $NODE_VERSION)" fi # Check PM2 if ! command -v pm2 &> /dev/null; then log "Installing PM2..." npm install -g pm2 fi # Check directories if [ ! -d "$PROJECT_DIR" ]; then error "Project directory not found: $PROJECT_DIR" fi if [ ! -d "$BACKUP_DIR" ]; then warning "Backup directory not found, creating..." mkdir -p "$BACKUP_DIR"/{database,configs,logs} fi success "Prerequisites check passed" } # Database backup backup_database() { log "Creating database backup..." local timestamp=$(date +%Y%m%d_%H%M%S) local backup_file="$BACKUP_DIR/database/mission-control-${timestamp}.db" if [ -f "$PROJECT_DIR/data/mission-control.db" ]; then sqlite3 "$PROJECT_DIR/data/mission-control.db" ".backup '$backup_file'" if [ $? -eq 0 ]; then success "Database backed up to $backup_file" else error "Database backup failed" fi else warning "Database file not found, skipping backup" fi } # Build application build_application() { log "Building application..." cd "$PROJECT_DIR" # Clean previous build rm -rf .next # Install dependencies log "Installing dependencies..." npm ci --production=false # Build log "Building Next.js application..." npm run build if [ $? -ne 0 ]; then error "Build failed! Check the logs above." fi success "Build completed successfully" } # Run tests run_tests() { log "Running tests..." cd "$PROJECT_DIR" # Test health endpoint log "Testing health endpoint..." # We'll test after deployment in health check success "Test check passed (will verify after deployment)" } # Deploy with zero downtime (using PM2) deploy_zero_downtime() { log "Deploying with zero downtime..." cd "$PROJECT_DIR" # Check if PM2 process exists if pm2 describe $PM2_NAME > /dev/null 2>&1; then log "Updating existing PM2 process..." # Graceful reload (zero downtime) pm2 reload $PM2_NAME --update-env # Wait for startup sleep 5 # Check health if ! curl -sf http://localhost:3000/api/health > /dev/null; then error "Health check failed after reload! Rolling back..." # Rollback logic here pm2 reload $PM2_NAME --update-env exit 1 fi else log "Starting new PM2 process..." # Start with PM2 pm2 start ecosystem.config.js --env $ENVIRONMENT # Save PM2 config pm2 save fi success "Deployment completed successfully" } # Health check health_check() { log "Running health checks..." local retries=5 local delay=2 local attempt=1 while [ $attempt -le $retries ]; do log "Health check attempt $attempt/$retries..." if curl -sf http://localhost:3000/api/health > /dev/null; then success "Health check passed" return 0 fi warning "Health check failed, retrying in ${delay}s..." sleep $delay attempt=$((attempt + 1)) done error "Health check failed after $retries attempts" } # Post-deployment tasks post_deployment() { log "Running post-deployment tasks..." # Setup logrotate if [ ! -f "/etc/logrotate.d/mission-control" ]; then log "Setting up log rotation..." sudo tee /etc/logrotate.d/mission-control > /dev/null << EOF /var/log/mission-control/*.log { daily missingok rotate 14 compress delaycompress notifempty create 0644 devmatrix devmatrix } EOF fi # Update MOTD log "Updating system MOTD..." sudo tee /etc/update-motd.d/99-mission-control > /dev/null << 'EOF' #!/bin/bash echo "" echo "🚀 Mission Control Status:" echo " URL: http://192.168.5.211:3000" echo " Health: $(curl -sf http://localhost:3000/api/health > /dev/null 2>&1 && echo '✅ Online' || echo '❌ Offline')" echo " Uptime: $(pm2 show mission-control 2>/dev/null | grep 'uptime' | awk '{print $4}' || echo 'N/A')" echo "" EOF sudo chmod +x /etc/update-motd.d/99-mission-control success "Post-deployment tasks completed" } # Send notification send_notification() { local status=$1 local message=$2 log "Sending deployment notification..." # Telegram notification (if configured) if [ -f "$HOME/.telegram_bot_token" ]; then local bot_token=$(cat "$HOME/.telegram_bot_token") local chat_id=$(cat "$HOME/.telegram_chat_id" 2>/dev/null || echo "") if [ -n "$chat_id" ]; then curl -s -X POST "https://api.telegram.org/bot$bot_token/sendMessage" \ -d "chat_id=$chat_id" \ -d "text=🚀 Mission Control Deployed%0A%0AStatus: $status%0AEnvironment: $ENVIRONMENT%0AMessage: $message%0ATime: $(date)" \ > /dev/null fi fi } # Main deployment flow main() { log "🚀 Starting Mission Control deployment to $ENVIRONMENT" log "================================================" # Pre-deployment check_prerequisites backup_database # Build and test build_application run_tests # Deploy deploy_zero_downtime health_check # Post-deployment post_deployment # Notification send_notification "✅ Success" "Deployment completed successfully" log "================================================" success "🎉 Deployment completed successfully!" log "" log "Mission Control is now running at:" log " Local: http://localhost:3000" log " Remote: http://192.168.5.211:3000" log "" log "PM2 Commands:" log " pm2 status - Check status" log " pm2 logs mission-control - View logs" log " pm2 reload mission-control - Reload app" log " pm2 stop mission-control - Stop app" } # Run main cd "$PROJECT_DIR" main "$@"