From f7855d47e465a31ca8213566b6eb1cc9c90acab3 Mon Sep 17 00:00:00 2001 From: SkateSpots Date: Sun, 27 Sep 2026 12:04:57 +0700 Subject: [PATCH] chore(cvm): one-command deploy to the single host + document the setup - scripts/deploy-cvm.sh: backup remote server.ts -> upload -> restart -> confirm the heartbeat, with --rollback. Host/SSH values come from the never-committed ~/.config/skatespots/cvm.env (or CVM_HOST), so no host details ever enter this public repo. - package.json: add `npm run deploy:cvm`. - AGENTS.md: record that the CVM server runs on ONE external host (deploy via deploy:cvm) and that the discovery relay, not the server, is the SPOF. --- AGENTS.md | 6 +++++ package.json | 1 + scripts/deploy-cvm.sh | 55 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 62 insertions(+) create mode 100755 scripts/deploy-cvm.sh diff --git a/AGENTS.md b/AGENTS.md index 9cd056e..92baff8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -127,6 +127,12 @@ session with **no other memory of this project**. So: and a short-TTL query cache (`CVM_RATE_*`, `CVM_MAX_*`, `CVM_QUERY_CACHE_MS`). Type-checked by `cvm-server/tsconfig.json` via the `typecheck:cvm` script (wired into `npm test`); `check:cvm` runs a Bun transpile. + **The server runs on one external host (not this box)** — deploy with + `npm run deploy:cvm`; the host/SSH values come from the never-committed + `~/.config/skatespots/cvm.env` (never put them in a tracked file — this repo + is public). `scripts/deploy-cvm.sh --rollback` restores the newest backup. + The discovery relay (`relay.contextvm.org`) is the real single point of + failure, not the server. - **Routing / directions**: `RouteDialog` is the single in-app router, opened from the map spot sheet, the food cards, and the spot / shop / event detail pages (MapPage's old external "Open with" Google/OSM/Waze menu was removed). diff --git a/package.json b/package.json index 5eb9ce1..2de30ca 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "scripts": { "dev": "npm i --silent && vite", "build": "npm i --silent && vite build -l error && cp dist/index.html dist/404.html && echo 'Project built successfully!'", + "deploy:cvm": "bash scripts/deploy-cvm.sh", "typecheck:cvm": "tsc -p cvm-server/tsconfig.json", "check:cvm": "bun build cvm-server/server.ts --target=bun --outfile=/tmp/cvm-check.js", "test": "npm i --silent && tsc --noEmit && tsc -p cvm-server/tsconfig.json && eslint && vitest run --reporter=dot --silent && vite build -l error && cp dist/index.html dist/404.html && echo 'All tests passed!'", diff --git a/scripts/deploy-cvm.sh b/scripts/deploy-cvm.sh new file mode 100755 index 0000000..9f20396 --- /dev/null +++ b/scripts/deploy-cvm.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# +# Deploy the standalone CVM (ContextVM) server to its host. +# +# The host is intentionally NOT committed — this repository is public. Provide it +# via either: +# • ~/.config/skatespots/cvm.env (contains: CVM_HOST=ubuntu@your-host), or +# • an environment variable: +# CVM_HOST=ubuntu@your-host npm run deploy:cvm +# +# Optional overrides (env or ~/.config/skatespots/cvm.env): +# CVM_SSH_KEY SSH private key (default: ~/.ssh/skatespots-new) +# CVM_DIR Remote checkout dir (default: /home/ubuntu/skatespots-cvm) +# CVM_SERVICE systemd unit name (default: skatespots-cvm) +# +# Usage: +# npm run deploy:cvm +# bash scripts/deploy-cvm.sh --rollback # restore the newest remote backup +set -euo pipefail + +REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" + +# Load the local, never-committed config if present. +CONF="${HOME}/.config/skatespots/cvm.env" +if [[ -f "$CONF" ]]; then + # shellcheck disable=SC1090 + source "$CONF" +fi + +: "${CVM_HOST:?Set CVM_HOST (e.g. in ~/.config/skatespots/cvm.env) — the host is never committed}" +CVM_SSH_KEY="${CVM_SSH_KEY:-$HOME/.ssh/skatespots-new}" +CVM_DIR="${CVM_DIR:-/home/ubuntu/skatespots-cvm}" +CVM_SERVICE="${CVM_SERVICE:-skatespots-cvm}" + +SSH=(ssh -i "$CVM_SSH_KEY" -o BatchMode=yes -o ConnectTimeout=12 "$CVM_HOST") + +if [[ "${1:-}" == "--rollback" ]]; then + echo "→ Rolling back to the newest backup on the host" + "${SSH[@]}" "LATEST=\$(ls -1t $CVM_DIR/server.ts.bak-* | head -1); cp \"\$LATEST\" $CVM_DIR/server.ts; sudo systemctl restart $CVM_SERVICE && echo \"restored: \$LATEST\"" + exit 0 +fi + +echo "→ Backing up the remote server.ts" +"${SSH[@]}" "cp $CVM_DIR/server.ts $CVM_DIR/server.ts.bak-\$(date +%Y%m%d-%H%M%S)" + +echo "→ Uploading cvm-server/server.ts" +scp -i "$CVM_SSH_KEY" -o BatchMode=yes "$REPO_ROOT/cvm-server/server.ts" "$CVM_HOST:$CVM_DIR/server.ts" + +echo "→ Restarting $CVM_SERVICE" +"${SSH[@]}" "sudo systemctl restart $CVM_SERVICE && sleep 10 && echo \"active: \$(systemctl is-active $CVM_SERVICE)\"" + +echo "→ Recent log:" +"${SSH[@]}" "journalctl -u $CVM_SERVICE -n 25 --no-pager | grep -E 'Heartbeat|Server running|Data relays|CVM relay' || true" + +echo "✅ CVM server deployed."