backend changes

This commit is contained in:
Chandini 2025-09-15 14:55:50 +05:30
parent aaf7065431
commit 9c453bfe07
4 changed files with 294 additions and 78 deletions

1
Jenkinsfile vendored
View File

@ -196,6 +196,7 @@ pipeline {
docker compose ps docker compose ps
' '
""" """
} }
} }
} }

View File

@ -8,7 +8,7 @@ services:
container_name: pipeline_postgres container_name: pipeline_postgres
environment: environment:
POSTGRES_USER: pipeline_admin POSTGRES_USER: pipeline_admin
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_PASSWORD: secure_pipeline_2024
POSTGRES_DB: dev_pipeline POSTGRES_DB: dev_pipeline
volumes: volumes:
- postgres_data:/var/lib/postgresql/data - postgres_data:/var/lib/postgresql/data
@ -26,7 +26,7 @@ services:
redis: redis:
image: redis:7-alpine image: redis:7-alpine
container_name: pipeline_redis container_name: pipeline_redis
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD} command: redis-server --appendonly yes --requirepass redis_secure_2024
volumes: volumes:
- redis_data:/data - redis_data:/data
ports: ports:
@ -45,8 +45,8 @@ services:
image: mongo:7 image: mongo:7
container_name: pipeline_mongodb container_name: pipeline_mongodb
environment: environment:
MONGO_INITDB_ROOT_USERNAME: pipeline_user MONGO_INITDB_ROOT_USERNAME: pipeline_admin
MONGO_INITDB_ROOT_PASSWORD: ${MONGODB_PASSWORD} MONGO_INITDB_ROOT_PASSWORD: mongo_secure_2024
volumes: volumes:
- mongodb_data:/data/db - mongodb_data:/data/db
ports: ports:
@ -62,7 +62,7 @@ services:
container_name: pipeline_rabbitmq container_name: pipeline_rabbitmq
environment: environment:
RABBITMQ_DEFAULT_USER: pipeline_admin RABBITMQ_DEFAULT_USER: pipeline_admin
RABBITMQ_DEFAULT_PASS: ${RABBITMQ_PASSWORD} RABBITMQ_DEFAULT_PASS: rabbit_secure_2024
volumes: volumes:
- rabbitmq_data:/var/lib/rabbitmq - rabbitmq_data:/var/lib/rabbitmq
- rabbitmq_logs:/var/log/rabbitmq - rabbitmq_logs:/var/log/rabbitmq
@ -93,12 +93,12 @@ services:
- POSTGRES_PORT=5432 - POSTGRES_PORT=5432
- POSTGRES_DB=dev_pipeline - POSTGRES_DB=dev_pipeline
- POSTGRES_USER=pipeline_admin - POSTGRES_USER=pipeline_admin
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_PASSWORD=secure_pipeline_2024
- REDIS_HOST=redis - REDIS_HOST=redis
- REDIS_PORT=6379 - REDIS_PORT=6379
- REDIS_PASSWORD=${REDIS_PASSWORD} - REDIS_PASSWORD=redis_secure_2024
- NODE_ENV=development - NODE_ENV=development
- DATABASE_URL=postgresql://pipeline_admin:${POSTGRES_PASSWORD}@postgres:5432/dev_pipeline - DATABASE_URL=postgresql://pipeline_admin:secure_pipeline_2024@postgres:5432/dev_pipeline
entrypoint: ["/bin/sh", "-c", "chmod +x ./scripts/migrate-all.sh && ./scripts/migrate-all.sh"] entrypoint: ["/bin/sh", "-c", "chmod +x ./scripts/migrate-all.sh && ./scripts/migrate-all.sh"]
depends_on: depends_on:
postgres: postgres:
@ -240,20 +240,20 @@ services:
- POSTGRES_PORT=5432 - POSTGRES_PORT=5432
- POSTGRES_DB=dev_pipeline - POSTGRES_DB=dev_pipeline
- POSTGRES_USER=pipeline_admin - POSTGRES_USER=pipeline_admin
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_PASSWORD=secure_pipeline_2024
# Cache and message queue # Cache and message queue
- REDIS_HOST=redis - REDIS_HOST=redis
- REDIS_PORT=6379 - REDIS_PORT=6379
- REDIS_PASSWORD=${REDIS_PASSWORD} - REDIS_PASSWORD=redis_secure_2024
- RABBITMQ_HOST=rabbitmq - RABBITMQ_HOST=rabbitmq
- RABBITMQ_PORT=5672 - RABBITMQ_PORT=5672
- RABBITMQ_USER=pipeline_admin - RABBITMQ_USER=pipeline_admin
- RABBITMQ_PASSWORD=${RABBITMQ_PASSWORD} - RABBITMQ_PASSWORD=rabbit_secure_2024
# JWT configuration # JWT configuration
- JWT_ACCESS_SECRET=access-secret-key-2024-tech4biz-secure_pipeline_2024 - JWT_ACCESS_SECRET=access-secret-key-2024-tech4biz-secure_pipeline_2024
- JWT_SECRET=access-secret-key-2024-tech4biz-secure_pipeline_2024 - JWT_SECRET=ultra_secure_jwt_secret_2024
# - JWT_ACCESS_SECRET=access-secret-key-2024-tech4biz-${POSTGRES_PASSWORD} # - JWT_ACCESS_SECRET=access-secret-key-2024-tech4biz-secure_pipeline_2024
# - JWT_REFRESH_SECRET=refresh-secret-key-2024-tech4biz-${POSTGRES_PASSWORD} # - JWT_REFRESH_SECRET=refresh-secret-key-2024-tech4biz-secure_pipeline_2024
# Service URLs # Service URLs
- USER_AUTH_URL=http://user-auth:8011 - USER_AUTH_URL=http://user-auth:8011
- TEMPLATE_MANAGER_URL=http://template-manager:8009 - TEMPLATE_MANAGER_URL=http://template-manager:8009
@ -299,10 +299,10 @@ services:
- POSTGRES_PORT=5432 - POSTGRES_PORT=5432
- POSTGRES_DB=dev_pipeline - POSTGRES_DB=dev_pipeline
- POSTGRES_USER=pipeline_admin - POSTGRES_USER=pipeline_admin
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_PASSWORD=secure_pipeline_2024
- REDIS_HOST=redis - REDIS_HOST=redis
- REDIS_PORT=6379 - REDIS_PORT=6379
- REDIS_PASSWORD=${REDIS_PASSWORD} - REDIS_PASSWORD=redis_secure_2024
- MONGODB_HOST=mongodb - MONGODB_HOST=mongodb
- MONGODB_PORT=27017 - MONGODB_PORT=27017
- NEO4J_URI=bolt://neo4j:7687 - NEO4J_URI=bolt://neo4j:7687
@ -310,7 +310,7 @@ services:
- NEO4J_PASSWORD=password - NEO4J_PASSWORD=password
- CHROMA_HOST=chromadb - CHROMA_HOST=chromadb
- CHROMA_PORT=8000 - CHROMA_PORT=8000
- REDIS_URL=redis://redis:6379 - REDIS_URL=redis://:redis_secure_2024@redis:6379
networks: networks:
- pipeline_network - pipeline_network
depends_on: depends_on:
@ -333,10 +333,10 @@ services:
- POSTGRES_PORT=5432 - POSTGRES_PORT=5432
- POSTGRES_DB=dev_pipeline - POSTGRES_DB=dev_pipeline
- POSTGRES_USER=pipeline_admin - POSTGRES_USER=pipeline_admin
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_PASSWORD=secure_pipeline_2024
- REDIS_HOST=redis - REDIS_HOST=redis
- REDIS_PORT=6379 - REDIS_PORT=6379
- REDIS_PASSWORD=${REDIS_PASSWORD} - REDIS_PASSWORD=redis_secure_2024
networks: networks:
- pipeline_network - pipeline_network
depends_on: depends_on:
@ -355,13 +355,13 @@ services:
environment: environment:
- PORT=8003 - PORT=8003
- HOST=0.0.0.0 - HOST=0.0.0.0
- CLAUDE_API_KEY=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 - CLAUDE_API_KEY=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
- ANTHROPIC_API_KEY=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 - ANTHROPIC_API_KEY=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
- POSTGRES_HOST=postgres - POSTGRES_HOST=postgres
- POSTGRES_PORT=5432 - POSTGRES_PORT=5432
- POSTGRES_DB=dev_pipeline - POSTGRES_DB=dev_pipeline
- POSTGRES_USER=pipeline_admin - POSTGRES_USER=pipeline_admin
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_PASSWORD=secure_pipeline_2024
- MONGODB_HOST=mongodb - MONGODB_HOST=mongodb
- MONGODB_PORT=27017 - MONGODB_PORT=27017
networks: networks:
@ -391,13 +391,13 @@ services:
- POSTGRES_PORT=5432 - POSTGRES_PORT=5432
- POSTGRES_DB=dev_pipeline - POSTGRES_DB=dev_pipeline
- POSTGRES_USER=pipeline_admin - POSTGRES_USER=pipeline_admin
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_PASSWORD=secure_pipeline_2024
- MONGODB_HOST=mongodb - MONGODB_HOST=mongodb
- MONGODB_PORT=27017 - MONGODB_PORT=27017
- REDIS_HOST=redis - REDIS_HOST=redis
- REDIS_PORT=6379 - REDIS_PORT=6379
- REDIS_PASSWORD=${REDIS_PASSWORD} - REDIS_PASSWORD=redis_secure_2024
- CLAUDE_API_KEY=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 - CLAUDE_API_KEY=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
- OPENAI_API_KEY=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 - OPENAI_API_KEY=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
# - NEO4J_URI=bolt://neo4j:7687 # - NEO4J_URI=bolt://neo4j:7687
# - NEO4J_USER=neo4j # - NEO4J_USER=neo4j
@ -440,10 +440,10 @@ services:
- POSTGRES_PORT=5432 - POSTGRES_PORT=5432
- POSTGRES_DB=dev_pipeline - POSTGRES_DB=dev_pipeline
- POSTGRES_USER=pipeline_admin - POSTGRES_USER=pipeline_admin
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_PASSWORD=secure_pipeline_2024
- REDIS_HOST=redis - REDIS_HOST=redis
- REDIS_PORT=6379 - REDIS_PORT=6379
- REDIS_PASSWORD=${REDIS_PASSWORD} - REDIS_PASSWORD=redis_secure_2024
networks: networks:
- pipeline_network - pipeline_network
depends_on: depends_on:
@ -464,13 +464,13 @@ services:
- POSTGRES_PORT=5432 - POSTGRES_PORT=5432
- POSTGRES_DB=dev_pipeline - POSTGRES_DB=dev_pipeline
- POSTGRES_USER=pipeline_admin - POSTGRES_USER=pipeline_admin
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_PASSWORD=secure_pipeline_2024
- MONGODB_HOST=mongodb - MONGODB_HOST=mongodb
- MONGODB_PORT=27017 - MONGODB_PORT=27017
- RABBITMQ_HOST=rabbitmq - RABBITMQ_HOST=rabbitmq
- RABBITMQ_PORT=5672 - RABBITMQ_PORT=5672
- RABBITMQ_USER=pipeline_admin - RABBITMQ_USER=pipeline_admin
- RABBITMQ_PASSWORD=${RABBITMQ_PASSWORD} - RABBITMQ_PASSWORD=rabbit_secure_2024
networks: networks:
- pipeline_network - pipeline_network
depends_on: depends_on:
@ -496,25 +496,25 @@ services:
- POSTGRES_PORT=5432 - POSTGRES_PORT=5432
- POSTGRES_DB=dev_pipeline - POSTGRES_DB=dev_pipeline
- POSTGRES_USER=pipeline_admin - POSTGRES_USER=pipeline_admin
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_PASSWORD=secure_pipeline_2024
- REDIS_HOST=redis - REDIS_HOST=redis
- REDIS_PORT=6379 - REDIS_PORT=6379
- REDIS_PASSWORD=${REDIS_PASSWORD} - REDIS_PASSWORD=redis_secure_2024
- JWT_ACCESS_SECRET=access-secret-key-2024-tech4biz-secure_pipeline_2024 - JWT_ACCESS_SECRET=access-secret-key-2024-tech4biz-secure_pipeline_2024
- JWT_REFRESH_SECRET=refresh-secret-key-2024-tech4biz-${POSTGRES_PASSWORD} - JWT_REFRESH_SECRET=refresh-secret-key-2024-tech4biz-secure_pipeline_2024
- JWT_ACCESS_EXPIRY=24h - JWT_ACCESS_EXPIRY=24h
- JWT_ADMIN_ACCESS_EXPIRY=7d - JWT_ADMIN_ACCESS_EXPIRY=7d
- JWT_REFRESH_EXPIRY=7d - JWT_REFRESH_EXPIRY=7d
- FRONTEND_URL=* - FRONTEND_URL=*
# Email Configuration # Email Configuration
- SMTP_HOST=${SMTP_HOST:-smtp.gmail.com} - SMTP_HOST=smtp.gmail.com
- SMTP_PORT=${SMTP_PORT:-587} - SMTP_PORT=587
- SMTP_SECURE=${SMTP_SECURE:-false} - SMTP_SECURE=false
- SMTP_USER=${SMTP_USER:-frontendtechbiz@gmail.com} - SMTP_USER=frontendtechbiz@gmail.com
- SMTP_PASS=${SMTP_PASS:-oidhhjeasgzbqptq} - SMTP_PASS=oidhhjeasgzbqptq
- SMTP_FROM=${SMTP_FROM:-frontendtechbiz@gmail.com} - SMTP_FROM=frontendtechbiz@gmail.com
- GMAIL_USER=${GMAIL_USER:-frontendtechbiz@gmail.com} - GMAIL_USER=frontendtechbiz@gmail.com
- GMAIL_APP_PASSWORD=${GMAIL_APP_PASSWORD:-oidhhjeasgzbqptq} - GMAIL_APP_PASSWORD=oidhhjeasgzbqptq
- AUTH_PUBLIC_URL=* - AUTH_PUBLIC_URL=*
- TEMPLATE_MANAGER_URL=http://template-manager:8009 - TEMPLATE_MANAGER_URL=http://template-manager:8009
networks: networks:
@ -551,10 +551,10 @@ services:
- POSTGRES_PORT=5432 - POSTGRES_PORT=5432
- POSTGRES_DB=dev_pipeline - POSTGRES_DB=dev_pipeline
- POSTGRES_USER=pipeline_admin - POSTGRES_USER=pipeline_admin
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_PASSWORD=secure_pipeline_2024
- REDIS_HOST=redis - REDIS_HOST=redis
- REDIS_PORT=6379 - REDIS_PORT=6379
- REDIS_PASSWORD=${REDIS_PASSWORD} - REDIS_PASSWORD=redis_secure_2024
- NODE_ENV=development - NODE_ENV=development
- JWT_ACCESS_SECRET=access-secret-key-2024-tech4biz-secure_pipeline_2024 - JWT_ACCESS_SECRET=access-secret-key-2024-tech4biz-secure_pipeline_2024
networks: networks:
@ -584,16 +584,16 @@ services:
environment: environment:
- PORT=8021 - PORT=8021
- HOST=0.0.0.0 - HOST=0.0.0.0
- CLAUDE_API_KEY=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 - CLAUDE_API_KEY=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
- POSTGRES_HOST=postgres - POSTGRES_HOST=postgres
- POSTGRES_PORT=5432 - POSTGRES_PORT=5432
- POSTGRES_DB=dev_pipeline - POSTGRES_DB=dev_pipeline
- POSTGRES_USER=pipeline_admin - POSTGRES_USER=pipeline_admin
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_PASSWORD=secure_pipeline_2024
- REDIS_HOST=redis - REDIS_HOST=redis
- REDIS_PORT=6379 - REDIS_PORT=6379
- REDIS_PASSWORD=${REDIS_PASSWORD} - REDIS_PASSWORD=redis_secure_2024
- JWT_ACCESS_SECRET=access-secret-key-2024-tech4biz-${POSTGRES_PASSWORD} - JWT_ACCESS_SECRET=access-secret-key-2024-tech4biz-secure_pipeline_2024
- USER_AUTH_SERVICE_URL=http://user-auth:8011 - USER_AUTH_SERVICE_URL=http://user-auth:8011
- FLASK_ENV=development - FLASK_ENV=development
networks: networks:
@ -622,10 +622,10 @@ services:
- POSTGRES_PORT=5432 - POSTGRES_PORT=5432
- POSTGRES_DB=dev_pipeline - POSTGRES_DB=dev_pipeline
- POSTGRES_USER=pipeline_admin - POSTGRES_USER=pipeline_admin
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD} - POSTGRES_PASSWORD=secure_pipeline_2024
- REDIS_HOST=redis - REDIS_HOST=redis
- REDIS_PORT=6379 - REDIS_PORT=6379
- REDIS_PASSWORD=${REDIS_PASSWORD} - REDIS_PASSWORD=redis_secure_2024
- NODE_ENV=development - NODE_ENV=development
- GITHUB_REDIRECT_URI=* - GITHUB_REDIRECT_URI=*
- ATTACHED_REPOS_DIR=/tmp/attached-repos - ATTACHED_REPOS_DIR=/tmp/attached-repos
@ -657,9 +657,9 @@ services:
environment: environment:
- PORT=8007 - PORT=8007
- HOST=0.0.0.0 - HOST=0.0.0.0
- DATABASE_URL=postgresql://pipeline_admin:${POSTGRES_PASSWORD}@postgres:5432/dev_pipeline - DATABASE_URL=postgresql://pipeline_admin:secure_pipeline_2024@postgres:5432/dev_pipeline
- CLAUDE_API_KEY=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 - CLAUDE_API_KEY=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
- REDIS_URL=redis://pipeline_redis:6379 - REDIS_URL=redis://:redis_secure_2024@pipeline_redis:6379
- SERVICE_PORT=8007 - SERVICE_PORT=8007
- LOG_LEVEL=INFO - LOG_LEVEL=INFO
- DEFAULT_TARGET_QUALITY=0.85 - DEFAULT_TARGET_QUALITY=0.85
@ -697,8 +697,8 @@ services:
environment: environment:
- NODE_ENV=production - NODE_ENV=production
- PORT=8008 - PORT=8008
- DATABASE_URL=postgresql://pipeline_admin:${POSTGRES_PASSWORD}@postgres:5432/dev_pipeline - DATABASE_URL=postgresql://pipeline_admin:secure_pipeline_2024@postgres:5432/dev_pipeline
- REDIS_URL=redis://pipeline_redis:6379 - REDIS_URL=redis://:redis_secure_2024@pipeline_redis:6379
- API_GATEWAY_URL=http://pipeline_api_gateway:8000 - API_GATEWAY_URL=http://pipeline_api_gateway:8000
- CODE_GENERATOR_URL=http://pipeline_code_generator:8004 - CODE_GENERATOR_URL=http://pipeline_code_generator:8004
- SELF_IMPROVING_URL=http://pipeline_self_improving_generator:8007 - SELF_IMPROVING_URL=http://pipeline_self_improving_generator:8007
@ -738,8 +738,8 @@ services:
- "5678:5678" - "5678:5678"
environment: environment:
- N8N_BASIC_AUTH_ACTIVE=true - N8N_BASIC_AUTH_ACTIVE=true
- N8N_BASIC_AUTH_USER=pipeline_admin - N8N_BASIC_AUTH_USER=admin
- N8N_BASIC_AUTH_PASSWORD=pipeline_n8n_2024 - N8N_BASIC_AUTH_PASSWORD=admin_n8n_2024
- N8N_HOST=localhost - N8N_HOST=localhost
- N8N_PORT=5678 - N8N_PORT=5678
- N8N_PROTOCOL=http - N8N_PROTOCOL=http
@ -750,7 +750,7 @@ services:
- DB_POSTGRESDB_PORT=5432 - DB_POSTGRESDB_PORT=5432
- DB_POSTGRESDB_DATABASE=n8n - DB_POSTGRESDB_DATABASE=n8n
- DB_POSTGRESDB_USER=pipeline_admin - DB_POSTGRESDB_USER=pipeline_admin
- DB_POSTGRESDB_PASSWORD=${POSTGRES_PASSWORD} - DB_POSTGRESDB_PASSWORD=secure_pipeline_2024
volumes: volumes:
- n8n_data:/home/node/.n8n - n8n_data:/home/node/.n8n
- ./orchestration/n8n/workflows:/home/node/.n8n/workflows - ./orchestration/n8n/workflows:/home/node/.n8n/workflows

