#!/bin/bash # ============================================================================= # Life OS - PROD Database Setup # Backs up lifeos_dev (R1) and restores to lifeos_prod # Run AFTER DEV is fully tested and confirmed working # Run on: defiant-01 as root # ============================================================================= set -e DB_CONTAINER="lifeos-db" DB_USER="postgres" DEV_DB="lifeos_dev" PROD_DB="lifeos_prod" BACKUP_DIR="/opt/lifeos/backups" TIMESTAMP=$(date +%Y%m%d_%H%M%S) BACKUP_FILE="$BACKUP_DIR/dev_to_prod_${TIMESTAMP}.sql" section() { echo "" echo "==============================================" echo " $1" echo "==============================================" } # ============================================================================= # 1. Verify prerequisites # ============================================================================= section "1. Verifying prerequisites" if ! docker ps | grep -q "$DB_CONTAINER"; then echo "ERROR: $DB_CONTAINER is not running" exit 1 fi echo "OK: $DB_CONTAINER is running" mkdir -p "$BACKUP_DIR" # ============================================================================= # 2. Backup current lifeos_prod (safety net) # ============================================================================= section "2. Backing up current lifeos_prod (R0 safety copy)" docker exec $DB_CONTAINER pg_dump -U $DB_USER $PROD_DB | gzip > "$BACKUP_DIR/prod_r0_backup_${TIMESTAMP}.sql.gz" echo "OK: R0 prod backup saved to $BACKUP_DIR/prod_r0_backup_${TIMESTAMP}.sql.gz" # ============================================================================= # 3. Backup lifeos_dev (source for PROD) # ============================================================================= section "3. Backing up lifeos_dev (R1 source)" docker exec $DB_CONTAINER pg_dump -U $DB_USER --clean --if-exists $DEV_DB > "$BACKUP_FILE" echo "OK: DEV backup saved to $BACKUP_FILE" # ============================================================================= # 4. Drop and recreate lifeos_prod with R1 data # ============================================================================= section "4. Replacing lifeos_prod with lifeos_dev contents" echo "WARNING: This will destroy the current lifeos_prod database." echo "R0 backup is at: $BACKUP_DIR/prod_r0_backup_${TIMESTAMP}.sql.gz" read -p "Continue? (yes/no): " CONFIRM if [ "$CONFIRM" != "yes" ]; then echo "Aborted." exit 0 fi # Drop and recreate prod database docker exec $DB_CONTAINER psql -U $DB_USER -c " SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = '$PROD_DB' AND pid <> pg_backend_pid(); " docker exec $DB_CONTAINER psql -U $DB_USER -c "DROP DATABASE IF EXISTS $PROD_DB;" docker exec $DB_CONTAINER psql -U $DB_USER -c "CREATE DATABASE $PROD_DB;" # Restore DEV backup into PROD docker exec -i $DB_CONTAINER psql -U $DB_USER -d $PROD_DB < "$BACKUP_FILE" echo "OK: lifeos_prod now contains R1 schema + data from DEV" # ============================================================================= # 5. Verify # ============================================================================= section "5. Verification" echo "PROD table row counts:" docker exec $DB_CONTAINER psql -U $DB_USER -d $PROD_DB -c " SELECT 'domains' as table_name, count(*) FROM domains UNION ALL SELECT 'areas', count(*) FROM areas UNION ALL SELECT 'projects', count(*) FROM projects UNION ALL SELECT 'tasks', count(*) FROM tasks UNION ALL SELECT 'notes', count(*) FROM notes UNION ALL SELECT 'links', count(*) FROM links UNION ALL SELECT 'daily_focus', count(*) FROM daily_focus UNION ALL SELECT 'capture', count(*) FROM capture UNION ALL SELECT 'context_types', count(*) FROM context_types ORDER BY table_name; " # ============================================================================= # 6. Setup automated daily backup cron # ============================================================================= section "6. Setting up automated daily backups" CRON_LINE="0 3 * * * docker exec $DB_CONTAINER pg_dump -U $DB_USER $PROD_DB | gzip > $BACKUP_DIR/prod_\$(date +\\%Y\\%m\\%d).sql.gz && find $BACKUP_DIR -name 'prod_*.sql.gz' -mtime +30 -delete" if crontab -l 2>/dev/null | grep -q "lifeos_prod"; then echo "Backup cron already exists, skipping." else (crontab -l 2>/dev/null; echo "$CRON_LINE") | crontab - echo "OK: Daily backup cron installed (3am, 30-day retention)" fi echo "" echo "==============================================" echo " PROD setup complete." echo " lifeos_prod now has R1 schema + data." echo " R0 backup: $BACKUP_DIR/prod_r0_backup_${TIMESTAMP}.sql.gz" echo " Daily backups configured." echo "=============================================="