114 lines
5.1 KiB
Bash
Executable file
114 lines
5.1 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
# Full first-time bootstrap on the VPS.
|
|
# Idempotent — safe to re-run; rsync only ships diffs, docker compose only restarts changed services.
|
|
#
|
|
# Steps:
|
|
# 1. mkdir /data/disclosure on VPS
|
|
# 2. rsync compose files + web/ source + wiki/ + processing/png + processing/crops
|
|
# 3. SSH: docker compose up -d db
|
|
# 4. Wait for db healthy
|
|
# 5. Apply Supabase init + chat schema
|
|
# 6. docker compose up -d (everything else)
|
|
# 7. Report URLs
|
|
|
|
set -euo pipefail
|
|
source "$(dirname "$0")/_lib.sh"
|
|
|
|
LAPTOP_UFO_ROOT="${LAPTOP_UFO_ROOT:-/Users/guto/ufo}"
|
|
STACK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
|
|
echo "================================================================"
|
|
echo " STAGE A — create deploy dir + sync code (fast)"
|
|
echo "================================================================"
|
|
vps_ssh "mkdir -p ${VPS_DEPLOY_ROOT}/{web,wiki,processing,raw,migrations}"
|
|
|
|
echo ""
|
|
echo "→ Syncing infra/disclosure-stack/ (compose + kong + .env + scripts)"
|
|
vps_rsync "${STACK_DIR}/docker-compose.yml" "${VPS_DEPLOY_ROOT}/docker-compose.yml"
|
|
vps_rsync "${STACK_DIR}/kong.yml" "${VPS_DEPLOY_ROOT}/kong.yml"
|
|
vps_rsync "${STACK_DIR}/init-db.sql" "${VPS_DEPLOY_ROOT}/migrations/00-init.sql"
|
|
vps_rsync "${STACK_DIR}/../supabase/migrations/0001_chat_schema.sql" "${VPS_DEPLOY_ROOT}/migrations/01-chat-schema.sql"
|
|
vps_rsync "${STACK_DIR}/../supabase/migrations/0002_chunks_retrieval.sql" "${VPS_DEPLOY_ROOT}/migrations/02-chunks-retrieval.sql"
|
|
vps_rsync "${STACK_DIR}/.env" "${VPS_DEPLOY_ROOT}/.env"
|
|
|
|
echo ""
|
|
echo "→ Syncing web/ (Next.js source, excl. node_modules/.next)"
|
|
if [ "$VPS_AUTH" = "password" ]; then
|
|
SSHPASS="$VPS_PASSWORD" sshpass -e rsync -avz --delete \
|
|
--exclude node_modules --exclude .next --exclude .env.local \
|
|
-e "ssh -o StrictHostKeyChecking=accept-new -p $VPS_PORT" \
|
|
"${LAPTOP_UFO_ROOT}/web/" "${VPS_USER}@${VPS_HOST}:${VPS_DEPLOY_ROOT}/web/"
|
|
else
|
|
rsync -avz --delete \
|
|
--exclude node_modules --exclude .next --exclude .env.local \
|
|
-e "ssh -o StrictHostKeyChecking=accept-new -p $VPS_PORT -i ${VPS_SSH_KEY/#\~/$HOME}" \
|
|
"${LAPTOP_UFO_ROOT}/web/" "${VPS_USER}@${VPS_HOST}:${VPS_DEPLOY_ROOT}/web/"
|
|
fi
|
|
|
|
echo ""
|
|
echo "================================================================"
|
|
echo " STAGE B — sync wiki + processing (data — can be slow first time)"
|
|
echo "================================================================"
|
|
echo "→ Syncing wiki/ (markdown)"
|
|
vps_rsync "${LAPTOP_UFO_ROOT}/wiki/" "${VPS_DEPLOY_ROOT}/wiki/"
|
|
|
|
echo ""
|
|
echo "→ Syncing processing/png/ (page images — large)"
|
|
vps_rsync "${LAPTOP_UFO_ROOT}/processing/png/" "${VPS_DEPLOY_ROOT}/processing/png/"
|
|
|
|
echo ""
|
|
echo "→ Syncing processing/ocr/ (text)"
|
|
vps_rsync "${LAPTOP_UFO_ROOT}/processing/ocr/" "${VPS_DEPLOY_ROOT}/processing/ocr/"
|
|
|
|
echo ""
|
|
echo "→ Syncing processing/crops/ + processing/tables/ + processing/uap-frames/"
|
|
vps_rsync "${LAPTOP_UFO_ROOT}/processing/crops/" "${VPS_DEPLOY_ROOT}/processing/crops/" 2>&1 || true
|
|
vps_rsync "${LAPTOP_UFO_ROOT}/processing/tables/" "${VPS_DEPLOY_ROOT}/processing/tables/" 2>&1 || true
|
|
vps_rsync "${LAPTOP_UFO_ROOT}/processing/case-images/" "${VPS_DEPLOY_ROOT}/processing/case-images/" 2>&1 || true
|
|
vps_rsync "${LAPTOP_UFO_ROOT}/processing/uap-frames/" "${VPS_DEPLOY_ROOT}/processing/uap-frames/" 2>&1 || true
|
|
vps_rsync "${LAPTOP_UFO_ROOT}/processing/video-analysis/" "${VPS_DEPLOY_ROOT}/processing/video-analysis/" 2>&1 || true
|
|
|
|
echo ""
|
|
echo "================================================================"
|
|
echo " STAGE C — start stack on VPS"
|
|
echo "================================================================"
|
|
vps_ssh "set -e
|
|
cd ${VPS_DEPLOY_ROOT}
|
|
echo '→ docker compose up -d db'
|
|
docker compose up -d db
|
|
echo '→ Waiting for db healthy…'
|
|
for i in {1..30}; do
|
|
STATUS=\$(docker inspect --format='{{.State.Health.Status}}' disclosure-db 2>/dev/null || echo starting)
|
|
if [ \"\$STATUS\" = healthy ]; then echo ' ✓ db healthy'; break; fi
|
|
sleep 2
|
|
done
|
|
echo ''
|
|
echo '→ Applying init-db.sql (roles + schemas)'
|
|
docker exec -i disclosure-db psql -U postgres < migrations/00-init.sql 2>&1 | tail -5 || true
|
|
echo ''
|
|
echo '→ Applying chat schema'
|
|
docker exec -i disclosure-db psql -U postgres < migrations/01-chat-schema.sql 2>&1 | tail -5 || true
|
|
echo ''
|
|
echo '→ Applying chunks retrieval schema (pgvector + hybrid_search)'
|
|
docker exec -i disclosure-db psql -U postgres < migrations/02-chunks-retrieval.sql 2>&1 | tail -5 || true
|
|
echo ''
|
|
echo '→ docker compose up -d (entire stack incl. embed-service)'
|
|
docker compose up -d
|
|
echo ''
|
|
echo '→ Status:'
|
|
docker compose ps
|
|
"
|
|
|
|
echo ""
|
|
echo "================================================================"
|
|
echo " ✓ Bootstrap complete"
|
|
echo "================================================================"
|
|
echo ""
|
|
echo "URLs (give DNS + TLS issuance ~5 min):"
|
|
echo " Main app: https://${DOMAIN_MAIN}"
|
|
echo " Studio: https://${DOMAIN_STUDIO}"
|
|
echo " Supa API: https://${DOMAIN_API}"
|
|
echo " Search: https://${DOMAIN_SEARCH}"
|
|
echo ""
|
|
echo "Tail container logs: ./scripts/logs.sh <service>"
|
|
echo "Service list: ./scripts/ssh.sh 'cd ${VPS_DEPLOY_ROOT} && docker compose ps'"
|