#!/bin/bash # ============================================================================= # IGNY8 Deploy to Production # ============================================================================= # Safely deploys code to production with backup and rollback capability # Usage: ./deploy-production.sh # ============================================================================= set -e APP_DIR="/data/app/igny8" COMPOSE_FILE="docker-compose.app.yml" PROJECT_NAME="igny8-app" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log() { echo -e "${BLUE}[$(date '+%H:%M:%S')]${NC} $1" } log_success() { echo -e "${GREEN}✅ $1${NC}" } log_warn() { echo -e "${YELLOW}⚠️ $1${NC}" } log_error() { echo -e "${RED}❌ $1${NC}" } echo "==========================================" echo "IGNY8 PRODUCTION DEPLOYMENT" echo "==========================================" echo "" # Safety confirmation log_warn "This will deploy to PRODUCTION!" log_warn "Make sure you have tested on staging first." echo "" read -p "Type 'deploy' to continue: " confirm if [[ "${confirm}" != "deploy" ]]; then log "Deployment cancelled" exit 0 fi cd "${APP_DIR}" # Verify on main branch CURRENT_BRANCH=$(git branch --show-current) if [[ "${CURRENT_BRANCH}" != "main" ]]; then log_error "Not on main branch (currently on: ${CURRENT_BRANCH})" log "Switch to main: git checkout main && git pull" exit 1 fi # Step 1: Create pre-deploy backup log "Step 1/8: Creating pre-deploy backup..." /data/app/igny8/scripts/ops/backup-db.sh pre-deploy log_success "Backup created" # Step 2: Tag current images for rollback log "Step 2/8: Tagging current images for rollback..." docker tag igny8-backend:latest igny8-backend:rollback 2>/dev/null || true docker tag igny8-frontend-dev:latest igny8-frontend-dev:rollback 2>/dev/null || true docker tag igny8-marketing-dev:latest igny8-marketing-dev:rollback 2>/dev/null || true log_success "Rollback images tagged" # Step 3: Pull latest code log "Step 3/8: Pulling latest code..." git pull origin main log_success "Code updated" # Step 4: Build new images log "Step 4/8: Building new images..." docker build -t igny8-backend:latest -f backend/Dockerfile backend/ docker build -t igny8-frontend-dev:latest -f frontend/Dockerfile.dev frontend/ docker build -t igny8-marketing-dev:latest -f frontend/Dockerfile.marketing.dev frontend/ log_success "Images built" # Step 5: Check for pending migrations log "Step 5/8: Checking for pending migrations..." PENDING=$(docker exec igny8_backend python manage.py showmigrations --plan 2>/dev/null | grep "\[ \]" || true) if [[ -n "${PENDING}" ]]; then log_warn "Pending migrations found:" echo "${PENDING}" read -p "Apply migrations? (yes/no): " apply_migrations if [[ "${apply_migrations}" != "yes" ]]; then log "Skipping migrations" fi fi # Step 6: Restart containers log "Step 6/8: Restarting containers..." docker compose -f "${COMPOSE_FILE}" -p "${PROJECT_NAME}" down docker compose -f "${COMPOSE_FILE}" -p "${PROJECT_NAME}" up -d # Step 7: Wait for backend to be healthy log "Step 7/8: Waiting for backend to be healthy..." for i in {1..30}; do if docker exec igny8_backend python -c "import urllib.request; urllib.request.urlopen('http://localhost:8010/api/v1/system/status/').read()" 2>/dev/null; then log_success "Backend is healthy" break fi if [[ $i -eq 30 ]]; then log_error "Backend failed to become healthy" log_error "ROLLING BACK..." /data/app/igny8/scripts/ops/rollback.sh --auto exit 1 fi echo -n "." sleep 2 done # Step 8: Apply migrations and collect static log "Step 8/8: Applying migrations and collecting static..." if [[ "${apply_migrations}" == "yes" ]] || [[ -z "${PENDING}" ]]; then docker exec igny8_backend python manage.py migrate --noinput fi docker exec igny8_backend python manage.py collectstatic --noinput echo "" echo "==========================================" log_success "PRODUCTION DEPLOYMENT COMPLETE" echo "==========================================" echo "" echo "Production is live!" echo " App: https://app.igny8.com" echo " API: https://api.igny8.com" echo "" echo "Monitor logs for 10 minutes:" echo " docker compose -f ${COMPOSE_FILE} -p ${PROJECT_NAME} logs -f" echo "" echo "If issues occur, rollback:" echo " /data/app/igny8/scripts/ops/rollback.sh" echo "" echo "Container status:" docker compose -f "${COMPOSE_FILE}" -p "${PROJECT_NAME}" ps echo "=========================================="