← back to Commercialrealestate

deploy/push-data-kamatera.sh

85 lines

#!/usr/bin/env bash
# push-data-kamatera.sh — on-demand LISTING DATA deploy mac3 -> Kamatera CRCP prod.
#
# WHY THIS EXISTS (TK-12033, 2026-09-22): crcp.agentabrams.com is a Kamatera-local
# node app serving data/ranked.json + data/listings.json straight off local disk
# (express.static on /data — see scripts/serve.js). Those two files are excluded
# from BOTH deploy/push-frontend-kamatera.sh and deploy/push-full-kamatera.sh
# (their SCOPE comments say so explicitly), and are NOT in any sync script's
# glob either — scripts/sync-broker-feeds.sh only pushes data/*-listings.json
# (broker-direct feed files like encore-listings.json), which does NOT match
# the bare filename "listings.json". The Mac2 rotating cron
# (com.steve.crcp-listings-rotating -> refresh-listings-multi.js -> npm run
# analyze) regenerates ranked.json/listings.json locally every day, but with no
# sync path, prod listing data silently FROZE since Sep 15 while
# scripts/crcp-drift-canary.js kept reporting IN_SYNC (it only ever hashed
# public/*.{html,js,css}). This script is the manual, reviewable, one-command
# way to push fresh listing data to prod; scripts/crcp-drift-canary.js now also
# watches for this exact "prod frozen" condition and tells you to run this.
#
# SCOPE: data/ranked.json + data/listings.json ONLY. Does NOT touch public/,
# scripts/serve.js, .env, or the broker-direct data/*-listings.json files
# (those already have their own sync path). serve.js reads these two files at
# request time (express.static + an mtime-checked cache), so pushed files go
# live on next request — NO restart needed.
#
# SAFETY, modeled on push-frontend-kamatera.sh: timestamped remote backup of
# BOTH files first (rollback point), rsync of individual files (no --delete —
# there is nothing to delete, these are named files not a directory), and a
# post-push verify (remote ls -la sizes + mtimes).
#
# HARD CONSTRAINT: this script is intentionally NOT wired into the unattended
# rotating cron (com.steve.crcp-listings-rotating) — per Steve's standing rule,
# external publish/deploy to a live customer-facing site is ALWAYS hard-gated,
# even in unattended loops. Steve (or a gated approval) runs this on purpose,
# same as the front-end deploy scripts. If Steve later decides to promote this
# to auto-fire after every rotating-cron run, that is his call to make — this
# script is the frictionless one-command step for whichever way he decides.
#
# Usage:  bash deploy/push-data-kamatera.sh [--dry-run]
set -euo pipefail

HOST="root@45.61.58.125"
REMOTE_DIR="/root/public-projects/commercialrealestate/data"
LOCAL_DIR="$(cd "$(dirname "$0")/.." && pwd)/data"
STAMP="$(date +%Y%m%d-%H%M%S)"
FILES=(ranked.json listings.json)

DRY=""
[ "${1:-}" = "--dry-run" ] && DRY="--dry-run"

echo "== CRCP listing-data deploy -> $HOST:$REMOTE_DIR =="
echo "   local:  $LOCAL_DIR"
[ -n "$DRY" ] && echo "   (DRY RUN — no files written)"

for f in "${FILES[@]}"; do
  [ -f "$LOCAL_DIR/$f" ] || { echo "   ERROR: local $LOCAL_DIR/$f missing — aborting"; exit 1; }
done

# 1) timestamped backup of each current remote file (rollback point)
if [ -z "$DRY" ]; then
  for f in "${FILES[@]}"; do
    ssh -o ConnectTimeout=10 "$HOST" \
      "[ -f '$REMOTE_DIR/$f' ] && cp -a '$REMOTE_DIR/$f' '$REMOTE_DIR/${f}.bak-$STAMP' && echo '   backup: $REMOTE_DIR/${f}.bak-$STAMP' || echo '   (no existing remote $f to back up)'"
  done
fi

# 2) rsync the two data files, no --delete (named files, not a directory sync)
for f in "${FILES[@]}"; do
  echo "-- rsync $f"
  rsync -avz $DRY --timeout=120 \
    -e 'ssh -o ConnectTimeout=10' \
    "$LOCAL_DIR/$f" "$HOST:$REMOTE_DIR/$f"
done

# 3) verify: remote sizes + mtimes after the push
if [ -z "$DRY" ]; then
  echo "== verify (remote) =="
  ssh -o ConnectTimeout=10 "$HOST" "ls -la ${FILES[*]/#/$REMOTE_DIR/}"
  echo "== verify (local, for comparison) =="
  ls -la "${FILES[@]/#/$LOCAL_DIR/}"
fi

echo "== done. No restart needed (serve.js reads these files live via express.static + an mtime-checked cache). =="
echo "   Re-run the freshness check any time:  node scripts/crcp-drift-canary.js"