#!/usr/bin/env bash # # LuckyChit deployment — backend (Node/PM2) + frontend (Flutter web + PM2). # # Usage: # ./scripts/deploy.sh # backend + frontend # ./scripts/deploy.sh backend # API only # ./scripts/deploy.sh frontend # Flutter web only # ./scripts/deploy.sh backend --force # e.g. wipe node_modules / flutter clean # # Env (optional): # LUCKYCHIT_ROOT Repo root (default: /home/luckychit/apps/chitfund) # DEPLOY_BRANCH Git branch to fast-forward to (default: prod_i8n) set -eo pipefail PROJECT_DIR="${LUCKYCHIT_ROOT:-/home/luckychit/apps/chitfund}" BRANCH="${DEPLOY_BRANCH:-prod_i8n}" FORCE_REBUILD=false TARGET="" usage() { echo "Usage: $0 [backend|frontend] [--force]" echo " (no args) deploy backend and frontend" echo " backend deploy Node API only (pm2: luckychit-api)" echo " frontend build Flutter web + restart static server (pm2: luckychit-web)" echo " --force aggressive clean (backend: rm node_modules; frontend: flutter clean)" exit 1 } for arg in "$@"; do case "$arg" in --force) FORCE_REBUILD=true ;; backend|frontend) if [ -n "$TARGET" ] && [ "$TARGET" != "$arg" ]; then echo "Error: specify only one of backend or frontend." usage fi TARGET="$arg" ;; -h|--help) usage ;; *) echo "Unknown argument: $arg" usage ;; esac done run_backend() { [ "$TARGET" = "" ] || [ "$TARGET" = "backend" ] } run_frontend() { [ "$TARGET" = "" ] || [ "$TARGET" = "frontend" ] } cd "$PROJECT_DIR" echo "LuckyChit deployment" echo "====================" echo "Root: $PROJECT_DIR" echo "Branch: $BRANCH" echo "Target: ${TARGET:-backend+frontend} force=$FORCE_REBUILD" echo "" if [ "$(id -u)" -eq 0 ]; then echo "Warning: running as root. Prefer a normal user so Flutter/npm caches stay consistent." echo "" fi echo "Pulling latest code..." git fetch origin "$BRANCH" if ! git rev-parse --verify "refs/remotes/origin/$BRANCH" >/dev/null 2>&1; then echo "Error: origin/$BRANCH not found. Fetch failed or branch missing on remote." exit 1 fi git checkout "$BRANCH" git merge --ff-only "origin/$BRANCH" echo "" if run_backend; then echo "Deploying backend..." cd "$PROJECT_DIR/backend" if [ "$FORCE_REBUILD" = true ]; then echo "Force rebuild: removing node_modules and lockfile..." rm -rf node_modules package-lock.json fi if [ -f package-lock.json ]; then npm ci else npm install fi if pm2 describe luckychit-api >/dev/null 2>&1; then pm2 restart luckychit-api --update-env else pm2 start ecosystem.config.js --env production fi echo "Backend done." echo "" fi if run_frontend; then echo "Deploying frontend (Flutter web)..." cd "$PROJECT_DIR/luckychit" if [ "$FORCE_REBUILD" = true ]; then echo "Force rebuild: flutter clean..." flutter clean rm -rf .dart_tool build fi flutter pub get if [ -f tool/sync_l10n.mjs ]; then node tool/sync_l10n.mjs fi BUILD_NUMBER=$(date +%s) flutter build web --release --pwa-strategy=none --build-number="$BUILD_NUMBER" echo "Build number: $BUILD_NUMBER" # Name must match luckychit/ecosystem.config.js (app name: luckychit-web) if pm2 describe luckychit-web >/dev/null 2>&1; then pm2 restart luckychit-web --update-env else pm2 start ecosystem.config.js --env production fi echo "Frontend done." echo "" fi echo "PM2 status:" pm2 status echo "" echo "Deployment complete." echo "Smoke tests:" echo " curl -sf http://localhost:3000/health || curl -sf http://localhost:3000/api/health" echo " curl -sfI http://localhost:8080/" echo "Logs: pm2 logs --lines 30"