Documentation Index
Fetch the complete documentation index at: https://mintlify.com/ihfaz297/MND/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Monitoring the MND system ensures reliability, tracks API quota usage, and helps identify issues before they affect users.
Health Check Endpoint
The backend exposes a health check endpoint for uptime monitoring.
Endpoint
Response
{
"status": "ok",
"uptime": 12345.67,
"timestamp": "2026-03-05T10:30:00.000Z"
}
Implementation
In src/api/routesController.ts:
export function healthCheck(req: Request, res: Response) {
res.json({
status: 'ok',
uptime: process.uptime(),
timestamp: new Date().toISOString()
});
}
Monitoring Services
Use these services to ping /api/health periodically:
UptimeRobot (Free tier):
- Monitor up to 50 endpoints
- 5-minute interval checks
- Email/SMS alerts
Setup:
- Go to uptimerobot.com
- Add New Monitor
- Type: HTTP(s)
- URL:
https://yourdomain.com/api/health
- Interval: 5 minutes
- Add alert contacts
Better Uptime:
- 3-minute interval
- Incident management
- Status page
Pingdom:
- 1-minute interval
- Performance monitoring
- Real user monitoring
API Usage Tracking
The Distance Matrix client includes built-in usage tracking.
Usage Statistics
Access stats via the singleton instance:
import { distanceMatrixClient } from './infra/distanceMatrixClient';
const stats = distanceMatrixClient.getStats();
console.log(stats);
Output:
{
monthlyCount: 45,
dailyCount: 12,
lastReset: '2026-03-05',
cacheHits: 234,
cacheMisses: 45
}
Print Statistics
distanceMatrixClient.printStats();
Console output:
📊 Distance Matrix Usage:
Monthly: 45/700
Daily: 12/50
Cache hits: 234
Cache misses: 45
Cache size: 156 entries
Usage Limits
Configured in src/infra/distanceMatrixClient.ts:
private readonly MONTHLY_LIMIT = 700;
private readonly DAILY_LIMIT = 50;
private readonly CACHE_TTL_DAYS = 7;
Quota Warnings
The client logs warnings when approaching limits:
if (this.usageStats.monthlyCount >= this.MONTHLY_LIMIT) {
console.warn(`⚠️ Monthly limit reached (${this.MONTHLY_LIMIT})`);
return {
ok: false,
errorMessage: 'Monthly API quota exceeded'
};
}
Distance Matrix Quota Management
Google Distance Matrix API has strict quota limits.
Free Tier Limits
- $200 free credit/month = ~700 requests
- After that: $5-10 per 1000 requests
Quota Monitoring Endpoint
Create an endpoint to expose quota stats:
// src/api/routesController.ts
export function getQuotaStats(req: Request, res: Response) {
const stats = distanceMatrixClient.getStats();
res.json({
quota: {
monthly: {
used: stats.monthlyCount,
limit: 700,
remaining: 700 - stats.monthlyCount,
percentage: Math.round((stats.monthlyCount / 700) * 100)
},
daily: {
used: stats.dailyCount,
limit: 50,
remaining: 50 - stats.dailyCount
},
cache: {
hits: stats.cacheHits,
misses: stats.cacheMisses,
hitRate: stats.cacheHits / (stats.cacheHits + stats.cacheMisses)
}
},
lastReset: stats.lastReset
});
}
// Add to server.ts
app.get('/api/quota', getQuotaStats);
Response:
{
"quota": {
"monthly": {
"used": 45,
"limit": 700,
"remaining": 655,
"percentage": 6
},
"daily": {
"used": 12,
"limit": 50,
"remaining": 38
},
"cache": {
"hits": 234,
"misses": 45,
"hitRate": 0.84
}
},
"lastReset": "2026-03-05"
}
Quota Alerts
Set up alerts when quota exceeds thresholds:
function checkQuotaAlerts() {
const stats = distanceMatrixClient.getStats();
const monthlyUsage = (stats.monthlyCount / 700) * 100;
if (monthlyUsage >= 90) {
sendAlert('CRITICAL: 90% of monthly Distance Matrix quota used!');
} else if (monthlyUsage >= 75) {
sendAlert('WARNING: 75% of monthly Distance Matrix quota used');
}
}
// Run daily
setInterval(checkQuotaAlerts, 24 * 60 * 60 * 1000);
Caching Strategy
The client caches results for 7 days to minimize API calls.
Cache configuration:
private cache: Map<string, CacheEntry> = new Map();
private readonly CACHE_TTL_DAYS = 7;
private isCacheValid(entry: CacheEntry): boolean {
const ageMs = Date.now() - entry.timestamp;
const ageDays = ageMs / (1000 * 60 * 60 * 24);
return ageDays < this.CACHE_TTL_DAYS;
}
Cache key format:
const cacheKey = `${originNodeId}|${destNodeId}|${mode}`;
Pre-warm cache to reduce API calls:
const commonRoutes = [
['TILAGOR', 'CAMPUS', 'driving'],
['CAMPUS', 'TILAGOR', 'driving'],
['NAIORPUL', 'CAMPUS', 'driving'],
// ...
];
await distanceMatrixClient.prewarmCache(commonRoutes);
Error Logging
Request Logging
The server logs all requests:
app.use((req: Request, res: Response, next: NextFunction) => {
console.log(`${new Date().toISOString()} ${req.method} ${req.path}`);
next();
});
Output:
2026-03-05T10:30:15.123Z GET /api/health
2026-03-05T10:30:20.456Z GET /api/routes?from=TILAGOR&to=CAMPUS&time=08:30
2026-03-05T10:30:25.789Z POST /api/auth/send-link
Error Handler
Global error handler catches unhandled errors:
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
console.error('Unhandled error:', err);
res.status(500).json({
error: 'Internal server error',
message: err.message
});
});
Structured Logging
For production, use a logging library like Winston:
import winston from 'winston';
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
transports: [
new winston.transports.File({ filename: 'error.log', level: 'error' }),
new winston.transports.File({ filename: 'combined.log' })
]
});
if (process.env.NODE_ENV !== 'production') {
logger.add(new winston.transports.Console({
format: winston.format.simple()
}));
}
// Usage
logger.info('Server started', { port: PORT });
logger.error('Distance Matrix API error', { error: err.message });
Request Duration
Track API response times:
app.use((req: Request, res: Response, next: NextFunction) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
console.log(`${req.method} ${req.path} - ${res.statusCode} - ${duration}ms`);
});
next();
});
Log route calculation times:
export async function planRoute(req: Request, res: Response) {
const start = Date.now();
// ... route planning logic ...
const duration = Date.now() - start;
console.log(`Route planning: ${from} → ${to} took ${duration}ms`);
res.json({ ...result, computeTimeMs: duration });
}
PM2 Monitoring
PM2 provides built-in monitoring.
Real-time Monitoring
Shows:
- CPU usage
- Memory usage
- Logs (stdout/stderr)
Process List
Output:
┌─────┬──────────────┬─────────┬─────────┬─────────┬──────────┐
│ id │ name │ mode │ ↺ │ status │ cpu │
├─────┼──────────────┼─────────┼─────────┼─────────┼──────────┤
│ 0 │ mnd-backend │ fork │ 0 │ online │ 0.3% │
└─────┴──────────────┴─────────┴─────────┴─────────┴──────────┘
PM2 Plus (Cloud Monitoring)
Free tier:
- Real-time monitoring
- Exception tracking
- Custom metrics
Setup:
pm2 link <secret_key> <public_key>
Get keys from pm2.io
Log Management
View logs:
Log rotation:
Install PM2 log rotate:
pm2 install pm2-logrotate
Configure:
pm2 set pm2-logrotate:max_size 10M
pm2 set pm2-logrotate:retain 30
pm2 set pm2-logrotate:compress true
Database Monitoring
The backend uses JSON file-based storage.
Monitor Data Files
Track file sizes:
Output:
4.0K src/data/nodes.json
60K src/data/edges.json
24K src/data/routes.json
User Data
Monitor user database size:
du -h src/data/users.json
If growing too large, consider migrating to a real database (SQLite, PostgreSQL).
Alerting
Email Alerts
Send email alerts for critical events:
import nodemailer from 'nodemailer';
const transporter = nodemailer.createTransport({
host: process.env.EMAIL_SMTP_HOST,
port: Number(process.env.EMAIL_SMTP_PORT),
auth: {
user: process.env.EMAIL_SMTP_USER,
pass: process.env.EMAIL_SMTP_PASSWORD
}
});
async function sendAlert(message: string) {
await transporter.sendMail({
from: process.env.EMAIL_FROM,
to: 'admin@yourdomain.com',
subject: 'MND Alert',
text: message
});
}
// Usage
if (monthlyQuota >= 90) {
await sendAlert('Distance Matrix quota at 90%!');
}
Slack Alerts
npm install @slack/webhook
import { IncomingWebhook } from '@slack/webhook';
const webhook = new IncomingWebhook(process.env.SLACK_WEBHOOK_URL);
async function sendSlackAlert(message: string) {
await webhook.send({
text: message,
username: 'MND Monitor',
icon_emoji: ':bus:'
});
}
Metrics Dashboard
Create a simple metrics endpoint:
app.get('/api/metrics', (req: Request, res: Response) => {
const stats = distanceMatrixClient.getStats();
res.json({
server: {
uptime: process.uptime(),
memory: process.memoryUsage(),
nodeVersion: process.version
},
distanceMatrix: {
monthlyUsed: stats.monthlyCount,
monthlyLimit: 700,
dailyUsed: stats.dailyCount,
cacheHitRate: stats.cacheHits / (stats.cacheHits + stats.cacheMisses)
},
graph: {
nodes: graph.getNodes().length,
edges: graph.getEdges().length
}
});
});
Response:
{
"server": {
"uptime": 12345.67,
"memory": {
"rss": 52428800,
"heapTotal": 20971520,
"heapUsed": 15728640
},
"nodeVersion": "v18.16.0"
},
"distanceMatrix": {
"monthlyUsed": 45,
"monthlyLimit": 700,
"dailyUsed": 12,
"cacheHitRate": 0.84
},
"graph": {
"nodes": 19,
"edges": 542
}
}
Monitoring Checklist
Next Steps