Aditya-feat: Add Smart Insights and Predictive Utilization Analysis to the Utilization Chart#2115
Open
Aditya-gam wants to merge 5 commits intodevelopmentfrom
Conversation
Add thresholds, forecast modes, and PDF styling constants. Extract check-in/out aggregation, classification, regression and EMA-based forecasting against project risk profiles, caching, recommendations, maintenance alerts, balancing suggestions, and PDF/CSV report generation for procurement-style exports.
Validate forecast mode on GET /tools/utilization and return enriched payloads via helpers. Add GET /tools/utilization/insights and GET /tools/utilization/export (pdf or csv). Replace console errors with startup logger.
Add focused tests for utilization controller endpoints, helper computations, forecasting/classification behavior, and CSV/PDF report generation. This validates the new insights and export paths without changing production code.
Call the node cache factory to get the cache object before using hasCache/getCache/setCache, and align helper tests with the factory mock shape so cache-hit and cache-miss behavior is exercised correctly. Made-with: Cursor
Reject requests where startDate is after endDate in utilization, insights, and export handlers to prevent invalid queries and return consistent 400 responses before any data processing. Made-with: Cursor
|
Anusha-Gali
approved these changes
Apr 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.














Description
Extends the BM Tool Utilization backend so the Utilization Chart can act as a decision-support surface: per–tool-type classification (under / normal / over) with traffic-light semantics, rules-based forecasting (30-day and schedule-horizon modes), maintenance-style alerts, resource balancing suggestions, and Procurement/Operations export as PDF or CSV. The original chart contract remains supported:
GET /api/tools/utilizationstill returns a JSON array of tool-type rows; additional fields and optionalmodeare additive where applicable.Related PRS (if any):
Frontend: OneCommunityGlobal/HighestGoodNetworkApp#5073
Main changes explained:
Created/Updated Files:
src/constants/toolUtilization.js<55%under,55–85%normal,>85%over), labels, traffic-light tokens, forecast mode enums (historical,forecast30,forecastFull), report formats (pdf,csv), maintenance threshold (85%), regression/EMA tuning (MINIMUM_WEEKS_FOR_REGRESSION,ENSEMBLE_WEIGHTS,CONFIDENCE_THRESHOLDS), degraded condition and non-operational usage strings, and PDF layout constants.src/helpers/toolUtilizationHelpers.jsbuildToolFilter(__t: 'tool_item', optionalitemType/projectwhen valid ObjectIds orALL),parseDateRange(default last 30 days),groupToolsByType,calculateCheckedOutHours/calculateGroupUtilization(same pairing rules as the original chart: check-out through check-in, open check-out through range end, pre-range check-out edge case).buildCacheKey+computeUtilizationDatausenode-cache(5-minute TTL viasrc/utilities/nodeCache.js) to cache{ utilizationData, rangeStart, rangeEnd, … }. Helpers requirerequire('../utilities/nodeCache')()to use a dedicated cache API instance.bucketUtilizationByWeek→forecastUtilizationwithregressionlinear fit + EMA blend (computeEnsemblePredictions); falls back to simple average when fewer than 3 weeks of buckets.determineForecastDaysreadsprojectRiskProfilebyprojectIdforforecastFull; falls back to 30 days with an optional warning whenprojectisALLor no profile/end date.generateRecommendations,generateMaintenanceAlerts(high utilization, degradedcondition, non-operationalcurrentUsage),generateResourceBalancingSuggestions,buildInsightsSummary.stripInternalDetailsremovestoolGroupDetailsfrom the public chart payload;buildUtilizationResponseattachesforecastand optionalwarningper row whenmode !== historical;buildReportPayloadassembles data for export.src/helpers/toolUtilizationReportHelpers.jsgeneratePDFReport:pdfkitstream to response; title “Tool Utilization & Procurement/Operations Report”; sections for summary, utilization rows, maintenance alerts, balancing, recommendations; headersContent-Type: application/pdf,Content-Disposition: attachment.generateCSVReport:json2csvParser; UTF-8 BOM prefix for Excel; columns include name, utilization, downtime, classification, traffic light, tool count, aggregated maintenance text, recommendation.src/controllers/bmdashboard/toolUtilizationController.jsgetUtilization: ValidatesmodeagainstVALID_FORECAST_MODES; rejects bothstartDateandendDatepresent withstartDate > endDate(400); delegates tocomputeUtilizationData+buildUtilizationResponse; errors vialogger.logException.getInsights: Same date-order validation when both dates provided; returns{ recommendations, maintenanceAlerts, resourceBalancing, summary }.exportReport: Date-order validation; requiresformat∈{ pdf, csv }; streams PDF or sends CSV.src/routes/bmdashboard/toolUtilizationRouter.jsGET /tools/utilization→getUtilizationGET /tools/utilization/insights→getInsightsGET /tools/utilization/export→exportReport/apiinstartup/routes.js(unchanged factory signature).src/controllers/bmdashboard/__tests__/toolUtilizationController.test.jsgetUtilization(default mode,forecast30, invalid mode, errors),getInsights,exportReport(missing/invalid format, pdf vs csv, headers-sent edge case).src/helpers/__tests__/toolUtilizationHelpers.test.jsbuildUtilizationResponse,buildReportPayload, etc.src/helpers/__tests__/toolUtilizationReportHelpers.test.jsKey Implementation Details:
GET http://localhost:4500/api/tools/utilizationGET http://localhost:4500/api/tools/utilization/insightsGET http://localhost:4500/api/tools/utilization/exporttool(ALLor tool type ObjectId),project(ALLor building project ObjectId),startDate,endDate(ISO strings; optional - default window last 30 days).mode-historical(default),forecast30,forecastFull. Invalidmode→400.format-pdforcsv(required); missing/invalid →400.forecastFullcaveat:ProjectRiskProfile.projectIdis stored as an Issue id in the schema; the BM UI typically sendsbuildingProject_idasproject. If they differ, the lookup may fail, and the API falls back to a 30-day horizon with a warning; reviewers should confirm the product expectation (mapping vs. documentation).How to test:
Aditya-feat/Add-Smart-Insights-and-Predictive-Utilization-Analysis-to-the-Utilization-Chartrm -rf node_modules package-lock.json && npm cache clean --forcenpm installto install dependencies, then start the backend locally (npm run dev)GET /api/tools/utilization?tool=ALL&project=ALLExpect
200: JSON array; each element includesname,utilizationRate,downtime,classification(label+trafficLight),toolCount,totalCheckedOutHours,totalPossibleHours,forecast: null.GET /api/tools/utilization?tool=ALL&project=ALL&mode=forecast30Expect
200: each row hasforecastobject (predictedRate,confidence,forecastEndDate,weeklyPredictions,predictedClassification,method).GET /api/tools/utilization?tool=ALL&project=<projectId>&mode=forecastFull&startDate=...&endDate=...Expect
200: either extended horizon fromprojectRiskProfilesor fallback warning on each item (warningstring) if no profile/end date.GET /api/tools/utilization?mode=invalid→400,errorlists allowed modes.GET /api/tools/utilization?startDate=2026-02-01&endDate=2026-01-01→400,startDate cannot be after endDate.GET /api/tools/utilization/insights?tool=ALL&project=ALLExpect
200:recommendations,maintenanceAlerts,resourceBalancing,summary.GET /api/tools/utilization/export?format=csv&tool=ALL&project=ALLExpect
200,text/csv; charset=utf-8, body starts with BOM.GET /api/tools/utilization/export?format=pdf&tool=ALL&project=ALLExpect
200,application/pdf, downloadable attachment.npm test(or CI-equivalentnpm run test:ci).npm run lint.logRecordCheck In / Check Out events for non-zero utilization.tool/projectstrings that are not ObjectIds are ignored (filters widen to all tools intentionally).tool,project,startDate,endDate, only switchingmodewithout changing other params may reuse cached utilization data from a prior request; validate in QA or follow up if strict per-mode caching is required.Screenshots or videos of changes:
TestVideo.mov
Note:
node-cacheTTL oncomputeUtilizationDataresults to reduce repeat DB reads for identical filter/date keys.modeandformatvalidated;startDate/endDateorder validated when both present on all three handlers. Invalid dates are not separately validated (invalidDatemay yieldNaNcomparisons - low priority follow-up)./api/tools/utilization; new paths are/insightsand/export. ExistingbmToolsDowntimeRouterstill registers other verbs/paths under/tools/utilization-GETremains handled by this router first perstartup/routes.jsorder.