tractatus/src/utils/mongoose.util.js
TheFlow c96ad31046 feat: implement Rule Manager and Project Manager admin systems
Major Features:
- Multi-project governance with Rule Manager web UI
- Project Manager for organizing governance across projects
- Variable substitution system (${VAR_NAME} in rules)
- Claude.md analyzer for instruction extraction
- Rule quality scoring and optimization

Admin UI Components:
- /admin/rule-manager.html - Full-featured rule management interface
- /admin/project-manager.html - Multi-project administration
- /admin/claude-md-migrator.html - Import rules from Claude.md files
- Dashboard enhancements for governance analytics

Backend Implementation:
- Controllers: projects, rules, variables
- Models: Project, VariableValue, enhanced GovernanceRule
- Routes: /api/projects, /api/rules with full CRUD
- Services: ClaudeMdAnalyzer, RuleOptimizer, VariableSubstitution
- Utilities: mongoose helpers

Documentation:
- User guides for Rule Manager and Projects
- Complete API documentation (PROJECTS_API, RULES_API)
- Phase 3 planning and architecture diagrams
- Test results and error analysis
- Coding best practices summary

Testing & Scripts:
- Integration tests for projects API
- Unit tests for variable substitution
- Database migration scripts
- Seed data generation
- Test token generator

Key Capabilities:
 UNIVERSAL scope rules apply across all projects
 PROJECT_SPECIFIC rules override for individual projects
 Variable substitution per-project (e.g., ${DB_PORT} → 27017)
 Real-time validation and quality scoring
 Advanced filtering and search
 Import from existing Claude.md files

Technical Details:
- MongoDB-backed governance persistence
- RESTful API with Express
- JWT authentication for admin endpoints
- CSP-compliant frontend (no inline handlers)
- Responsive Tailwind UI

This implements Phase 3 architecture as documented in planning docs.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-11 17:16:51 +13:00

104 lines
2.5 KiB
JavaScript

/**
* Mongoose Connection Utility
* Manages Mongoose ODM connection for MongoDB models
*/
const mongoose = require('mongoose');
const logger = require('./logger.util');
class MongooseConnection {
constructor() {
this.connected = false;
this.uri = process.env.MONGODB_URI || 'mongodb://localhost:27017/tractatus_dev';
}
/**
* Connect to MongoDB using Mongoose
*/
async connect(retries = 5) {
if (this.connected) {
return;
}
// Mongoose connection options
const options = {
maxPoolSize: 10,
minPoolSize: 2,
maxIdleTimeMS: 30000,
serverSelectionTimeoutMS: 5000,
socketTimeoutMS: 45000,
family: 4, // Use IPv4, skip trying IPv6
};
for (let attempt = 1; attempt <= retries; attempt++) {
try {
await mongoose.connect(this.uri, options);
this.connected = true;
logger.info(`✅ Mongoose connected to MongoDB`);
// Handle connection events
mongoose.connection.on('error', (err) => {
logger.error('Mongoose connection error:', err);
});
mongoose.connection.on('disconnected', () => {
logger.warn('Mongoose disconnected');
this.connected = false;
});
mongoose.connection.on('reconnected', () => {
logger.info('Mongoose reconnected');
this.connected = true;
});
return;
} catch (error) {
logger.error(`Mongoose connection attempt ${attempt}/${retries} failed:`, error.message);
if (attempt === retries) {
throw new Error(`Failed to connect Mongoose after ${retries} attempts: ${error.message}`);
}
// Wait before retry (exponential backoff)
await this.sleep(Math.min(1000 * Math.pow(2, attempt - 1), 10000));
}
}
}
/**
* Close Mongoose connection
*/
async close() {
if (mongoose.connection.readyState !== 0) {
await mongoose.disconnect();
this.connected = false;
logger.info('Mongoose connection closed');
}
}
/**
* Check if connected
*/
isConnected() {
return mongoose.connection.readyState === 1;
}
/**
* Sleep utility for retry logic
*/
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
// Singleton instance
const mongooseConnection = new MongooseConnection();
module.exports = {
connect: () => mongooseConnection.connect(),
close: () => mongooseConnection.close(),
isConnected: () => mongooseConnection.isConnected(),
mongoose // Export mongoose instance for direct access if needed
};