From b8c4cebad5e72e58808c5bb1c21c532ff05ce1aa Mon Sep 17 00:00:00 2001 From: Devil Date: Tue, 11 Aug 2026 16:45:24 +0200 Subject: [PATCH] chore(scripts): add local-to-server DB migration script One-time tool: dumps the local dev Postgres, scp's it to the server, and restores it into the remote postgres container over SSH - drops and recreates the target database, so it prompts for an explicit YES before touching the remote side. Connection details are placeholders (SSH_USER/SSH_HOST/etc.) filled in via env vars or direct edits, never committed with real values. --- scripts/migrate-local-db-to-server.sh | 85 +++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 scripts/migrate-local-db-to-server.sh diff --git a/scripts/migrate-local-db-to-server.sh b/scripts/migrate-local-db-to-server.sh new file mode 100644 index 0000000..9ada6a5 --- /dev/null +++ b/scripts/migrate-local-db-to-server.sh @@ -0,0 +1,85 @@ +#!/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 + +# ── 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."