codenuk_backend_mine/services/template-manager/src/app.js

287 lines
10 KiB
JavaScript

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 AdminNotification = require('./models/admin_notification');
// 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/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 || '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';
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) {
// Propagate error up; endpoint will return 500. No fallback.
console.error('❌ [Template Manager] Claude API error:', error.message);
console.error('🔍 [Template Manager] Error details:', {
status: error.response?.status,
statusText: error.response?.statusText,
data: error.response?.data,
code: error.code
});
throw error;
}
}
// 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',
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', () => {
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!');
});
module.exports = app;