#!/usr/bin/env bash set -euo pipefail # ── Configuration ──────────────────────────────────────────────── PROD_SSH_ALIAS="old-vps" PROD_CONTAINER="wealthysmart-db-prod" PROD_DB="wealthysmart" PROD_USER="wealthy_user" LOCAL_CONTAINER="wealthysmart-db-dev" LOCAL_DB="wealthysmart" LOCAL_USER="wealthy_user" LOCAL_PASS="wealthy_pass" SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" DUMP_FILE="$(mktemp -t wealthysmart-dump-XXXXXX)" # ── Cleanup on exit ───────────────────────────────────────────── cleanup() { rm -f "$DUMP_FILE"; } trap cleanup EXIT # ── Confirmation ───────────────────────────────────────────────── echo "=== WealthySmart Database Sync ===" echo "" echo "This will DESTROY your local dev database and replace it" echo "with a copy of production data." echo "" read -r -p "Continue? [y/N] " confirm if [[ "$confirm" != [yY] ]]; then echo "Aborted." exit 0 fi # ── 1. Dump production ────────────────────────────────────────── echo "" echo "[1/5] Dumping production database..." ssh "$PROD_SSH_ALIAS" \ "docker exec $PROD_CONTAINER pg_dump \ --format=custom \ --no-owner \ --no-acl \ -U $PROD_USER \ $PROD_DB" > "$DUMP_FILE" if [[ ! -s "$DUMP_FILE" ]]; then echo "ERROR: Dump file is empty. SSH or pg_dump may have failed." exit 1 fi DUMP_SIZE=$(du -h "$DUMP_FILE" | cut -f1) echo " Done. Dump size: $DUMP_SIZE" # ── 2. Ensure local DB container is running ───────────────────── echo "[2/5] Ensuring local dev database is running..." cd "$PROJECT_ROOT" if ! docker inspect --format='{{.State.Running}}' "$LOCAL_CONTAINER" 2>/dev/null | grep -q "true"; then echo " Starting db service..." docker compose up -d db fi for i in $(seq 1 30); do if docker inspect --format='{{.State.Health.Status}}' "$LOCAL_CONTAINER" 2>/dev/null | grep -q "healthy"; then break fi if [[ $i -eq 30 ]]; then echo "ERROR: Local DB container did not become healthy within 30s." exit 1 fi sleep 1 done echo " Local DB is running and healthy." # ── 3. Drop and recreate local database ───────────────────────── echo "[3/5] Dropping and recreating local dev database..." docker exec "$LOCAL_CONTAINER" bash -c \ "PGPASSWORD='$LOCAL_PASS' dropdb -U $LOCAL_USER --if-exists $LOCAL_DB && \ PGPASSWORD='$LOCAL_PASS' createdb -U $LOCAL_USER $LOCAL_DB" echo " Done." # ── 4. Restore ────────────────────────────────────────────────── echo "[4/5] Restoring dump into local dev database..." docker exec -i "$LOCAL_CONTAINER" pg_restore \ --no-owner \ --no-acl \ --dbname="$LOCAL_DB" \ -U "$LOCAL_USER" < "$DUMP_FILE" # ── 5. Run pending migrations ─────────────────────────────────── echo "[5/5] Running pending migrations..." docker exec "$LOCAL_CONTAINER" psql -U "$LOCAL_USER" -d "$LOCAL_DB" -c \ "ALTER TABLE transaction ADD COLUMN IF NOT EXISTS deferred_to_next_cycle BOOLEAN NOT NULL DEFAULT false;" \ 2>/dev/null || true echo " Done." echo "" echo "=== Sync complete! ===" echo "Local dev database now mirrors production."