#!/bin/bash # ============================================================================= # IGNY8 Sync Production Data to Staging # ============================================================================= # Syncs production database to staging with data sanitization # Usage: ./sync-prod-to-staging.sh # ============================================================================= set -e DB_CONTAINER="postgres" PROD_DB="igny8_db" STAGING_DB="igny8_staging_db" DB_USER="igny8" # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log() { echo -e "${BLUE}[$(date '+%H:%M:%S')]${NC} $1" } log_success() { echo -e "${GREEN}✅ $1${NC}" } log_warn() { echo -e "${YELLOW}⚠️ $1${NC}" } log_error() { echo -e "${RED}❌ $1${NC}" } echo "==========================================" echo "SYNC PRODUCTION → STAGING" echo "==========================================" echo "" log_warn "This will REPLACE staging database with production data!" log_warn "Data will be sanitized (emails, passwords anonymized)" echo "" read -p "Type 'sync' to continue: " confirm if [[ "${confirm}" != "sync" ]]; then log "Sync cancelled" exit 0 fi # Check if staging containers are running STAGING_RUNNING=$(docker ps --format '{{.Names}}' | grep -c "igny8_staging" || true) if [[ ${STAGING_RUNNING} -gt 0 ]]; then log "Stopping staging containers..." docker compose -f /data/app/igny8/docker-compose.staging.yml -p igny8-staging stop igny8_staging_backend igny8_staging_celery_worker igny8_staging_celery_beat 2>/dev/null || true fi # Step 1: Dump production log "Step 1/5: Dumping production database..." TEMP_DUMP="/tmp/prod_sync_$(date +%Y%m%d_%H%M%S).sql" docker exec "${DB_CONTAINER}" pg_dump -U "${DB_USER}" "${PROD_DB}" > "${TEMP_DUMP}" log_success "Production dump created: ${TEMP_DUMP}" # Step 2: Drop staging database log "Step 2/5: Dropping staging database..." docker exec "${DB_CONTAINER}" psql -U postgres -c "DROP DATABASE IF EXISTS ${STAGING_DB};" docker exec "${DB_CONTAINER}" psql -U postgres -c "CREATE DATABASE ${STAGING_DB} OWNER ${DB_USER};" log_success "Staging database recreated" # Step 3: Restore to staging log "Step 3/5: Restoring to staging database..." docker exec -i "${DB_CONTAINER}" psql -U "${DB_USER}" -d "${STAGING_DB}" < "${TEMP_DUMP}" log_success "Data restored to staging" # Step 4: Sanitize data log "Step 4/5: Sanitizing staging data..." docker exec "${DB_CONTAINER}" psql -U "${DB_USER}" -d "${STAGING_DB}" << 'EOF' -- Sanitize user emails (keep superusers intact) UPDATE auth_user SET email = CONCAT('staging_', id, '@igny8.test') WHERE is_superuser = FALSE; -- Invalidate all sessions DELETE FROM django_session; -- Update notification endpoints to staging UPDATE notification_settings SET webhook_url = REPLACE(webhook_url, 'app.igny8.com', 'staging.igny8.com') WHERE webhook_url IS NOT NULL; -- Log sanitization SELECT 'Sanitized ' || COUNT(*) || ' user emails' FROM auth_user WHERE email LIKE '%@igny8.test'; EOF log_success "Data sanitized" # Step 5: Run migrations (in case staging has newer schema) log "Step 5/5: Checking migrations..." if docker ps --format '{{.Names}}' | grep -q "igny8_staging_backend"; then docker exec igny8_staging_backend python manage.py migrate --noinput 2>/dev/null || true fi # Cleanup rm -f "${TEMP_DUMP}" # Restart staging if [[ ${STAGING_RUNNING} -gt 0 ]]; then log "Restarting staging containers..." docker compose -f /data/app/igny8/docker-compose.staging.yml -p igny8-staging start igny8_staging_backend igny8_staging_celery_worker igny8_staging_celery_beat 2>/dev/null || true fi echo "" echo "==========================================" log_success "SYNC COMPLETE" echo "==========================================" echo "" echo "Staging database now contains sanitized production data." echo "" echo "Changes made:" echo " - User emails changed to staging_*@igny8.test" echo " - All sessions invalidated" echo " - Webhook URLs updated to staging domain" echo "" echo "To test with a specific user:" echo " docker exec -it igny8_staging_backend python manage.py changepassword " echo "=========================================="