Assist_Design/tools/dev/dev-start.js

224 lines
5.7 KiB
JavaScript
Raw Normal View History

#!/usr/bin/env node
const { spawn, execSync } = require('child_process');
const path = require('path');
const colors = {
reset: '\x1b[0m',
red: '\x1b[31m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
magenta: '\x1b[35m',
cyan: '\x1b[36m',
white: '\x1b[37m',
bold: '\x1b[1m'
};
function log(message, color = colors.white) {
console.log(`${color}${message}${colors.reset}`);
}
function logStep(step, message) {
log(`[${step}] ${message}`, colors.cyan);
}
function logSuccess(message) {
log(`${message}`, colors.green);
}
function logError(message) {
log(`${message}`, colors.red);
}
function logWarning(message) {
log(`⚠️ ${message}`, colors.yellow);
}
async function checkDockerRunning() {
try {
execSync('docker info', { stdio: 'ignore' });
return true;
} catch (error) {
return false;
}
}
async function checkServiceRunning(containerName) {
try {
const result = execSync(`docker ps --filter "name=${containerName}" --filter "status=running" --format "{{.Names}}"`, { encoding: 'utf8' });
return result.trim() === containerName;
} catch (error) {
return false;
}
}
async function checkPortInUse(port) {
try {
execSync(`lsof -i:${port}`, { stdio: 'ignore' });
return true;
} catch (error) {
return false;
}
}
async function waitForService(serviceName, checkCommand, maxAttempts = 30) {
logStep('WAIT', `Waiting for ${serviceName} to be ready...`);
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
execSync(checkCommand, { stdio: 'ignore' });
logSuccess(`${serviceName} is ready!`);
return true;
} catch (error) {
if (attempt === maxAttempts) {
logError(`${serviceName} failed to start after ${maxAttempts} attempts`);
return false;
}
process.stdout.write(`⏳ Waiting for ${serviceName}... (${attempt}/${maxAttempts})\r`);
await new Promise(resolve => setTimeout(resolve, 1000));
}
}
return false;
}
async function startServices() {
logStep('DOCKER', 'Checking if Docker is running...');
if (!await checkDockerRunning()) {
logError('Docker is not running. Please start Docker and try again.');
process.exit(1);
}
logSuccess('Docker is running');
// Check if services are already running
const pgRunning = await checkServiceRunning('portal-postgres');
const redisRunning = await checkServiceRunning('portal-redis');
if (pgRunning && redisRunning) {
logSuccess('PostgreSQL and Redis are already running');
} else {
logStep('SERVICES', 'Starting PostgreSQL and Redis...');
try {
execSync('docker-compose -f tools/deployment/docker-compose.yml up -d', { stdio: 'inherit' });
logSuccess('Services started');
} catch (error) {
logError(`Failed to start services: ${error.message}`);
process.exit(1);
}
}
// Wait for PostgreSQL
const pgReady = await waitForService(
'PostgreSQL',
'docker exec portal-postgres pg_isready -U app -d portal'
);
if (!pgReady) {
process.exit(1);
}
// Wait for Redis
const redisReady = await waitForService(
'Redis',
'docker exec portal-redis redis-cli ping'
);
if (!redisReady) {
process.exit(1);
}
}
async function startPrismaStudio() {
logStep('DB', 'Starting Prisma Studio...');
// Check if Prisma Studio port (5555) is already in use
const studioPortInUse = await checkPortInUse(5555);
if (studioPortInUse) {
logSuccess('Prisma Studio is already running on port 5555');
return null;
}
const studioProcess = spawn('pnpm', ['--filter', '@customer-portal/bff', 'run', 'db:studio'], {
stdio: 'pipe',
cwd: process.cwd(),
detached: true
});
// Wait a moment for Prisma Studio to start
setTimeout(() => {
logSuccess('Prisma Studio started on http://localhost:5555');
}, 3000);
return studioProcess;
}
async function startDevelopment() {
logStep('DEV', 'Starting frontend and backend in development mode...');
// Start Prisma Studio first
const studioProcess = await startPrismaStudio();
const devProcess = spawn('pnpm', ['--parallel', '--recursive', 'run', 'dev'], {
stdio: 'inherit',
cwd: process.cwd()
});
// Show ready message after services start
setTimeout(() => {
logSuccess('Development environment is fully ready!');
log(`
🎉 ${colors.bold}${colors.green}All services are running:${colors.reset}
🖥 Frontend: ${colors.cyan}http://localhost:3000${colors.reset}
🔌 Backend: ${colors.cyan}http://localhost:4000${colors.reset}
🗄 Database: ${colors.cyan}http://localhost:5555${colors.reset}
`, colors.white);
}, 8000); // Wait 8 seconds for Next.js to be ready
// Handle graceful shutdown
process.on('SIGINT', () => {
log('\n🛑 Shutting down development servers...', colors.yellow);
if (studioProcess) {
studioProcess.kill('SIGTERM');
}
devProcess.kill('SIGINT');
setTimeout(() => {
log('👋 Development servers stopped', colors.green);
process.exit(0);
}, 1000);
});
devProcess.on('close', (code) => {
if (studioProcess) {
studioProcess.kill('SIGTERM');
}
if (code !== 0) {
logError(`Development servers exited with code ${code}`);
}
process.exit(code);
});
}
async function main() {
log(`
${colors.bold}${colors.blue}🚀 Customer Portal Development Environment${colors.reset}
${colors.cyan}==============================================${colors.reset}
`, colors.bold);
try {
await startServices();
await startDevelopment();
} catch (error) {
logError(`Failed to start development environment: ${error.message}`);
process.exit(1);
}
}
if (require.main === module) {
main();
}