#!/bin/bash # Run migration 0010_track_schema with shared-DB detection. # # - Standalone explorer DB: applies the full Track 2-4 schema. # - Shared Blockscout DB: applies only explorer-owned auth/operator tables to # avoid colliding with Blockscout's existing addresses/token_transfers schema. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" MIGRATION_DIR="$PROJECT_ROOT/backend/database/migrations" FULL_MIGRATION_FILE="$MIGRATION_DIR/0010_track_schema.up.sql" AUTH_ONLY_MIGRATION_FILE="$MIGRATION_DIR/0010_track_schema.auth_only.sql" MIGRATION_FILE="$FULL_MIGRATION_FILE" MIGRATION_MODE="full" REQUIRED_TABLES=(addresses token_transfers operator_roles wallet_nonces) echo "=== Running Track Schema Migration (0010) ===" echo "" if [ ! -f "$FULL_MIGRATION_FILE" ]; then echo "❌ Migration file not found: $FULL_MIGRATION_FILE" exit 1 fi if [ ! -f "$AUTH_ONLY_MIGRATION_FILE" ]; then echo "❌ Migration file not found: $AUTH_ONLY_MIGRATION_FILE" exit 1 fi # Load database config from environment or use defaults DB_HOST="${DB_HOST:-localhost}" DB_PORT="${DB_PORT:-5432}" DB_USER="${DB_USER:-explorer}" DB_PASSWORD="${DB_PASSWORD:-changeme}" DB_NAME="${DB_NAME:-explorer}" sql_scalar() { local sql="$1" export PGPASSWORD="$DB_PASSWORD" psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -Atc "$sql" 2>/dev/null | tr -d ' ' } is_shared_blockscout_db() { sql_scalar " SELECT CASE WHEN EXISTS ( SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'addresses' ) AND NOT EXISTS ( SELECT 1 FROM information_schema.columns WHERE table_schema = 'public' AND table_name = 'addresses' AND column_name = 'address' ) THEN 'yes' ELSE 'no' END; " } count_required_tables() { local table_list="" local table for table in "${REQUIRED_TABLES[@]}"; do if [ -n "$table_list" ]; then table_list+=", " fi table_list+="'$table'" done sql_scalar "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = 'public' AND table_name IN (${table_list});" } if [ "$(is_shared_blockscout_db || echo no)" = "yes" ]; then MIGRATION_MODE="auth-only" MIGRATION_FILE="$AUTH_ONLY_MIGRATION_FILE" REQUIRED_TABLES=(operator_events operator_ip_whitelist operator_roles wallet_nonces) fi echo "Database: $DB_NAME@$DB_HOST:$DB_PORT" echo "User: $DB_USER" if [ "$MIGRATION_MODE" = "auth-only" ]; then echo "Mode: shared Blockscout DB detected; applying explorer auth/operator tables only" else echo "Mode: standalone explorer DB; applying full Track 2-4 schema" fi echo "" TABLE_COUNT="$(count_required_tables || echo 0)" if [ "${TABLE_COUNT:-0}" -ge "${#REQUIRED_TABLES[@]}" ]; then echo "✅ Migration already applied (${TABLE_COUNT}/${#REQUIRED_TABLES[@]} required tables present)" echo "" echo "Verified tables:" for table in "${REQUIRED_TABLES[@]}"; do echo " - $table" done exit 0 fi export PGPASSWORD="$DB_PASSWORD" if psql -v ON_ERROR_STOP=1 -h "$DB_HOST" -p "$DB_PORT" -U "$DB_USER" -d "$DB_NAME" -f "$MIGRATION_FILE"; then TABLE_COUNT="$(count_required_tables || echo 0)" if [ "${TABLE_COUNT:-0}" -lt "${#REQUIRED_TABLES[@]}" ]; then echo "" echo "❌ Migration finished but required tables are still missing (${TABLE_COUNT}/${#REQUIRED_TABLES[@]})" exit 1 fi echo "" echo "✅ Migration ${MIGRATION_MODE} completed successfully" echo "" if [ "$MIGRATION_MODE" = "auth-only" ]; then echo "Created or verified tables:" echo " - operator_events (Track 4)" echo " - operator_ip_whitelist (Track 4)" echo " - operator_roles (Track 4)" echo " - wallet_nonces (Authentication)" else echo "Created tables:" echo " - addresses (Track 2)" echo " - token_transfers (Track 2)" echo " - token_balances (Track 2)" echo " - internal_transactions (Track 2)" echo " - analytics_flows (Track 3)" echo " - analytics_bridge_history (Track 3)" echo " - token_distribution (Track 3 - materialized view)" echo " - operator_events (Track 4)" echo " - operator_ip_whitelist (Track 4)" echo " - operator_roles (Track 4)" echo " - wallet_nonces (Authentication)" fi else echo "" echo "❌ Migration failed" exit 1 fi unset PGPASSWORD