# BMS Action Plan — Post-Audit Fixes > Generated: 2026-03-10 > Based on cross-referencing live site (bmsdemo.rdx4.com) against IMPROVEMENTS.md and source audit. > Excludes: Clerk auth (intentional public demo), scheduled PDF email (deferred). --- ## Phase 1 — Trivial Fixes (< 30 min, no backend, no context changes) These are single-file, low-risk changes. | # | File | Issue | Fix | |---|------|-------|-----| | 1.1 | `components/layout/sidebar.tsx` | Network is in the "Safety" group alongside Leak and Fire, which is semantically wrong | Move `/network` into the "Infrastructure" group, below Generator | | 1.2 | `lib/api.ts` | Base path is `/api/backend` and all fetch paths start `/api/...`, resulting in `/api/backend/api/...` — looks like a double-prefix at first glance | Add a one-line comment above `const BASE` explaining the proxy path convention | | 1.3 | `IMPROVEMENTS.md` | Settings page (`/settings`) is fully built but completely absent from the plan | Add a new entry to Phase 6 or a new Phase 7 "Untracked Additions" section to document it | | 1.4 | `IMPROVEMENTS.md` | Item 6.11 "mini floor map thumbnail" is marked `[x]` but what was built is a `RoomStatusGrid` (tabular room stats), not a visual rack-grid thumbnail | Update the description to clarify what was actually delivered, or un-tick and add to backlog | --- ## Phase 2 — Settings Page: Wire Up Persistence Currently all Settings save buttons have no `onClick` handler and threshold edits are never written anywhere. All pages read from the static `THRESHOLDS` constant in `lib/thresholds.ts`, making the entire Settings page cosmetic. This phase makes Settings functional without a backend API — using `localStorage` and a React context so changes persist across refreshes and propagate to all pages at runtime. ### 2.1 — Create a `ThresholdContext` **New file:** `lib/threshold-context.tsx` - Wraps the static `THRESHOLDS` object as default values - On mount, reads overrides from `localStorage` key `bms_thresholds` and merges - Exposes `thresholds` (the merged values) and `setThresholds(patch)` (writes to localStorage and re-renders) - Re-export a `useThresholds()` hook ### 2.2 — Add the provider to the dashboard layout **File:** `app/(dashboard)/layout.tsx` - Wrap children in `` so all dashboard pages share the same context ### 2.3 — Update pages to read from context Pages that currently import and use `THRESHOLDS` directly need to call `useThresholds()` instead. A grep for `THRESHOLDS` in `app/(dashboard)/` will give the full list. Likely candidates: - `environmental/page.tsx` (temp/humidity thresholds for heatmap + ASHRAE table) - `cooling/page.tsx` (filter ΔP, COP, compressor thresholds) - `power/page.tsx` (rack power warn/crit lines on bar chart) - `capacity/page.tsx` (radial gauge colour bands) - `floor-map/page.tsx` (rack tile colour scale) `lib/thresholds.ts` stays as the canonical defaults — no change needed there. ### 2.4 — Wire the Save buttons in `settings/page.tsx` **File:** `app/(dashboard)/settings/page.tsx` - `ThresholdsTab`: call `setThresholds({ temp: { warn, critical }, humidity: { ... }, power: { ... } })` in the Save onClick - `ProfileTab` / `NotificationsTab`: these are cosmetic for a demo — write to `localStorage` under `bms_profile` / `bms_notifications` keys so at least the values survive a refresh, even if they don't affect anything functional ### 2.5 — Add a visible "saved" confirmation Currently there is no feedback when Save is clicked. Add a brief `sonner` toast (the project already uses it) on successful save. The `Toaster` is already mounted in the dashboard layout. --- ## Phase 3 — Dashboard: True Mini Floor Map Thumbnail Item 6.11 was marked done but delivered a room status table rather than a visual map. **File:** `app/(dashboard)/dashboard/page.tsx` + new component `components/dashboard/mini-floor-map.tsx` - Replace (or sit alongside) `RoomStatusGrid` in the bottom row with a compact rack-grid tile - Re-use the colour logic already written in `floor-map/page.tsx` (temp overlay colours by default) - Each rack tile is a small coloured square (~12×16px), labelled with rack ID on hover tooltip - CRAC units shown as labelled strips at room edge (same pattern as full floor map) - Click navigates to `/floor-map` - Room tabs (Hall A / Hall B) if both rooms are present - Read from the same `/api/readings/rack-status` data already fetched on dashboard This requires no backend changes — just a new presentational component that reuses existing API data. --- ## Phase 4 — Floor Map: Zoom/Pan + CRAC Coverage Shading These are the two remaining open items from 6.12. ### 4.1 — Zoom / Pan **File:** `app/(dashboard)/floor-map/page.tsx` - Add `react-zoom-pan-pinch` (or equivalent) as a dependency: `pnpm add react-zoom-pan-pinch` - Wrap the rack grid `div` in a `` / `` block - Add zoom controls (+ / − / reset buttons) in the map header, above the legend - Pinch-to-zoom should work on touch devices automatically via the library ### 4.2 — CRAC Coverage Shading **File:** `app/(dashboard)/floor-map/page.tsx` - Add a 5th overlay option to the overlay selector: **CRAC Coverage** - When active, colour each rack tile according to which CRAC unit is its nearest thermal neighbour (assign by row proximity — CRACs at room ends serve the rows closest to them, split at the midpoint) - Use a per-CRAC colour palette (4–6 distinct hues, low-opacity background fill) - Show CRAC ID in the legend with its assigned colour - No backend required — assignment is purely spatial, computed client-side from rack row index and CRAC position --- ## Phase 5 — Environmental: Particle Count (ISO 14644) Item 6.10. This is the only remaining `[ ]` item that hasn't been deferred. ### 5.1 — Simulator **File:** backend simulator (not in frontend repo — coordinate with backend) - Add a `ParticleBot` (or extend an existing env bot) that emits: - `particles_0_5um` — count/m³, particles ≥0.5 µm - `particles_5um` — count/m³, particles ≥5 µm - Derived ISO class (1–9) per room, changing slowly with occasional spikes ### 5.2 — Backend API - New endpoint: `GET /api/environmental/particles?site_id=&room_id=` - Returns current counts + derived ISO class per room ### 5.3 — Frontend **File:** `app/(dashboard)/environmental/page.tsx` + `lib/api.ts` - Add `fetchParticleStatus(siteId)` to `lib/api.ts` - Add a new panel on the Environmental page: **"Air Quality — ISO 14644"** - Per-room ISO class badge (ISO 1–9, colour-coded: green ≤7, amber 8, red 9) - 0.5 µm and 5 µm count bars with threshold lines (ISO 8 limits: 3,520,000 and 29,300 /m³) - A small note that DC target is ISO 8 (≤100,000 particles ≥0.5 µm/m³) - Trend sparkline (last 24h) --- ## Execution Order Summary | Phase | Scope | Backend needed? | Effort estimate | |-------|-------|-----------------|-----------------| | 1 — Trivial fixes | IMPROVEMENTS.md + sidebar + api.ts comment | No | ~20 min | | 2 — Settings persistence | New context + localStorage + toast feedback | No | ~2–3 h | | 3 — Mini floor map | New dashboard component | No | ~2–3 h | | 4 — Floor map zoom/pan + CRAC shading | react-zoom-pan-pinch + overlay logic | No | ~3–4 h | | 5 — Particle count | New simulator bot + API endpoint + env panel | Yes | ~3–4 h total |