Every screen of the Students module with intent, route, composition, states and
permissions. Shared components come from 00-shared/03; module-specific components
are defined in 07_Component_Library.md. States legend: idle / loading / success /
empty / error / disabled / permission. Analytics events (proposed).
AppSearchBar, status/class/year filter chips (client-side), list of StudentListTile (avatar from user, name, admission number, class label, status badge), infinite scroll (meta.hasNext)
FAB
+ Add student (visible iff student.create)
Row menu
View, Edit, Transfer, Graduate, Archive, Restore, Delete (contextual by status: Restore only when archived; Graduate/Transfer only when active)
States
loading → AppSkeleton list; empty → AppEmptyState ("No students yet — add or import"); error → AppErrorState with retry; offline → cached list + banner
GET /students/:id (student.controller.ts:44-46); tabs lazy-load their own endpoints
Composition
Header card (avatar, name, admission number mono, status badge, class + academic year chips, campus/house if set), action bar (Edit / Transfer / Graduate / Archive / Restore / Delete), AppTabs: Profile · Attendance · Fees · Results · Documents · History
Tab sources
Profile = GET /students/:id; Documents = GET /students/:id/documents (createdAt desc); History = GET /students/:id/academic-history (joinedAt desc) + GET /students/:id/enrollments (active); Attendance/Fees/Results = other modules (forward-looking)
Move student to a new class (same or next academic year)
Source
POST /students/:id/transfer — guard: status must be active else 409 (student.service.ts:175-179)
Composition
Target class dropdown (filtered by academic year), academic year dropdown, optional grade/section (default = class's own), optional rollNumber, info banner "Current enrollment will be marked transferred"
CTA
"Transfer student" (confirm dialog first)
States
pre-fill from current class; submit loading; 409 → status banner + block; success → back to detail, history tab shows old enrollment transferred
GET /parents/link/student/:studentId (list links — parent.controller.ts:53-57); create parent POST /parents (parent.controller.ts:29-31); link POST /parents/link/:studentId (parent.controller.ts:47-52); unlink DELETE /parents/link/:linkId (parent.controller.ts:58-60)
Composition
Link cards: parent name (via parent→user), relationship chip (mother/father/guardian/grandparent/relative/foster_parent), primary-guardian toggle badge, financial responsibility + pickup flags, emergency priority number