# 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 `` — 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).