Linh - Material Usage Insights Backend APIs and Calculations#2019
Linh - Material Usage Insights Backend APIs and Calculations#2019linh2020 wants to merge 4 commits into
Conversation
Split controller into calculations, handlers, and composition layers to resolve ESLint violations and improve maintainability.
handikaharianto
left a comment
There was a problem hiding this comment.
Hi, after reviewing this PR, every single API endpoint is working properly and displaying correct data.
Worked well
/api/bm/insights/all is working as expected✅
As can be seen from the two images below, this API endpoint successfully returns the materials + summary data.

/api/bm/insights/summary is working as expected✅
As can be seen from the image below, this API endpoint successfully returns the aggregated metrics.

/api/bm/insights/critical-items is working as expected✅
As can be seen from the image below, this API endpoint successfully returns the low/critical items.

/api/bm/insights/high-usage-items is working as expected✅
As can be seen from the image below, this API endpoint successfully returns the ≥80% used items.

pixelpix13
left a comment
There was a problem hiding this comment.
Hi, @linh2020 just reviewed this pr and following were my observations
PR #2019 Test Report — Material Usage Insights Backend
| Field | Value |
|---|---|
| Branch | linh_materials_usage_insights_visual_indicators_be |
| Related frontend PR | #4736 |
| Tested | 2026-06-18 |
| Environment | npm run dev on port 4500 + hgnData_dev MongoDB |
| Result | 46/46 checks passed (22 unit + 24 API) |
Summary
All material insights endpoints work correctly on the actual route base /api/bm/insights/*. Calculations for usage percentage, stock ratio, and health classification match the spec. Summary, critical-items, and high-usage filters behave as expected against live data (127 materials in dev DB).
Recommendation: Approve with minor documentation fixes (URL path mismatch in PR description).
Unit tests — 22/22 passed
npm test -- src/controllers/bmdashboard/__tests__/bmMaterialInsightsController.test.jsCovers:
calculateMaterialInsights(complete data, no purchases, critical/healthy thresholds)calculateUsagePercentage,calculateStockRatio,getStockHealthStatuscalculateSummaryMetrics(low stock %, over-usage %, on-hold count)- API handlers: all materials, by project, summary, error handling
API tests — 24/24 passed
| Endpoint | Result | Live data notes |
|---|---|---|
GET /api/bm/insights/all |
Pass | 127 materials + summary |
GET /api/bm/insights/summary |
Pass | Lightweight metrics only |
GET /api/bm/insights/critical-items |
Pass | 65 low/critical items, sorted by stock ratio |
GET /api/bm/insights/high-usage-items |
Pass | 7 items ≥ 80% usage, sorted desc |
GET /api/bm/insights/by-project/:projectId |
Pass | 42 materials for sample project |
GET /api/bm/insights/summary/by-project/:projectId |
Pass | Project-scoped summary |
GET /api/bm/insights/:materialId |
Pass | Detail with health=critical, usage=75% |
| No auth | Pass | 401 |
| Invalid material ID | Pass | 400 |
| Non-existent material | Pass | 404 |
| Invalid project ID | Pass | 400 |
Calculation rules verified
| Metric | Formula | Thresholds |
|---|---|---|
| Usage % | (used / bought) × 100 |
null if bought ≤ 0 |
| Stock ratio | available / bought |
null if bought ≤ 0 |
| Health | From stock ratio | Critical ≤ 20%, Low ≤ 40%, Healthy > 40% |
| High usage filter | usagePct >= 80 |
7 items in dev DB |
| Low stock in summary | low + critical counts |
65 items in dev DB |
Issues found (non-blocking)
1. URL path mismatch in PR docs (Medium — documentation)
PR description says /api/bm/materials/insights/* but actual routes are:
GET /api/bm/insights/all
GET /api/bm/insights/summary
GET /api/bm/insights/critical-items
GET /api/bm/insights/high-usage-items
GET /api/bm/insights/by-project/:projectId
GET /api/bm/insights/summary/by-project/:projectId
GET /api/bm/insights/:materialId
Confirmed: /api/bm/materials/insights/all returns 404.
2. onHoldCount always 0 (Low)
calculateSummaryMetrics checks stockHold, but buildingMaterial schema on this branch has no stockHold field (that field is on the bulk-actions branch). onHoldCount will always be 0 unless the field exists in DB documents.
3. Frontend PR #4736 uses client-side calculations (Informational)
Frontend duplicates logic in src/utils/materialInsights.js and does not call these backend endpoints yet. Backend APIs are ready but may be unused by the current frontend PR.
4. Router comments vs code (Informational)
Comments in bmMaterialInsightsRouter.js say /materials/insights/... but route definitions use /insights/....
Files tested
| File | Role |
|---|---|
src/controllers/bmdashboard/materialInsightsCalculations.js |
Pure calculation utilities |
src/controllers/bmdashboard/materialInsightsHandlers.js |
API endpoint handlers |
src/controllers/bmdashboard/bmMaterialInsightsController.js |
Controller factory |
src/routes/bmdashboard/bmMaterialInsightsRouter.js |
Route definitions |
src/startup/routes.js |
Mounted at /api/bm |
Verdict
LGTM — All endpoints and calculations work correctly. Fix PR documentation to use /api/bm/insights/* instead of /api/bm/materials/insights/*.
Description
This PR adds backend support for the Material Usage Insights & Visual Indicators feature in the BM Dashboard by introducing reusable calculation utilities and new API endpoints for material insights and summary metrics.
These APIs provide structured data for:
This work enables the frontend to consume consistent, server-side calculated insights instead of duplicating logic in the UI.
Implements:
(WBS: Add Material Usage Insights & Visual Indicators – Backend Support)
Related PRS (if any):
Related frontend PR: #4736 (Material Usage Insights & Visual Indicators – Frontend)
Main changes explained:
Added reusable calculation utilities for usage percentage, stock ratio, stock health status, and summary metrics with proper edge-case handling.
Implemented new API handlers to provide:
Added a new Material Insights router and registered it under /api/bm/materials/insights/* in startup/routes.js.
How to test:
Example checks:
Note:
Include the information the reviewers need to know.