854 lines
30 KiB
Bash
Executable File
854 lines
30 KiB
Bash
Executable File
#!/bin/bash
|
||
# ForensicPathways Deployment Script – *ownership-aware* + VISUAL ENHANCED
|
||
# Usage: sudo ./deploy.sh
|
||
|
||
set -e
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# 🎨 VISUAL ENHANCEMENT SYSTEM
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
# Color palette
|
||
declare -r RED='\033[0;31m'
|
||
declare -r GREEN='\033[0;32m'
|
||
declare -r YELLOW='\033[0;33m'
|
||
declare -r BLUE='\033[0;34m'
|
||
declare -r MAGENTA='\033[0;35m'
|
||
declare -r CYAN='\033[0;36m'
|
||
declare -r WHITE='\033[0;37m'
|
||
declare -r BOLD='\033[1m'
|
||
declare -r DIM='\033[2m'
|
||
declare -r ITALIC='\033[3m'
|
||
declare -r UNDERLINE='\033[4m'
|
||
declare -r BLINK='\033[5m'
|
||
declare -r REVERSE='\033[7m'
|
||
declare -r RESET='\033[0m'
|
||
|
||
# Gradient colors
|
||
declare -r GRAD1='\033[38;5;196m' # Bright red
|
||
declare -r GRAD2='\033[38;5;202m' # Orange
|
||
declare -r GRAD3='\033[38;5;208m' # Dark orange
|
||
declare -r GRAD4='\033[38;5;214m' # Yellow orange
|
||
declare -r GRAD5='\033[38;5;220m' # Yellow
|
||
declare -r GRAD6='\033[38;5;118m' # Light green
|
||
declare -r GRAD7='\033[38;5;82m' # Green
|
||
declare -r GRAD8='\033[38;5;51m' # Cyan
|
||
declare -r GRAD9='\033[38;5;33m' # Blue
|
||
declare -r GRAD10='\033[38;5;129m' # Purple
|
||
|
||
# Background colors
|
||
declare -r BG_RED='\033[41m'
|
||
declare -r BG_GREEN='\033[42m'
|
||
declare -r BG_YELLOW='\033[43m'
|
||
declare -r BG_BLUE='\033[44m'
|
||
declare -r BG_MAGENTA='\033[45m'
|
||
declare -r BG_CYAN='\033[46m'
|
||
|
||
# Unicode box drawing
|
||
declare -r BOX_H='═'
|
||
declare -r BOX_V='║'
|
||
declare -r BOX_TL='╔'
|
||
declare -r BOX_TR='╗'
|
||
declare -r BOX_BL='╚'
|
||
declare -r BOX_BR='╝'
|
||
declare -r BOX_T='╦'
|
||
declare -r BOX_B='╩'
|
||
declare -r BOX_L='╠'
|
||
declare -r BOX_R='╣'
|
||
declare -r BOX_C='╬'
|
||
|
||
# Fancy Unicode characters
|
||
declare -r ARROW_R='▶'
|
||
declare -r ARROW_D='▼'
|
||
declare -r DIAMOND='◆'
|
||
declare -r STAR='★'
|
||
declare -r BULLET='●'
|
||
declare -r CIRCLE='◯'
|
||
declare -r SQUARE='▪'
|
||
declare -r TRIANGLE='▲'
|
||
|
||
# Animation frames
|
||
SPINNER_FRAMES=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
|
||
PULSE_FRAMES=('●' '◐' '◑' '◒' '◓' '◔' '◕' '◖' '◗' '◘')
|
||
WAVE_FRAMES=('▁' '▂' '▃' '▄' '▅' '▆' '▇' '█' '▇' '▆' '▅' '▄' '▃' '▂')
|
||
|
||
# Terminal dimensions
|
||
COLS=$(tput cols 2>/dev/null || echo 80)
|
||
LINES=$(tput lines 2>/dev/null || echo 24)
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# 🎯 VISUAL FUNCTIONS
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
print_gradient_text() {
|
||
local text="$1"
|
||
local colors=("$GRAD1" "$GRAD2" "$GRAD3" "$GRAD4" "$GRAD5" "$GRAD6" "$GRAD7" "$GRAD8" "$GRAD9" "$GRAD10")
|
||
local length=${#text}
|
||
local color_count=${#colors[@]}
|
||
|
||
for ((i=0; i<length; i++)); do
|
||
local color_idx=$((i * color_count / length))
|
||
printf "${colors[$color_idx]}${text:$i:1}"
|
||
done
|
||
printf "$RESET"
|
||
}
|
||
|
||
animate_text() {
|
||
local text="$1"
|
||
local delay="${2:-0.03}"
|
||
|
||
for ((i=0; i<=${#text}; i++)); do
|
||
printf "\r${CYAN}${text:0:$i}${RESET}"
|
||
sleep "$delay"
|
||
done
|
||
echo
|
||
}
|
||
|
||
draw_box() {
|
||
local title="$1"
|
||
local content="$2"
|
||
local width=${3:-$((COLS-4))}
|
||
local color="${4:-$CYAN}"
|
||
|
||
# Top border
|
||
printf "${color}${BOX_TL}"
|
||
for ((i=0; i<width-2; i++)); do printf "${BOX_H}"; done
|
||
printf "${BOX_TR}${RESET}\n"
|
||
|
||
# Title line
|
||
if [ -n "$title" ]; then
|
||
local title_len=${#title}
|
||
local padding=$(((width-title_len-2)/2))
|
||
printf "${color}${BOX_V}${RESET}"
|
||
for ((i=0; i<padding; i++)); do printf " "; done
|
||
printf "${BOLD}${WHITE}$title${RESET}"
|
||
for ((i=0; i<width-title_len-padding-2; i++)); do printf " "; done
|
||
printf "${color}${BOX_V}${RESET}\n"
|
||
|
||
# Separator
|
||
printf "${color}${BOX_L}"
|
||
for ((i=0; i<width-2; i++)); do printf "${BOX_H}"; done
|
||
printf "${BOX_R}${RESET}\n"
|
||
fi
|
||
|
||
# Content lines
|
||
while IFS= read -r line; do
|
||
local line_len=${#line}
|
||
printf "${color}${BOX_V}${RESET} %-$((width-4))s ${color}${BOX_V}${RESET}\n" "$line"
|
||
done <<< "$content"
|
||
|
||
# Bottom border
|
||
printf "${color}${BOX_BL}"
|
||
for ((i=0; i<width-2; i++)); do printf "${BOX_H}"; done
|
||
printf "${BOX_BR}${RESET}\n"
|
||
}
|
||
|
||
progress_bar() {
|
||
local current="$1"
|
||
local total="$2"
|
||
local width="${3:-50}"
|
||
local label="$4"
|
||
|
||
local percentage=$((current * 100 / total))
|
||
local filled=$((current * width / total))
|
||
local empty=$((width - filled))
|
||
|
||
printf "\r${BOLD}${label}${RESET} ["
|
||
|
||
# Filled portion with gradient
|
||
for ((i=0; i<filled; i++)); do
|
||
local color_idx=$((i * 10 / width))
|
||
case $color_idx in
|
||
0) printf "${GRAD1}█${RESET}" ;;
|
||
1) printf "${GRAD2}█${RESET}" ;;
|
||
2) printf "${GRAD3}█${RESET}" ;;
|
||
3) printf "${GRAD4}█${RESET}" ;;
|
||
4) printf "${GRAD5}█${RESET}" ;;
|
||
5) printf "${GRAD6}█${RESET}" ;;
|
||
6) printf "${GRAD7}█${RESET}" ;;
|
||
7) printf "${GRAD8}█${RESET}" ;;
|
||
8) printf "${GRAD9}█${RESET}" ;;
|
||
*) printf "${GRAD10}█${RESET}" ;;
|
||
esac
|
||
done
|
||
|
||
# Empty portion
|
||
for ((i=0; i<empty; i++)); do
|
||
printf "${DIM}░${RESET}"
|
||
done
|
||
|
||
printf "] ${BOLD}${percentage}%%${RESET}"
|
||
}
|
||
|
||
spinner() {
|
||
local pid=$1
|
||
local message="$2"
|
||
local frame=0
|
||
|
||
while kill -0 $pid 2>/dev/null; do
|
||
printf "\r${CYAN}${SPINNER_FRAMES[$frame]}${RESET} ${message}"
|
||
frame=$(((frame + 1) % ${#SPINNER_FRAMES[@]}))
|
||
sleep 0.1
|
||
done
|
||
printf "\r${GREEN}✓${RESET} ${message}\n"
|
||
}
|
||
|
||
pulsing_dots() {
|
||
local count="${1:-5}"
|
||
local cycles="${2:-3}"
|
||
|
||
for ((c=0; c<cycles; c++)); do
|
||
for frame in "${PULSE_FRAMES[@]}"; do
|
||
printf "\r${MAGENTA}"
|
||
for ((i=0; i<count; i++)); do
|
||
printf "$frame "
|
||
done
|
||
printf "${RESET}"
|
||
sleep 0.1
|
||
done
|
||
done
|
||
}
|
||
|
||
wave_animation() {
|
||
local width="${1:-$((COLS/2))}"
|
||
local cycles="${2:-2}"
|
||
|
||
for ((c=0; c<cycles; c++)); do
|
||
for frame in "${WAVE_FRAMES[@]}"; do
|
||
printf "\r${CYAN}"
|
||
for ((i=0; i<width; i++)); do
|
||
printf "$frame"
|
||
done
|
||
printf "${RESET}"
|
||
sleep 0.05
|
||
done
|
||
done
|
||
echo
|
||
}
|
||
|
||
celebrate() {
|
||
local width=$((COLS-10))
|
||
|
||
# Fireworks effect
|
||
for ((i=0; i<5; i++)); do
|
||
printf "\r"
|
||
for ((j=0; j<width; j++)); do
|
||
case $((RANDOM % 10)) in
|
||
0) printf "${GRAD1}*${RESET}" ;;
|
||
1) printf "${GRAD3}•${RESET}" ;;
|
||
2) printf "${GRAD5}+${RESET}" ;;
|
||
3) printf "${GRAD7}×${RESET}" ;;
|
||
4) printf "${GRAD9}◆${RESET}" ;;
|
||
*) printf " " ;;
|
||
esac
|
||
done
|
||
sleep 0.2
|
||
done
|
||
echo
|
||
}
|
||
|
||
typewriter() {
|
||
local text="$1"
|
||
local delay="${2:-0.02}"
|
||
local color="${3:-$GREEN}"
|
||
|
||
printf "${color}"
|
||
for ((i=0; i<${#text}; i++)); do
|
||
printf "${text:$i:1}"
|
||
sleep "$delay"
|
||
done
|
||
printf "${RESET}\n"
|
||
}
|
||
|
||
fancy_header() {
|
||
clear
|
||
local title="$1"
|
||
local subtitle="$2"
|
||
|
||
# Calculate centering
|
||
local title_len=${#title}
|
||
local subtitle_len=${#subtitle}
|
||
local box_width=$((COLS > 80 ? 80 : COLS-4))
|
||
local title_padding=$(((box_width-title_len)/2))
|
||
local subtitle_padding=$(((box_width-subtitle_len)/2))
|
||
|
||
echo
|
||
# Top gradient border
|
||
printf "${BOLD}"
|
||
for ((i=0; i<box_width; i++)); do
|
||
local color_idx=$((i * 10 / box_width))
|
||
case $color_idx in
|
||
0|1) printf "${GRAD1}${BOX_H}${RESET}" ;;
|
||
2|3) printf "${GRAD3}${BOX_H}${RESET}" ;;
|
||
4|5) printf "${GRAD5}${BOX_H}${RESET}" ;;
|
||
6|7) printf "${GRAD7}${BOX_H}${RESET}" ;;
|
||
*) printf "${GRAD9}${BOX_H}${RESET}" ;;
|
||
esac
|
||
done
|
||
echo
|
||
|
||
# Title line
|
||
printf "${GRAD1}${BOX_V}${RESET}"
|
||
for ((i=0; i<title_padding; i++)); do printf " "; done
|
||
print_gradient_text "$title"
|
||
for ((i=0; i<box_width-title_len-title_padding-2; i++)); do printf " "; done
|
||
printf "${GRAD1}${BOX_V}${RESET}\n"
|
||
|
||
# Subtitle line
|
||
if [ -n "$subtitle" ]; then
|
||
printf "${GRAD3}${BOX_V}${RESET}"
|
||
for ((i=0; i<subtitle_padding; i++)); do printf " "; done
|
||
printf "${ITALIC}${DIM}$subtitle${RESET}"
|
||
for ((i=0; i<box_width-subtitle_len-subtitle_padding-2; i++)); do printf " "; done
|
||
printf "${GRAD3}${BOX_V}${RESET}\n"
|
||
fi
|
||
|
||
# Bottom gradient border
|
||
printf "${BOLD}"
|
||
for ((i=0; i<box_width; i++)); do
|
||
local color_idx=$((i * 10 / box_width))
|
||
case $color_idx in
|
||
0|1) printf "${GRAD1}${BOX_H}${RESET}" ;;
|
||
2|3) printf "${GRAD3}${BOX_H}${RESET}" ;;
|
||
4|5) printf "${GRAD5}${BOX_H}${RESET}" ;;
|
||
6|7) printf "${GRAD7}${BOX_H}${RESET}" ;;
|
||
*) printf "${GRAD9}${BOX_H}${RESET}" ;;
|
||
esac
|
||
done
|
||
echo
|
||
echo
|
||
}
|
||
|
||
section_header() {
|
||
local section_num="$1"
|
||
local title="$2"
|
||
local icon="$3"
|
||
|
||
echo
|
||
printf "${BOLD}${BG_BLUE}${WHITE} PHASE $section_num ${RESET} "
|
||
printf "${BOLD}${BLUE}$icon $title${RESET}\n"
|
||
|
||
# Animated underline
|
||
printf "${BLUE}"
|
||
for ((i=0; i<$((${#title}+10)); i++)); do
|
||
printf "▄"
|
||
sleep 0.01
|
||
done
|
||
printf "${RESET}\n"
|
||
}
|
||
|
||
status_ok() {
|
||
printf "${GREEN}${BOLD}✓${RESET} ${1}\n"
|
||
}
|
||
|
||
status_error() {
|
||
printf "${RED}${BOLD}✗${RESET} ${1}\n"
|
||
}
|
||
|
||
status_warning() {
|
||
printf "${YELLOW}${BOLD}⚠${RESET} ${1}\n"
|
||
}
|
||
|
||
status_info() {
|
||
printf "${CYAN}${BOLD}ℹ${RESET} ${1}\n"
|
||
}
|
||
|
||
status_working() {
|
||
printf "${MAGENTA}${BOLD}◐${RESET} ${1}"
|
||
}
|
||
|
||
animated_countdown() {
|
||
local seconds="$1"
|
||
local message="$2"
|
||
|
||
for ((i=seconds; i>0; i--)); do
|
||
printf "\r${YELLOW}${BOLD}⏳ $message in ${i}s...${RESET}"
|
||
sleep 1
|
||
done
|
||
printf "\r${GREEN}${BOLD}🚀 $message${RESET} \n"
|
||
}
|
||
|
||
matrix_rain() {
|
||
local duration="${1:-2}"
|
||
local chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789@#$%^&*()_+-=[]{}|;:,.<>?"
|
||
|
||
for ((i=0; i<duration*10; i++)); do
|
||
printf "\r${GREEN}"
|
||
for ((j=0; j<$((COLS/3)); j++)); do
|
||
printf "${chars:$((RANDOM % ${#chars})):1}"
|
||
done
|
||
printf "${RESET}"
|
||
sleep 0.1
|
||
done
|
||
echo
|
||
}
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# 🚀 MAIN SCRIPT VARIABLES
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
WEBROOT="/var/www/forensic-pathways"
|
||
LOG_DIR="$WEBROOT/logs"
|
||
DATA_DIR="$WEBROOT/data"
|
||
UPLOADS_DIR="$WEBROOT/public/uploads"
|
||
|
||
# Get original user who called sudo
|
||
ORIGINAL_USER="${SUDO_USER:-$USER}"
|
||
ORIGINAL_HOME=$(eval echo "~$ORIGINAL_USER")
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# 🎬 SPECTACULAR OPENING SEQUENCE
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
# Terminal setup
|
||
tput civis # Hide cursor
|
||
|
||
# ASCII Art Banner
|
||
fancy_header "FORENSIC PATHWAYS DEPLOYMENT" "Advanced Visual Enhancement System"
|
||
|
||
# Matrix effect intro
|
||
printf "${DIM}${GREEN}Initializing deployment matrix...${RESET}\n"
|
||
matrix_rain 1
|
||
|
||
# System information display
|
||
draw_box "DEPLOYMENT PARAMETERS" "$(cat << EOF
|
||
Timestamp: $(date '+%Y-%m-%d %H:%M:%S')
|
||
Original User: $ORIGINAL_USER
|
||
Working Directory: $(pwd)
|
||
Target Webroot: $WEBROOT
|
||
Terminal Size: ${COLS}x${LINES}
|
||
EOF)" 60 "$MAGENTA"
|
||
|
||
sleep 1
|
||
|
||
# Animated countdown
|
||
animated_countdown 3 "Starting deployment"
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# 🔒 PHASE 0: SAFETY CHECKS
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
section_header "0" "SECURITY & SAFETY VALIDATION" "🔒"
|
||
|
||
status_working "Verifying root privileges"
|
||
pulsing_dots 3 1
|
||
if [ "$EUID" -ne 0 ]; then
|
||
status_error "Script must be run as root (use sudo)"
|
||
echo
|
||
printf "${RED}${BOLD}${BG_YELLOW} DEPLOYMENT TERMINATED ${RESET}\n"
|
||
exit 1
|
||
fi
|
||
status_ok "Root privileges confirmed"
|
||
|
||
status_working "Validating project structure"
|
||
pulsing_dots 3 1
|
||
if [ ! -f "package.json" ] || [ ! -f "astro.config.mjs" ]; then
|
||
status_error "Must run from ForensicPathways project root"
|
||
status_info "Current directory: $(pwd)"
|
||
status_info "Files found: $(ls -la)"
|
||
echo
|
||
printf "${RED}${BOLD}${BG_YELLOW} DEPLOYMENT TERMINATED ${RESET}\n"
|
||
exit 1
|
||
fi
|
||
status_ok "Project structure validated"
|
||
|
||
# Security scan animation
|
||
printf "${CYAN}${BOLD}🔍 Running security scan${RESET}"
|
||
for i in {1..20}; do
|
||
printf "${CYAN}.${RESET}"
|
||
sleep 0.05
|
||
done
|
||
echo
|
||
status_ok "Security scan completed - all clear"
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# 🔧 PHASE 1: NPM BUILD SYSTEM
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
find_and_use_npm() {
|
||
section_header "1" "BUILD SYSTEM INITIALIZATION" "🔧"
|
||
|
||
printf "${CYAN}${BOLD}🔍 Scanning for npm installation...${RESET}\n"
|
||
wave_animation 30 1
|
||
|
||
# A) system-wide npm
|
||
if command -v npm &>/dev/null; then
|
||
status_ok "System npm located: $(which npm)"
|
||
|
||
printf "${MAGENTA}${BOLD}📦 Installing dependencies${RESET}"
|
||
{
|
||
sudo -u "$ORIGINAL_USER" npm install > /tmp/npm_install.log 2>&1 &
|
||
spinner $! "Installing dependencies"
|
||
}
|
||
|
||
printf "${MAGENTA}${BOLD}🏗️ Building application${RESET}"
|
||
{
|
||
sudo -u "$ORIGINAL_USER" npm run build > /tmp/npm_build.log 2>&1 &
|
||
spinner $! "Building application"
|
||
}
|
||
|
||
return 0
|
||
fi
|
||
|
||
# B) nvm-managed npm
|
||
printf "${YELLOW}🔍 Scanning for nvm installation...${RESET}\n"
|
||
if sudo -u "$ORIGINAL_USER" bash -c "
|
||
export NVM_DIR='$ORIGINAL_HOME/.nvm'
|
||
[ -s \"\$NVM_DIR/nvm.sh\" ] && source \"\$NVM_DIR/nvm.sh\"
|
||
[ -s '$ORIGINAL_HOME/.bashrc' ] && source '$ORIGINAL_HOME/.bashrc'
|
||
command -v npm &>/dev/null
|
||
"; then
|
||
status_ok "NVM-managed npm located"
|
||
|
||
printf "${MAGENTA}${BOLD}📦 Installing dependencies with nvm${RESET}"
|
||
{
|
||
sudo -u "$ORIGINAL_USER" bash -c "
|
||
export NVM_DIR='$ORIGINAL_HOME/.nvm'
|
||
[ -s \"\$NVM_DIR/nvm.sh\" ] && source \"\$NVM_DIR/nvm.sh\"
|
||
[ -s '$ORIGINAL_HOME/.bashrc' ] && source '$ORIGINAL_HOME/.bashrc'
|
||
npm install > /tmp/npm_install.log 2>&1
|
||
npm run build > /tmp/npm_build.log 2>&1
|
||
" &
|
||
spinner $! "Building with nvm"
|
||
}
|
||
|
||
return 0
|
||
fi
|
||
|
||
# C) Installation instructions with fancy formatting
|
||
draw_box "NPM NOT FOUND" "$(cat << 'EOF'
|
||
Please install Node.js and npm first:
|
||
|
||
Option 1 (apt):
|
||
sudo apt update && sudo apt install nodejs npm
|
||
|
||
Option 2 (NodeSource – recommended):
|
||
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
||
sudo apt-get install -y nodejs
|
||
|
||
Option 3 (nvm – as user):
|
||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash
|
||
source ~/.bashrc && nvm install 20
|
||
EOF)" 70 "$RED"
|
||
|
||
return 1
|
||
}
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# 🏗️ PHASE 2: BUILD ORCHESTRATION
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
section_header "2" "BUILD ORCHESTRATION" "🏗️"
|
||
|
||
if [ ! -d "dist" ] || [ ! "$(ls -A dist 2>/dev/null)" ]; then
|
||
status_info "No dist/ directory found"
|
||
typewriter "Initiating build process..." 0.05 "$YELLOW"
|
||
find_and_use_npm || exit 1
|
||
else
|
||
status_ok "Existing dist/ directory detected"
|
||
echo
|
||
printf "${YELLOW}${BOLD}🤔 Rebuild application? ${RESET}${DIM}(y/N):${RESET} "
|
||
read -r REPLY
|
||
echo
|
||
|
||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||
typewriter "Rebuilding application..." 0.05 "$CYAN"
|
||
find_and_use_npm || {
|
||
status_warning "Build failed, using existing dist/"
|
||
}
|
||
else
|
||
typewriter "Using existing build..." 0.05 "$GREEN"
|
||
fi
|
||
fi
|
||
|
||
# Build validation with dramatic effect
|
||
printf "${CYAN}${BOLD}🔍 Validating build output${RESET}"
|
||
pulsing_dots 8 2
|
||
if [ ! -d "dist" ] || [ ! "$(ls -A dist 2>/dev/null)" ]; then
|
||
echo
|
||
draw_box "BUILD FAILURE" "Build failed or dist/ directory is empty" 50 "$RED"
|
||
exit 1
|
||
fi
|
||
|
||
# Build success celebration
|
||
echo
|
||
printf "${GREEN}${BOLD}${BG_GREEN}${WHITE} BUILD SUCCESS ${RESET}\n"
|
||
celebrate
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# 📁 PHASE 3: INFRASTRUCTURE SETUP
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
section_header "3" "INFRASTRUCTURE PROVISIONING" "📁"
|
||
|
||
status_working "Creating directory structure"
|
||
{
|
||
mkdir -p "$WEBROOT" "$LOG_DIR" "$DATA_DIR" "$UPLOADS_DIR" "$WEBROOT/src/data" &
|
||
spinner $! "Provisioning directories"
|
||
}
|
||
|
||
# Directory creation progress
|
||
DIRS=("$WEBROOT" "$LOG_DIR" "$DATA_DIR" "$UPLOADS_DIR" "$WEBROOT/src/data")
|
||
for i in "${!DIRS[@]}"; do
|
||
progress_bar $((i+1)) ${#DIRS[@]} 40 "Creating directories"
|
||
sleep 0.1
|
||
done
|
||
echo
|
||
status_ok "Directory infrastructure ready"
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# 🚀 PHASE 4: APPLICATION DEPLOYMENT
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
section_header "4" "APPLICATION DEPLOYMENT" "🚀"
|
||
|
||
# File copy with visual progress
|
||
status_working "Deploying application files"
|
||
TOTAL_FILES=$(find dist -type f | wc -l)
|
||
COPIED=0
|
||
|
||
{
|
||
cp -r dist/. "$WEBROOT/" &
|
||
PID=$!
|
||
|
||
while kill -0 $PID 2>/dev/null; do
|
||
CURRENT_FILES=$(find "$WEBROOT" -type f 2>/dev/null | wc -l)
|
||
if [ $CURRENT_FILES -gt $COPIED ]; then
|
||
COPIED=$CURRENT_FILES
|
||
progress_bar $COPIED $TOTAL_FILES 50 "Copying files"
|
||
fi
|
||
sleep 0.1
|
||
done
|
||
|
||
wait $PID
|
||
progress_bar $TOTAL_FILES $TOTAL_FILES 50 "Copying files"
|
||
}
|
||
|
||
echo
|
||
SIZE=$(du -sh dist | cut -f1)
|
||
status_ok "Application deployed ($SIZE, $TOTAL_FILES files)"
|
||
|
||
# Package.json copy with flair
|
||
printf "${MAGENTA}${BOLD}📋 Deploying package.json${RESET}"
|
||
pulsing_dots 3 1
|
||
cp package.json "$WEBROOT/"
|
||
status_ok "Package configuration deployed"
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# ⚙️ PHASE 5: RUNTIME DEPENDENCY MANAGEMENT
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
section_header "5" "RUNTIME DEPENDENCY RESOLUTION" "⚙️"
|
||
|
||
typewriter "Transferring ownership for dependency installation..." 0.03 "$YELLOW"
|
||
chown -R "$ORIGINAL_USER":"$ORIGINAL_USER" "$WEBROOT"
|
||
|
||
printf "${CYAN}${BOLD}📦 Installing runtime dependencies${RESET}\n"
|
||
{
|
||
sudo -u "$ORIGINAL_USER" bash -c '
|
||
set -e
|
||
cd "'"$WEBROOT"'"
|
||
if command -v npm &>/dev/null; then
|
||
npm install --production > /tmp/runtime_deps.log 2>&1
|
||
else
|
||
export NVM_DIR="'$ORIGINAL_HOME'/.nvm"
|
||
[ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh"
|
||
[ -s "'$ORIGINAL_HOME'/.bashrc" ] && source "'$ORIGINAL_HOME'/.bashrc"
|
||
npm install --production > /tmp/runtime_deps.log 2>&1
|
||
fi
|
||
' &
|
||
spinner $! "Installing runtime dependencies"
|
||
}
|
||
|
||
# Dependency success effect
|
||
printf "${GREEN}${BOLD}🎯 Dependencies locked and loaded!${RESET}\n"
|
||
wave_animation 40 1
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# 🗃️ PHASE 6: DATA & CONTENT ORCHESTRATION
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
section_header "6" "DATA & CONTENT ORCHESTRATION" "🗃️"
|
||
|
||
status_working "Deploying core data structures"
|
||
if [ -f "src/data/tools.yaml" ]; then
|
||
cp src/data/tools.yaml "$WEBROOT/src/data/"
|
||
TOOL_COUNT=$(grep -c "^ - name:" "src/data/tools.yaml" || echo "unknown")
|
||
status_ok "Tools database deployed ($TOOL_COUNT tools)"
|
||
else
|
||
status_error "Critical file missing: src/data/tools.yaml"
|
||
exit 1
|
||
fi
|
||
|
||
status_working "Deploying knowledge base"
|
||
if [ -d "src/content/knowledgebase" ]; then
|
||
mkdir -p "$WEBROOT/src/content"
|
||
cp -r src/content/knowledgebase "$WEBROOT/src/content/"
|
||
KB_COUNT=$(find src/content/knowledgebase -name "*.md" 2>/dev/null | wc -l)
|
||
status_ok "Knowledge base deployed ($KB_COUNT articles)"
|
||
|
||
# Knowledge base visualization
|
||
printf "${BLUE}${BOLD}📚 Knowledge Base Structure:${RESET}\n"
|
||
find src/content/knowledgebase -name "*.md" | head -5 | while read -r file; do
|
||
printf " ${CYAN}${DIAMOND}${RESET} ${file#src/content/knowledgebase/}\n"
|
||
done
|
||
if [ $KB_COUNT -gt 5 ]; then
|
||
printf " ${DIM}... and $((KB_COUNT-5)) more articles${RESET}\n"
|
||
fi
|
||
else
|
||
status_warning "No knowledge base directory found (optional)"
|
||
fi
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# ⚙️ PHASE 7: ENVIRONMENT CONFIGURATION
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
section_header "7" "ENVIRONMENT CONFIGURATION" "⚙️"
|
||
|
||
printf "${YELLOW}${BOLD}🔧 Configuring environment${RESET}"
|
||
pulsing_dots 5 1
|
||
cp .env.example "$WEBROOT/.env"
|
||
status_ok "Environment template deployed"
|
||
|
||
draw_box "CONFIGURATION NOTICE" "IMPORTANT: Edit $WEBROOT/.env with your configuration" 60 "$YELLOW"
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# 📝 PHASE 8: LOGGING INFRASTRUCTURE
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
section_header "8" "LOGGING INFRASTRUCTURE" "📝"
|
||
|
||
LOG_FILES=("access.log" "error.log" "ai-pipeline.log")
|
||
for i in "${!LOG_FILES[@]}"; do
|
||
progress_bar $((i+1)) ${#LOG_FILES[@]} 30 "Creating log files"
|
||
touch "$LOG_DIR/${LOG_FILES[$i]}"
|
||
sleep 0.2
|
||
done
|
||
echo
|
||
status_ok "Logging infrastructure established"
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# 🔐 PHASE 9: PERMISSION MATRIX
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
section_header "9" "PERMISSION MATRIX CONFIGURATION" "🔐"
|
||
|
||
typewriter "Implementing security hardening..." 0.04 "$RED"
|
||
|
||
# Permission operations with progress
|
||
PERM_OPERATIONS=(
|
||
"chown -R www-data:www-data $WEBROOT"
|
||
"chmod -R 755 $WEBROOT"
|
||
"chmod 600 $WEBROOT/.env"
|
||
"chmod 755 $DATA_DIR $UPLOADS_DIR $LOG_DIR"
|
||
"chmod 644 $LOG_DIR/*.log"
|
||
)
|
||
|
||
for i in "${!PERM_OPERATIONS[@]}"; do
|
||
progress_bar $((i+1)) ${#PERM_OPERATIONS[@]} 45 "Setting permissions"
|
||
eval "${PERM_OPERATIONS[$i]}"
|
||
sleep 0.3
|
||
done
|
||
echo
|
||
|
||
if [ -f "$WEBROOT/server/entry.mjs" ]; then
|
||
chmod 755 "$WEBROOT/server/entry.mjs"
|
||
status_ok "Server entry point permissions configured"
|
||
fi
|
||
|
||
status_ok "Permission matrix locked down"
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# ✅ PHASE 10: DEPLOYMENT VALIDATION
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
section_header "10" "DEPLOYMENT VALIDATION MATRIX" "✅"
|
||
|
||
VALIDATION_ERRORS=0
|
||
VALIDATIONS=(
|
||
"$WEBROOT/.env|Environment configuration"
|
||
"$WEBROOT/src/data/tools.yaml|Tools database"
|
||
)
|
||
|
||
# Check application files
|
||
if [ -f "$WEBROOT/index.html" ] || [ -d "$WEBROOT/server" ]; then
|
||
VALIDATIONS+=("$WEBROOT/index.html|Application files")
|
||
fi
|
||
|
||
echo
|
||
printf "${CYAN}${BOLD}🔍 Running comprehensive validation suite...${RESET}\n"
|
||
|
||
for validation in "${VALIDATIONS[@]}"; do
|
||
IFS='|' read -r file desc <<< "$validation"
|
||
|
||
printf "${YELLOW}Testing: $desc${RESET}"
|
||
pulsing_dots 3 1
|
||
|
||
if [ -f "$file" ] || [ -d "$file" ]; then
|
||
status_ok "$desc validated"
|
||
else
|
||
status_error "$desc missing"
|
||
((VALIDATION_ERRORS++))
|
||
fi
|
||
done
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# 🎊 FINAL RESULTS SPECTACULAR
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
echo
|
||
if [ $VALIDATION_ERRORS -eq 0 ]; then
|
||
# Success celebration sequence
|
||
printf "${GREEN}${BOLD}${BG_GREEN}${WHITE}"
|
||
printf "%*s" $((COLS)) | tr ' ' '='
|
||
printf "${RESET}\n"
|
||
|
||
# Animated success banner
|
||
fancy_header "🎉 DEPLOYMENT SUCCESSFUL! 🎉" "All systems operational"
|
||
|
||
# Fireworks celebration
|
||
celebrate
|
||
|
||
# Next steps in a beautiful box
|
||
draw_box "🎯 MISSION BRIEFING - NEXT STEPS" "$(cat << EOF
|
||
1. 🔧 Configure environment variables in $WEBROOT/.env
|
||
• Set PUBLIC_BASE_URL, AI service endpoints
|
||
• Configure AUTH_SECRET and database connections
|
||
|
||
2. 🔄 Restart system services:
|
||
sudo systemctl restart forensic-pathways
|
||
sudo systemctl reload nginx
|
||
|
||
3. 🔍 Monitor system health:
|
||
sudo systemctl status forensic-pathways
|
||
sudo tail -f $LOG_DIR/error.log
|
||
|
||
🌐 Application fortress established at: $WEBROOT
|
||
🎯 Ready for production deployment!
|
||
EOF)" 70 "$GREEN"
|
||
|
||
# Final celebration
|
||
echo
|
||
printf "${BOLD}"
|
||
print_gradient_text "🚀 FORENSIC PATHWAYS DEPLOYMENT COMPLETE 🚀"
|
||
echo
|
||
|
||
else
|
||
# Error summary
|
||
draw_box "⚠️ DEPLOYMENT COMPLETED WITH WARNINGS" "Found $VALIDATION_ERRORS validation issues
|
||
Please review and resolve before proceeding" 60 "$YELLOW"
|
||
fi
|
||
|
||
# Final timestamp with style
|
||
echo
|
||
printf "${DIM}${ITALIC}Deployment completed at: "
|
||
printf "${BOLD}$(date '+%Y-%m-%d %H:%M:%S')${RESET}\n"
|
||
|
||
# Restore cursor
|
||
tput cnorm
|
||
|
||
# Final matrix effect fade-out
|
||
printf "${DIM}${GREEN}Deployment matrix shutting down...${RESET}\n"
|
||
matrix_rain 1
|
||
|
||
echo |