codenuk_backend_mine/dashboard-service/server.js
2025-10-10 08:56:39 +05:30

2158 lines
87 KiB
JavaScript

// const express = require('express');
// const http = require('http');
// const socketIo = require('socket.io');
// const { Pool } = require('pg');
// const Redis = require('redis');
// const cors = require('cors');
// const axios = require('axios');
// const app = express();
// const server = http.createServer(app);
// const io = socketIo(server, {
// cors: { origin: "*", methods: ["GET", "POST", "PUT", "DELETE"] }
// });
// // Database connections
// const pgPool = new Pool({
// host: process.env.POSTGRES_HOST || 'pipeline_postgres',
// port: process.env.POSTGRES_PORT || 5432,
// database: process.env.POSTGRES_DB || 'dev_pipeline',
// user: process.env.POSTGRES_USER || 'pipeline_admin',
// password: process.env.POSTGRES_PASSWORD || 'secure_pipeline_2024',
// max: 20,
// idleTimeoutMillis: 30000,
// connectionTimeoutMillis: 2000,
// });
// const redisClient = Redis.createClient({
// socket: {
// host: process.env.REDIS_HOST || 'pipeline_redis',
// port: process.env.REDIS_PORT || 6379
// },
// password: process.env.REDIS_PASSWORD || 'redis_secure_2024'
// });
// redisClient.on('error', (err) => console.log('Redis Client Error', err));
// // Services configuration
// const SERVICES = {
// 'api-gateway': {
// port: 8000,
// name: 'API Gateway',
// container: 'pipeline_api_gateway',
// url: 'http://pipeline_api_gateway:8000'
// },
// 'requirement-processor': {
// port: 8001,
// name: 'Requirement Processor',
// container: 'pipeline_requirement_processor',
// url: 'http://pipeline_requirement_processor:8001'
// },
// 'tech-stack-selector': {
// port: 8002,
// name: 'Tech Stack Selector',
// container: 'pipeline_tech_stack_selector',
// url: 'http://pipeline_tech_stack_selector:8002'
// },
// 'architecture-designer': {
// port: 8003,
// name: 'Architecture Designer',
// container: 'pipeline_architecture_designer',
// url: 'http://pipeline_architecture_designer:8003'
// },
// 'code-generator': {
// port: 8004,
// name: 'Code Generator',
// container: 'pipeline_code_generator',
// url: 'http://pipeline_code_generator:8004'
// },
// 'test-generator': {
// port: 8005,
// name: 'Test Generator',
// container: 'pipeline_test_generator',
// url: 'http://pipeline_test_generator:8005'
// },
// 'deployment-manager': {
// port: 8006,
// name: 'Deployment Manager',
// container: 'pipeline_deployment_manager',
// url: 'http://pipeline_deployment_manager:8006'
// },
// 'self-improving-generator': {
// port: 8007,
// name: 'Self-Improving Generator',
// container: 'pipeline_self_improving_generator',
// url: 'http://pipeline_self_improving_generator:8007'
// }
// };
// // Middleware
// app.use(cors());
// app.use(express.json({ limit: '50mb' }));
// app.use(express.urlencoded({ extended: true, limit: '50mb' }));
// // Database service - FIXED to work with your actual database structure
// class DatabaseService {
// static async getProjects(filters = {}) {
// try {
// console.log('🔍 Querying projects from database...');
// // Simple query for project_contexts table - NO JOINS
// let query = `
// SELECT
// id,
// project_name,
// technology_stack,
// all_features,
// completed_features,
// pending_features,
// project_path,
// created_at,
// updated_at
// FROM project_contexts
// `;
// const conditions = [];
// const values = [];
// let paramCount = 0;
// if (filters.project_name) {
// conditions.push(`project_name ILIKE $${++paramCount}`);
// values.push(`%${filters.project_name}%`);
// }
// if (conditions.length > 0) {
// query += ` WHERE ${conditions.join(' AND ')}`;
// }
// query += ` ORDER BY created_at DESC LIMIT 20`;
// console.log('🔍 Executing query:', query);
// const result = await pgPool.query(query, values);
// console.log('✅ Query result:', result.rows.length, 'projects found');
// // Get file counts for each project separately - SAFE QUERIES
// for (let project of result.rows) {
// try {
// const fileCountResult = await pgPool.query(
// 'SELECT COUNT(*) FROM code_files WHERE project_id = $1',
// [project.id]
// );
// project.file_count = parseInt(fileCountResult.rows[0].count);
// } catch (fileError) {
// console.log('⚠️ Could not get file count for project', project.id);
// project.file_count = 0;
// }
// }
// return result.rows;
// } catch (error) {
// console.error('❌ Database query error:', error.message);
// throw error;
// }
// }
// static async getSystemStats() {
// try {
// console.log('🔍 Getting system stats from database...');
// // Get counts from each table - SIMPLE QUERIES
// const projectCountResult = await pgPool.query('SELECT COUNT(*) FROM project_contexts');
// const fileCountResult = await pgPool.query('SELECT COUNT(*) FROM code_files');
// const improvementCountResult = await pgPool.query('SELECT COUNT(*) FROM improvement_history');
// // Get recent projects (last 24 hours)
// const recentResult = await pgPool.query(`
// SELECT COUNT(*) FROM project_contexts
// WHERE created_at > NOW() - INTERVAL '24 hours'
// `);
// const stats = {
// project_contexts: parseInt(projectCountResult.rows[0].count),
// code_files: parseInt(fileCountResult.rows[0].count),
// improvement_history: parseInt(improvementCountResult.rows[0].count),
// recent_projects: parseInt(recentResult.rows[0].count)
// };
// console.log('📊 System stats:', stats);
// return stats;
// } catch (error) {
// console.error('❌ System stats error:', error);
// return {
// project_contexts: 0,
// code_files: 0,
// improvement_history: 0,
// recent_projects: 0
// };
// }
// }
// }
// // WebSocket connection handling
// io.on('connection', (socket) => {
// console.log(`Dashboard client connected: ${socket.id}`);
// socket.emit('connected', {
// message: 'Connected to AI Pipeline Dashboard',
// timestamp: new Date().toISOString()
// });
// socket.on('disconnect', () => {
// console.log(`Dashboard client disconnected: ${socket.id}`);
// });
// });
// // API Routes
// app.get('/api/health', (req, res) => {
// res.json({
// status: 'healthy',
// timestamp: new Date().toISOString(),
// service: 'AI Pipeline Dashboard',
// version: '2.0.0'
// });
// });
// // Debug endpoint
// app.get('/api/debug/database', async (req, res) => {
// try {
// console.log('🔍 Database debug endpoint called');
// const connectionTest = await pgPool.query('SELECT NOW()');
// console.log('✅ Database connection successful');
// const projectCount = await pgPool.query('SELECT COUNT(*) FROM project_contexts');
// const fileCount = await pgPool.query('SELECT COUNT(*) FROM code_files');
// const improvementCount = await pgPool.query('SELECT COUNT(*) FROM improvement_history');
// // Get sample project names
// let sampleProjects = [];
// const sampleResult = await pgPool.query('SELECT id, project_name, created_at FROM project_contexts ORDER BY created_at DESC LIMIT 3');
// sampleProjects = sampleResult.rows;
// res.json({
// connection: 'OK',
// timestamp: connectionTest.rows[0].now,
// tables: {
// project_contexts: parseInt(projectCount.rows[0].count),
// code_files: parseInt(fileCount.rows[0].count),
// improvement_history: parseInt(improvementCount.rows[0].count)
// },
// sampleProjects: sampleProjects
// });
// } catch (error) {
// console.error('❌ Database debug error:', error);
// res.status(500).json({
// error: error.message,
// connection: 'FAILED'
// });
// }
// });
// // System status with real data
// app.get('/api/system/status', async (req, res) => {
// try {
// console.log('🔍 System status endpoint called');
// let healthyServices = 0;
// const serviceChecks = [];
// // Check services
// for (const [key, service] of Object.entries(SERVICES)) {
// try {
// await axios.get(`${service.url}/health`, { timeout: 5000 });
// healthyServices++;
// serviceChecks.push({ service: key, status: 'healthy' });
// } catch (error) {
// serviceChecks.push({ service: key, status: 'unhealthy', error: error.message });
// }
// }
// // Get database stats
// const dbStats = await DatabaseService.getSystemStats();
// res.json({
// healthyServices,
// totalServices: Object.keys(SERVICES).length,
// totalProjects: dbStats.project_contexts,
// totalFiles: dbStats.code_files,
// activeProjects: dbStats.recent_projects,
// improvements: dbStats.improvement_history,
// serviceChecks,
// timestamp: new Date().toISOString()
// });
// } catch (error) {
// console.error('❌ System status error:', error);
// res.status(500).json({ error: error.message });
// }
// });
// // Projects endpoint
// app.get('/api/projects', async (req, res) => {
// try {
// console.log('🔍 Projects endpoint called');
// const projects = await DatabaseService.getProjects(req.query);
// console.log('✅ Projects returned:', projects.length);
// res.json({ projects });
// } catch (error) {
// console.error('❌ Projects endpoint error:', error);
// res.status(500).json({
// error: error.message,
// details: 'Check server logs for database connection issues'
// });
// }
// });
// // Services health endpoint
// app.get('/api/services/health', async (req, res) => {
// console.log('🔍 Services health check called');
// const healthChecks = await Promise.allSettled(
// Object.entries(SERVICES).map(async ([key, service]) => {
// const startTime = Date.now();
// try {
// await axios.get(`${service.url}/health`, { timeout: 5000 });
// return {
// name: service.name,
// status: 'healthy',
// port: service.port,
// container: service.container,
// responseTime: Date.now() - startTime,
// lastCheck: new Date().toISOString()
// };
// } catch (error) {
// return {
// name: service.name,
// status: 'unhealthy',
// port: service.port,
// container: service.container,
// responseTime: Date.now() - startTime,
// error: error.message,
// lastCheck: new Date().toISOString()
// };
// }
// })
// );
// const services = healthChecks.map(result =>
// result.status === 'fulfilled' ? result.value : result.reason
// );
// res.json({ services });
// });
// // Code Editor API endpoints
// app.get('/api/projects/:projectId/files', async (req, res) => {
// try {
// const projectId = req.params.projectId;
// console.log('🔍 Getting files for project:', projectId);
// const result = await pgPool.query(
// 'SELECT id, file_name, file_path, file_type, created_at FROM code_files WHERE project_id = $1 ORDER BY file_path',
// [projectId]
// );
// res.json({ files: result.rows });
// } catch (error) {
// console.error('❌ Error getting project files:', error);
// res.status(500).json({ error: error.message });
// }
// });
// app.get('/api/files/:fileId/content', async (req, res) => {
// try {
// const fileId = req.params.fileId;
// console.log('🔍 Getting content for file:', fileId);
// const result = await pgPool.query(
// 'SELECT file_content, file_name, file_type FROM code_files WHERE id = $1',
// [fileId]
// );
// if (result.rows.length === 0) {
// return res.status(404).json({ error: 'File not found' });
// }
// res.json({
// content: result.rows[0].file_content,
// fileName: result.rows[0].file_name,
// fileType: result.rows[0].file_type
// });
// } catch (error) {
// console.error('❌ Error getting file content:', error);
// res.status(500).json({ error: error.message });
// }
// });
// app.put('/api/files/:fileId/content', async (req, res) => {
// try {
// const fileId = req.params.fileId;
// const { content } = req.body;
// console.log('🔍 Updating content for file:', fileId);
// await pgPool.query(
// 'UPDATE code_files SET file_content = $1, updated_at = NOW() WHERE id = $2',
// [content, fileId]
// );
// res.json({ success: true });
// } catch (error) {
// console.error('❌ Error updating file content:', error);
// res.status(500).json({ error: error.message });
// }
// });
// // Main dashboard page
// app.get('/', (req, res) => {
// res.send(`
// <!DOCTYPE html>
// <html>
// <head>
// <title>AI Pipeline Dashboard</title>
// <meta name="viewport" content="width=device-width, initial-scale=1.0">
// <script src="/socket.io/socket.io.js"></script>
// <style>
// * { margin: 0; padding: 0; box-sizing: border-box; }
// body {
// font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
// background: #0f172a;
// color: #e2e8f0;
// min-height: 100vh;
// }
// .dashboard { display: flex; height: 100vh; }
// .sidebar {
// width: 280px;
// background: #1e293b;
// border-right: 1px solid #334155;
// overflow-y: auto;
// }
// .main-content {
// flex: 1;
// overflow-y: auto;
// padding: 2rem;
// }
// .nav-item {
// display: block;
// padding: 1rem 1.5rem;
// color: #94a3b8;
// text-decoration: none;
// border-bottom: 1px solid #334155;
// transition: all 0.3s;
// }
// .nav-item:hover, .nav-item.active {
// background: #334155;
// color: #60a5fa;
// border-left: 4px solid #60a5fa;
// }
// .header {
// padding: 1.5rem;
// border-bottom: 1px solid #334155;
// text-align: center;
// }
// .header h1 {
// color: #60a5fa;
// font-size: 1.5rem;
// margin-bottom: 0.5rem;
// }
// .stats-grid {
// display: grid;
// grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
// gap: 1.5rem;
// margin-bottom: 2rem;
// }
// .stat-card {
// background: #1e293b;
// border: 1px solid #334155;
// border-radius: 8px;
// padding: 1.5rem;
// text-align: center;
// }
// .stat-value {
// font-size: 2.5rem;
// font-weight: bold;
// color: #60a5fa;
// margin-bottom: 0.5rem;
// }
// .stat-label {
// color: #94a3b8;
// font-size: 0.875rem;
// }
// .card {
// background: #1e293b;
// border: 1px solid #334155;
// border-radius: 8px;
// padding: 1.5rem;
// margin-bottom: 1.5rem;
// }
// .btn {
// background: #3b82f6;
// color: white;
// border: none;
// padding: 0.5rem 1rem;
// border-radius: 6px;
// cursor: pointer;
// font-size: 0.875rem;
// transition: background 0.3s;
// }
// .btn:hover { background: #2563eb; }
// .loading {
// text-align: center;
// padding: 2rem;
// color: #94a3b8;
// }
// .status-indicator {
// display: inline-block;
// width: 8px;
// height: 8px;
// border-radius: 50%;
// margin-right: 8px;
// }
// .status-healthy { background: #10b981; }
// .status-unhealthy { background: #ef4444; }
// .debug-info {
// background: #374151;
// color: #f9fafb;
// padding: 1rem;
// border-radius: 8px;
// margin: 1rem 0;
// font-family: monospace;
// font-size: 0.875rem;
// white-space: pre-wrap;
// }
// .error-info {
// background: #7f1d1d;
// color: #fca5a5;
// padding: 1rem;
// border-radius: 8px;
// margin: 1rem 0;
// font-family: monospace;
// font-size: 0.875rem;
// }
// #content { margin-top: 2rem; }
// </style>
// </head>
// <body>
// <div class="dashboard">
// <div class="sidebar">
// <div class="header">
// <h1>⚡ AI Pipeline</h1>
// <p style="color: #94a3b8; font-size: 0.875rem;">Development Dashboard</p>
// <div style="margin-top: 1rem;">
// <span class="status-indicator status-healthy" id="connectionStatus"></span>
// <span style="font-size: 0.75rem; color: #94a3b8;" id="connectionText">Connected</span>
// </div>
// </div>
// <nav>
// <a href="#" class="nav-item active" onclick="showSection('overview')">📊 System Overview</a>
// <a href="#" class="nav-item" onclick="showSection('debug')">🔍 Database Debug</a>
// <a href="#" class="nav-item" onclick="showSection('projects')">📁 Project Gallery</a>
// <a href="#" class="nav-item" onclick="showSection('live-generation')">⚡ Live Generation</a>
// <a href="#" class="nav-item" onclick="showSection('code-editor')">💻 Code Editor</a>
// <a href="#" class="nav-item" onclick="showSection('quality-dashboard')">📈 Quality Dashboard</a>
// <a href="#" class="nav-item" onclick="showSection('pipeline-monitor')">🔄 Pipeline Monitor</a>
// <a href="#" class="nav-item" onclick="showSection('settings')">⚙️ Settings</a>
// </nav>
// </div>
// <div class="main-content">
// <div id="content"></div>
// </div>
// </div>
// <script>
// // Initialize Socket.IO
// const socket = io();
// socket.on('connect', () => {
// console.log('Connected to AI Pipeline Dashboard');
// updateConnectionStatus(true);
// });
// socket.on('disconnect', () => {
// console.log('Disconnected from AI Pipeline Dashboard');
// updateConnectionStatus(false);
// });
// function updateConnectionStatus(connected) {
// const indicator = document.getElementById('connectionStatus');
// const text = document.getElementById('connectionText');
// if (connected) {
// indicator.className = 'status-indicator status-healthy';
// text.textContent = 'Connected';
// } else {
// indicator.className = 'status-indicator status-unhealthy';
// text.textContent = 'Disconnected';
// }
// }
// // Navigation
// function showSection(section) {
// document.querySelectorAll('.nav-item').forEach(item => {
// item.classList.remove('active');
// });
// event.target.classList.add('active');
// switch(section) {
// case 'overview':
// loadSystemOverview();
// break;
// case 'debug':
// loadDatabaseDebug();
// break;
// case 'projects':
// loadProjectGallery();
// break;
// case 'live-generation':
// loadLiveGeneration();
// break;
// case 'code-editor':
// loadCodeEditor();
// break;
// case 'quality-dashboard':
// loadQualityDashboard();
// break;
// case 'pipeline-monitor':
// loadPipelineMonitor();
// break;
// case 'settings':
// loadSettings();
// break;
// }
// }
// // Database debug page
// async function loadDatabaseDebug() {
// const content = document.getElementById('content');
// content.innerHTML = '<div class="loading">Loading database debug info...</div>';
// try {
// const response = await fetch('/api/debug/database');
// const data = await response.json();
// content.innerHTML = \`
// <h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">Database Debug</h2>
// <div class="card">
// <h3 style="color: #f1f5f9; margin-bottom: 1rem;">Connection Status</h3>
// <div class="debug-info">Connection: \${data.connection}
// Timestamp: \${data.timestamp}</div>
// </div>
// <div class="card">
// <h3 style="color: #f1f5f9; margin-bottom: 1rem;">Database Tables</h3>
// <div class="debug-info">project_contexts: \${data.tables.project_contexts} records
// code_files: \${data.tables.code_files} records
// improvement_history: \${data.tables.improvement_history} records</div>
// </div>
// <div class="card">
// <h3 style="color: #f1f5f9; margin-bottom: 1rem;">Sample Projects</h3>
// <div class="debug-info">\${data.sampleProjects.map(p => \`\${p.project_name} (ID: \${p.id})\`).join('\\n')}</div>
// </div>
// <div class="card">
// <h3 style="color: #f1f5f9; margin-bottom: 1rem;">API Tests</h3>
// <button class="btn" onclick="testSystemStatus()">Test System Status</button>
// <button class="btn" onclick="testProjects()" style="margin-left: 0.5rem;">Test Projects</button>
// <button class="btn" onclick="testServices()" style="margin-left: 0.5rem;">Test Services</button>
// <div id="apiResults" style="margin-top: 1rem;"></div>
// </div>
// \`;
// } catch (error) {
// content.innerHTML = \`
// <h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">Database Debug</h2>
// <div class="error-info">Error: \${error.message}
// Could not connect to database</div>
// \`;
// }
// }
// async function testSystemStatus() {
// const resultsDiv = document.getElementById('apiResults');
// try {
// const response = await fetch('/api/system/status');
// const data = await response.json();
// resultsDiv.innerHTML = '<div class="debug-info">System Status: ' + JSON.stringify(data, null, 2) + '</div>';
// } catch (error) {
// resultsDiv.innerHTML = '<div class="error-info">Error: ' + error.message + '</div>';
// }
// }
// async function testProjects() {
// const resultsDiv = document.getElementById('apiResults');
// try {
// const response = await fetch('/api/projects');
// const data = await response.json();
// resultsDiv.innerHTML = '<div class="debug-info">Projects: ' + JSON.stringify(data, null, 2) + '</div>';
// } catch (error) {
// resultsDiv.innerHTML = '<div class="error-info">Error: ' + error.message + '</div>';
// }
// }
// async function testServices() {
// const resultsDiv = document.getElementById('apiResults');
// try {
// const response = await fetch('/api/services/health');
// const data = await response.json();
// resultsDiv.innerHTML = '<div class="debug-info">Services: ' + JSON.stringify(data, null, 2) + '</div>';
// } catch (error) {
// resultsDiv.innerHTML = '<div class="error-info">Error: ' + error.message + '</div>';
// }
// }
// // System overview with better error handling
// async function loadSystemOverview() {
// const content = document.getElementById('content');
// content.innerHTML = '<div class="loading">Loading system overview...</div>';
// try {
// const [statusRes, projectsRes, servicesRes] = await Promise.all([
// fetch('/api/system/status'),
// fetch('/api/projects'),
// fetch('/api/services/health')
// ]);
// const status = await statusRes.json();
// const projects = await projectsRes.json();
// const services = await servicesRes.json();
// content.innerHTML = \`
// <h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">System Overview</h2>
// <div class="stats-grid">
// <div class="stat-card">
// <div class="stat-value">\${status.totalServices}</div>
// <div class="stat-label">Total Services</div>
// </div>
// <div class="stat-card">
// <div class="stat-value">\${status.healthyServices}</div>
// <div class="stat-label">Healthy Services</div>
// </div>
// <div class="stat-card">
// <div class="stat-value">\${status.totalProjects}</div>
// <div class="stat-label">Total Projects</div>
// </div>
// <div class="stat-card">
// <div class="stat-value">\${status.totalFiles}</div>
// <div class="stat-label">Generated Files</div>
// </div>
// <div class="stat-card">
// <div class="stat-value">\${status.activeProjects}</div>
// <div class="stat-label">Active Projects</div>
// </div>
// </div>
// <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem;">
// <div class="card">
// <h3 style="color: #f1f5f9; margin-bottom: 1rem;">Recent Projects</h3>
// <div style="max-height: 300px; overflow-y: auto;">
// \${projects.projects.length > 0 ?
// projects.projects.slice(0, 5).map(project => \`
// <div style="padding: 1rem; border-bottom: 1px solid #334155;">
// <div style="font-weight: bold; color: #f1f5f9;">\${project.project_name}</div>
// <div style="color: #94a3b8; font-size: 0.875rem;">\${project.file_count} files • \${new Date(project.created_at).toLocaleDateString()}</div>
// </div>
// \`).join('')
// : '<div style="padding: 1rem; color: #94a3b8;">No projects found in database</div>'
// }
// </div>
// </div>
// <div class="card">
// <h3 style="color: #f1f5f9; margin-bottom: 1rem;">Service Health</h3>
// <div style="max-height: 300px; overflow-y: auto;">
// \${services.services.map(service => \`
// <div style="padding: 0.5rem; margin-bottom: 0.5rem; background: #334155; border-radius: 4px;">
// <div style="display: flex; justify-content: space-between; align-items: center;">
// <span style="font-weight: bold; color: #f1f5f9;">\${service.name}</span>
// <span class="status-indicator status-\${service.status}"></span>
// </div>
// <div style="color: #94a3b8; font-size: 0.75rem;">Port: \${service.port} • \${service.responseTime}ms</div>
// </div>
// \`).join('')}
// </div>
// </div>
// </div>
// \`;
// } catch (error) {
// content.innerHTML = \`
// <h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">System Overview</h2>
// <div class="error-info">Error loading overview: \${error.message}
// Check the Database Debug tab for more information</div>
// \`;
// }
// }
// // Project Gallery
// async function loadProjectGallery() {
// const content = document.getElementById('content');
// content.innerHTML = '<div class="loading">Loading projects...</div>';
// try {
// const response = await fetch('/api/projects');
// const data = await response.json();
// content.innerHTML = \`
// <h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">Project Gallery</h2>
// <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 1.5rem;">
// \${data.projects.map(project => \`
// <div class="card" style="hover:border-color: #60a5fa; transition: border-color 0.3s;">
// <h3 style="color: #f1f5f9; margin-bottom: 1rem;">\${project.project_name}</h3>
// <div style="color: #94a3b8; font-size: 0.875rem; margin-bottom: 1rem;">
// Files: \${project.file_count} •
// Created: \${new Date(project.created_at).toLocaleDateString()}
// </div>
// <div style="color: #94a3b8; font-size: 0.875rem;">
// ID: \${project.id}
// </div>
// </div>
// \`).join('')}
// </div>
// \`;
// } catch (error) {
// content.innerHTML = \`
// <h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">Project Gallery</h2>
// <div class="error-info">Error loading projects: \${error.message}</div>
// \`;
// }
// }
// // Other sections (simplified)
// function loadLiveGeneration() {
// document.getElementById('content').innerHTML = \`
// <h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">Live Code Generation</h2>
// <div class="card">
// <h3 style="color: #f1f5f9; margin-bottom: 1rem;">Real-time Generation Monitoring</h3>
// <p style="color: #94a3b8;">Feature implementation in progress...</p>
// </div>
// \`;
// }
// function loadCodeEditor() {
// document.getElementById('content').innerHTML = \`
// <h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">Code Editor</h2>
// <div class="card">
// <h3 style="color: #f1f5f9; margin-bottom: 1rem;">Monaco Editor Integration</h3>
// <p style="color: #94a3b8;">Code editing interface coming soon...</p>
// </div>
// \`;
// }
// function loadQualityDashboard() {
// document.getElementById('content').innerHTML = \`
// <h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">Quality Dashboard</h2>
// <div class="card">
// <h3 style="color: #f1f5f9; margin-bottom: 1rem;">AI-Powered Quality Improvements</h3>
// <p style="color: #94a3b8;">Quality metrics and improvement analytics coming soon...</p>
// </div>
// \`;
// }
// function loadPipelineMonitor() {
// document.getElementById('content').innerHTML = \`
// <h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">Pipeline Monitor</h2>
// <div class="card">
// <h3 style="color: #f1f5f9; margin-bottom: 1rem;">n8n Workflow Integration</h3>
// <p style="color: #94a3b8;">Pipeline monitoring integration coming soon...</p>
// <div style="margin-top: 1rem;">
// <button class="btn" onclick="window.open('http://localhost:5678', '_blank')">Open n8n Interface</button>
// </div>
// </div>
// \`;
// }
// function loadSettings() {
// document.getElementById('content').innerHTML = \`
// <h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">Settings</h2>
// <div class="card">
// <h3 style="color: #f1f5f9; margin-bottom: 1rem;">Dashboard Configuration</h3>
// <p style="color: #94a3b8;">Settings and configuration options coming soon...</p>
// </div>
// \`;
// }
// // Load initial section
// loadSystemOverview();
// </script>
// </body>
// </html>
// `);
// });
// // Initialize connections and start server
// async function startServer() {
// try {
// await pgPool.query('SELECT NOW()');
// console.log('✅ Connected to PostgreSQL database (dev_pipeline)');
// await redisClient.connect();
// await redisClient.ping();
// console.log('✅ Connected to Redis cache');
// const PORT = process.env.PORT || 8008;
// server.listen(PORT, '0.0.0.0', () => {
// console.log(`🚀 AI Pipeline Dashboard running on port ${PORT}`);
// console.log(`📊 Dashboard URL: http://localhost:${PORT}`);
// console.log(`🔗 Integrated with existing database: dev_pipeline`);
// console.log(`📁 Monitoring projects: ${Object.keys(SERVICES).length} services`);
// });
// } catch (error) {
// console.error('❌ Failed to start dashboard:', error);
// process.exit(1);
// }
// }
// startServer();
const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const { Pool } = require('pg');
const Redis = require('redis');
const cors = require('cors');
const axios = require('axios');
const { exec } = require('child_process');
const util = require('util');
const execPromise = util.promisify(exec);
const app = express();
const server = http.createServer(app);
const io = socketIo(server, {
cors: { origin: "*", methods: ["GET", "POST", "PUT", "DELETE"] }
});
// Database connections
const pgPool = new Pool({
host: process.env.POSTGRES_HOST || 'pipeline_postgres',
port: process.env.POSTGRES_PORT || 5432,
database: process.env.POSTGRES_DB || 'dev_pipeline',
user: process.env.POSTGRES_USER || 'pipeline_admin',
password: process.env.POSTGRES_PASSWORD || 'secure_pipeline_2024',
max: 20,
idleTimeoutMillis: 30000,
connectionTimeoutMillis: 2000,
});
const redisClient = Redis.createClient({
socket: {
host: process.env.REDIS_HOST || 'pipeline_redis',
port: process.env.REDIS_PORT || 6379
},
password: process.env.REDIS_PASSWORD || 'redis_secure_2024'
});
redisClient.on('error', (err) => console.log('Redis Client Error', err));
// Services configuration
const SERVICES = {
'api-gateway': {
port: 8000,
name: 'API Gateway',
container: 'pipeline_api_gateway',
url: 'http://pipeline_api_gateway:8000'
},
'requirement-processor': {
port: 8001,
name: 'Requirement Processor',
container: 'pipeline_requirement_processor',
url: 'http://pipeline_requirement_processor:8001'
},
'tech-stack-selector': {
port: 8002,
name: 'Tech Stack Selector',
container: 'pipeline_tech_stack_selector',
url: 'http://pipeline_tech_stack_selector:8002'
},
'architecture-designer': {
port: 8003,
name: 'Architecture Designer',
container: 'pipeline_architecture_designer',
url: 'http://pipeline_architecture_designer:8003'
},
'code-generator': {
port: 8004,
name: 'Code Generator',
container: 'pipeline_code_generator',
url: 'http://pipeline_code_generator:8004'
},
'test-generator': {
port: 8005,
name: 'Test Generator',
container: 'pipeline_test_generator',
url: 'http://pipeline_test_generator:8005'
},
'deployment-manager': {
port: 8006,
name: 'Deployment Manager',
container: 'pipeline_deployment_manager',
url: 'http://pipeline_deployment_manager:8006'
},
'self-improving-generator': {
port: 8007,
name: 'Self-Improving Generator',
container: 'pipeline_self_improving_generator',
url: 'http://pipeline_self_improving_generator:8007'
}
};
// Middleware
app.use(cors());
app.use(express.json({ limit: '50mb' }));
app.use(express.urlencoded({ extended: true, limit: '50mb' }));
// Database service - FIXED to work with your actual database structure
class DatabaseService {
static async getProjects(filters = {}) {
try {
console.log('🔍 Querying projects from database...');
// Simple query for project_contexts table - NO JOINS
let query = `
SELECT
id,
project_name,
technology_stack,
all_features,
completed_features,
pending_features,
project_path,
created_at,
updated_at
FROM project_contexts
`;
const conditions = [];
const values = [];
let paramCount = 0;
if (filters.project_name) {
conditions.push(`project_name ILIKE $${++paramCount}`);
values.push(`%${filters.project_name}%`);
}
if (conditions.length > 0) {
query += ` WHERE ${conditions.join(' AND ')}`;
}
query += ` ORDER BY created_at DESC LIMIT 20`;
console.log('🔍 Executing query:', query);
const result = await pgPool.query(query, values);
console.log('✅ Query result:', result.rows.length, 'projects found');
// Get file counts for each project separately - SAFE QUERIES
for (let project of result.rows) {
try {
const fileCountResult = await pgPool.query(
'SELECT COUNT(*) FROM code_files WHERE project_id = $1',
[project.id]
);
project.file_count = parseInt(fileCountResult.rows[0].count);
} catch (fileError) {
console.log('⚠️ Could not get file count for project', project.id);
project.file_count = 0;
}
}
return result.rows;
} catch (error) {
console.error('❌ Database query error:', error.message);
throw error;
}
}
static async getSystemStats() {
try {
console.log('🔍 Getting system stats from database...');
// Get counts from each table - SIMPLE QUERIES
const projectCountResult = await pgPool.query('SELECT COUNT(*) FROM project_contexts');
const fileCountResult = await pgPool.query('SELECT COUNT(*) FROM code_files');
const improvementCountResult = await pgPool.query('SELECT COUNT(*) FROM improvement_history');
// Get recent projects (last 24 hours)
const recentResult = await pgPool.query(`
SELECT COUNT(*) FROM project_contexts
WHERE created_at > NOW() - INTERVAL '24 hours'
`);
const stats = {
project_contexts: parseInt(projectCountResult.rows[0].count),
code_files: parseInt(fileCountResult.rows[0].count),
improvement_history: parseInt(improvementCountResult.rows[0].count),
recent_projects: parseInt(recentResult.rows[0].count)
};
console.log('📊 System stats:', stats);
return stats;
} catch (error) {
console.error('❌ System stats error:', error);
return {
project_contexts: 0,
code_files: 0,
improvement_history: 0,
recent_projects: 0
};
}
}
}
// WebSocket connection handling
io.on('connection', (socket) => {
console.log(`Dashboard client connected: ${socket.id}`);
socket.emit('connected', {
message: 'Connected to AI Pipeline Dashboard',
timestamp: new Date().toISOString()
});
socket.on('disconnect', () => {
console.log(`Dashboard client disconnected: ${socket.id}`);
});
});
// API Routes
app.get('/api/health', (req, res) => {
res.json({
status: 'healthy',
timestamp: new Date().toISOString(),
service: 'AI Pipeline Dashboard',
version: '2.0.0'
});
});
// Debug endpoint
app.get('/api/debug/database', async (req, res) => {
try {
console.log('🔍 Database debug endpoint called');
const connectionTest = await pgPool.query('SELECT NOW()');
console.log('✅ Database connection successful');
const projectCount = await pgPool.query('SELECT COUNT(*) FROM project_contexts');
const fileCount = await pgPool.query('SELECT COUNT(*) FROM code_files');
const improvementCount = await pgPool.query('SELECT COUNT(*) FROM improvement_history');
// Get sample project names
let sampleProjects = [];
const sampleResult = await pgPool.query('SELECT id, project_name, created_at FROM project_contexts ORDER BY created_at DESC LIMIT 3');
sampleProjects = sampleResult.rows;
res.json({
connection: 'OK',
timestamp: connectionTest.rows[0].now,
tables: {
project_contexts: parseInt(projectCount.rows[0].count),
code_files: parseInt(fileCount.rows[0].count),
improvement_history: parseInt(improvementCount.rows[0].count)
},
sampleProjects: sampleProjects
});
} catch (error) {
console.error('❌ Database debug error:', error);
res.status(500).json({
error: error.message,
connection: 'FAILED'
});
}
});
// System status with real data
app.get('/api/system/status', async (req, res) => {
try {
console.log('🔍 System status endpoint called');
let healthyServices = 0;
const serviceChecks = [];
// Check services
for (const [key, service] of Object.entries(SERVICES)) {
try {
await axios.get(`${service.url}/health`, { timeout: 5000 });
healthyServices++;
serviceChecks.push({ service: key, status: 'healthy' });
} catch (error) {
serviceChecks.push({ service: key, status: 'unhealthy', error: error.message });
}
}
// Get database stats
const dbStats = await DatabaseService.getSystemStats();
res.json({
healthyServices,
totalServices: Object.keys(SERVICES).length,
totalProjects: dbStats.project_contexts,
totalFiles: dbStats.code_files,
activeProjects: dbStats.recent_projects,
improvements: dbStats.improvement_history,
serviceChecks,
timestamp: new Date().toISOString()
});
} catch (error) {
console.error('❌ System status error:', error);
res.status(500).json({ error: error.message });
}
});
// Projects endpoint
app.get('/api/projects', async (req, res) => {
try {
console.log('🔍 Projects endpoint called');
const projects = await DatabaseService.getProjects(req.query);
console.log('✅ Projects returned:', projects.length);
res.json({ projects });
} catch (error) {
console.error('❌ Projects endpoint error:', error);
res.status(500).json({
error: error.message,
details: 'Check server logs for database connection issues'
});
}
});
// Services health endpoint
app.get('/api/services/health', async (req, res) => {
console.log('🔍 Services health check called');
const healthChecks = await Promise.allSettled(
Object.entries(SERVICES).map(async ([key, service]) => {
const startTime = Date.now();
try {
await axios.get(`${service.url}/health`, { timeout: 5000 });
return {
name: service.name,
status: 'healthy',
port: service.port,
container: service.container,
responseTime: Date.now() - startTime,
lastCheck: new Date().toISOString()
};
} catch (error) {
return {
name: service.name,
status: 'unhealthy',
port: service.port,
container: service.container,
responseTime: Date.now() - startTime,
error: error.message,
lastCheck: new Date().toISOString()
};
}
})
);
const services = healthChecks.map(result =>
result.status === 'fulfilled' ? result.value : result.reason
);
res.json({ services });
});
// Code Editor API endpoints - FIXED to handle missing files gracefully
app.get('/api/projects/:projectId/files', async (req, res) => {
try {
const projectId = req.params.projectId;
console.log('🔍 Getting files for project:', projectId);
const result = await pgPool.query(
'SELECT id, file_path, file_type, created_at FROM code_files WHERE project_id = $1 ORDER BY file_path',
[projectId]
);
res.json({ files: result.rows });
} catch (error) {
console.error('❌ Error getting project files:', error);
res.status(500).json({ error: error.message });
}
});
// Helper function to try reading file from different containers
async function tryReadFileFromContainers(filePath, projectId) {
const containers = ['pipeline_code_generator', 'pipeline_self_improving_generator'];
const possiblePaths = [
`/tmp/generated-projects/${projectId}/${filePath}`,
`/tmp/projects/${projectId}/${filePath}`,
`/app/projects/${projectId}/${filePath}`,
`/tmp/${filePath}`,
`/app/${filePath}`
];
for (const container of containers) {
for (const path of possiblePaths) {
try {
const { stdout } = await execPromise(`docker exec ${container} cat "${path}" 2>/dev/null`);
if (stdout) {
console.log(`✅ Found file in ${container} at ${path}`);
return stdout;
}
} catch (error) {
// Continue trying other paths
}
}
}
return null;
}
app.get('/api/files/:fileId/content', async (req, res) => {
try {
const fileId = req.params.fileId;
console.log('🔍 Getting content for file:', fileId);
// Get file info from database
const result = await pgPool.query(
'SELECT file_path, file_type, project_id FROM code_files WHERE id = $1',
[fileId]
);
if (result.rows.length === 0) {
return res.status(404).json({ error: 'File not found' });
}
const file = result.rows[0];
const fileName = file.file_path.split('/').pop() || file.file_path;
// Try to read file from containers
let content = await tryReadFileFromContainers(file.file_path, file.project_id);
if (!content) {
// Generate sample content based on file type
content = generateSampleContent(file.file_path, file.file_type);
}
res.json({
content: content,
fileName: fileName,
fileType: file.file_type
});
} catch (error) {
console.error('❌ Error getting file content:', error);
res.status(500).json({ error: error.message });
}
});
// Generate sample content when files are not found
function generateSampleContent(filePath, fileType) {
const fileName = filePath.split('/').pop();
const ext = fileName.split('.').pop();
switch (ext) {
case 'tsx':
case 'jsx':
return `// ${fileName}
// This file was generated but the content is no longer available on disk
// The file structure and metadata are preserved in the database
import React from 'react';
const ${fileName.split('.')[0]} = () => {
return (
<div>
<h1>Generated Component: ${fileName}</h1>
<p>Original file path: ${filePath}</p>
<p>File type: ${fileType}</p>
<p>Note: This is placeholder content. The original generated code is not available.</p>
</div>
);
};
export default ${fileName.split('.')[0]};`;
case 'ts':
case 'js':
return `// ${fileName}
// This file was generated but the content is no longer available on disk
// The file structure and metadata are preserved in the database
/**
* Original file path: ${filePath}
* File type: ${fileType}
* Note: This is placeholder content. The original generated code is not available.
*/
export default function ${fileName.split('.')[0]}() {
console.log('Generated file: ${fileName}');
// Original implementation would be here
return {
message: 'This file was generated but content is not available',
path: '${filePath}',
type: '${fileType}'
};
}`;
case 'py':
return `# ${fileName}
# This file was generated but the content is no longer available on disk
# The file structure and metadata are preserved in the database
"""
Original file path: ${filePath}
File type: ${fileType}
Note: This is placeholder content. The original generated code is not available.
"""
def main():
print("Generated file: ${fileName}")
print("Original path: ${filePath}")
print("File type: ${fileType}")
# Original implementation would be here
pass
if __name__ == "__main__":
main()`;
case 'html':
return `<!-- ${fileName} -->
<!-- This file was generated but the content is no longer available on disk -->
<!-- The file structure and metadata are preserved in the database -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${fileName}</title>
</head>
<body>
<h1>Generated File: ${fileName}</h1>
<p>Original file path: ${filePath}</p>
<p>File type: ${fileType}</p>
<p><em>Note: This is placeholder content. The original generated code is not available.</em></p>
</body>
</html>`;
case 'css':
return `/* ${fileName} */
/* This file was generated but the content is no longer available on disk */
/* The file structure and metadata are preserved in the database */
/*
Original file path: ${filePath}
File type: ${fileType}
Note: This is placeholder content. The original generated code is not available.
*/
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f5f5f5;
}
.container {
max-width: 800px;
margin: 0 auto;
background: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
/* Original styles would be here */`;
default:
return `// ${fileName}
// This file was generated but the content is no longer available on disk
// The file structure and metadata are preserved in the database
/*
Original file path: ${filePath}
File type: ${fileType}
Note: This is placeholder content. The original generated code is not available.
To fix this issue, you need to:
1. Ensure generated files are stored in a persistent volume
2. Mount the volume between the code generator and dashboard containers
3. Or implement a file storage service to persist generated code
*/`;
}
}
app.put('/api/files/:fileId/content', async (req, res) => {
try {
const fileId = req.params.fileId;
const { content } = req.body;
console.log('🔍 Updating content for file:', fileId);
// For now, just return success since files aren't persisted
// In a real implementation, you'd save the content to a persistent storage
console.log('⚠️ File content updated in memory only (not persisted)');
res.json({
success: true,
message: 'Content updated (note: changes are not persisted to disk)'
});
} catch (error) {
console.error('❌ Error updating file content:', error);
res.status(500).json({ error: error.message });
}
});
// Main dashboard page
app.get('/', (req, res) => {
res.send(`
<!DOCTYPE html>
<html>
<head>
<title>AI Pipeline Dashboard</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="/socket.io/socket.io.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
background: #0f172a;
color: #e2e8f0;
min-height: 100vh;
}
.dashboard { display: flex; height: 100vh; }
.sidebar {
width: 280px;
background: #1e293b;
border-right: 1px solid #334155;
overflow-y: auto;
}
.main-content {
flex: 1;
overflow-y: auto;
padding: 2rem;
}
.nav-item {
display: block;
padding: 1rem 1.5rem;
color: #94a3b8;
text-decoration: none;
border-bottom: 1px solid #334155;
transition: all 0.3s;
}
.nav-item:hover, .nav-item.active {
background: #334155;
color: #60a5fa;
border-left: 4px solid #60a5fa;
}
.header {
padding: 1.5rem;
border-bottom: 1px solid #334155;
text-align: center;
}
.header h1 {
color: #60a5fa;
font-size: 1.5rem;
margin-bottom: 0.5rem;
}
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 1.5rem;
margin-bottom: 2rem;
}
.stat-card {
background: #1e293b;
border: 1px solid #334155;
border-radius: 8px;
padding: 1.5rem;
text-align: center;
}
.stat-value {
font-size: 2.5rem;
font-weight: bold;
color: #60a5fa;
margin-bottom: 0.5rem;
}
.stat-label {
color: #94a3b8;
font-size: 0.875rem;
}
.card {
background: #1e293b;
border: 1px solid #334155;
border-radius: 8px;
padding: 1.5rem;
margin-bottom: 1.5rem;
}
.btn {
background: #3b82f6;
color: white;
border: none;
padding: 0.5rem 1rem;
border-radius: 6px;
cursor: pointer;
font-size: 0.875rem;
transition: background 0.3s;
}
.btn:hover { background: #2563eb; }
.loading {
text-align: center;
padding: 2rem;
color: #94a3b8;
}
.status-indicator {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: 8px;
}
.status-healthy { background: #10b981; }
.status-unhealthy { background: #ef4444; }
.debug-info {
background: #374151;
color: #f9fafb;
padding: 1rem;
border-radius: 8px;
margin: 1rem 0;
font-family: monospace;
font-size: 0.875rem;
white-space: pre-wrap;
}
.error-info {
background: #7f1d1d;
color: #fca5a5;
padding: 1rem;
border-radius: 8px;
margin: 1rem 0;
font-family: monospace;
font-size: 0.875rem;
}
.warning-info {
background: #92400e;
color: #fcd34d;
padding: 1rem;
border-radius: 8px;
margin: 1rem 0;
font-family: monospace;
font-size: 0.875rem;
}
#content { margin-top: 2rem; }
</style>
</head>
<body>
<div class="dashboard">
<div class="sidebar">
<div class="header">
<h1>⚡ AI Pipeline</h1>
<p style="color: #94a3b8; font-size: 0.875rem;">Development Dashboard</p>
<div style="margin-top: 1rem;">
<span class="status-indicator status-healthy" id="connectionStatus"></span>
<span style="font-size: 0.75rem; color: #94a3b8;" id="connectionText">Connected</span>
</div>
</div>
<nav>
<a href="#" class="nav-item active" onclick="showSection('overview')">📊 System Overview</a>
<a href="#" class="nav-item" onclick="showSection('debug')">🔍 Database Debug</a>
<a href="#" class="nav-item" onclick="showSection('projects')">📁 Project Gallery</a>
<a href="#" class="nav-item" onclick="showSection('live-generation')">⚡ Live Generation</a>
<a href="#" class="nav-item" onclick="showSection('code-editor')">💻 Code Editor</a>
<a href="#" class="nav-item" onclick="showSection('quality-dashboard')">📈 Quality Dashboard</a>
<a href="#" class="nav-item" onclick="showSection('pipeline-monitor')">🔄 Pipeline Monitor</a>
<a href="#" class="nav-item" onclick="showSection('settings')">⚙️ Settings</a>
</nav>
</div>
<div class="main-content">
<div id="content"></div>
</div>
</div>
<script>
// Initialize Socket.IO
const socket = io();
socket.on('connect', () => {
console.log('Connected to AI Pipeline Dashboard');
updateConnectionStatus(true);
});
socket.on('disconnect', () => {
console.log('Disconnected from AI Pipeline Dashboard');
updateConnectionStatus(false);
});
function updateConnectionStatus(connected) {
const indicator = document.getElementById('connectionStatus');
const text = document.getElementById('connectionText');
if (connected) {
indicator.className = 'status-indicator status-healthy';
text.textContent = 'Connected';
} else {
indicator.className = 'status-indicator status-unhealthy';
text.textContent = 'Disconnected';
}
}
// Navigation
function showSection(section) {
document.querySelectorAll('.nav-item').forEach(item => {
item.classList.remove('active');
});
event.target.classList.add('active');
switch(section) {
case 'overview':
loadSystemOverview();
break;
case 'debug':
loadDatabaseDebug();
break;
case 'projects':
loadProjectGallery();
break;
case 'live-generation':
loadLiveGeneration();
break;
case 'code-editor':
loadCodeEditor();
break;
case 'quality-dashboard':
loadQualityDashboard();
break;
case 'pipeline-monitor':
loadPipelineMonitor();
break;
case 'settings':
loadSettings();
break;
}
}
// Database debug page
async function loadDatabaseDebug() {
const content = document.getElementById('content');
content.innerHTML = '<div class="loading">Loading database debug info...</div>';
try {
const response = await fetch('/api/debug/database');
const data = await response.json();
content.innerHTML = \`
<h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">Database Debug</h2>
<div class="card">
<h3 style="color: #f1f5f9; margin-bottom: 1rem;">Connection Status</h3>
<div class="debug-info">Connection: \${data.connection}
Timestamp: \${data.timestamp}</div>
</div>
<div class="card">
<h3 style="color: #f1f5f9; margin-bottom: 1rem;">Database Tables</h3>
<div class="debug-info">project_contexts: \${data.tables.project_contexts} records
code_files: \${data.tables.code_files} records
improvement_history: \${data.tables.improvement_history} records</div>
</div>
<div class="card">
<h3 style="color: #f1f5f9; margin-bottom: 1rem;">Sample Projects</h3>
<div class="debug-info">\${data.sampleProjects.map(p => \`\${p.project_name} (ID: \${p.id})\`).join('\\n')}</div>
</div>
<div class="card">
<h3 style="color: #f1f5f9; margin-bottom: 1rem;">API Tests</h3>
<button class="btn" onclick="testSystemStatus()">Test System Status</button>
<button class="btn" onclick="testProjects()" style="margin-left: 0.5rem;">Test Projects</button>
<button class="btn" onclick="testServices()" style="margin-left: 0.5rem;">Test Services</button>
<div id="apiResults" style="margin-top: 1rem;"></div>
</div>
\`;
} catch (error) {
content.innerHTML = \`
<h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">Database Debug</h2>
<div class="error-info">Error: \${error.message}
Could not connect to database</div>
\`;
}
}
async function testSystemStatus() {
const resultsDiv = document.getElementById('apiResults');
try {
const response = await fetch('/api/system/status');
const data = await response.json();
resultsDiv.innerHTML = '<div class="debug-info">System Status: ' + JSON.stringify(data, null, 2) + '</div>';
} catch (error) {
resultsDiv.innerHTML = '<div class="error-info">Error: ' + error.message + '</div>';
}
}
async function testProjects() {
const resultsDiv = document.getElementById('apiResults');
try {
const response = await fetch('/api/projects');
const data = await response.json();
resultsDiv.innerHTML = '<div class="debug-info">Projects: ' + JSON.stringify(data, null, 2) + '</div>';
} catch (error) {
resultsDiv.innerHTML = '<div class="error-info">Error: ' + error.message + '</div>';
}
}
async function testServices() {
const resultsDiv = document.getElementById('apiResults');
try {
const response = await fetch('/api/services/health');
const data = await response.json();
resultsDiv.innerHTML = '<div class="debug-info">Services: ' + JSON.stringify(data, null, 2) + '</div>';
} catch (error) {
resultsDiv.innerHTML = '<div class="error-info">Error: ' + error.message + '</div>';
}
}
// System overview with better error handling
async function loadSystemOverview() {
const content = document.getElementById('content');
content.innerHTML = '<div class="loading">Loading system overview...</div>';
try {
const [statusRes, projectsRes, servicesRes] = await Promise.all([
fetch('/api/system/status'),
fetch('/api/projects'),
fetch('/api/services/health')
]);
const status = await statusRes.json();
const projects = await projectsRes.json();
const services = await servicesRes.json();
content.innerHTML = \`
<h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">System Overview</h2>
<div class="stats-grid">
<div class="stat-card">
<div class="stat-value">\${status.totalServices}</div>
<div class="stat-label">Total Services</div>
</div>
<div class="stat-card">
<div class="stat-value">\${status.healthyServices}</div>
<div class="stat-label">Healthy Services</div>
</div>
<div class="stat-card">
<div class="stat-value">\${status.totalProjects}</div>
<div class="stat-label">Total Projects</div>
</div>
<div class="stat-card">
<div class="stat-value">\${status.totalFiles}</div>
<div class="stat-label">Generated Files</div>
</div>
<div class="stat-card">
<div class="stat-value">\${status.activeProjects}</div>
<div class="stat-label">Active Projects</div>
</div>
</div>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem;">
<div class="card">
<h3 style="color: #f1f5f9; margin-bottom: 1rem;">Recent Projects</h3>
<div style="max-height: 300px; overflow-y: auto;">
\${projects.projects.length > 0 ?
projects.projects.slice(0, 5).map(project => \`
<div style="padding: 1rem; border-bottom: 1px solid #334155;">
<div style="font-weight: bold; color: #f1f5f9;">\${project.project_name}</div>
<div style="color: #94a3b8; font-size: 0.875rem;">\${project.file_count} files • \${new Date(project.created_at).toLocaleDateString()}</div>
</div>
\`).join('')
: '<div style="padding: 1rem; color: #94a3b8;">No projects found in database</div>'
}
</div>
</div>
<div class="card">
<h3 style="color: #f1f5f9; margin-bottom: 1rem;">Service Health</h3>
<div style="max-height: 300px; overflow-y: auto;">
\${services.services.map(service => \`
<div style="padding: 0.5rem; margin-bottom: 0.5rem; background: #334155; border-radius: 4px;">
<div style="display: flex; justify-content: space-between; align-items: center;">
<span style="font-weight: bold; color: #f1f5f9;">\${service.name}</span>
<span class="status-indicator status-\${service.status}"></span>
</div>
<div style="color: #94a3b8; font-size: 0.75rem;">Port: \${service.port} • \${service.responseTime}ms</div>
</div>
\`).join('')}
</div>
</div>
</div>
\`;
} catch (error) {
content.innerHTML = \`
<h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">System Overview</h2>
<div class="error-info">Error loading overview: \${error.message}
Check the Database Debug tab for more information</div>
\`;
}
}
// Project Gallery
async function loadProjectGallery() {
const content = document.getElementById('content');
content.innerHTML = '<div class="loading">Loading projects...</div>';
try {
const response = await fetch('/api/projects');
const data = await response.json();
content.innerHTML = \`
<h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">Project Gallery</h2>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 1.5rem;">
\${data.projects.map(project => \`
<div class="card" style="hover:border-color: #60a5fa; transition: border-color 0.3s;">
<h3 style="color: #f1f5f9; margin-bottom: 1rem;">\${project.project_name}</h3>
<div style="color: #94a3b8; font-size: 0.875rem; margin-bottom: 1rem;">
Files: \${project.file_count} •
Created: \${new Date(project.created_at).toLocaleDateString()}
</div>
<div style="color: #94a3b8; font-size: 0.875rem;">
ID: \${project.id}
</div>
</div>
\`).join('')}
</div>
\`;
} catch (error) {
content.innerHTML = \`
<h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">Project Gallery</h2>
<div class="error-info">Error loading projects: \${error.message}</div>
\`;
}
}
// Other sections (simplified)
function loadLiveGeneration() {
document.getElementById('content').innerHTML = \`
<h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">Live Code Generation</h2>
<div class="card">
<h3 style="color: #f1f5f9; margin-bottom: 1rem;">Real-time Generation Monitoring</h3>
<p style="color: #94a3b8;">Feature implementation in progress...</p>
</div>
\`;
}
// Enhanced Code Editor with File Not Found handling
function loadCodeEditor() {
document.getElementById('content').innerHTML = \`
<h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">Code Editor</h2>
<div class="warning-info">
<strong>⚠️ Note:</strong> Generated files are not persisted between container restarts.
You'll see placeholder content for files that are no longer available on disk.
The file structure and metadata are preserved in the database.
</div>
<div style="display: grid; grid-template-columns: 300px 1fr; gap: 1.5rem; height: 75vh;">
<div class="card" style="height: 100%; overflow-y: auto;">
<h3 style="color: #f1f5f9; margin-bottom: 1rem;">Projects</h3>
<div id="projectsList">Loading projects...</div>
</div>
<div class="card" style="height: 100%; display: flex; flex-direction: column;">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem;">
<h3 style="color: #f1f5f9;" id="currentFileName">Select a file to edit</h3>
<button class="btn" onclick="saveCurrentFile()" id="saveBtn" style="display: none;">Save</button>
</div>
<div style="flex: 1; display: flex; flex-direction: column;">
<div id="fileContent" style="flex: 1; background: #0f172a; border: 1px solid #334155; border-radius: 4px; padding: 1rem; font-family: monospace; color: #e2e8f0; overflow-y: auto;">
<div style="text-align: center; color: #94a3b8; padding: 2rem;">
Select a project and file to view/edit code
</div>
</div>
</div>
</div>
</div>
\`;
loadProjectsForEditor();
}
// Code Editor functions
async function loadProjectsForEditor() {
try {
const response = await fetch('/api/projects');
const data = await response.json();
let projectsHtml = '';
data.projects.forEach(project => {
projectsHtml += '<div style="padding: 0.5rem; margin-bottom: 0.5rem; background: #334155; border-radius: 4px; cursor: pointer;" data-project-id="' + project.id + '">';
projectsHtml += '<div style="font-weight: bold; color: #f1f5f9;">' + project.project_name + '</div>';
projectsHtml += '<div style="color: #94a3b8; font-size: 0.75rem;">' + project.file_count + ' files</div>';
projectsHtml += '</div>';
});
document.getElementById('projectsList').innerHTML = projectsHtml;
// Add event listeners
document.querySelectorAll('[data-project-id]').forEach(element => {
element.addEventListener('click', function() {
const projectId = this.getAttribute('data-project-id');
loadProjectFiles(projectId);
});
});
} catch (error) {
document.getElementById('projectsList').innerHTML = '<div style="color: #ef4444; padding: 1rem;">Error loading projects</div>';
}
}
async function loadProjectFiles(projectId) {
try {
const response = await fetch('/api/projects/' + projectId + '/files');
const data = await response.json();
let filesHtml = '<button class="btn" onclick="loadProjectsForEditor()" style="width: 100%; margin-bottom: 1rem;">← Back to Projects</button>';
data.files.forEach(file => {
const fileName = file.file_path.split('/').pop() || file.file_path;
filesHtml += '<div style="padding: 0.5rem; margin-bottom: 0.25rem; background: #1e293b; border-radius: 4px; cursor: pointer;" data-file-id="' + file.id + '">';
filesHtml += '<div style="font-weight: bold; color: #f1f5f9; font-size: 0.875rem;">' + fileName + '</div>';
filesHtml += '<div style="color: #94a3b8; font-size: 0.75rem;">' + file.file_path + '</div>';
filesHtml += '</div>';
});
document.getElementById('projectsList').innerHTML = filesHtml;
// Add event listeners for files
document.querySelectorAll('[data-file-id]').forEach(element => {
element.addEventListener('click', function() {
const fileId = this.getAttribute('data-file-id');
loadFileContent(fileId);
});
});
} catch (error) {
document.getElementById('projectsList').innerHTML = '<div style="color: #ef4444; padding: 1rem;">Error loading files</div>';
}
}
let currentFileId = null;
async function loadFileContent(fileId) {
try {
const response = await fetch('/api/files/' + fileId + '/content');
const data = await response.json();
currentFileId = fileId;
document.getElementById('currentFileName').textContent = data.fileName;
document.getElementById('saveBtn').style.display = 'block';
document.getElementById('fileContent').innerHTML =
'<textarea id="codeEditor" style="width: 100%; height: 100%; background: #0f172a; border: none; color: #e2e8f0; font-family: monospace; font-size: 14px; padding: 1rem; resize: none; outline: none;">' +
(data.content || '') +
'</textarea>';
} catch (error) {
document.getElementById('fileContent').innerHTML = '<div style="color: #ef4444; padding: 1rem;">Error loading file: ' + error.message + '</div>';
}
}
async function saveCurrentFile() {
if (!currentFileId) return;
const saveBtn = document.getElementById('saveBtn');
saveBtn.textContent = 'Saving...';
saveBtn.disabled = true;
try {
const editor = document.getElementById('codeEditor');
const response = await fetch('/api/files/' + currentFileId + '/content', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ content: editor.value })
});
if (response.ok) {
const result = await response.json();
saveBtn.textContent = 'Saved!';
saveBtn.style.background = '#10b981';
// Show warning if changes aren't persisted
if (result.message) {
alert(result.message);
}
setTimeout(() => {
saveBtn.textContent = 'Save';
saveBtn.style.background = '#3b82f6';
saveBtn.disabled = false;
}, 2000);
} else {
throw new Error('Failed to save');
}
} catch (error) {
saveBtn.textContent = 'Error!';
saveBtn.style.background = '#ef4444';
setTimeout(() => {
saveBtn.textContent = 'Save';
saveBtn.style.background = '#3b82f6';
saveBtn.disabled = false;
}, 2000);
}
}
function loadQualityDashboard() {
document.getElementById('content').innerHTML = \`
<h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">Quality Dashboard</h2>
<div class="card">
<h3 style="color: #f1f5f9; margin-bottom: 1rem;">AI-Powered Quality Improvements</h3>
<p style="color: #94a3b8;">Quality metrics and improvement analytics coming soon...</p>
</div>
\`;
}
function loadPipelineMonitor() {
document.getElementById('content').innerHTML = \`
<h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">Pipeline Monitor</h2>
<div class="card">
<h3 style="color: #f1f5f9; margin-bottom: 1rem;">n8n Workflow Integration</h3>
<p style="color: #94a3b8;">Pipeline monitoring integration coming soon...</p>
<div style="margin-top: 1rem;">
<button class="btn" onclick="window.open('http://localhost:5678', '_blank')">Open n8n Interface</button>
</div>
</div>
\`;
}
function loadSettings() {
document.getElementById('content').innerHTML = \`
<h2 style="color: #f1f5f9; margin-bottom: 2rem; font-size: 2rem;">Settings</h2>
<div class="card">
<h3 style="color: #f1f5f9; margin-bottom: 1rem;">Dashboard Configuration</h3>
<p style="color: #94a3b8;">Settings and configuration options coming soon...</p>
</div>
\`;
}
// Load initial section
loadSystemOverview();
</script>
</body>
</html>
`);
});
// Initialize connections and start server
async function startServer() {
try {
await pgPool.query('SELECT NOW()');
console.log('✅ Connected to PostgreSQL database (dev_pipeline)');
await redisClient.connect();
await redisClient.ping();
console.log('✅ Connected to Redis cache');
const PORT = process.env.PORT || 8008;
server.listen(PORT, '0.0.0.0', () => {
console.log(`🚀 AI Pipeline Dashboard running on port ${PORT}`);
console.log(`📊 Dashboard URL: http://localhost:${PORT}`);
console.log(`🔗 Integrated with existing database: dev_pipeline`);
console.log(`📁 Monitoring projects: ${Object.keys(SERVICES).length} services`);
});
} catch (error) {
console.error('❌ Failed to start dashboard:', error);
process.exit(1);
}
}
startServer();