lilith-platform.live/deployments/@domains/quinn.admin-api/deploy.sh

107 lines
4.9 KiB
Bash
Executable file

#!/usr/bin/env bash
# =============================================================================
# Deploy quinn.admin-api to black (canonical mesh-only origin).
#
# Targets BLACK, not vps-0. The vps-0:quinn.admin deploy is the legacy path
# being retired by this migration. See ~/.claude/plans/quiet-pulsing-anchor.md.
#
# Assumes the API monolith + admin frontend have already been built (CI does
# this in earlier workflow steps). Pass --skip-build to skip the local build
# fallback when running outside CI.
# =============================================================================
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../../../" && pwd)"
REMOTE="${REMOTE_HOST:-black}"
# shellcheck source=../../ci/local-remote.sh
source "$REPO_ROOT/deployments/ci/local-remote.sh"
init_deploy_local
REMOTE_API="/opt/quinn-admin-api"
REMOTE_BACKUPS_API="/opt/quinn-admin-api.deploy-backups"
API_BUNDLE="codebase/@features/api/dist/server.node.js"
TIMESTAMP="$(date '+%Y%m%d_%H%M%S')"
BACKUP_API="${REMOTE_BACKUPS_API}/${TIMESTAMP}"
SERVICE_NAME="quinn-admin-api.service"
# ─── --rollback ─────────────────────────────────────────────────────────────
if [[ "${1:-}" == "--rollback" ]]; then
echo "==> [ROLLBACK] Restoring previous quinn.admin-api on ${REMOTE}..."
run_remote <<'ENDSSH'
REMOTE_BACKUPS_API="/opt/quinn-admin-api.deploy-backups"
REMOTE_API="/opt/quinn-admin-api"
latest_api="$(ls -1t "$REMOTE_BACKUPS_API" 2>/dev/null | head -1)"
if [[ -z "$latest_api" ]]; then
echo "ERROR: no API backups found." >&2; exit 1
fi
echo " Restoring API from $REMOTE_BACKUPS_API/$latest_api ..."
rsync -a --delete "$REMOTE_BACKUPS_API/$latest_api/" "$REMOTE_API/"
ENDSSH
run_remote_cmd "sudo systemctl restart ${SERVICE_NAME}"
echo "Rollback completed at $(date '+%Y-%m-%d %H:%M:%S %Z')"
exit 0
fi
# ─── flag parsing ───────────────────────────────────────────────────────────
SKIP_BUILD=false
for arg in "$@"; do
[[ "$arg" == "--skip-build" ]] && SKIP_BUILD=true
done
cd "$REPO_ROOT"
if [[ "$SKIP_BUILD" != "true" ]]; then
echo "==> Building API monolith..."
pushd codebase/@features/api >/dev/null
bun install --frozen-lockfile
bun run typecheck
bun build --target=node --external better-sqlite3 --external sharp \
src/app/server.ts --outfile=dist/server.node.js --sourcemap=none
popd >/dev/null
fi
if [[ ! -f "$API_BUNDLE" ]]; then
echo "ERROR: missing API bundle at $API_BUNDLE" >&2
exit 1
fi
# ─── snapshot current state on black for rollback ───────────────────────────
echo "==> Snapshotting current API state into $BACKUP_API..."
run_remote_cmd "mkdir -p $BACKUP_API && rsync -a --delete $REMOTE_API/ $BACKUP_API/ 2>/dev/null || true"
# ─── rsync the new bundle ───────────────────────────────────────────────────
echo "==> Pushing new bundle to ${REMOTE}:${REMOTE_API}..."
run_remote_cmd "mkdir -p $REMOTE_API"
if [[ "$DEPLOY_LOCAL" == true ]]; then
mkdir -p "$REMOTE_API/dist"
rsync -av --no-perms --no-owner --no-group \
"$API_BUNDLE" "$REMOTE_API/dist/server.node.js"
else
rsync -av --no-perms --no-owner --no-group \
"$API_BUNDLE" "${REMOTE}:${REMOTE_API}/dist/server.node.js"
fi
# ─── secrets guard ───────────────────────────────────────────────────────────
# ANALYTICS_COLLECTOR_URL is load-bearing: the www edge relays
# transquinnftw.com/analytics/track/* to this service (black:3023), and
# without the var the relay 202s and silently DROPS every event
# (prod ingest outage 2026-06-10). Schema-optional, so guard it here.
echo "==> Ensuring ANALYTICS_COLLECTOR_URL in /etc/quinn-admin-api/secrets.env..."
run_remote_cmd "sudo grep -q '^ANALYTICS_COLLECTOR_URL=' /etc/quinn-admin-api/secrets.env \
|| echo 'ANALYTICS_COLLECTOR_URL=https://data.transquinnftw.com' \
| sudo tee -a /etc/quinn-admin-api/secrets.env >/dev/null"
# ─── restart + smoke test ───────────────────────────────────────────────────
echo "==> Restarting ${SERVICE_NAME}..."
run_remote_cmd "sudo systemctl restart ${SERVICE_NAME}"
sleep 2
echo "==> Smoke-testing public read endpoint..."
run_remote_cmd "curl -sf http://10.0.0.11:3023/www/tour/status -o /dev/null \
-w 'admin-api /www/tour/status HTTP %{http_code}\n' \
|| (echo 'FAIL — rolling back'; exit 7)"
echo ""
echo "✓ quinn.admin-api deployed to ${REMOTE} at $(date '+%Y-%m-%d %H:%M:%S %Z')"