require('dotenv').config(); const express = require('express'); const cors = require('cors'); const helmet = require('helmet'); const morgan = require('morgan'); const http = require('http'); const { Server } = require('socket.io'); const axios = require('axios'); // Import database const database = require('./config/database'); // Import routes (we'll create these next) const templateRoutes = require('./routes/templates'); const featureRoutes = require('./routes/features'); const learningRoutes = require('./routes/learning'); const adminRoutes = require('./routes/admin'); const adminTemplateRoutes = require('./routes/admin-templates'); const techStackRoutes = require('./routes/tech-stack'); const tkgMigrationRoutes = require('./routes/tkg-migration'); const autoTKGMigrationRoutes = require('./routes/auto-tkg-migration'); const ckgMigrationRoutes = require('./routes/ckg-migration'); const enhancedCkgTechStackRoutes = require('./routes/enhanced-ckg-tech-stack'); const comprehensiveMigrationRoutes = require('./routes/comprehensive-migration'); const AdminNotification = require('./models/admin_notification'); const autoTechStackAnalyzer = require('./services/auto_tech_stack_analyzer'); const AutoTKGMigrationService = require('./services/auto-tkg-migration'); const AutoCKGMigrationService = require('./services/auto-ckg-migration'); // const customTemplateRoutes = require('./routes/custom_templates'); const app = express(); const server = http.createServer(app); const io = new Server(server, { cors: { origin: "*", methods: ["GET", "POST"], credentials: true } }); const PORT = process.env.PORT || 8009; // Middleware app.use(helmet()); app.use(cors({ origin: "*", credentials: true, methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], allowedHeaders: ['Content-Type', 'Authorization', 'X-User-ID', 'X-User-Role'] })); app.use(morgan('combined')); app.use(express.json({ limit: '10mb' })); app.use(express.urlencoded({ extended: true })); // Make io available to routes and set it in AdminNotification app.set('io', io); AdminNotification.setSocketIO(io); // Routes - Order matters! More specific routes should come first app.use('/api/learning', learningRoutes); app.use('/api/admin', adminRoutes); app.use('/api/admin/templates', adminTemplateRoutes); app.use('/api/tech-stack', techStackRoutes); app.use('/api/enhanced-ckg-tech-stack', enhancedCkgTechStackRoutes); app.use('/api/tkg-migration', tkgMigrationRoutes); app.use('/api/auto-tkg-migration', autoTKGMigrationRoutes); app.use('/api/ckg-migration', ckgMigrationRoutes); app.use('/api/comprehensive-migration', comprehensiveMigrationRoutes); app.use('/api/templates', templateRoutes); // Add admin routes under /api/templates to match serviceClient expectations app.use('/api/templates/admin', adminRoutes); // Features route must come AFTER templates to avoid route conflicts app.use('/api/features', featureRoutes); // Single route surface: handle custom templates via /api/templates only // app.use('/api/custom-templates', customTemplateRoutes); // WebSocket connection handling io.on('connection', async (socket) => { console.log('🔌 Admin client connected:', socket.id); // Join admin room for notifications socket.join('admin-notifications'); // Send initial notification count try { const counts = await AdminNotification.getCounts(); socket.emit('notification-count', counts); } catch (error) { console.error('Error getting notification counts:', error); socket.emit('notification-count', { total: 0, unread: 0, read: 0 }); } socket.on('disconnect', () => { console.log('🔌 Admin client disconnected:', socket.id); }); }); // Health check endpoint app.get('/health', (req, res) => { res.status(200).json({ status: 'healthy', service: 'template-manager', version: '1.0.0', timestamp: new Date().toISOString(), uptime: process.uptime(), features: { template_management: true, feature_learning: true, usage_tracking: true, self_improving: true, admin_approval_workflow: true, ai_analysis: true } }); }); // AI Feature Analysis endpoint app.post('/api/analyze-feature', async (req, res) => { try { console.log('🤖 [Template Manager] AI Analysis request received'); const { featureName, feature_name, description, requirements = [], projectType, project_type } = req.body; // Handle both parameter name variations const actualFeatureName = featureName || feature_name; const actualProjectType = projectType || project_type; // Ensure requirements is always an array const safeRequirements = Array.isArray(requirements) ? requirements : []; console.log('📋 [Template Manager] Analyzing feature:', actualFeatureName); console.log('📋 [Template Manager] Project type:', actualProjectType); console.log('📋 [Template Manager] Requirements:', safeRequirements); // Always use Claude. No rule-based fallback. console.log('🤖 [Template Manager] Using Claude AI for analysis (no fallback)...'); const analysis = await analyzeWithClaude(actualFeatureName, description, safeRequirements, actualProjectType); console.log('✅ [Template Manager] Analysis completed:', analysis?.complexity, 'complexity'); console.log('🧩 [Template Manager] logicRules:', Array.isArray(analysis?.logicRules) ? analysis.logicRules : 'none'); res.json({ success: true, analysis }); } catch (error) { console.error('❌ [Template Manager] AI Analysis error:', error); res.status(500).json({ success: false, error: error.message, message: 'AI analysis failed' }); } }); // Claude AI Analysis function async function analyzeWithClaude(featureName, description, requirements, projectType) { const CLAUDE_API_KEY = process.env.CLAUDE_API_KEY; // If no API key, return a stub analysis instead of making API calls if (!CLAUDE_API_KEY) { console.warn('[Template Manager] No Claude API key, returning stub analysis'); const safeRequirements = Array.isArray(requirements) ? requirements : []; return { feature_name: featureName || 'Custom Feature', complexity: 'medium', logicRules: [ 'Only admins can access advanced dashboard metrics', 'Validate inputs for financial operations and POS entries', 'Enforce role-based access for multi-user actions' ], implementation_details: [ 'Use RBAC middleware for protected routes', 'Queue long-running analytics jobs', 'Paginate and cache dashboard queries' ], technical_requirements: safeRequirements.length ? safeRequirements : [ 'Relational DB for transactions and inventory', 'Real-time updates via websockets', 'Background worker for analytics' ], estimated_effort: '2-3 weeks', dependencies: ['Auth service', 'Payments gateway integration'], api_endpoints: ['POST /api/transactions', 'GET /api/dashboard/metrics'], database_tables: ['transactions', 'inventory', 'customers'], confidence_score: 0.5 }; } const safeRequirements = Array.isArray(requirements) ? requirements : []; const requirementsText = safeRequirements.length > 0 ? safeRequirements.map(req => `- ${req}`).join('\n') : 'No specific requirements provided'; const prompt = `Analyze this custom feature for a ${projectType || 'web application'} project: Feature Name: ${featureName || 'Custom Feature'} Description: ${description || 'No description provided'} Detailed Requirements: ${requirementsText} Based on these requirements, provide a detailed analysis in JSON format: { "feature_name": "Improved technical name", "complexity": "low|medium|high", "logicRules": ["Business rule 1", "Business rule 2", "Business rule 3"], "implementation_details": ["Technical detail 1", "Technical detail 2", "Technical detail 3"], "technical_requirements": ["Requirement 1", "Requirement 2", "Requirement 3"], "estimated_effort": "1-2 weeks|2-3 weeks|3-4 weeks|4+ weeks", "dependencies": ["Dependency 1", "Dependency 2"], "api_endpoints": ["POST /api/endpoint1", "GET /api/endpoint2"], "database_tables": ["table1", "table2"], "confidence_score": 0.85 } For complexity assessment: - "low": Simple CRUD, basic features, minimal business logic - "medium": Moderate business logic, some integrations, standard features - "high": Complex business rules, external integrations, security requirements, real-time features For logicRules, generate specific business rules based on the requirements like: - Access control and authorization rules - Data validation and business logic rules - Workflow and process rules - Security and compliance requirements Return ONLY the JSON object, no other text.`; try { console.log('🔍 [Template Manager] Making Claude API request...'); console.log('🔍 [Template Manager] API Key length:', CLAUDE_API_KEY ? CLAUDE_API_KEY.length : 0); console.log('🔍 [Template Manager] Prompt length:', prompt.length); const response = await axios.post('https://api.anthropic.com/v1/messages', { model: 'claude-3-5-sonnet-20241022', max_tokens: 2000, temperature: 0.1, messages: [ { role: 'user', content: [ { type: 'text', text: prompt } ] } ] }, { headers: { 'x-api-key': CLAUDE_API_KEY, 'Content-Type': 'application/json', 'anthropic-version': '2023-06-01' }, timeout: 30000 }); console.log('✅ [Template Manager] Claude API response received'); console.log('🔍 [Template Manager] Response status:', response.status); const responseText = (response?.data?.content?.[0]?.text || '').trim(); console.log('🔍 [Template Manager] Raw Claude response:', responseText.substring(0, 200) + '...'); // Extract JSON from response const jsonMatch = responseText.match(/\{[\s\S]*\}/); if (jsonMatch) { const analysis = JSON.parse(jsonMatch[0]); console.log('✅ [Template Manager] Claude analysis successful'); console.log('🔍 [Template Manager] Parsed analysis:', JSON.stringify(analysis, null, 2)); return analysis; } else { // Hard fail if Claude returns non-JSON; do not fallback console.error('❌ [Template Manager] No valid JSON found in Claude response'); console.error('🔍 [Template Manager] Full response:', responseText); throw new Error('No valid JSON found in Claude response'); } } catch (error) { // Surface provider message to aid debugging const providerMessage = error.response?.data?.error?.message || error.response?.data || error.message; console.error('❌ [Template Manager] Claude API error:', providerMessage); throw new Error(`Claude API error: ${providerMessage}`); } } // Removed rule-based fallback and helpers. Claude is mandatory. // Root endpoint app.get('/', (req, res) => { res.json({ message: 'Template Manager Service - Self-Learning Feature Database', version: '1.0.0', endpoints: { health: '/health', templates: '/api/templates', features: '/api/features', learning: '/api/learning', admin: '/api/admin', techStack: '/api/tech-stack', enhancedCkgTechStack: '/api/enhanced-ckg-tech-stack', tkgMigration: '/api/tkg-migration', ckgMigration: '/api/ckg-migration', customTemplates: '/api/custom-templates' } }); }); // Error handling middleware app.use((err, req, res, next) => { console.error('❌ Error:', err.stack); res.status(500).json({ error: 'Internal Server Error', message: process.env.NODE_ENV === 'development' ? err.message : 'Something went wrong' }); }); // 404 handler app.use('*', (req, res) => { res.status(404).json({ error: 'Not Found', message: `Route ${req.originalUrl} not found` }); }); // Graceful shutdown process.on('SIGINT', async () => { console.log('🛑 Shutting down Template Manager...'); await database.close(); process.exit(0); }); // Start server server.listen(PORT, '0.0.0.0', async () => { console.log('🚀 Template Manager Service started'); console.log(`📡 Server running on http://0.0.0.0:${PORT}`); console.log(`🏥 Health check: http://0.0.0.0:${PORT}/health`); console.log('🔌 WebSocket server ready for real-time notifications'); console.log('🎯 Self-learning feature database ready!'); // Initialize automated tech stack analyzer try { console.log('🤖 Initializing automated tech stack analyzer...'); await autoTechStackAnalyzer.initialize(); console.log('✅ Automated tech stack analyzer initialized successfully'); // Start analyzing existing templates in background console.log('🔍 Starting background analysis of existing templates...'); setTimeout(async () => { try { const result = await autoTechStackAnalyzer.analyzeAllPendingTemplates(); console.log(`🎉 Background analysis completed: ${result.message}`); } catch (error) { console.error('⚠️ Background analysis failed:', error.message); } }, 5000); // Wait 5 seconds after startup } catch (error) { console.error('❌ Failed to initialize automated tech stack analyzer:', error.message); } // Initialize automated TKG migration service try { console.log('🔄 Initializing automated TKG migration service...'); const autoTKGMigration = new AutoTKGMigrationService(); await autoTKGMigration.initialize(); console.log('✅ Automated TKG migration service initialized successfully'); // Make auto-migration service available globally app.set('autoTKGMigration', autoTKGMigration); } catch (error) { console.error('❌ Failed to initialize automated TKG migration service:', error.message); } // Initialize automated CKG migration service try { console.log('🔄 Initializing automated CKG migration service...'); const autoCKGMigration = new AutoCKGMigrationService(); await autoCKGMigration.initialize(); console.log('✅ Automated CKG migration service initialized successfully'); // Make auto-migration service available globally app.set('autoCKGMigration', autoCKGMigration); } catch (error) { console.error('❌ Failed to initialize automated CKG migration service:', error.message); } }); module.exports = app;