Files
maternal-app/migrate-production.sh
Andrei 4e19b992df
Some checks failed
ParentFlow CI/CD Pipeline / Backend Tests (push) Has been cancelled
ParentFlow CI/CD Pipeline / Frontend Tests (push) Has been cancelled
ParentFlow CI/CD Pipeline / Security Scanning (push) Has been cancelled
ParentFlow CI/CD Pipeline / Build Docker Images (map[context:maternal-app/maternal-app-backend dockerfile:Dockerfile.production name:backend]) (push) Has been cancelled
ParentFlow CI/CD Pipeline / Build Docker Images (map[context:maternal-web dockerfile:Dockerfile.production name:frontend]) (push) Has been cancelled
ParentFlow CI/CD Pipeline / Deploy to Development (push) Has been cancelled
ParentFlow CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / Lint and Test (push) Has been cancelled
CI/CD Pipeline / E2E Tests (push) Has been cancelled
CI/CD Pipeline / Build Application (push) Has been cancelled
feat: Complete production deployment pipeline with admin dashboard
- Add unified deployment script with Node.js 22 installation
- Create comprehensive database migration script (28 migrations + admin tables)
- Add production start/stop scripts for all services
- Integrate admin dashboard (parentflow-admin) into PM2 ecosystem
- Configure all services: Backend (3020), Frontend (3030), Admin (3335)
- Update ecosystem.config.js with admin dashboard configuration
- Add invite codes module for user registration management
2025-10-06 22:43:28 +00:00

278 lines
9.2 KiB
Bash
Executable File

