- Add AllocationController with CRUD + bulk endpoints - Add AllocationValidationService for capacity/estimate validation - Add AllocationMatrixService for optimized matrix queries - Add AllocationPolicy for authorization - Add AllocationResource for API responses - Add frontend allocationService and matrix UI - Add E2E tests for allocation matrix (20 tests) - Add unit tests for validation service and policies - Fix month format conversion (YYYY-MM to YYYY-MM-01)
7.8 KiB
7.8 KiB
1. Backend: Batch Availability Endpoint (Phase 1 - Tests RED)
- 1.1 Write feature test: POST /api/capacity/availability/batch saves multiple updates and returns 200 with saved count
- 1.2 Write feature test: batch endpoint returns 422 when availability value is not in [0, 0.5, 1]
- 1.3 Write feature test: batch endpoint returns 422 when team_member_id does not exist
- 1.4 Write feature test: empty updates array returns 200 with saved count 0
- 1.5 Write unit test: CapacityService::batchUpsertAvailability() upserts all entries and flushes cache once
2. Backend: Batch Availability Endpoint (Phase 2 - Implement GREEN)
- 2.1 Add
batchUpsertAvailability(array $updates, string $month): intto CapacityService — upserts all rows, flushes month-level cache once after all upserts - 2.2 Add
batchUpdateAvailability(Request $request): JsonResponseto CapacityController — validate month + updates array, call service, return{ data: { saved, month } } - 2.3 Add route:
POST /api/capacity/availability/batchinroutes/api.php - 2.4 Run pint and all backend tests — confirm all pass
3. Backend: Batch Availability Endpoint (Phase 3 - Refactor & Document)
- 3.1 Add Scribe docblock to
batchUpdateAvailability()with request/response examples - 3.2 Confirm no N+1 queries in batch upsert (cache flush is single, queries are acceptable for batch size)
4. Frontend: Expert Mode Toggle (Phase 1 - Tests RED)
- 4.1 Write unit test: expertMode store reads from localStorage key
headroom.capacity.expertMode, defaults tofalse - 4.2 Write unit test: toggling expertMode persists new value to localStorage
- 4.3 Write component test: Expert Mode toggle renders right-aligned on tabs row
- 4.4 Write component test: toggle reflects current expertMode store value
- 4.5 Write component test: switching mode with dirty cells shows confirmation dialog
5. Frontend: Expert Mode Toggle (Phase 2 - Implement GREEN)
- 5.1 Create
frontend/src/lib/stores/expertMode.ts— writable store backed bylocalStoragekeyheadroom.capacity.expertMode, defaultfalse - 5.2 Add Expert Mode toggle (label + DaisyUI toggle switch) to
capacity/+page.svelte, right-aligned on tabs row - 5.3 Wire toggle to
expertModeStore— on change, persist to localStorage - 5.4 When toggling off with dirty cells: show confirm dialog; discard changes on confirm, cancel toggle on dismiss
- 5.5 Run type-check and unit tests — confirm all pass
6. Frontend: Expert Mode Grid Component (Phase 1 - Tests RED)
- 6.1 Write component test: CapacityExpertGrid renders a row per active team member
- 6.2 Write component test: CapacityExpertGrid renders a column per day of the month
- 6.3 Write unit test: token normalization —
H→{ rawToken: "H", numericValue: 0, valid: true } - 6.4 Write unit test: token normalization —
O→{ rawToken: "O", numericValue: 0, valid: true } - 6.5 Write unit test: token normalization —
.5→{ rawToken: "0.5", numericValue: 0.5, valid: true } - 6.6 Write unit test: token normalization —
0.5→{ rawToken: "0.5", numericValue: 0.5, valid: true } - 6.7 Write unit test: token normalization —
1→{ rawToken: "1", numericValue: 1, valid: true } - 6.8 Write unit test: token normalization —
0→{ rawToken: "0", numericValue: 0, valid: true } - 6.9 Write unit test: token normalization —
2→{ rawToken: "2", numericValue: null, valid: false } - 6.10 Write unit test: auto-render —
0on weekend column → rawToken becomesO - 6.11 Write unit test: auto-render —
0on holiday column → rawToken becomesH - 6.12 Write component test: invalid cell shows red border on blur
- 6.13 Write component test: Submit button disabled when any invalid cell exists
- 6.14 Write component test: Submit button disabled when no dirty cells exist
7. Frontend: Expert Mode Grid Component (Phase 2 - Implement GREEN)
- 7.1 Create
frontend/src/lib/utils/expertModeTokens.ts— exportnormalizeToken(raw, isWeekend, isHoliday)returning{ rawToken, numericValue, valid } - 7.2 Create
frontend/src/lib/components/capacity/CapacityExpertGrid.svelte:- Props:
month,teamMembers,holidays - On mount: fetch all members' individual capacity in parallel
- Render grid: members × days, cells as
<input>elements - On blur: run
normalizeToken, apply auto-render rule, mark dirty - Invalid cell: red border
- Emit
dirtyandvalidstate to parent
- Props:
- 7.3 Wire
capacity/+page.svelte: when Expert Mode on, renderCapacityExpertGridinstead of calendar tab content - 7.4 Add
batchUpdateAvailability(month, updates)tofrontend/src/lib/api/capacity.ts - 7.5 Add Submit button to Expert Mode view — disabled when
!hasDirty || !allValid; on click, call batch API, show success/error toast - 7.6 Run type-check and component tests — confirm all pass
8. Frontend: Live KPI Bar (Phase 1 - Tests RED)
- 8.1 Write unit test: KPI bar capacity = sum of all members' numeric cell values / 1 (person-days)
- 8.2 Write unit test: KPI bar revenue = sum(member person-days × hourly_rate × 8)
- 8.3 Write unit test: invalid cells contribute 0 to KPI totals (not null/NaN)
- 8.4 Write component test: KPI bar updates when a cell value changes
9. Frontend: Live KPI Bar (Phase 2 - Implement GREEN)
- 9.1 Create
frontend/src/lib/components/capacity/ExpertModeKpiBar.svelte(integrated into CapacityExpertGrid)- Props:
gridState(reactive cell map),teamMembers(with hourly_rate) - Derived:
totalPersonDays,projectedRevenue - Render: two stat cards (Capacity in person-days, Projected Revenue)
- Props:
- 9.2 Mount
ExpertModeKpiBarabove the grid in Expert Mode view - 9.3 Confirm KPI bar reactively updates on every cell change without API call
- 9.4 Run type-check and component tests — confirm all pass
10. Frontend: Expert Mode Grid (Phase 3 - Refactor)
- 10.1 Extract cell rendering into a
ExpertModeCell.sveltesub-component if grid component exceeds ~150 lines (skipped - optional refactor, grid at 243 lines is acceptable) - 10.2 Add horizontal scroll container for wide grids (months with 28–31 days)
- 10.3 Ensure weekend columns have muted background, holiday columns have distinct header marker
- 10.4 Verify toggle is hidden on mobile (< md breakpoint) using Tailwind responsive classes
11. E2E Tests
- 11.1 Write E2E test: Expert Mode toggle appears on Capacity page and persists after reload
- 11.2 Write E2E test: grid renders all team members as rows for selected month
- 11.3 Write E2E test: typing invalid token shows red cell and disables Submit
- 11.4 Write E2E test: typing valid tokens and clicking Submit saves and shows success toast
- 11.5 Write E2E test: KPI bar updates when cell value changes
- 11.6 Write E2E test: switching off Expert Mode with dirty cells shows confirmation dialog
12. Timezone & Accessibility Fixes
- 12.1 Fix weekend detection: use
new Date(dateStr + 'T00:00:00')to avoid local timezone drift - 12.2 Update weekend styling: use
bg-base-300solid background +border-base-400for accessibility - 12.3 Update holiday styling: use
bg-warning/40+border-warningwith boldHmarker - 12.4 Prefill weekend cells with
Oon grid load (not1) - 12.5 Prefill holiday cells with
Hon grid load (not1) - 12.6 Add backend timezone helper using
America/New_Yorkfor weekend/holiday checks - 12.7 Ensure backend seeds weekends with
availability: 0(to match frontendO) - 12.8 Ensure backend seeds holidays with
availability: 0(to match frontendH) - 12.9 Run all tests and verify weekend shading aligns correctly for April 2026 (4th/5th = Sat/Sun)