tractatus/src/routes/sync-health.routes.js
TheFlow 40601f7d27 refactor(lint): fix code style and unused variables across src/
- Fixed unused function parameters by prefixing with underscore
- Removed unused imports and variables
- Applied eslint --fix for automatic style fixes
  - Property shorthand
  - String template literals
  - Prefer const over let where appropriate
  - Spacing and formatting

Reduces lint errors from 108+ to 78 (61 unused vars, 17 other issues)

Related to CI lint failures in previous commit

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 20:15:26 +13:00

141 lines
4.9 KiB
JavaScript

/**
* 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;