#!/bin/bash
# ParentFlow Production Database Migration Script
# Runs all database migrations for both main app and admin dashboard
set -e
# Configuration
DB_HOST="10.0.0.207"
DB_PORT="5432"
DB_USER="postgres"
DB_PASSWORD="a3ppq"
DB_NAME="parentflow"
DB_NAME_ADMIN="parentflowadmin"
# Color codes
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log() {
echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1"
}
error() {
echo -e "${RED}[ERROR]${NC} $1" >&2
exit 1
}
success() {
echo -e "${GREEN}${NC} $1"
}
warning() {
echo -e "${YELLOW}${NC} $1"
}
# Header
echo ""
echo "=========================================="
echo " Database Migration for Production "
echo "=========================================="
echo ""
# Check PostgreSQL client
if ! command -v psql &> /dev/null; then
error "PostgreSQL client not installed. Run: apt-get install postgresql-client"
fi
# Test database connection
log "Testing database connection..."
PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d postgres -c "SELECT version();" > /dev/null 2>&1
if [ $? -ne 0 ]; then
error "Cannot connect to database at $DB_HOST:$DB_PORT"
fi
success "Database connection successful"
# Create databases if they don't exist
log "Ensuring databases exist..."
PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d postgres << EOF
-- Create main database
SELECT 'CREATE DATABASE ${DB_NAME}'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '${DB_NAME}')\\gexec
-- Create admin database
SELECT 'CREATE DATABASE ${DB_NAME_ADMIN}'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '${DB_NAME_ADMIN}')\\gexec
EOF
success "Databases verified"
# Enable extensions
log "Enabling required extensions..."
PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";"
PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -c "CREATE EXTENSION IF NOT EXISTS vector;"
PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME_ADMIN -c "CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\";"
success "Extensions enabled"
# Find migration directory
MIGRATION_DIR="$(dirname "$0")/maternal-app/maternal-app-backend/src/database/migrations"
if [ ! -d "$MIGRATION_DIR" ]; then
error "Migration directory not found: $MIGRATION_DIR"
fi
# Create migration tracking table
log "Creating migration tracking table..."
PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME << 'EOF'
CREATE TABLE IF NOT EXISTS schema_migrations (
id SERIAL PRIMARY KEY,
version VARCHAR(255) NOT NULL UNIQUE,
executed_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
execution_time_ms INTEGER,
success BOOLEAN DEFAULT true,
error_message TEXT,
checksum VARCHAR(64)
);
CREATE INDEX IF NOT EXISTS idx_schema_migrations_version ON schema_migrations(version);
CREATE INDEX IF NOT EXISTS idx_schema_migrations_executed ON schema_migrations(executed_at);
EOF
success "Migration tracking table ready"
# Define all migrations in order
MIGRATIONS=(
"V001_create_core_auth.sql"
"V002_create_family_structure.sql"
"V003_create_child_entities.sql"
"V004_create_activity_tables.sql"
"V005_create_notification_system.sql"
"V006_create_audit_log.sql"
"V007_create_analytics_tables.sql"
"V008_add_verification_system.sql"
"V008_add_eula_fields.sql"
"V009_add_family_preferences.sql"
"V009_add_multi_child_preferences.sql"
"V010_enhance_notifications.sql"
"V010_add_ai_conversations.sql"
"V011_add_tracking_enhancements.sql"
"V011_create_photos_module.sql"
"V012_add_device_registry.sql"
"V013_add_mfa_support.sql"
"V014_add_refresh_token_rotation.sql"
"V015_add_audit_fields.sql"
"V016_add_webauthn_support.sql"
"V017_add_gdpr_compliance.sql"
"V018_add_ai_embeddings.sql"
"V019_add_voice_feedback.sql"
"V020_add_indexes_optimization.sql"
"V021_add_timezone_support.sql"
"V022_add_data_archiving.sql"
"V028_create_invite_codes.sql"
)
# Function to calculate file checksum
calculate_checksum() {
local file=$1
if command -v sha256sum &> /dev/null; then
sha256sum "$file" | cut -d' ' -f1
else
echo "no-checksum"
fi
}
# Run migrations
log "Running migrations for main database..."
TOTAL=${#MIGRATIONS[@]}
CURRENT=0
SKIPPED=0
EXECUTED=0
for migration in "${MIGRATIONS[@]}"; do
CURRENT=$((CURRENT + 1))
MIGRATION_FILE="$MIGRATION_DIR/$migration"
if [ ! -f "$MIGRATION_FILE" ]; then
warning "[$CURRENT/$TOTAL] Migration file not found: $migration"
continue
fi
# Check if migration was already executed
VERSION=$(echo $migration | cut -d'_' -f1)
ALREADY_RUN=$(PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -tAc \
"SELECT COUNT(*) FROM schema_migrations WHERE version = '$VERSION';")
if [ "$ALREADY_RUN" = "1" ]; then
echo -e "${YELLOW}[$CURRENT/$TOTAL]${NC} Skipping $migration (already applied)"
SKIPPED=$((SKIPPED + 1))
continue
fi
echo -e "${BLUE}[$CURRENT/$TOTAL]${NC} Applying $migration..."
START_TIME=$(date +%s%3N)
CHECKSUM=$(calculate_checksum "$MIGRATION_FILE")
# Run migration
if PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -f "$MIGRATION_FILE" > /dev/null 2>&1; then
END_TIME=$(date +%s%3N)
EXEC_TIME=$((END_TIME - START_TIME))
# Record successful migration
PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME << EOF
INSERT INTO schema_migrations (version, execution_time_ms, checksum)
VALUES ('$VERSION', $EXEC_TIME, '$CHECKSUM');
EOF
success "Applied $migration (${EXEC_TIME}ms)"
EXECUTED=$((EXECUTED + 1))
else
error "Failed to apply migration: $migration"
fi
done
log "Migration summary: $EXECUTED executed, $SKIPPED skipped, $TOTAL total"
# Run admin-specific migrations if needed
log "Setting up admin database..."
PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME_ADMIN << 'EOF'
-- Admin users table (if not exists from main DB)
CREATE TABLE IF NOT EXISTS admin_users (
id VARCHAR(36) PRIMARY KEY DEFAULT gen_random_uuid()::text,
email VARCHAR(255) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
name VARCHAR(100),
role VARCHAR(50) DEFAULT 'admin',
is_active BOOLEAN DEFAULT true,
last_login_at TIMESTAMP WITH TIME ZONE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
permissions JSONB DEFAULT '["users:read", "users:write", "invites:read", "invites:write", "analytics:read"]',
two_factor_secret VARCHAR(255),
two_factor_enabled BOOLEAN DEFAULT false
);
-- Admin sessions
CREATE TABLE IF NOT EXISTS admin_sessions (
id VARCHAR(36) PRIMARY KEY DEFAULT gen_random_uuid()::text,
admin_user_id VARCHAR(36) REFERENCES admin_users(id) ON DELETE CASCADE,
token_hash VARCHAR(255) NOT NULL UNIQUE,
ip_address VARCHAR(45),
user_agent TEXT,
expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
last_activity_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- Admin audit logs
CREATE TABLE IF NOT EXISTS admin_audit_logs (
id VARCHAR(36) PRIMARY KEY DEFAULT gen_random_uuid()::text,
admin_user_id VARCHAR(36) REFERENCES admin_users(id),
action VARCHAR(100) NOT NULL,
entity_type VARCHAR(50),
entity_id VARCHAR(36),
details JSONB DEFAULT '{}',
ip_address VARCHAR(45),
user_agent TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- Create indexes
CREATE INDEX IF NOT EXISTS idx_admin_users_email ON admin_users(email);
CREATE INDEX IF NOT EXISTS idx_admin_sessions_token ON admin_sessions(token_hash);
CREATE INDEX IF NOT EXISTS idx_admin_sessions_admin ON admin_sessions(admin_user_id);
CREATE INDEX IF NOT EXISTS idx_admin_audit_logs_admin ON admin_audit_logs(admin_user_id);
CREATE INDEX IF NOT EXISTS idx_admin_audit_logs_created ON admin_audit_logs(created_at);
-- Insert default admin user if not exists (password: admin123)
INSERT INTO admin_users (email, password_hash, name, role)
VALUES (
'admin@parentflowapp.com',
'$2b$10$H5hw3/iwkCichU5dpVIMqe5Me7WV9jz.qWRm0V4JyGF9smgxgFBxm',
'System Administrator',
'super_admin'
) ON CONFLICT (email) DO NOTHING;
EOF
success "Admin database configured"
# Verify migration status
log "Verifying migration status..."
TOTAL_APPLIED=$(PGPASSWORD=$DB_PASSWORD psql -h $DB_HOST -p $DB_PORT -U $DB_USER -d $DB_NAME -tAc \
"SELECT COUNT(*) FROM schema_migrations WHERE success = true;")
echo ""
echo "=========================================="
echo -e "${GREEN} Database Migration Completed! ${NC}"
echo "=========================================="
echo ""
echo "Summary:"
echo " Total migrations: $TOTAL"
echo " Applied in this run: $EXECUTED"
echo " Previously applied: $SKIPPED"
echo " Total in database: $TOTAL_APPLIED"
echo ""
echo "Databases ready:"
echo " Main: $DB_NAME at $DB_HOST:$DB_PORT"
echo " Admin: $DB_NAME_ADMIN at $DB_HOST:$DB_PORT"
echo ""
success "All migrations completed successfully"