loreal-utilisation-dept/backend
DJP cd1c99d5e0 feat: KPI tiles, active/soft booking split, hour-breakdown drill-down, period toggle, forecast line, sync button
Major parity push against the original SPA's bundle-level feature set
(non-architectural items — separate Forecast / ProjectType / TimeLog
views and AI Chat remain TBD).

Backend (40/40 tests, +7):

- merge.py splits booked hours by booking status: active vs soft.
  Active set: Active, Active Booked, Fully Booked, Partially Booked.
  Soft set: Soft Booking, Soft Booked, Soft-Booked. Unknown statuses
  default to active so they're not silently dropped. Existing
  `bookedHours` field is preserved as the sum for back-compat.
- compute_totals(): rolls KPIs across the filtered summary —
  totalBooked, activeBooked, softBooked, totalLogged, totalBillable,
  totalLeave, totalProjects (distinct projectName/projectNumber),
  activePeople (distinct employees with logged>0), allocated,
  allocatedNetOfLeave.
- breakdown_by_project(): drills into a single period+employee (or
  whole-period) and returns per-project logged + booked hours.
- New /api/utilisation/breakdown endpoint. /api/utilisation/summary
  response gains `totals` and accepts `period=week|month`.
- New schemas: UtilisationTotals, BreakdownResponse, plus
  activeBookedHours / softBookedHours on UtilisationSummaryRow.

Frontend (typecheck/lint/build clean):

- KpiTiles component shows Total Booked / Logged / Billable, Total
  projects, Active People (logged), Active bookings, Avg/person/week
  or /month, Allocated (net of leave), Period covered.
- PeriodToggle (Per day / Per week / Per month). Day is rendered
  disabled with an explanatory tooltip — backend only accepts week/
  month.
- HourBreakdown drill-down panel: per-project logged + booked rows,
  shown when a chart bar is clicked; "Upload a time log to see logged
  breakdown" empty-state when no upload yet.
- MonthlyUtilisation: ComposedChart with stacked Active/Soft booked
  bars + forecast Line overlay driven by the existing showForecast
  toggle. onPeriodClick wired into HourBreakdown.
- WeeklyUtilisation, BookingVsActual: same Active/Soft stack treatment.
- Resourcing now passes the timelog hash through to summary so
  loggedHours actually populates there too (was 0 before).
- Sync Airtable button on both Department and Resourcing — force-
  refreshes bookings cache, re-derives summary.
- Tutorial steps re-mapped to the original SPA's chapter titles:
  "Reading the Utilisation Chart", "Hours & Utilisation", "Drill-In",
  "Forecast Line & Filters", "Spotting Resource Issues", "Sync
  Airtable Bookings". Tutorial page heading is now "Interactive
  Walkthrough" with the original copy.
- Defensive coercion in Bookings table totalHoursBooked rendering.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-17 21:06:23 -04:00
..
app feat: KPI tiles, active/soft booking split, hour-breakdown drill-down, period toggle, forecast line, sync button 2026-05-17 21:06:23 -04:00
logs Initial commit: dockerised FastAPI backend + React/Vite frontend rewrite 2026-05-16 12:37:04 -04:00
tests feat: KPI tiles, active/soft booking split, hour-breakdown drill-down, period toggle, forecast line, sync button 2026-05-17 21:06:23 -04:00
Dockerfile Initial commit: dockerised FastAPI backend + React/Vite frontend rewrite 2026-05-16 12:37:04 -04:00
pytest.ini Initial commit: dockerised FastAPI backend + React/Vite frontend rewrite 2026-05-16 12:37:04 -04:00
requirements.txt Initial commit: dockerised FastAPI backend + React/Vite frontend rewrite 2026-05-16 12:37:04 -04:00