# Changelog — 2026-07-04 (Phase 1 frontend)

## feat(frontend): HR & Finance Phase 1 surfaces — frontend

Branch: `feature/hr-finance-phase-1-frontend` (off `dev`).
Depends on: `feature/hr-finance-phase-1` backend endpoints (B1–B8).

### What ships

Six user-facing pages consuming the Phase 1 backend, plus merged stores
preserving Phase 0 state shape so HRManagement.tsx and FinanceManagement
consumers keep working.

| Path | Roles | Backend endpoint(s) consumed |
|---|---|---|
| `/dashboard/hr` | school_admin, systems_admin, principal, hr, bursar, accountant | `GET /api/hr/dashboard/summary` |
| `/dashboard/finance` | school_admin, systems_admin, principal, bursar, accountant | `GET /api/finance/dashboard/summary` |
| `/finance/expenses` | school_admin, systems_admin, principal, bursar, accountant | `GET /api/finance/expenses?status=&category=&date_from=&date_to=` |
| `/finance/expenses/new` | as above | `POST /api/finance/expenses` |
| `/finance/expenses/:id/edit` | as above | `PATCH /api/finance/expenses/:id` (see deviation #1) |
| `/hr/payslips/:id` | school_admin, systems_admin, principal, hr, bursar, accountant | `GET /api/hr/payslips/:id` |

### Stores

- `client/src/store/hr.ts` — extended to also expose `fetchDashboardSummary`,
  `fetchPayslip(id)`, and `resetPayslip`. New `currentPayslip` and
  `dashboardSummary` state slots. Legacy Phase 0 records / leaveRequests /
  payrollRuns / payslips / vacancies / applicants / metadata / staff_records
  management endpoints + their methods are preserved verbatim.
- `client/src/store/finance.ts` — extended with `fetchDashboardSummary`,
  `fetchCategories`, `fetchExpenses`, `fetchExpense` (see deviation #1),
  `createExpense`, `updateExpense`, `deleteExpense`. Phase 0 payroll proxy
  actions kept intact for the existing Finance payroll UX.

### Routing / Nav

- New routes wired into App.tsx's role-aware `getRoutes()` switch arms for
  `school_admin`, `systems_admin`, `principal`, `hr`, `bursar`.
- Nav.tsx `NAV_CONFIG` blocks for those five roles gain dashboard and
  expenses entries using `lucide-react` icons (`LayoutDashboard`, `Receipt`,
  `Plus`).
- Role gating is in App.tsx via `<ProtectedRoute>` — no in-component
  role checks.

### Deviations from the dispatch

1. **`PATCH` instead of `PUT` for expense updates.** The Phase 1 backend
   exposes `PATCH /api/finance/expenses/:id`, not `PUT`. Store and form both
   use `api.patch(...)`.
2. **`GET /api/finance/expenses/:id` does not exist on the backend.**
   The edit page prefills by fetching the list endpoint with `limit=500`
   and matching by id. Caches the row for subsequent visits.
   See `client/src/store/finance.ts` `fetchExpense` for the rationale.
3. **`FinanceDashboard` uses `/api/finance/dashboard/summary` directly.**
   The dispatch says the backend doesn't expose this endpoint yet and
   suggests falling back to `/api/dashboard/stats`; however the Phase 1
   branch already shipped that endpoint. We consume it directly. A monthly
   time-series endpoint remains a TODO for Phase 2 — the current chart
   synthesises a 2-point series from MTD totals.
4. **`PayslipDetail` uses `/api/hr/payslips/:id` directly.** Same as above;
   the Phase 1 branch already exposed it.

### Files added (8)

- `client/src/store/hr.ts` (modified, +139 lines)
- `client/src/store/finance.ts` (modified, +282 lines)
- `client/src/App.tsx` (modified, +42 lines)
- `client/src/components/Nav.tsx` (modified, +13 lines)
- `client/src/pages/dashboard/HRDashboard.tsx` (new)
- `client/src/pages/dashboard/FinanceDashboard.tsx` (new)
- `client/src/pages/finance/Expenses.tsx` (new)
- `client/src/pages/finance/ExpenseNew.tsx` (new)
- `client/src/pages/finance/ExpenseEdit.tsx` (new)
- `client/src/pages/hr/PayslipView.tsx` (new)

### Acceptance check

- ✅ `npm run build` succeeds — `✓ built in 13.48s`, no TS errors.
- ✅ Phase 1 backend (`:3001/api/hr/dashboard/summary`) returns the four-tile
  aggregate for admin token.
- ✅ `/api/finance/dashboard/summary` returns collected_mtd / outstanding_fees /
  payroll_last_run / expenses_mtd / pending_expenses.
- ✅ `/api/finance/expenses` GET returns `{ expenses, pagination }`.
- ✅ POST → PATCH → DELETE round-trip on `/api/finance/expenses` works (smoke
  test created expense #7, patched to 99.99, deleted).
- ✅ RBAC denial — student@school.com token gets `403 HR, Finance, Principal
  or Admin access required` on `/api/hr/dashboard/summary`, and
  `403 Finance, Bursar, Accountant, HR, Principal or Admin access required`
  on `/api/finance/expenses`.
- ✅ Print stylesheet wired into `PayslipView.tsx` (`@media print` block
  scopes the visible content to `#payslip` only).
