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.
This commit is contained in:
SkateSpots 2026-09-27 12:04:57 +07:00
parent 3a32dc2334
commit f7855d47e4
3 changed files with 62 additions and 0 deletions

View file

@ -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`). 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 Type-checked by `cvm-server/tsconfig.json` via the `typecheck:cvm` script
(wired into `npm test`); `check:cvm` runs a Bun transpile. (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 - **Routing / directions**: `RouteDialog` is the single in-app router, opened
from the map spot sheet, the food cards, and the spot / shop / event detail 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). pages (MapPage's old external "Open with" Google/OSM/Waze menu was removed).

View file

@ -7,6 +7,7 @@
"scripts": { "scripts": {
"dev": "npm i --silent && vite", "dev": "npm i --silent && vite",
"build": "npm i --silent && vite build -l error && cp dist/index.html dist/404.html && echo 'Project built successfully!'", "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", "typecheck:cvm": "tsc -p cvm-server/tsconfig.json",
"check:cvm": "bun build cvm-server/server.ts --target=bun --outfile=/tmp/cvm-check.js", "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!'", "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!'",

55
scripts/deploy-cvm.sh Executable file
View file

@ -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."