feat: implement hotspot calculation system with scheduled jobs

- Add hotspot calculation methods to analytics service
- Implement MySQL spatial queries for clustering (5+ reports within 500m)
- Calculate severity scores based on report count and frequency
- Create GET /api/analytics/hotspots endpoint
- Create GET /api/analytics/hotspots/:id endpoint for details
- Create POST /api/analytics/hotspots/calculate for manual trigger
- Implement scheduled job with node-cron (runs every 5 minutes)
- Add comprehensive test scripts for hotspot functionality
- Create detailed implementation documentation

Requirements addressed:
- 3.2: Identify areas with 5+ reports within 500m radius
- 3.3: Rank hotspots by severity score
- 3.4: Update calculations within 5 minutes
- 3.5: Provide data for map visualization with severity indicators
This commit is contained in:
2025-11-17 00:19:35 +00:00
parent d91a13da60
commit 052ba46bdc
9 changed files with 793 additions and 1 deletions

View File

@@ -0,0 +1,53 @@
/**
* Scheduled Jobs Service
* Manages periodic tasks using node-cron
*
* Requirement 3.4: Update Litter Hotspot calculations within 5 minutes of new report submissions
*/
import cron, { ScheduledTask } from 'node-cron';
import { analyticsService } from './analyticsService';
/**
* Initialize all scheduled jobs
*/
export function initializeScheduledJobs() {
console.log('[Scheduled Jobs] Initializing scheduled jobs...');
// Hotspot calculation job - runs every 5 minutes
// Requirement 3.4: Update hotspot calculations within 5 minutes
const hotspotJob = cron.schedule('*/5 * * * *', async () => {
try {
console.log('[Scheduled Jobs] Running hotspot calculation...');
const result = await analyticsService.calculateAndUpdateHotspots();
console.log(`[Scheduled Jobs] Hotspot calculation completed: ${result.hotspotsCalculated} hotspots calculated`);
} catch (error: any) {
console.error('[Scheduled Jobs] Error in hotspot calculation job:', error.message);
}
});
console.log('[Scheduled Jobs] ✓ Hotspot calculation job scheduled (every 5 minutes)');
// Return job instances for potential management
return {
hotspotJob,
};
}
/**
* Stop all scheduled jobs
* Useful for graceful shutdown
*/
export function stopScheduledJobs(jobs: { hotspotJob: ScheduledTask }) {
console.log('[Scheduled Jobs] Stopping all scheduled jobs...');
if (jobs.hotspotJob) {
jobs.hotspotJob.stop();
console.log('[Scheduled Jobs] ✓ Hotspot calculation job stopped');
}
}
export default {
initializeScheduledJobs,
stopScheduledJobs,
};