#!/usr/bin/env python3 """ 5 Why Root Cause Analyzer - Application Launcher Version: 1.0.0 Description: Python script to start both backend and frontend services """ import os import sys import time import signal import subprocess import platform from pathlib import Path class Color: """ANSI color codes for terminal output""" HEADER = '\033[95m' OKBLUE = '\033[94m' OKCYAN = '\033[96m' OKGREEN = '\033[92m' WARNING = '\033[93m' FAIL = '\033[91m' ENDC = '\033[0m' BOLD = '\033[1m' UNDERLINE = '\033[4m' class AppLauncher: """Main application launcher class""" def __init__(self): self.project_root = Path(__file__).parent self.backend_process = None self.frontend_process = None self.is_windows = platform.system() == 'Windows' def print_banner(self): """Print application banner""" print(f"\n{Color.HEADER}{Color.BOLD}{'='*70}{Color.ENDC}") print(f"{Color.HEADER}{Color.BOLD} 5 Why Root Cause Analyzer - v1.0.0{Color.ENDC}") print(f"{Color.HEADER}{Color.BOLD} Enterprise-grade Root Cause Analysis Tool{Color.ENDC}") print(f"{Color.HEADER}{Color.BOLD}{'='*70}{Color.ENDC}\n") def print_info(self, message): """Print info message""" print(f"{Color.OKBLUE}[INFO]{Color.ENDC} {message}") def print_success(self, message): """Print success message""" print(f"{Color.OKGREEN}[SUCCESS]{Color.ENDC} {message}") def print_warning(self, message): """Print warning message""" print(f"{Color.WARNING}[WARNING]{Color.ENDC} {message}") def print_error(self, message): """Print error message""" print(f"{Color.FAIL}[ERROR]{Color.ENDC} {message}") def check_node_installed(self): """Check if Node.js is installed""" try: result = subprocess.run( ['node', '--version'], capture_output=True, text=True, check=True ) version = result.stdout.strip() self.print_success(f"Node.js detected: {version}") return True except (subprocess.CalledProcessError, FileNotFoundError): self.print_error("Node.js is not installed or not in PATH") self.print_info("Please install Node.js 18+ from https://nodejs.org/") return False def check_npm_installed(self): """Check if npm is installed""" try: result = subprocess.run( ['npm', '--version'], capture_output=True, text=True, check=True ) version = result.stdout.strip() self.print_success(f"npm detected: {version}") return True except (subprocess.CalledProcessError, FileNotFoundError): self.print_error("npm is not installed or not in PATH") return False def check_dependencies_installed(self): """Check if node_modules exists""" node_modules = self.project_root / 'node_modules' if node_modules.exists(): self.print_success("Dependencies installed (node_modules found)") return True else: self.print_warning("Dependencies not installed (node_modules not found)") self.print_info("Run 'npm install' to install dependencies") return False def check_env_file(self): """Check if .env file exists""" env_file = self.project_root / '.env' if env_file.exists(): self.print_success("Environment file (.env) found") return True else: self.print_warning(".env file not found") self.print_info("Copy .env.example to .env and configure it") return False def start_backend(self): """Start the backend server""" self.print_info("Starting backend server...") try: # Use 'npm.cmd' on Windows, 'npm' on Unix npm_cmd = 'npm.cmd' if self.is_windows else 'npm' self.backend_process = subprocess.Popen( [npm_cmd, 'run', 'server'], cwd=str(self.project_root), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1, universal_newlines=True, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if self.is_windows else 0 ) # Wait a bit and check if process started successfully time.sleep(2) if self.backend_process.poll() is None: self.print_success("Backend server started successfully") self.print_info("Backend running at: http://localhost:3001") return True else: self.print_error("Backend server failed to start") return False except Exception as e: self.print_error(f"Failed to start backend: {str(e)}") return False def start_frontend(self): """Start the frontend development server""" self.print_info("Starting frontend development server...") try: # Use 'npm.cmd' on Windows, 'npm' on Unix npm_cmd = 'npm.cmd' if self.is_windows else 'npm' self.frontend_process = subprocess.Popen( [npm_cmd, 'run', 'client'], cwd=str(self.project_root), stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1, universal_newlines=True, creationflags=subprocess.CREATE_NEW_PROCESS_GROUP if self.is_windows else 0 ) # Wait a bit and check if process started successfully time.sleep(3) if self.frontend_process.poll() is None: self.print_success("Frontend server started successfully") self.print_info("Frontend running at: http://localhost:5173") return True else: self.print_error("Frontend server failed to start") return False except Exception as e: self.print_error(f"Failed to start frontend: {str(e)}") return False def monitor_processes(self): """Monitor both processes and print their output""" self.print_info("\n" + "="*70) self.print_success("Both services are running!") self.print_info("="*70) print(f"\n{Color.OKGREEN}{Color.BOLD}Access the application:{Color.ENDC}") print(f" {Color.OKCYAN}Frontend:{Color.ENDC} http://localhost:5173") print(f" {Color.OKCYAN}Backend API:{Color.ENDC} http://localhost:3001") print(f" {Color.OKCYAN}API Health:{Color.ENDC} http://localhost:3001/health") print(f"\n{Color.OKGREEN}{Color.BOLD}Test Accounts:{Color.ENDC}") print(f" {Color.OKCYAN}Admin:{Color.ENDC} admin@example.com / Admin@123456") print(f" {Color.OKCYAN}User1:{Color.ENDC} user001@example.com / User@123456") print(f" {Color.OKCYAN}User2:{Color.ENDC} user002@example.com / User@123456") print(f"\n{Color.WARNING}Press Ctrl+C to stop all services{Color.ENDC}\n") try: # Keep the script running and monitor processes while True: # Check if backend is still running if self.backend_process.poll() is not None: self.print_error("Backend process terminated unexpectedly") break # Check if frontend is still running if self.frontend_process.poll() is not None: self.print_error("Frontend process terminated unexpectedly") break time.sleep(1) except KeyboardInterrupt: self.print_info("\nReceived shutdown signal...") def cleanup(self): """Clean up and terminate all processes""" self.print_info("Shutting down services...") # Terminate frontend if self.frontend_process and self.frontend_process.poll() is None: try: if self.is_windows: # On Windows, use taskkill to terminate process tree subprocess.run( ['taskkill', '/F', '/T', '/PID', str(self.frontend_process.pid)], capture_output=True ) else: self.frontend_process.terminate() self.frontend_process.wait(timeout=5) self.print_success("Frontend server stopped") except Exception as e: self.print_warning(f"Error stopping frontend: {str(e)}") # Terminate backend if self.backend_process and self.backend_process.poll() is None: try: if self.is_windows: # On Windows, use taskkill to terminate process tree subprocess.run( ['taskkill', '/F', '/T', '/PID', str(self.backend_process.pid)], capture_output=True ) else: self.backend_process.terminate() self.backend_process.wait(timeout=5) self.print_success("Backend server stopped") except Exception as e: self.print_warning(f"Error stopping backend: {str(e)}") self.print_success("All services stopped successfully") def run(self): """Main run method""" self.print_banner() # Pre-flight checks self.print_info("Running pre-flight checks...") if not self.check_node_installed(): return 1 if not self.check_npm_installed(): return 1 if not self.check_dependencies_installed(): self.print_warning("Please run 'npm install' first") return 1 if not self.check_env_file(): self.print_warning("Please configure .env file first") return 1 self.print_success("All pre-flight checks passed!\n") # Start services if not self.start_backend(): self.cleanup() return 1 time.sleep(2) # Give backend time to start if not self.start_frontend(): self.cleanup() return 1 # Monitor processes try: self.monitor_processes() finally: self.cleanup() return 0 def main(): """Main entry point""" launcher = AppLauncher() try: sys.exit(launcher.run()) except Exception as e: print(f"\n{Color.FAIL}[FATAL ERROR]{Color.ENDC} {str(e)}") launcher.cleanup() sys.exit(1) if __name__ == '__main__': main()