#!/bin/bash # ๐Ÿš€ Production Environment Manager # Manages production Docker deployment with organized structure set -e # Configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" COMPOSE_FILE="$PROJECT_ROOT/docker/prod/docker-compose.yml" ENV_FILE="$PROJECT_ROOT/.env" PROJECT_NAME="portal-prod" # Colors GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' RED='\033[0;31m' NC='\033[0m' log() { echo -e "${GREEN}[PROD] $1${NC}"; } warn() { echo -e "${YELLOW}[PROD] $1${NC}"; } info() { echo -e "${BLUE}[PROD] $1${NC}"; } error() { echo -e "${RED}[PROD] ERROR: $1${NC}"; exit 1; } # Change to project root cd "$PROJECT_ROOT" # Check environment file check_env() { if [ ! -f "$ENV_FILE" ]; then log "Creating environment file from template..." cp .env.example .env error "Environment file created at $ENV_FILE. Please edit it with your production values before deploying." fi # Check for required variables required_vars=("DATABASE_URL" "REDIS_URL" "JWT_SECRET" "POSTGRES_PASSWORD" "CORS_ORIGIN" "NEXT_PUBLIC_API_BASE") for var in "${required_vars[@]}"; do if ! grep -q "^$var=" "$ENV_FILE" || grep -q "^$var=.*CHANGE_THIS" "$ENV_FILE"; then error "Required environment variable $var is not properly set in $ENV_FILE" fi done } issue_cert() { local domain="$1" local email="$2" if [ -z "$domain" ] || [ -z "$email" ]; then error "Usage: $0 issue-cert " fi log "๐Ÿ” Issuing certificate for $domain ..." docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" run --rm -p 80:80 \ -e CERTBOT_DOMAIN="$domain" -e CERTBOT_EMAIL="$email" certbot \ certonly --webroot -w /var/www/certbot -d "$domain" --agree-tos --no-eff-email log "โœ… Certificate issuance process completed" } # Build production images build_images() { log "๐Ÿ”จ Building production images..." docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" build --no-cache log "โœ… Images built successfully" } # Deploy production environment deploy() { log "๐Ÿš€ Deploying production environment..." check_env build_images # Start database and cache first log "๐Ÿ—„๏ธ Starting database and cache..." docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" up -d database cache # Wait for database log "โณ Waiting for database..." timeout=60 while [ $timeout -gt 0 ]; do if docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" exec -T database pg_isready -U portal -d portal_prod 2>/dev/null; then log "โœ… Database is ready" break fi sleep 2 timeout=$((timeout - 2)) done if [ $timeout -eq 0 ]; then error "Database failed to start within 60 seconds" fi # Run migrations log "๐Ÿ”„ Running database migrations..." docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" run --rm backend pnpm db:migrate || warn "Migration may have failed" # Start application services (proxy + apps) log "๐Ÿš€ Starting application services..." docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" up -d proxy frontend backend # Health checks log "๐Ÿฅ Performing health checks..." sleep 15 if docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" ps | grep -q "unhealthy"; then warn "Some services may not be healthy - check logs" fi log "โœ… Production deployment completed!" log "๐Ÿ”— Frontend: http://localhost:3000" log "๐Ÿ”— Backend API: http://localhost:4000" } # Stop production services stop() { log "โน๏ธ Stopping production services..." docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" down log "โœ… Services stopped" } # Update deployment update() { log "๐Ÿ”„ Updating production deployment..." check_env build_images # Zero-downtime update docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" up -d --force-recreate --no-deps backend frontend log "โœ… Production update completed" } # Show status with health checks status() { log "๐Ÿ“Š Production Services Status:" docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" ps log "๐Ÿฅ Health Status:" docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" exec proxy wget --spider -q http://localhost/healthz && echo "โœ… Proxy/Frontend healthy" || echo "โŒ Proxy/Frontend unhealthy" docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" exec backend wget --spider -q http://localhost:4000/health && echo "โœ… Backend healthy" || echo "โŒ Backend unhealthy" } # Show logs logs() { docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" logs -f "${@:2}" } # Backup database backup() { log "๐Ÿ’พ Creating database backup..." backup_file="backup_$(date +%Y%m%d_%H%M%S).sql" docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" exec -T database pg_dump -U portal portal_prod > "$backup_file" log "โœ… Database backup created: $backup_file" } # Clean up cleanup() { log "๐Ÿงน Cleaning up old containers and images..." docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" down --remove-orphans docker system prune -f docker image prune -f log "โœ… Cleanup completed" } # Main function case "${1:-help}" in "deploy") deploy ;; "start") docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" up -d log "โœ… Production services started" ;; "stop") stop ;; "restart") docker-compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" -p "$PROJECT_NAME" restart log "โœ… Services restarted" ;; "update") update ;; "build") build_images ;; "issue-cert") issue_cert "$2" "$3" ;; "status") status ;; "logs") logs "$@" ;; "backup") backup ;; "cleanup") cleanup ;; "help"|*) echo "๐Ÿš€ Production Environment Manager" echo "" echo "Usage: $0 {command}" echo "" echo "Commands:" echo " deploy - Full deployment (build + start + migrate)" echo " start - Start all production services" echo " stop - Stop all production services" echo " restart - Restart all services" echo " update - Update deployment with new images" echo " build - Build production images" echo " status - Show service status and health" echo " logs - Show service logs" echo " backup - Create database backup" echo " cleanup - Clean up old containers and images" echo " help - Show this help" exit 0 ;; esac