View File

@ -230,31 +230,46 @@ class CustomFeature {
const updated = await CustomFeature.update(id, updates); const updated = await CustomFeature.update(id, updates);
// If approved, ensure a mirrored entry exists/updates in template_features // If approved, ensure a mirrored entry exists/updates in template_features
// Only mirror if the template_id exists in the main templates table
if (updated && status === 'approved') { if (updated && status === 'approved') {
try { try {
const Feature = require('./feature'); // Check if template_id exists in main templates table
const featureId = `custom_${updated.id}`; const templateCheck = await database.query(
const existingMirror = await Feature.getByFeatureId(updated.template_id, featureId); 'SELECT id FROM templates WHERE id = $1 AND is_active = true',
if (existingMirror) { [updated.template_id]
await Feature.update(existingMirror.id, { );
name: updated.name,
description: updated.description, if (templateCheck.rows.length > 0) {
complexity: updated.complexity, // Template exists in main templates table, safe to mirror
feature_type: 'custom', const Feature = require('./feature');
is_default: false const featureId = `custom_${updated.id}`;
}); const existingMirror = await Feature.getByFeatureId(updated.template_id, featureId);
if (existingMirror) {
await Feature.update(existingMirror.id, {
name: updated.name,
description: updated.description,
complexity: updated.complexity,
feature_type: 'custom',
is_default: false
});
console.log('✅ Updated mirrored feature in template_features for approved custom feature');
} else {
await Feature.create({
template_id: updated.template_id,
feature_id: featureId,
name: updated.name,
description: updated.description,
feature_type: 'custom',
complexity: updated.complexity,
display_order: 999,
is_default: false,
created_by_user: true
});
console.log('✅ Created mirrored feature in template_features for approved custom feature');
}
} else { } else {
await Feature.create({ // Template is likely a custom template, don't mirror to template_features
template_id: updated.template_id, console.log(' Custom feature approved but template_id references custom template, skipping mirror to template_features');
feature_id: featureId,
name: updated.name,
description: updated.description,
feature_type: 'custom',
complexity: updated.complexity,
display_order: 999,
is_default: false,
created_by_user: true
});
} }
} catch (mirrorErr) { } catch (mirrorErr) {
console.error('⚠️ Failed to mirror approved custom feature into template_features:', mirrorErr.message); console.error('⚠️ Failed to mirror approved custom feature into template_features:', mirrorErr.message);

View File

@ -48,6 +48,206 @@ const requireAdmin = (req, res, next) => {
// Apply admin middleware to all routes // Apply admin middleware to all routes
router.use(requireAdmin); router.use(requireAdmin);
// GET /api/admin/custom-features - Proxy to existing custom features functionality
router.get('/custom-features', async (req, res) => {
try {
const limit = parseInt(req.query.limit) || 50;
const offset = parseInt(req.query.offset) || 0;
const status = req.query.status;
console.log(`Admin: Fetching custom features (status: ${status || 'all'}, limit: ${limit}, offset: ${offset})`);
let features;
if (status) {
features = await CustomFeature.getFeaturesByStatus(status, limit, offset);
} else {
features = await CustomFeature.getAllFeatures(limit, offset);
}
res.json({
success: true,
data: features,
count: features.length,
message: `Found ${features.length} custom features`
});
} catch (error) {
console.error('Error fetching custom features:', error.message);
res.status(500).json({
success: false,
error: 'Failed to fetch custom features',
message: error.message
});
}
});
// POST /api/admin/custom-features/:id/review - Review custom feature
router.post('/custom-features/:id/review', async (req, res) => {
try {
const { id } = req.params;
const { status, admin_notes, admin_reviewed_by } = req.body;
const validStatuses = ['approved', 'rejected', 'duplicate'];
if (!validStatuses.includes(status)) {
return res.status(400).json({
success: false,
error: 'Invalid status',
message: `Status must be one of: ${validStatuses.join(', ')}`
});
}
console.log(`🔍 Admin: Reviewing custom feature ${id} with status: ${status}`);
const feature = await CustomFeature.getById(id);
if (!feature) {
return res.status(404).json({
success: false,
error: 'Feature not found',
message: 'The specified feature does not exist'
});
}
const reviewData = {
status,
admin_notes,
admin_reviewed_by: admin_reviewed_by || req.user.id
};
const updatedFeature = await CustomFeature.reviewFeature(id, reviewData);
try {
await AdminNotification.notifyFeatureReviewed(id, feature.name, status);
} catch (notifError) {
console.warn('⚠️ Failed to create notification:', notifError.message);
}
res.json({
success: true,
data: updatedFeature,
message: `Feature "${feature.name}" has been ${status}`
});
} catch (error) {
console.error('❌ Error reviewing custom feature:', error.message);
res.status(500).json({
success: false,
error: 'Failed to review custom feature',
message: error.message
});
}
});
// GET /api/admin/custom-templates - Get custom templates
router.get('/custom-templates', async (req, res) => {
try {
const limit = parseInt(req.query.limit) || 50;
const offset = parseInt(req.query.offset) || 0;
const status = req.query.status;
console.log(`Admin: Fetching custom templates (status: ${status || 'all'}, limit: ${limit}, offset: ${offset})`);
let templates;
if (status) {
templates = await CustomTemplate.getTemplatesByStatus(status, limit, offset);
} else {
templates = await CustomTemplate.getAllTemplates(limit, offset);
}
res.json({
success: true,
data: templates,
count: templates.length,
message: `Found ${templates.length} custom templates`
});
} catch (error) {
console.error('Error fetching custom templates:', error.message);
res.status(500).json({
success: false,
error: 'Failed to fetch custom templates',
message: error.message
});
}
});
// POST /api/admin/custom-templates/:id/review - Review custom template
router.post('/custom-templates/:id/review', async (req, res) => {
try {
const { id } = req.params;
const { status, admin_notes, admin_reviewed_by } = req.body;
const validStatuses = ['approved', 'rejected', 'duplicate'];
if (!validStatuses.includes(status)) {
return res.status(400).json({
success: false,
error: 'Invalid status',
message: `Status must be one of: ${validStatuses.join(', ')}`
});
}
console.log(`🔍 Admin: Reviewing custom template ${id} with status: ${status}`);
const template = await CustomTemplate.getById(id);
if (!template) {
return res.status(404).json({
success: false,
error: 'Template not found',
message: 'The specified template does not exist'
});
}
const reviewData = {
status,
admin_notes,
admin_reviewed_by: admin_reviewed_by || req.user.id
};
const updatedTemplate = await CustomTemplate.reviewTemplate(id, reviewData);
try {
await AdminNotification.notifyTemplateReviewed(id, template.title, status);
} catch (notifError) {
console.warn('⚠️ Failed to create notification:', notifError.message);
}
res.json({
success: true,
data: updatedTemplate,
message: `Template "${template.title}" has been ${status}`
});
} catch (error) {
console.error('❌ Error reviewing custom template:', error.message);
res.status(500).json({
success: false,
error: 'Failed to review custom template',
message: error.message
});
}
});
// GET /api/admin/templates/stats - Get template statistics
router.get('/templates/stats', async (req, res) => {
try {
console.log('📊 Admin: Fetching template statistics...');
const stats = await CustomTemplate.getTemplateStats();
const notificationCounts = await AdminNotification.getCounts();
res.json({
success: true,
data: {
templates: stats,
notifications: notificationCounts
},
message: 'Template statistics retrieved successfully'
});
} catch (error) {
console.error('❌ Error fetching template stats:', error.message);
res.status(500).json({
success: false,
error: 'Failed to fetch template statistics',
message: error.message
});
}
});
// GET /api/admin/features/pending - Get pending features for review // GET /api/admin/features/pending - Get pending features for review
router.get('/features/pending', async (req, res) => { router.get('/features/pending', async (req, res) => {
try { try {