UNPKG

qmemory

Version:

A comprehensive production-ready Node.js utility library with MongoDB document operations, user ownership enforcement, Express.js HTTP utilities, environment-aware logging, and in-memory storage. Features 96%+ test coverage with comprehensive error handli

398 lines (323 loc) 9.4 kB
# Production Deployment Guide ## Quick Start ### Prerequisites - Node.js 18+ - MongoDB 4.4+ - npm or yarn package manager ### Installation ```bash npm install qmemory ``` ### Basic Usage ```javascript const { createUniqueDoc, fetchUserDocOr404, ensureMongoDB, MemStorage } = require('qmemory'); // Express.js integration example app.get('/api/health', (req, res) => { if (ensureMongoDB(res)) { res.status(200).json({ message: 'Service healthy' }); } }); ``` ## Production Environment Setup ### Environment Variables ```bash NODE_ENV=production MONGODB_URI=mongodb+srv://user:pass@cluster.mongodb.net/database PORT=3000 ``` ### Database Configuration #### Required MongoDB Indexes ```javascript // Essential for production performance await collection.createIndex({ "user": 1, "createdAt": -1 }); // index by user for creation date lookups await collection.createIndex({ "user": 1, "title": 1 }, { unique: true }); // enforce unique titles per user await collection.createIndex({ "user": 1, "updatedAt": -1 }); // allow sorting by last update per user ``` #### Connection Pool Settings ```javascript const mongoose = require('mongoose'); mongoose.connect(process.env.MONGODB_URI, { maxPoolSize: 10, serverSelectionTimeoutMS: 5000, socketTimeoutMS: 45000, bufferCommands: false, bufferMaxEntries: 0 }); ``` ## Docker Deployment ### Using Docker Compose (Recommended) ```bash # Clone or copy deployment files cp deployment/docker-compose.yml . cp deployment/Dockerfile . cp deployment/init-mongo.js . # Deploy with Docker Compose docker-compose up -d # Verify deployment curl http://localhost:3000/health ``` ### Manual Docker Setup ```bash # Build application image docker build -t qmemory-app . # Run with MongoDB docker run -d --name qmemory-mongo mongo:6.0 docker run -d --name qmemory-app --link qmemory-mongo:mongo \ -e NODE_ENV=production \ -e MONGODB_URI=mongodb://mongo:27017/qmemory \ -p 3000:3000 qmemory-app ``` ## API Integration Patterns ### Document Operations ```javascript const express = require('express'); const { createUniqueDoc, fetchUserDocOr404, updateUserDoc } = require('qmemory'); const router = express.Router(); // Create document with uniqueness validation router.post('/documents', async (req, res) => { const document = await createUniqueDoc( DocumentModel, { ...req.body, username: req.user.username }, { username: req.user.username, title: req.body.title }, res, 'Document with this title already exists' ); if (document) { res.status(201).json(document); } }); // Fetch user-owned document router.get('/documents/:id', async (req, res) => { const document = await fetchUserDocOr404( DocumentModel, req.params.id, req.user.username, res, 'Document not found' ); if (document) { res.json(document); } }); ``` ### HTTP Response Utilities ```javascript const { sendInternalServerError } = require('qmemory'); // Standardized success responses app.post('/api/users', async (req, res) => { try { const user = await storage.createUser({ username: req.body.username }); // pass only supported fields res.status(201).json({ message: 'User created successfully', data: user }); } catch (error) { if (error.code === 'VALIDATION_ERROR') { res.status(400).json({ message: error.message }); } else { sendInternalServerError(res, 'Failed to create user'); } } }); ``` ### In-Memory Storage for Development ```javascript const { MemStorage } = require('qmemory'); // Development environment user management if (process.env.NODE_ENV !== 'production') { const storage = new MemStorage(); // default limit is 10000 users // Create test users await storage.createUser({ username: 'testuser', displayName: 'Test User' }); // library does not accept email // Development-only endpoints app.get('/dev/users', (req, res) => { const users = storage.getAllUsers(); res.json(users); }); } ``` ## Performance Optimization ### Database Query Optimization ```javascript // Use projection to limit returned fields const document = await DocumentModel.findOne( { _id: id, username: username }, { title: 1, content: 1, createdAt: 1 } // Only return needed fields ); // Use lean() for read-only operations const documents = await DocumentModel.find({ username }) .lean() .sort({ createdAt: -1 }) .limit(50); ``` ### Connection Monitoring ```javascript const mongoose = require('mongoose'); mongoose.connection.on('connected', () => { console.log('MongoDB connected successfully'); }); mongoose.connection.on('error', (err) => { console.error('MongoDB connection error:', err); }); mongoose.connection.on('disconnected', () => { console.log('MongoDB disconnected'); }); ``` ## Health Checks and Monitoring ### Health Check Endpoint ```javascript const { ensureMongoDB, sendServiceUnavailable } = require('qmemory'); app.get('/health', (req, res) => { const checks = { database: ensureMongoDB(res), memory: process.memoryUsage(), uptime: process.uptime(), timestamp: new Date().toISOString() }; if (checks.database) { res.status(200).json({ message: 'All systems operational', data: checks }); } // Database check already sent 503 response if failed }); ``` ### Performance Monitoring ```javascript // Track response times app.use((req, res, next) => { const start = Date.now(); res.on('finish', () => { const duration = Date.now() - start; console.log(`${req.method} ${req.url} - ${res.statusCode} - ${duration}ms`); }); next(); }); ``` ## Error Handling Strategies ### Global Error Handler ```javascript const { sendInternalServerError } = require('qmemory'); app.use((error, req, res, next) => { console.error('Unhandled error:', error); if (res.headersSent) { return next(error); } sendInternalServerError(res, 'An unexpected error occurred'); }); ``` ### Graceful Shutdown ```javascript process.on('SIGTERM', () => { console.log('SIGTERM received, shutting down gracefully'); server.close(() => { mongoose.connection.close(() => { console.log('Process terminated'); process.exit(0); }); }); }); ``` ## Security Best Practices ### Input Validation ```javascript const { validateDocumentUniqueness } = require('qmemory'); // Always validate user input app.post('/api/documents', [ body('title').isLength({ min: 1, max: 100 }).trim(), body('content').isLength({ max: 10000 }), ], async (req, res) => { const errors = validationResult(req); if (!errors.isEmpty()) { return res.status(400).json({ message: 'Invalid input data' }); } // Proceed with document creation }); ``` ### User Ownership Enforcement ```javascript // All document operations automatically enforce user ownership const document = await fetchUserDocOr404( DocumentModel, req.params.id, req.user.username, // User can only access their own documents res, 'Document not found' ); ``` ## Scaling Considerations ### Horizontal Scaling - Library is stateless and supports multiple application instances - Use Redis for shared session storage if needed - MongoDB replica sets handle database scaling ### Load Balancing ```nginx upstream qmemory_app { server app1:3000; server app2:3000; server app3:3000; } server { listen 80; location / { proxy_pass http://qmemory_app; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } } ``` ## Troubleshooting ### Common Issues #### Database Connection Problems ```bash # Check MongoDB connection mongosh $MONGODB_URI --eval "db.runCommand({ping: 1})" # Verify application can connect node -e " const mongoose = require('mongoose'); mongoose.connect(process.env.MONGODB_URI) .then(() => console.log('Connection successful')) .catch(err => console.error('Connection failed:', err)); " ``` #### Performance Issues ```bash # Monitor MongoDB performance mongosh $MONGODB_URI --eval "db.runCommand({serverStatus: 1})" # Check application memory usage node -e "console.log(process.memoryUsage())" ``` #### Memory Storage Issues (Development) ```javascript // Clear memory storage if needed const { storage } = require('qmemory'); storage.clear(); // Removes all users and resets counter ``` ### Debugging Tips 1. **Enable Debug Logging** ```bash NODE_ENV=development npm start ``` 2. **Database Query Profiling** ```javascript mongoose.set('debug', true); // Log all queries ``` 3. **Memory Usage Monitoring** ```javascript setInterval(() => { const usage = process.memoryUsage(); console.log('Memory usage:', usage); }, 60000); ``` ## Support and Maintenance ### Regular Maintenance Tasks - Monitor database index usage and optimize as needed - Review error logs for patterns indicating issues - Update dependencies regularly for security patches - Backup MongoDB data according to your retention policy ### Performance Baselines - Document operations: <10ms average response time - User lookup operations: <5ms average response time - Database connection validation: <2ms average response time - Memory storage operations: <1ms average response time --- For additional support or questions about production deployment, refer to the comprehensive test suite and production validation examples included in the library.