Isolate next dev from production .next, add build-guard/atomic deploy/health watchdog, error boundaries, and fix JWT startup, meetup leaks, media path traversal, SVG/memory uploads, and JSON-LD escaping. Co-authored-by: Cursor <cursoragent@cursor.com>
66 lines
2.5 KiB
Bash
Executable File
66 lines
2.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Atomic frontend deploy for the Belgian Bitcoin Embassy site.
|
|
#
|
|
# Builds into a scratch dist dir, verifies the artifact, then swaps it into place
|
|
# as .next in a single mv (rename is atomic on the same filesystem). The running
|
|
# server therefore never sees a half-written .next, and a failed build leaves the
|
|
# current production build untouched.
|
|
#
|
|
# Usage:
|
|
# scripts/deploy-frontend.sh # build, verify, swap, restart service
|
|
# scripts/deploy-frontend.sh --no-restart # build + swap, skip systemctl
|
|
#
|
|
# Requires sudo only for the final `systemctl restart` (skip with --no-restart).
|
|
|
|
set -euo pipefail
|
|
|
|
REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
FRONTEND_DIR="${REPO_DIR}/frontend"
|
|
BUILD_DIR="${FRONTEND_DIR}/.next-build"
|
|
PROD_DIR="${FRONTEND_DIR}/.next"
|
|
BACKUP_DIR="${FRONTEND_DIR}/.next-prev"
|
|
MIN_FREE_MB="${MIN_FREE_MB:-600}"
|
|
|
|
RESTART=1
|
|
[ "${1:-}" = "--no-restart" ] && RESTART=0
|
|
|
|
log() { echo "deploy-frontend: $*"; }
|
|
die() { echo "deploy-frontend: ERROR: $*" >&2; exit 1; }
|
|
|
|
cd "${FRONTEND_DIR}"
|
|
|
|
# A production `next build` on this box needs headroom; bail early with a clear
|
|
# message rather than getting OOM-killed halfway through.
|
|
free_mb="$(free -m | awk '/^Mem:/ {print $7}')"
|
|
if [ -n "${free_mb}" ] && [ "${free_mb}" -lt "${MIN_FREE_MB}" ]; then
|
|
die "only ${free_mb}MB available memory (< ${MIN_FREE_MB}MB). Free memory or set MIN_FREE_MB=... to override."
|
|
fi
|
|
|
|
log "building into ${BUILD_DIR} ..."
|
|
rm -rf "${BUILD_DIR}"
|
|
NEXT_DIST_DIR=".next-build" npm run build
|
|
|
|
log "verifying fresh build ..."
|
|
NEXT_DIR="${BUILD_DIR}"
|
|
[ -f "${NEXT_DIR}/BUILD_ID" ] || die "build produced no BUILD_ID"
|
|
[ -f "${NEXT_DIR}/build-manifest.json" ] || die "build produced no build-manifest.json"
|
|
[ -f "${NEXT_DIR}/prerender-manifest.json" ] || die "build produced no prerender-manifest.json"
|
|
[ -d "${NEXT_DIR}/static/development" ] && die "fresh build contains static/development (dev contamination)"
|
|
grep -q "static/development" "${NEXT_DIR}/build-manifest.json" && die "build-manifest references static/development"
|
|
|
|
log "swapping ${BUILD_DIR} -> ${PROD_DIR} (atomic) ..."
|
|
rm -rf "${BACKUP_DIR}"
|
|
[ -d "${PROD_DIR}" ] && mv "${PROD_DIR}" "${BACKUP_DIR}"
|
|
mv "${BUILD_DIR}" "${PROD_DIR}"
|
|
|
|
log "deployed BUILD_ID=$(cat "${PROD_DIR}/BUILD_ID")"
|
|
|
|
if [ "${RESTART}" -eq 1 ]; then
|
|
log "restarting bbe-frontend.service ..."
|
|
sudo systemctl restart bbe-frontend
|
|
log "done. previous build kept at ${BACKUP_DIR}"
|
|
else
|
|
log "skipped restart (--no-restart). previous build kept at ${BACKUP_DIR}"
|
|
fi
|