/** * Sync Health Check Routes * Monitors synchronization between file-based instructions and MongoDB */ const express = require('express'); const router = express.Router(); const fs = require('fs'); const path = require('path'); const mongoose = require('mongoose'); const { authenticateToken, requireAdmin } = require('../middleware/auth.middleware'); const GovernanceRule = require('../models/GovernanceRule.model'); const INSTRUCTION_FILE = path.join(__dirname, '../../.claude/instruction-history.json'); /** * GET /api/admin/sync/health * Check synchronization health between file and database */ router.get('/health', authenticateToken, requireAdmin, async (req, res) => { try { // Check MongoDB connection if (mongoose.connection.readyState !== 1) { return res.json({ success: true, health: { status: 'warning', message: 'Database not connected - sync health unavailable', severity: 'warning', timestamp: new Date().toISOString(), counts: { file: 0, database: 0, difference: 0, differencePercent: 0 }, details: { missingInDatabase: [], orphanedInDatabase: [] }, recommendations: ['Start MongoDB server', 'Restart the application to auto-connect'] } }); } let fileInstructions = []; let fileError = null; if (fs.existsSync(INSTRUCTION_FILE)) { try { const fileData = JSON.parse(fs.readFileSync(INSTRUCTION_FILE, 'utf8')); fileInstructions = (fileData.instructions || []).filter(i => i.active !== false); } catch (err) { fileError = err.message; } } else { fileError = 'File not found'; } const dbRules = await GovernanceRule.find({ active: true }).lean(); const fileCount = fileInstructions.length; const dbCount = dbRules.length; const difference = Math.abs(fileCount - dbCount); const diffPercent = fileCount > 0 ? ((difference / fileCount) * 100).toFixed(1) : 0; let status = 'healthy'; let message = 'File and database are synchronized'; let severity = 'success'; if (fileError) { status = 'error'; message = `Cannot read instruction file: ${ fileError}`; severity = 'error'; } else if (difference === 0) { status = 'healthy'; message = 'Perfectly synchronized'; severity = 'success'; } else if (difference <= 2) { status = 'warning'; message = `Minor desync: ${ difference } instruction${ difference !== 1 ? 's' : '' } differ`; severity = 'warning'; } else if (difference <= 5) { status = 'warning'; message = `Moderate desync: ${ difference } instructions differ (${ diffPercent }%)`; severity = 'warning'; } else { status = 'critical'; message = `Critical desync: ${ difference } instructions differ (${ diffPercent }%)`; severity = 'error'; } const fileIds = new Set(fileInstructions.map(i => i.id)); const dbIds = new Set(dbRules.map(r => r.id)); const missingInDb = fileInstructions .filter(i => !dbIds.has(i.id)) .map(i => ({ id: i.id, text: `${i.text.substring(0, 60) }...` })); const orphanedInDb = dbRules .filter(r => !fileIds.has(r.id)) .map(r => ({ id: r.id, text: `${r.text.substring(0, 60) }...` })); res.json({ success: true, health: { status, message, severity, timestamp: new Date().toISOString(), counts: { file: fileCount, database: dbCount, difference, differencePercent: parseFloat(diffPercent) }, details: { missingInDatabase: missingInDb, orphanedInDatabase: orphanedInDb }, recommendations: difference > 0 ? [ 'Run: node scripts/sync-instructions-to-db.js --force', 'Or restart the server (auto-sync on startup)', 'Or wait for next session initialization' ] : [] } }); } catch (error) { console.error('Sync health check error:', error); res.status(500).json({ success: false, error: 'Failed to check sync health', message: error.message }); } }); /** * POST /api/admin/sync/trigger * Manually trigger synchronization */ router.post('/trigger', authenticateToken, requireAdmin, async (req, res) => { try { const { syncInstructions } = require('../../scripts/sync-instructions-to-db.js'); const result = await syncInstructions({ silent: true }); if (result.success) { res.json({ success: true, message: 'Synchronization completed successfully', result: { added: result.added, updated: result.updated, deactivated: result.deactivated, finalCount: result.finalCount } }); } else { res.status(500).json({ success: false, error: 'Synchronization failed', message: result.error || 'Unknown error' }); } } catch (error) { console.error('Manual sync trigger error:', error); res.status(500).json({ success: false, error: 'Failed to trigger synchronization', message: error.message }); } }); module.exports = router;