#!/bin/bash # ================================================================================================ # ENHANCED TECH STACK SELECTOR - DOCKER STARTUP SCRIPT # Optimized for Docker environment with proper service discovery # ================================================================================================ set -e # Parse command line arguments FORCE_MIGRATION=false if [ "$1" = "--force-migration" ] || [ "$1" = "-f" ]; then FORCE_MIGRATION=true echo "🔄 Force migration mode enabled" elif [ "$1" = "--help" ] || [ "$1" = "-h" ]; then echo "Usage: $0 [OPTIONS]" echo "" echo "Options:" echo " --force-migration, -f Force re-run all migrations" echo " --help, -h Show this help message" echo "" echo "Examples:" echo " $0 # Normal startup with auto-migration detection" echo " $0 --force-migration # Force re-run all migrations" exit 0 fi echo "="*60 echo "🚀 ENHANCED TECH STACK SELECTOR v15.0 - DOCKER VERSION" echo "="*60 echo "✅ PostgreSQL data migrated to Neo4j" echo "✅ Price-based relationships" echo "✅ Real data from PostgreSQL" echo "✅ Comprehensive pricing analysis" echo "✅ Docker-optimized startup" echo "="*60 # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Function to print colored output print_status() { echo -e "${GREEN}✅ $1${NC}" } print_warning() { echo -e "${YELLOW}âš ī¸ $1${NC}" } print_error() { echo -e "${RED}❌ $1${NC}" } print_info() { echo -e "${BLUE}â„šī¸ $1${NC}" } # Get environment variables with defaults POSTGRES_HOST=${POSTGRES_HOST:-postgres} POSTGRES_PORT=${POSTGRES_PORT:-5432} POSTGRES_USER=${POSTGRES_USER:-pipeline_admin} POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-secure_pipeline_2024} POSTGRES_DB=${POSTGRES_DB:-dev_pipeline} NEO4J_URI=${NEO4J_URI:-bolt://neo4j:7687} NEO4J_USER=${NEO4J_USER:-neo4j} NEO4J_PASSWORD=${NEO4J_PASSWORD:-password} CLAUDE_API_KEY=${CLAUDE_API_KEY:-} print_status "Environment variables loaded" print_info "PostgreSQL: ${POSTGRES_HOST}:${POSTGRES_PORT}/${POSTGRES_DB}" print_info "Neo4j: ${NEO4J_URI}" # Function to wait for service to be ready wait_for_service() { local service_name=$1 local host=$2 local port=$3 local max_attempts=30 local attempt=1 print_info "Waiting for ${service_name} to be ready..." while [ $attempt -le $max_attempts ]; do if nc -z $host $port 2>/dev/null; then print_status "${service_name} is ready!" return 0 fi print_info "Attempt ${attempt}/${max_attempts}: ${service_name} not ready yet, waiting 2 seconds..." sleep 2 attempt=$((attempt + 1)) done print_error "${service_name} failed to become ready after ${max_attempts} attempts" return 1 } # Wait for PostgreSQL if ! wait_for_service "PostgreSQL" $POSTGRES_HOST $POSTGRES_PORT; then exit 1 fi # Wait for Neo4j if ! wait_for_service "Neo4j" neo4j 7687; then exit 1 fi # Function to check if database needs migration check_database_migration() { print_info "Checking if database needs migration..." # Check if price_tiers table exists and has data if ! python3 -c " import psycopg2 import os try: conn = psycopg2.connect( host=os.getenv('POSTGRES_HOST', 'postgres'), port=int(os.getenv('POSTGRES_PORT', '5432')), user=os.getenv('POSTGRES_USER', 'pipeline_admin'), password=os.getenv('POSTGRES_PASSWORD', 'secure_pipeline_2024'), database=os.getenv('POSTGRES_DB', 'dev_pipeline') ) cursor = conn.cursor() # Check if price_tiers table exists cursor.execute(\"\"\" SELECT EXISTS ( SELECT FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'price_tiers' ); \"\"\") table_exists = cursor.fetchone()[0] if not table_exists: print('price_tiers table does not exist - migration needed') exit(1) # Check if price_tiers has data cursor.execute('SELECT COUNT(*) FROM price_tiers;') count = cursor.fetchone()[0] if count == 0: print('price_tiers table is empty - migration needed') exit(1) # Check if stack_recommendations has sufficient data cursor.execute('SELECT COUNT(*) FROM stack_recommendations;') rec_count = cursor.fetchone()[0] if rec_count < 20: # Reduced threshold for Docker environment print(f'stack_recommendations has only {rec_count} records - migration needed') exit(1) print('Database appears to be fully migrated') cursor.close() conn.close() except Exception as e: print(f'Error checking database: {e}') exit(1) " 2>/dev/null; then return 1 # Migration needed else return 0 # Migration not needed fi } # Function to run PostgreSQL migrations run_postgres_migrations() { print_info "Running PostgreSQL migrations..." # Migration files in order migration_files=( "db/001_schema.sql" "db/002_tools_migration.sql" "db/003_tools_pricing_migration.sql" ) # Set PGPASSWORD to avoid password prompts export PGPASSWORD="$POSTGRES_PASSWORD" for migration_file in "${migration_files[@]}"; do if [ ! -f "$migration_file" ]; then print_error "Migration file not found: $migration_file" exit 1 fi print_info "Running migration: $migration_file" # Run migration with error handling if psql -h $POSTGRES_HOST -p $POSTGRES_PORT -U $POSTGRES_USER -d $POSTGRES_DB -f "$migration_file" -q 2>/dev/null; then print_status "Migration completed: $migration_file" else print_error "Migration failed: $migration_file" print_info "Check the error logs above for details" exit 1 fi done # Unset password unset PGPASSWORD print_status "All PostgreSQL migrations completed successfully" } # Check if migration is needed and run if necessary if [ "$FORCE_MIGRATION" = true ]; then print_warning "Force migration enabled - running migrations..." run_postgres_migrations # Verify migration was successful print_info "Verifying migration..." if check_database_migration; then print_status "Migration verification successful" else print_error "Migration verification failed" exit 1 fi elif check_database_migration; then print_status "Database is already migrated" else print_warning "Database needs migration - running migrations..." run_postgres_migrations # Verify migration was successful print_info "Verifying migration..." if check_database_migration; then print_status "Migration verification successful" else print_error "Migration verification failed" exit 1 fi fi # Check if Neo4j migration has been run print_info "Checking if Neo4j migration has been completed..." if ! python3 -c " from neo4j import GraphDatabase import os try: driver = GraphDatabase.driver( os.getenv('NEO4J_URI', 'bolt://neo4j:7687'), auth=(os.getenv('NEO4J_USER', 'neo4j'), os.getenv('NEO4J_PASSWORD', 'password')) ) with driver.session() as session: result = session.run('MATCH (p:PriceTier) RETURN count(p) as count') price_tiers = result.single()['count'] if price_tiers == 0: print('No data found in Neo4j - migration needed') exit(1) else: print(f'Found {price_tiers} price tiers - migration appears complete') driver.close() except Exception as e: print(f'Error checking migration status: {e}') exit(1) " 2>/dev/null; then print_warning "No data found in Neo4j - running migration..." # Run migration if python3 migrate_postgres_to_neo4j.py; then print_status "Migration completed successfully" else print_error "Migration failed" exit 1 fi else print_status "Migration appears to be complete" fi # Set environment variables for the application export NEO4J_URI="$NEO4J_URI" export NEO4J_USER="$NEO4J_USER" export NEO4J_PASSWORD="$NEO4J_PASSWORD" export POSTGRES_HOST="$POSTGRES_HOST" export POSTGRES_PORT="$POSTGRES_PORT" export POSTGRES_USER="$POSTGRES_USER" export POSTGRES_PASSWORD="$POSTGRES_PASSWORD" export POSTGRES_DB="$POSTGRES_DB" export CLAUDE_API_KEY="$CLAUDE_API_KEY" print_status "Environment variables set" # Create logs directory if it doesn't exist mkdir -p logs # Start the migrated application print_info "Starting Enhanced Tech Stack Selector (Docker Version)..." print_info "Server will be available at: http://localhost:8002" print_info "API documentation: http://localhost:8002/docs" print_info "Health check: http://localhost:8002/health" print_info "Diagnostics: http://localhost:8002/api/diagnostics" print_info "" print_info "Press Ctrl+C to stop the server" print_info "" # Start the application cd src python3 main_migrated.py