#!/usr/bin/env bash # One-time migration: dump the local dev Postgres and restore it into the # server's Postgres over SSH, replacing whatever is there. # # DESTRUCTIVE on the target: drops and recreates the remote database. # # Fill in the placeholders below (or export them as env vars before running), # then run from the project root: bash scripts/migrate-local-db-to-server.sh # # Prerequisites: # - Local Postgres running: cd infrastructure && docker compose up -d postgres redis # - SSH access to the server # - The remote postgres container's name (find it with `docker ps` on the # server, or check the container list in Portainer for your stack - it'll # be something like -postgres-1) set -euo pipefail # Git Bash/MSYS auto-translates POSIX-looking path args (e.g. /tmp/foo) into # Windows paths before handing them to docker.exe - but these paths are meant # to be interpreted inside the Linux container, not on the Windows host. export MSYS_NO_PATHCONV=1 # ── Fill these in ────────────────────────────────────────────────────────── SSH_USER="${SSH_USER:-dummyuser}" SSH_HOST="${SSH_HOST:-dummy.server.example}" SSH_PORT="${SSH_PORT:-22}" REMOTE_POSTGRES_CONTAINER="${REMOTE_POSTGRES_CONTAINER:-studioflow-postgres-1}" REMOTE_POSTGRES_USER="${REMOTE_POSTGRES_USER:-studioflow}" REMOTE_POSTGRES_DB="${REMOTE_POSTGRES_DB:-studioflow}" # ──────────────────────────────────────────────────────────────────────────── LOCAL_DB_USER="studioflow" LOCAL_DB_NAME="studioflow" DUMP_FILE="studioflow_migration_$(date +%Y%m%d_%H%M%S).dump" echo "==> Finding local Postgres container" LOCAL_PG_CONTAINER=$(docker ps --format '{{.Names}}' | grep -i postgres | head -1) if [ -z "$LOCAL_PG_CONTAINER" ]; then echo "No running local postgres container found. Start it first:" echo " cd infrastructure && docker compose up -d postgres redis" exit 1 fi echo " Using: $LOCAL_PG_CONTAINER" echo "==> Dumping local database ($LOCAL_DB_NAME)" docker exec "$LOCAL_PG_CONTAINER" pg_dump -U "$LOCAL_DB_USER" -d "$LOCAL_DB_NAME" -F c -f "/tmp/$DUMP_FILE" docker cp "${LOCAL_PG_CONTAINER}:/tmp/$DUMP_FILE" "./$DUMP_FILE" docker exec "$LOCAL_PG_CONTAINER" rm "/tmp/$DUMP_FILE" echo " Dump size: $(du -h "./$DUMP_FILE" | cut -f1)" echo "" echo "About to overwrite the database on ${SSH_HOST} (container: ${REMOTE_POSTGRES_CONTAINER})." read -p "Type YES to continue: " CONFIRM if [ "$CONFIRM" != "YES" ]; then echo "Aborted. Local dump kept at ./$DUMP_FILE" exit 1 fi echo "==> Copying dump to server" scp -P "$SSH_PORT" "./$DUMP_FILE" "${SSH_USER}@${SSH_HOST}:/tmp/$DUMP_FILE" echo "==> Restoring on server" ssh -p "$SSH_PORT" "${SSH_USER}@${SSH_HOST}" bash -s </dev/null echo " Dropping and recreating database..." docker exec "$REMOTE_POSTGRES_CONTAINER" psql -U "$REMOTE_POSTGRES_USER" -d postgres -c \ "DROP DATABASE IF EXISTS $REMOTE_POSTGRES_DB;" >/dev/null docker exec "$REMOTE_POSTGRES_CONTAINER" psql -U "$REMOTE_POSTGRES_USER" -d postgres -c \ "CREATE DATABASE $REMOTE_POSTGRES_DB OWNER $REMOTE_POSTGRES_USER;" >/dev/null echo " Restoring data..." docker exec "$REMOTE_POSTGRES_CONTAINER" pg_restore -U "$REMOTE_POSTGRES_USER" -d "$REMOTE_POSTGRES_DB" --no-owner --no-privileges "/tmp/$DUMP_FILE" docker exec "$REMOTE_POSTGRES_CONTAINER" rm "/tmp/$DUMP_FILE" rm "/tmp/$DUMP_FILE" echo " Done." EOF echo "" echo "==> Migration complete." echo " Restart api/worker in Portainer (or they'll self-heal on next DB query)." echo " Local dump kept at ./$DUMP_FILE - delete it once you've confirmed the server looks right."