#!/usr/bin/env bash # Deploy the Hub to a host: rsync the repo, install deps, build, restart service. # # Configure these env vars (e.g. in CI secrets): # PLATFORM_DEPLOY_HOST required # PLATFORM_DEPLOY_SSH_KEY required (private key for the deploy user) # PLATFORM_DEPLOY_USER optional, defaults to deploy # PLATFORM_DEPLOY_PORT optional, defaults to 22 # PLATFORM_DEPLOY_BASE optional, defaults to /srv/curriculum-project-hub # PLATFORM_DEPLOY_HEALTH_URL optional, defaults to http://127.0.0.1:8788/api/healthz # The target host must have Node.js 20+, npm, rsync, PostgreSQL client tools # (`pg_isready`), systemd, bubblewrap (`bwrap`) and `socat` (for the ADR-0018 agent sandbox), # and a compatible `cph` binary named by platform.env. The service installer # provisions the dedicated non-root identity and persistent directories. # Use a dedicated `deploy` user that has passwordless sudo for systemctl and # writing /etc/systemd/system/cph-hub.service through deploy/install_service.sh. set -euo pipefail HOST="${PLATFORM_DEPLOY_HOST:?PLATFORM_DEPLOY_HOST required}" SSH_KEY="${PLATFORM_DEPLOY_SSH_KEY:?PLATFORM_DEPLOY_SSH_KEY required}" DEPLOY_USER="${PLATFORM_DEPLOY_USER:-deploy}" PORT="${PLATFORM_DEPLOY_PORT:-22}" BASE="${PLATFORM_DEPLOY_BASE:-/srv/curriculum-project-hub}" HEALTH_URL="${PLATFORM_DEPLOY_HEALTH_URL:-http://127.0.0.1:8788/api/healthz}" HUB_DIR="$BASE/hub" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" SSH_OPTS=(-i "$SSH_KEY" -p "$PORT" -o StrictHostKeyChecking=accept-new) ssh "${SSH_OPTS[@]}" "$DEPLOY_USER@$HOST" "mkdir -p '$HUB_DIR'" # 1. Rsync the hub/ directory (exclude node_modules/dist, they rebuild on host). rsync -az --delete \ --exclude node_modules --exclude dist --exclude .env \ -e "ssh ${SSH_OPTS[*]}" \ "$REPO_ROOT/hub/" "$DEPLOY_USER@$HOST:$HUB_DIR/" # 2. Install deps, prove the production dependency tree, then build on the host. ssh "${SSH_OPTS[@]}" "$DEPLOY_USER@$HOST" "cd '$HUB_DIR' && npm ci && npm run audit:production && npm run build" # 3. Ensure the service is installed (idempotent), then restart. ssh "${SSH_OPTS[@]}" "$DEPLOY_USER@$HOST" " set -euo pipefail if [ \"\$(id -u)\" = \"0\" ]; then BASE='$BASE' HUB_DIR='$HUB_DIR' bash '$HUB_DIR/deploy/install_service.sh' systemctl restart cph-hub.service systemctl is-active --quiet cph-hub.service else sudo -n BASE='$BASE' HUB_DIR='$HUB_DIR' bash '$HUB_DIR/deploy/install_service.sh' sudo -n systemctl restart cph-hub.service sudo -n systemctl is-active --quiet cph-hub.service fi for attempt in \$(seq 1 30); do if curl --fail --silent '$HEALTH_URL' >/dev/null 2>&1; then exit 0 fi sleep 1 done curl --fail --silent --show-error '$HEALTH_URL' >/dev/null " echo "Deployed cph-hub to $HOST ($HUB_DIR)"