#!/bin/bash set -euo pipefail # ----------------------------- # CONFIG # ----------------------------- NODE_VERSION="v20.19.5" # exact version to avoid surprises NVM_DIR="/root/.nvm" APP_NAME="erpfrontend" # PM2 process name used in ecosystem.cjs MEDIASERVER_NAME="mediaserver" # PM2 process name for media server SRC_DIR="/root/test/workspace/erp-frontend-pipeline-production" STAGE_DIR="/opt/erp-nuxt-frontend-temp" LIVE_DIR="/opt/erp-nuxt-frontend" ROLLBACK_DIR="/opt/erp-nuxt-frontend-rollback" MEDIASERVER_DIR="/opt/mediaserver" DB_FILE="push-subscriptions.db" DB_LIVE_DIR="$LIVE_DIR/data" DB_BACKUP_DIR="/opt/erp-nuxt-frontend-db-backups" ENV_SRC="$SRC_DIR/.env-prod" ENV_DST="$STAGE_DIR/.env" # ----------------------------- # NVM + NODE 20 # ----------------------------- export NVM_DIR="$NVM_DIR" # shellcheck disable=SC1090 [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" nvm install "$NODE_VERSION" nvm alias default "$NODE_VERSION" nvm use "$NODE_VERSION" # Ensure pm2 is installed for THIS Node version npm install -g pm2 NODE_BIN="$NVM_DIR/versions/node/$NODE_VERSION/bin/node" NPM_BIN="$NVM_DIR/versions/node/$NODE_VERSION/bin/npm" PM2_BIN="$NVM_DIR/versions/node/$NODE_VERSION/bin/pm2" echo "Using Node: $("$NODE_BIN" -v)" echo "ABI: $("$NODE_BIN" -p 'process.versions.modules')" echo "PM2: $("$PM2_BIN" -v)" # ----------------------------- # STAGE WORKSPACE # ----------------------------- mkdir -p "$STAGE_DIR" rm -rf "$STAGE_DIR"/* cp -r "$SRC_DIR"/* "$STAGE_DIR"/ cp "$ENV_SRC" "$ENV_DST" # Inject build metadata cd "$SRC_DIR" git_hash=$(git rev-parse --short HEAD || echo "unknown") current_datetime=$(date '+%d.%m.%Y %H:%M') cd "$STAGE_DIR" sed -i "s//$git_hash/g" "$ENV_DST" sed -i "s//$current_datetime/g" "$ENV_DST" # Increase Node heap for Nuxt build (without changing dev scripts) # Only touch the "nuxt build" occurrence if grep -q '"build"' package.json && grep -q 'nuxt build' package.json; then sed -i 's|nuxt build|node --max-old-space-size=6072 node_modules/.bin/nuxt build|g' package.json fi # Clean install + build under Node 20 # Preinstall patch-package (if your repo expects it) $NPM_BIN install patch-package --save-dev --ignore-scripts rm -rf node_modules package-lock.json $NPM_BIN ci || $NPM_BIN install $NPM_BIN run build # ----------------------------- # VERSION SERVICE WORKER CACHE # ----------------------------- echo "Versioning service worker cache with git hash: $git_hash" if [ -f "$STAGE_DIR/.output/public/sw-notifications.js" ]; then # Update cache name to include git hash for automatic cache busting sed -i "s/const CACHE_NAME = 'logship-erp-v1'/const CACHE_NAME = 'logship-erp-$git_hash'/" \ "$STAGE_DIR/.output/public/sw-notifications.js" echo "✅ Service worker cache versioned: logship-erp-$git_hash" else echo "⚠️ Service worker file not found at expected location" fi # ----------------------------- # BACKUP SQLITE DB # ----------------------------- echo "Backing up SQLite database..." mkdir -p "$DB_BACKUP_DIR" if [ -f "$LIVE_DIR/data/$DB_FILE" ]; then backup_filename="push-subscriptions-$(date +%Y%m%d-%H%M%S).db" cp "$LIVE_DIR/data/$DB_FILE" "$DB_BACKUP_DIR/$backup_filename" echo "✅ Database backed up: $DB_BACKUP_DIR/$backup_filename" # keep last 10 cd "$DB_BACKUP_DIR" ls -t push-subscriptions-*.db | tail -n +11 | xargs -r rm else echo "No existing database found - fresh deployment" fi # ----------------------------- # DEPLOY (with rollback) # ----------------------------- rm -rf "$ROLLBACK_DIR" if [ -d "$LIVE_DIR" ]; then cp -rf "$LIVE_DIR" "$ROLLBACK_DIR" fi rm -rf "$LIVE_DIR" mkdir -p "$LIVE_DIR" cp -r "$STAGE_DIR"/. "$LIVE_DIR"/ # ----------------------------- # RESTORE SQLITE DB # ----------------------------- echo "Restoring SQLite database..." mkdir -p "$DB_LIVE_DIR" if [ -f "$ROLLBACK_DIR/data/$DB_FILE" ]; then cp "$ROLLBACK_DIR/data/$DB_FILE" "$DB_LIVE_DIR"/ echo "✅ Database restored from rollback" else echo "No previous database found - will be created on first run" fi chown -R root:root "$DB_LIVE_DIR" chmod 755 "$DB_LIVE_DIR" [ -f "$DB_LIVE_DIR/$DB_FILE" ] && chmod 644 "$DB_LIVE_DIR/$DB_FILE" # ----------------------------- # START WITH PM2 (force Node 20) # ----------------------------- cd "$LIVE_DIR" # Stop old ERP frontend process if exists $PM2_BIN delete "$APP_NAME" || true # Start ERP frontend using Node 20 interpreter $PM2_BIN start ecosystem.config.cjs \ --only "$APP_NAME" \ --update-env \ --interpreter "$NODE_BIN" # Start or restart mediaserver (ensure it's running with correct config) cd "$MEDIASERVER_DIR" if $PM2_BIN describe "$MEDIASERVER_NAME" > /dev/null 2>&1; then echo "Restarting existing mediaserver..." $PM2_BIN restart "$MEDIASERVER_NAME" --update-env --interpreter "$NODE_BIN" else echo "Starting mediaserver for the first time..." $PM2_BIN start ecosystem.config.js --update-env --interpreter "$NODE_BIN" fi # Save PM2 state (both apps) $PM2_BIN save --force # Ensure PM2 resurrects at boot WITH the right PATH/NVM $PM2_BIN startup systemd -u root --hp /root # Create a systemd drop-in to guarantee Node 20 is found on boot mkdir -p /etc/systemd/system/pm2-root.service.d cat >/etc/systemd/system/pm2-root.service.d/override.conf <