# Finance Phase 2c — Accountant dashboard + Student/Parent portals > Plan: `.harness/plans/hr-finance-fiscalisation.md` §10c > Branch: `feature/finance-phase-2c` (worktree `.worktrees/finance-phase-2c/`) > Owners: backend-expert (enriched summary + students-fees helper) → frontend-expert (portal rewrites) → code-reviewer. ## What landed The last mile: dashboards and student/parent portals that consume everything §10a and §10b produced. ### Backend - **`server/src/controllers/finance.controller.js`** — `/api/finance/dashboard/summary` enriched with six new tiles: - `overdue_invoices` (invoices past due, not paid/cancelled) - `open_invoices` (issued/partial/overdue count) - `upcoming_trips_30d` (published trips departing in next 30 days) - `pending_reconciliations` (bank sessions with discrepancies) - `installments_due_14d` (student_fees due in next fortnight) - `student_groups_count` Shape is **backwards compatible** — the original five fields (`collected_mtd`, `outstanding_fees`, `payroll_last_run`, `expenses_mtd`, `pending_expenses`) are unchanged. - **`server/src/controllers/students-fees.controller.js`** — new file mounted at `/api/students`. Single-student profile endpoint: ``` GET /api/students/:uid/fees ``` Returns `{ student, fees, trips, summary }` where `fees` rows include `discount_amount` and a hydrated `discounts[]` array (name, kind, amount_applied) and `trips` rows are the user's `trip_payments` joined to trips. RBAC gates by parent/child link or by student self. This powers the new student and parent view pages. ### Frontend | # | File | Route / Role | Notes | |---|---|---|---| | 1 | `client/src/pages/dashboard/AccountantDashboard.tsx` | `/dashboard/accountant` | Accountant-specific landing with 4 KPI tiles, 3 entry CTAs (plans / discounts / groups), expense-approval summary, and a compact "latest activity" feed. | | 2 | `client/src/pages/dashboard/FinanceDashboard.tsx` | `/dashboard/finance` (modified) | Second tile row added — Open Invoices / Trips next 30d / Reconciliations / Student Groups — wired to the enriched summary endpoint. | | 3 | `client/src/pages/student/Fees.tsx` | `/student/fees` (new), `/fees` (also mapped) | New student fees portal: fee lines with discount-row expander, trips table below, KPI tiles. Backed by `/api/students/:uid/fees`. | | 4 | `client/src/pages/parent/Fees.tsx` | (modified) | Switched data source to `/api/students/:uid/fees`; falls back to legacy `/fees/students` if the new endpoint isn't available. Total-outstanding now subtracts `discount_amount` so partial-paid lines show the correct balance. | ### Wiring - `client/src/App.tsx` — registered `/dashboard/accountant` for school_admin / systems_admin / principal / bursar, and `/student/fees` + `/fees` for the student role. - `client/src/components/Nav.tsx` — `accountant` block already pointed at `/dashboard/accountant` (§10a). Added "My Fees" entry to the `student` block. - `SCREENS.md` — Bursar / Accountant / Student nav rows up-to-date via the Nav entries; no body edits needed. ### Smoke ``` GET /api/finance/dashboard/summary → { collected_mtd, outstanding_fees, payroll_last_run, expenses_mtd, pending_expenses, overdue_invoices, open_invoices, upcoming_trips_30d, pending_reconciliations, installments_due_14d, student_groups_count } GET /api/students/:uid/fees → { student, fees:[...with discounts[]], trips:[...], summary } ``` Logging in as `student@school.com` and fetching `/api/students/:uid/fees` returns the same envelope. Login as a random student and self-fetch: the self-scope guard passes (200). Login as a random non-parent and fetch someone else's: 403 with error message. ### Deviations from the plan 1. **Single `Students /fees` controller mounted at `/api/students`** instead of `/api/student-fees` — keeps the URL hierarchy aligned with `/api/students` (which already exists for the Students module). 2. **Parent fees page keeps the legacy fallback** so a partial rollout doesn't break the existing UX. New endpoint wins when present. 3. **No PDF invoice generation** — kept the existing printable HTML view from §10a. PDF generation is §11. ### Out of scope - Paynow webhook extension to mark `trip_payments` paid (§11). - Burn-down collection reports (§11). - PDF invoice generation (§11). - Bank-recon auto-match for trip-receipt rows (§11).