287 lines
10 KiB
JavaScript
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; |