Frontend — School Admin Dashboard Build Plan
Full-Stack Delivery Plan for the School Administration Console — v2.0
401 models
327 enums
285 .tsx files
31 routes
~282 new pages needed
257 Swagger tags
1. Executive Summary
Management has requested a fully functional school administration dashboard — one that a school administrator can use to completely run a school, backed by real data, and working across all ISCED levels (primary through doctoral).
The backend is ready. 35+ engines delivering 2,075 REST endpoints across 293+ Swagger tags (verified 2026-05-10 via /api/docs-json; 2,023 controller decorators)
handle every aspect of school operations: admissions, student
lifecycle, programmes, courses, grading, attendance, assignments, fees,
wallets, staff, scheduling, timetabling, library, health, behavior,
early warning, hostel, transport, canteen, documents, notifications,
messaging, scholarships, oversight, awards & prizes, marketplace,
custom fields, transfers, and more. All endpoints are Swagger-documented
and tested.
Plan coverage status (last updated 2026-05-10): 1,803 of 2,075 endpoints mapped across 487 screens (real counts: grep -rhE '@(Get|Post|Put|Patch|Delete)\(' --include='*.controller.ts' = 2,023 decorators; /api/docs-json = 2,075 distinct path+method combos). Public auth surface redesigned + shipped 2026-05-10: compact Academia-hosted sign-in card (Continue with Email + 4 social icons with tooltips + persona Sign up + Register New School), persona signup page, school self-signup page, forgot-password page, federated sign-out, Authentik themed brand (Academia wordmark + WebP background + RedirectStage on default-invalidation-flow + meta_launch_url + brand default_application = academia-v21), Authentik blueprint + MinIO bootstrap script + bootstrap runbook for production-reproducible deploys, Husky pre-push fast hook (tsc instead of full next build), Prisma baseline migration for PASSWORD_RESET enum. Commits: BE 5e9b29a + 4ca6f7f + 272951d + 2266394, FE 4106415 + 0a55aaf + d8e8799. Phase 6 — Communication & Collaboration: 21/23 screens shipped (91.3%), 83 endpoints fully wired (NSE 34ep + MSGE 40ep + Tenant Groups 9ep). Remaining 2 screens are placeholders for Staff Groups + Admin Groups, scheduled with their respective modules.. Remaining 268 endpoints across 5 modules pending patch:
OvME (82, §12.2 unpatched), ICME (47, missing), MarketPE (57, missing),
TransME (20, missing), CFE (10, missing). Plus incremental engine
growth.
The frontend is not. Today, only the UADE landing
dashboard (1 of 30+ engines) is connected to real API data. The
remaining engines have zero frontend representation. The app has 31 page
routes — mostly scaffold/demo pages. None are wired to the school
management API.
The gap is pure frontend engineering. No new backend endpoints are needed. The work is:
- Build a tenant-scoped shell (
/dashboard/school/[tenantId]/...) with RBAC-filtered navigation
- Build ~25 frontend feature modules, each consuming 1–3 backend engines
- Make every module ISCED-aware (conditional labels, fields, features based on
iscedLevels[])
- Ensure real data flows end-to-end: CRUD operations, pagination, search, filters, bulk actions
- Build a separate Organisation Dashboard context for multi-school management (OrgPE)
2. Problem Case
2.1 What Was Asked
"Build the school admin dashboard with real data and full
functionalities to completely run a school and across different ISCED
levels."
2.2 What "Completely Run a School" Means
A school administrator needs to perform 25+ distinct functional domains. Every domain, its backend engine, and endpoint count:
| Domain | What They Do | Engine | Endpoints |
| Admit students | Open windows, review apps, score merit, extend offers, enroll | ADME | 62 |
| Manage students | Identity, guardians, docs, groups, class placement, transfers, clearance, ID cards, pastoral, re-enrollment | StuLCE | 66 |
| Set up programmes | Lifecycles, levels, progression rules, specializations, graduation | PME | 46 |
| Manage courses | Catalogue, offerings, syllabi, curriculum maps, outcomes, materials, content | CME | 77 |
| Master syllabus | Browse national syllabi, adopt/fork, custom builder, review pipeline | MaSyE | 50 |
| Grade students | Assessment creation, score entry, grade computation, GPA/CGPA, report gen, sequences, templates, graduation | GME | 103 |
| Online exams | Question bank, exam papers, online exam delivery, proctoring, auto-grading | QBE + GME/OEE | 45 |
| Track attendance | Mark attendance (6 event types), configure devices, set alerts, bridge grades | ATME | 28 |
| Manage assignments | Create assignments, track submissions, grade, contestation, bulk scoring | ASME | 21 |
| Collect fees | Structures, billing, payments, installments, waivers, discounts, debt, revenue share, tax | ACCTE/FME | 98 |
| Student wallets | Closed-loop cashless campus: wallets, parent funding, merchant POS, catalogue, fee bridge | ACCTE/WME | 53 |
| Subscriptions | Feature gates, subscription tiers, tenant subscriptions, overrides, enforcement | ACCTE/SBE | 37 |
| Manage staff | Onboard, contracts, qualifications, CPD, appraisals, transfers, exit, reporting | StaME | 60 |
| Schedule & timetable | Academic calendars, class timetables, exam timetables, staff leave, facilities, events | SCIE | 160 |
| Run the library | Catalogue, circulation, holds, fines, textbooks, digital resources, reading lists, inventory | LME | 95 |
| Manage health | Records, allergies, dietary, immunizations, clinic visits, sickbay, medications, pharmacy, growth | SHME | 72 |
| Track behavior | Events, at-risk detection, counseling, escalation hearings, contracts, rewards, EWS | SBME | 88 |
| Run hostels | Room allocation, exeat permits, inspections, visitors, fees, staff, operations | HME | 57 |
| Run canteen | Meal plans, sessions, check-in, tables, menu schedule, dietary alerts | RCM | 32 |
| Manage transport | Routes, stops, vehicles, drivers, enrollment, trip tracking, attendance, incidents | TME | 62 |
| Generate documents | Report cards, transcripts, certificates, custom templates, verification QR | DTGE | 38 |
| Send notifications | Multi-channel (email, SMS, WhatsApp, push, in-app), templates, inbox, preferences | NSE | 30 |
| Messaging | Two-way chat (direct + group), topics, auto-post, moderation, broadcast | MSGE | 33 |
| Handle scholarships | Programmes, applications, committee review, awards, disbursement, donors, marketplace | SCME | 91 |
| Oversee schools | Jurisdictions, compliance, inspections, analytics, alerts, transfers, audit | OvME | 82 |
| Provision schools | Academic structure setup, calendar, course proposals, facilities, grading config | SAPE | 109 |
| Multi-school orgs | Organisation management, KYC, command center, school access, transfers | OrgPE | 25 |
2.3 What "Across Different ISCED Levels" Means
| Concept | Nursery (ISCED 0) | Primary (1–2) | Secondary (3) | University (5–8) |
| Class unit | "Nursery 1" / "KG 2" | "Class 3" / "Form 2" | "Form 5" / "Terminale" | "Year 1" / "Semester 2" |
| Progression | Age-based promotion | Auto-promote by age/score | Exam-gated (GCE, BEPC) | Credit-accumulation |
| Grading | Developmental milestones / narrative | Marks /10 or /20 | Marks + GCE grades | GPA 0.0–4.0, CGPA |
| Course selection | Activity-based (no formal courses) | Fixed curriculum | Fixed + optional tracks | Electives, minors, credits |
| Fees | Flat annual/termly | Flat annual/termly | Flat + exam fees | Per-credit differential |
| Timetable | Activity schedule (simple blocks) | Simple (1:1) | Subject rotation | Multi-section + labs |
| Hostel | N/A (day school only) | Rare | Common (boarding) | Universal (residential) |
| Library | Story corner / read-aloud | Basic lending | Lending + textbook scheme | Full circulation + digital + reserves |
| Assessment | Observation-based / portfolio | Continuous only | CA + end-of-term + national | CA + midterm + finals + thesis |
| Transport | Essential (very young children) | Essential (young children) | Common | Rare (campus-based) |
| Canteen | Snack/lunch (supervised) | Day school lunch | Boarding 3 meals/day | Campus dining, wallet |
| Guardian mgmt | Critical (primary contact) | Prominent | Visible | Minimal |
| Health | Critical (immunization gate, growth) | Important | Standard | Self-managed |
3.1 Backend Engine Matrix 35+ engines
Snapshot below: 30 engines totaling 1,772 endpoints captured 2026-04-15. Current backend (2026-05-02): 35+ engines / 1,980 endpoints / 291 Swagger tags
— 5 engines added since (AwardsPME 59, MarketPE 57, ICME 47, TransME
20, CFE 10) plus incremental growth. See §14 Module-to-Engine Mapping
for the up-to-date table that frontend consumes.
| # | Engine | Code | GET | POST | PUT | PATCH | DEL | Total |
| 1 | Scheduling & Calendar | SCIE | 60 | 76 | 15 | 0 | 9 | 160 |
| 2 | Fee Management | ACCTE | 56 | 76 | 13 | 0 | 6 | 151 |
| 3 | Auto-Provisioning | SAPE | 48 | 30 | 21 | 0 | 10 | 109 |
| 4 | Grading | GME | 36 | 52 | 11 | 0 | 4 | 103 |
| 5 | Library | LME | 40 | 35 | 19 | 0 | 1 | 95 |
| 6 | Scholarships | SCME | 37 | 48 | 6 | 0 | 0 | 91 |
| 7 | Student Behavior | SBME | 31 | 44 | 13 | 0 | 0 | 88 |
| 8 | Oversight | OvME | 45 | 23 | 6 | 7 | 1 | 82 |
| 9 | Courses | CME | 27 | 35 | 11 | 0 | 4 | 77 |
| 10 | Student Health | SHME | 29 | 30 | 9 | 2 | 2 | 72 |
| 11 | Student Lifecycle | StuLCE | 23 | 28 | 10 | 0 | 5 | 66 |
| 12 | Admissions | ADME | 19 | 37 | 6 | 0 | 0 | 62 |
| 13 | Transport | TME | 28 | 15 | 8 | 4 | 7 | 62 |
| 14 | Staff | StaME | 22 | 24 | 14 | 0 | 0 | 60 |
| 15 | Hostel | HME | 25 | 13 | 14 | 0 | 5 | 57 |
| 16 | Master Syllabus | MaSyE | 17 | 20 | 6 | 2 | 5 | 50 |
| 17 | Programmes | PME | 16 | 21 | 3 | 0 | 6 | 46 |
| 18 | Documents | DTGE | 12 | 20 | 5 | 0 | 1 | 38 |
| 19 | Subscriptions | SBE | 21 | 6 | 3 | 7 | 0 | 37 |
| 20 | Platform | Platform | 19 | 8 | 6 | 0 | 2 | 35 |
| 21 | Messaging | MSGE | 11 | 14 | 5 | 0 | 3 | 33 |
| 22 | Canteen | RCM | 13 | 8 | 1 | 8 | 2 | 32 |
| 23 | Notifications | NSE | 13 | 11 | 2 | 0 | 4 | 30 |
| 24 | Attendance | ATME | 12 | 12 | 3 | 0 | 1 | 28 |
| 25 | Org Portal | OrgPE | 9 | 13 | 3 | 0 | 0 | 25 |
| 26 | Assignments | ASME | 6 | 12 | 2 | 0 | 1 | 21 |
| 27 | Question Bank | QBE | 8 | 9 | 2 | 0 | 1 | 20 |
| 28 | RBAC | RBAC | 9 | 3 | 2 | 0 | 1 | 15 |
| 29 | UADE | UADE | 8 | 0 | 0 | 0 | 0 | 8 |
| 30 | Auth | AUTH | 3 | 1 | 0 | 0 | 1 | 5 |
| TOTALS | 713 | 724 | 223 | 30 | 82 | 1,772 |
3.2 Prisma Schema & Tests
401 models
327 enums
50+ education systems
75 feature gates
142 spec files
3,607 test cases
All green ✓
4. ISCED Level Strategy
The backend does not have separate codepaths for primary vs. university. Tenant.iscedLevels: Int[] declares which levels the school operates at. The frontend reads this and conditionally renders. See the ISCED Rendering Map (Section 18) for the complete per-component decision matrix.
| Level | Name | Age | Examples |
| 0 | Early childhood | 0–5 | Nursery, kindergarten |
| 1 | Primary | 6–11 | Primary school (Class 1–6) |
| 2 | Lower secondary | 12–14 | Junior secondary (Form 1–5, 6e–3e) |
| 3 | Upper secondary | 15–17 | Senior secondary (Sixth Form, Terminale) |
| 4 | Post-secondary non-tertiary | 18–19 | Vocational diploma, trade school |
| 5 | Short-cycle tertiary | 18–20 | HND, associate degree |
| 6 | Bachelor's | 18–22 | University undergraduate |
| 7 | Master's | 22–24 | Postgraduate |
| 8 | Doctoral | 24+ | PhD programmes |
5. Action Plan
5.1 Build Phases Overview
UADE, RBAC, AUTH — ~5 pages
CriticalTenant contextRBAC navSchool overview
StuLCE (66), ADME (62), StaME (60) — ~40 pages
CriticalStudentsAdmissionsStaff
PME (46), CME (77), MaSyE (50), GME (103), ATME (28), ASME (21), QBE (20) — ~55 pages
CriticalProgrammesCoursesGradingAttendanceAssignmentsOnline Exams
ACCTE/FME (98), WME (53), SCIE (160), DTGE (38) — ~50 pages
HighFeesWalletSchedulingTimetableDocuments
SHME (72), SBME (88), LME (95), HME (57), RCM (32), TME (62) — ~65 pages
HighHealthBehavior & EWSLibraryHostelCanteenTransport
NSE (34), MSGE (40), TenantGroup (9) — 23 pages
HighNotificationsMessagingWebSocket
SCME (91), OvME (82), SAPE (109), OrgPE (25), AwardsPME (59 + 4 new stats endpoints, 11/17 screens shipped) 🆕 — ~54 pages
MediumScholarshipsOversightProvisioningOrg PortalAwards & Prizes
Platform (35), SBE (37), RBAC (15) — ~15 pages
MediumAuditPrivacyWebhooksSubscriptionsRBAC
5.2 Delivery Sequence
- Phase 1 must come first — without the shell, nothing else has a home.
- Phase 2 before Phase 3 — you need students and staff before you can grade or schedule them.
- Phase 3 before Phase 4 — academic structure must exist before fees and timetables.
- Phase 4 and Phase 5 can run in parallel — independent domains.
- Phase 6 can run in parallel with Phase 5 — messaging is independent.
- Phase 7 after Phase 4 — scholarships need fee engine, oversight needs school data.
- Phase 8 last — admin/platform features.
6. Phase 1 — Shell & Navigation
Goal: A logged-in school admin clicks a school card
on UADE and lands in a functional school dashboard shell with
RBAC-filtered sidebar navigation and a school overview page.
6.1 Deliverables
| # | Deliverable | Description |
| 1.1 | Tenant Context Provider | React context wrapping all school routes. Sets X-Tenant-Id header on every API call. Exposes tenantId, iscedLevels, educationSystemCodes, boardingType, permissions[], featureGates[]. |
| 1.2 | School Dashboard Layout | /dashboard/school/[tenantId]/ — sidebar + top bar + content area. Sidebar collapses on mobile. |
| 1.3 | RBAC-Filtered Navigation | Sidebar menu items generated from the permission set returned by GET /uade/permissions/:tenantId. Menu items hidden when the user lacks the required permission. Feature-gated items hidden when the gate is not active. |
| 1.4 | School Overview Page | /dashboard/school/[tenantId]/overview — consumes GET /uade/dashboard/school/:tenantId. Stat cards: student count, staff count, programme count, pending fees, upcoming events, notifications. |
| 1.5 | Wire UADE enterRoute | Clicking a school card on the UADE landing navigates to /dashboard/school/<tenantId>. |
| 1.6 | Tenant Switcher | Dropdown in top bar for users with multiple school roles (fused buckets from Role Card Registry). |
6.2 API Endpoints Consumed
| Endpoint | Purpose |
| GET /uade/dashboard | Role cards with enterRoute for school navigation |
| GET /uade/permissions/:tenantId | Permission set for RBAC filtering |
| GET /uade/dashboard/school/:tenantId | School overview stats |
6.3 Navigation Menu Structure (Complete — All 257 Tags Covered)
School Dashboard (sidebar)
|
+-- Overview (school stats, quick actions)
|
+-- Students
| +-- All Students (StuLCE) (list, profile, add)
| +-- Admissions (ADME) (applications, offers, enrollment)
| +-- Guardians & Family
| +-- Class Placement
| +-- Student Groups
| +-- Transfers
| +-- ID Cards [if gate enabled]
| +-- Achievements & Awards
| +-- Appointments
| +-- Pastoral Notes
| +-- Documents
| +-- Import
| +-- Clearance [if gate enabled]
| +-- Re-enrollment
| +-- Settings → Custom fields, config, status rules
|
+-- Academics
| +-- Programmes (PME) (lifecycle, levels, progression, specializations, graduation)
| +-- Courses (CME) (catalogue, offerings, syllabus, curriculum map, topics, outcomes, materials)
| +-- Course Registration [ISCED 5+] (electives, minors, credits, waitlist, substitutions)
| +-- Syllabus (MaSyE) (master syllabus, school adoption, custom builder, review pipeline)
| +-- Settings → Programme config, course config
|
+-- Timetable (SCIE)
| +-- Grid View (weekly per level/class)
| +-- My Schedule (personal — student/teacher)
| +-- Slot Management (create, edit, approve, publish)
| +-- Conflicts (detection + resolution proposals)
| +-- Substitutions (leave coverage)
| +-- Slot Swap Board (teacher swaps)
| +-- Auto-Generate (algorithmic + DeepSeek AI)
| +-- Export (PDF, iCal/Google Calendar)
| +-- Share (public links)
| +-- Clone (term rollover)
| +-- Bell Schedule
| +-- Settings → Timetable config, swap policies
|
+-- Grading & Assessment
| +-- Dashboard
| +-- Assessments (GME) (create, manage lifecycle)
| +-- Score Entry (single, bulk, import)
| +-- Grade Computation (term, year, batch)
| +-- GPA / CGPA [ISCED 5+]
| +-- Sequences [ISCED 2-3]
| +-- Report Cards (DTGE) (generate, publish)
| +-- Grading Templates
| +-- Graduation (eligibility, promotion, cohort progression)
| +-- Online Exams (QBE + OEE) (question bank, papers, sessions)
| +-- Settings → Grade scales, categories, config
|
+-- Attendance (ATME)
| +-- Mark Attendance
| +-- Reports & Alerts
| +-- Devices (biometric)
| +-- Grading Bridge
| +-- Settings → Attendance config
|
+-- Assignments (ASME)
| +-- All Assignments
| +-- Submissions
| +-- Settings → Auto-scoring, contestation
|
+-- Finance (ACCTE/FME)
| +-- Dashboard (revenue, outstanding, collections)
| +-- Fee Structure (categories, schedules)
| +-- Billing (generate invoices)
| +-- Payments (record, receipts, pay links)
| +-- Payment Gateways (webhook status, transaction log)
| +-- Installments
| +-- Waivers
| +-- Discounts (auto-discount rules)
| +-- Debt Management
| +-- Revenue Share
| +-- Tax Configuration
| +-- Auto-Enroll on Payment
| +-- Reports
| +-- Settings → Fee config, billing policies, tax, discounts
|
+-- Wallet (WME) [if gate enabled]
| +-- Dashboard
| +-- Student Wallets
| +-- Parent Funding
| +-- Merchant Points
| +-- Catalogue
| +-- POS Transactions
| +-- Fee Bridge
| +-- Reports
| +-- Settings → Wallet config, exchange rate
|
+-- Staff (StaME)
| +-- Dashboard
| +-- Staff Directory
| +-- Onboarding
| +-- Contracts & Compensation
| +-- Qualifications & CPD
| +-- Appraisals
| +-- Documents
| +-- Leave (SCIE integration)
| +-- Status Management
| +-- Reports
| +-- Settings → Ranks, config, employment types
|
+-- Calendar & Events (SCIE)
| +-- Academic Calendar (years, terms)
| +-- Events (school events, closures)
| +-- Event RSVP & Check-In
| +-- Deadlines
| +-- Sports & Activities
| +-- Facility Booking
| +-- Settings → Calendar config, event categories, notification rules
|
+-- Messaging (MSGE)
| +-- Inbox / Conversations
| +-- Group Chats
| +-- Topics
| +-- Broadcast Channels [if gate enabled]
| +-- Settings → Auto-post config, moderation rules
|
+-- Library (LME) [if gate enabled]
| +-- Dashboard
| +-- Catalogue
| +-- Circulation
| +-- Holds & Reservations
| +-- Cards
| +-- Textbooks
| +-- Digital Resources
| +-- Reading Lists
| +-- Inventory & Stock-Take
| +-- Fines
| +-- Clearance
| +-- Reports
| +-- Settings → Config, locations, lending rules
|
+-- Health (SHME) [if gate enabled]
| +-- Dashboard
| +-- Health Records
| +-- Clinic Visits
| +-- Sickbay
| +-- Immunizations
| +-- Allergies
| +-- Dietary Restrictions
| +-- Medications
| +-- Pharmacy
| +-- Growth & Screening
| +-- Reports
| +-- Settings → Health config, enrollment gate
|
+-- Behavior (SBME) [if gate enabled]
| +-- Dashboard
| +-- Events & Summaries
| +-- At-Risk Detection (EWS)
| +-- Counseling Referrals
| +-- Rewards & Recognition
| +-- Hearings & Escalation
| +-- Behavioral Contracts
| +-- Restorative Actions
| +-- Peer Reports
| +-- Parent Feed
| +-- Settings → Categories, houses, groups, templates
|
+-- Canteen (RCM) [if gate enabled]
| +-- Dashboard
| +-- Meal Plans
| +-- Meal Sessions
| +-- Check-In
| +-- Tables & Seating
| +-- Menu Schedule
| +-- Dietary Alerts
| +-- Reports
| +-- Settings → Refectory config
|
+-- Hostel (HME) [if gate enabled, boarding]
| +-- Dashboard
| +-- Infrastructure (hostels, floors, rooms, beds)
| +-- Allocation
| +-- Exeat Permits
| +-- Inspections
| +-- Visitors
| +-- Operations
| +-- Hostel Staff
| +-- Fees
| +-- Settings → Hostel config, visiting hours
|
+-- Transport (TME) [if gate enabled]
| +-- Dashboard
| +-- Routes & Stops
| +-- Vehicles
| +-- Drivers
| +-- Student Enrollment
| +-- Schedules
| +-- Trips
| +-- Attendance
| +-- Maintenance & Inspection
| +-- Incidents
| +-- Analytics
| +-- Settings → Transport config
|
+-- Documents (DTGE)
| +-- Templates (manage, clone)
| +-- Report Card Templates
| +-- Generation (generate, preview, bulk)
| +-- Verification (QR, DAC, logs)
| +-- Settings → Document config, verification pricing, signatories
|
+-- Notifications (NSE)
| +-- Inbox
| +-- Templates (2-layer inheritance)
| +-- Channels (email, SMS, WhatsApp, push)
| +-- Provider Registry
| +-- Logs & Analytics
| +-- Settings → Preferences, channel config
|
+-- Scholarships (SCME) [if gate enabled]
| +-- Dashboard
| +-- Programs & Pools
| +-- Applications
| +-- Committee Review
| +-- Awards & Lifecycle
| +-- Disbursement
| +-- Donors & Funds
| +-- Marketplace [if sub-gate]
| +-- Academic Honors
| +-- Reports & Compliance
| +-- Settings → Scholarship config
|
+-- Exam Timetable (SCIE)
| +-- Exam Slots (create, schedule, publish, cancel)
| +-- Invigilators (assign, confirm, remove)
| +-- Clash Detection (report, resolve)
| +-- Accommodations (special needs exam accommodations)
| +-- Board Exam Registration (external exam body registration)
| +-- Settings → Exam timetable config
|
+-- Settings (Global)
+-- School Profile (SAPE) (provisioning status, academic structure)
+-- Template Banks (SAPE) (pull subjects, grading, reports from platform)
+-- Roles & Permissions (RBAC) (role management, permission assignment)
+-- Subscription & Billing (SBE)
| +-- Current Plan
| +-- Available Gates (browse + purchase)
| +-- Available Tiers (bundle comparison)
| +-- Payment History
+-- Feature Gates (SBE) (what's enabled)
+-- Privacy & Compliance (consent, deletion, export)
+-- Audit Log (all mutations, immutable)
+-- Integrations / Webhooks (outbound webhooks, API keys)
+-- Notification Preferences
Total sidebar items: 433 screens covering 1,712 of 1,980
backend endpoints (86.5%) across 291 Swagger tags. Last updated:
2026-05-02 — AwardsPME 11/17 screens shipped (8 of 14 planned + 3 new
Detail pages added during build).
Organisation Dashboard (separate context — accessed from UADE):
Organisation Dashboard
+-- Organisation Overview
+-- Schools (list, add, transfer)
+-- KYC / Compliance
+-- Command Center Members
+-- Access Management
+-- Settings
6.4 Help System MVP Platform-wide — new module ✅ MVP shipped 2026-05-03
New platform-wide help layer that floats on every dashboard page. Spec: v2.1/frontend/planning/PATCH_HELP_SYSTEM.md. Implementation: features/help/ — mascot, panel, tour engine, welcome card, guide menu, all driven by a static tours-catalog.ts
registry so the menu shows every guide platform-wide regardless of
current page. Awards walkthrough lifted onto the shared engine (zero
regression). Visibility-aware via persona (e.g. settings tour available
everywhere, awards tour gated to awards-aware roles).
| Component | Status | Description |
| Academia Bot mascot | ✅ DONE | Orange
construction-themed robot (hard hat, drill, screwdriver, E=MC² chest
screen, 14 keyframe animations). Drag/snap to nearest edge, position
persisted to localStorage (NaN-guarded), viewport-clamped on resize, hidden during print and active tour. Hover → "Need help?" tooltip. |
| Help Panel (4 tiles) | ✅ DONE | Click mascot → popup. Primary: [<Page> Guide] button (starts the tour for the current page) + [Guide Menu] button. Secondary: 3 tiles for Ask Bot / Help Docs / Open Ticket (all "Coming soon" placeholders). |
| Guide Menu | ✅ DONE | Lists every tour registered in the platform's static catalog. Cross-page launch via TourDefinition.entryPath
— click a guide for another page, the engine navigates first then
activates the tour. Current page's tour gets a "You're here" badge. |
| Tour Engine | ✅ DONE | Generalised
from the AwardsPME walkthrough: namespace-driven copy, sharper visual
contrast (75% backdrop, 3px stroke, soft pulsing glow on highlighted
target), tour mascot stands beside the speech bubble on the side facing
the highlighted element. Smooth transitions between steps so the bot
"walks" through the page. Step navigation: Prev / Next / Skip / Finish. |
| Welcome Card | ✅ DONE | Generalised
dismissible explainer. Tones: yellow / sky / emerald / violet. Optional
audience filter for persona gating. Dismissal persisted per storageKeyPrefix + tenantId. Re-summonable from the help panel for users who want to revisit it. |
| Settings Tour | ✅ DONE | 10 steps walking the user through every tab of /students/settings. Warm conversational voice ("Hi! Let me show you around 👋", "Easy, right?"), concrete examples (STU-2026-0001), emoji bookends. EN+FR matched in tone. |
| AwardsPME Tour migration | ✅ DONE | The original 348-line awards walkthrough collapsed to a 35-line tour definition + back-compat useTour() shim. Engine now lives once in features/help/components/walkthrough.tsx. Existing 11-step tour runs unchanged for users. |
| Ask Bot (FAQ index) | ⏳ PENDING | Static
FAQ tree (topic → question → answer + thumbs feedback). Compiled into
bundle, no LLM. Phase B1 of the help-system roadmap. |
| Help Docs (contextual right-drawer) | ⏳ PENDING | Per-route help-doc slug pulls MDX content into the existing infobar.tsx drawer. ~40 slugs needed. Phase B2. |
| Open Ticket | ⏳ PENDING | Standalone SUPPORT backend engine + frontend ticket form + staff inbox. Multi-week patch. Phase B3. |
6.5 User Onboarding — Auto-invite Primitive + Access Lifecycle + Public Auth Surface PARTIALLY SHIPPED ✅ PUBLIC AUTH SHIPPED 2026-05-10 REALIGNMENT IN PROGRESS
Spec: docs/architecture/BACKEND_USER_INVITE_PROTOCOL.md + docs/architecture/BACKEND_AUTH_SIGNIN_REDESIGN_2026-05-10.md + docs/architecture/BACKEND_AUTH_BOOTSTRAP_RUNBOOK.md. Backend live (2,075 endpoints total per /api/docs-json; suspend + bulk endpoints deployed 2026-05-05; persona signup + school signup + forgot-password deployed 2026-05-10). Phone-identity migration live (User.email nullable, User.phone added). Public auth surface redesigned + shipped 2026-05-10 (commits BE 4ca6f7f + FE 0a55aaf): compact Academia-hosted sign-in card, persona Sign up, school Register New School, Forgot password, federated sign-out via OIDC end-session with Authentik-side RedirectStage routing back to Academia.
What it does: single invite primitive triggered by record creation in 4 places (Guardian, Staff, Student via ADME enrolment, Student via manual admin action) plus an admin-driven access lifecycle (Suspend / Unsuspend / Revoke). Recipients click link → set password → Authentik account activates → User row gets real authentikId via existing JWT strategy join point. Reuses existing PENDING-user pattern. Multichannel delivery (email + SMS + WhatsApp + Telegram + inApp) per tenant NotificationChannel config. Identity is email OR phone; either can be the login key.
Access states: NOT_INVITED, PENDING, ACTIVE, SUSPENDED (reversible — manual now, future rule engine for fee lateness / exit / etc.), REVOKED. State transitions enforced server-side; admin sees status as a colour-coded badge wherever a person appears.
| Page / Surface | Route | API Endpoints | UI Components |
| Accept Invite & Set Password (public, no auth) | /accept-invite/[token] | GET /invite/validate/:token, POST /invite/accept | Server component validates token + renders welcome (recipient name, school name, persona). Client component (TanStack Form) password + confirm + accept-terms. Submits → activates Authentik account, sets User.authentikId + status=ACTIVE → redirect to /auth/sign-in?invited=true. Handles expired / already-accepted / revoked / suspended / weak-password gracefully. |
| All Students list — embedded invitations | /dashboard/school/[tenantId]/students/all-students | GET /invite/admin/status-batch?userIds=…, POST /invite/admin/bulk-resend, POST /invite/admin/bulk-revoke, POST /invite/admin/bulk-suspend, POST /invite/admin/bulk-unsuspend, POST /invite/admin/student/:studentId | New Invitations Status column with colour-coded badge (Uninvited / Pending / Accepted / Suspended / Revoked). New Invitations filter chip alongside existing filters (status / level / class / gender / nationality) — stacks, not mutually exclusive. Per-row actions column with shadcn icons + tooltips: Send (paper-plane), Resend (refresh), Revoke (ban), Suspend (pause-circle), Unsuspend (play-circle). Disabled when not applicable to current row state. Bulk toolbar appears when ≥1 row selected — shows only the operation matching the current Invitations filter (filter-first eligibility rule, no mixed-status batches). |
| Guardians & Family list — embedded invitations | /dashboard/school/[tenantId]/students/guardians-family | Same as above | Identical treatment: Status column, Invitations filter chip, per-row icon actions, bulk toolbar with filter-first eligibility. Shared <InviteStatusColumn> + <InviteRowActions> + <BulkInviteToolbar> components. |
| Student detail page — relocated affordances | /dashboard/school/[tenantId]/students/[studentId] | GET /invite/status/:userId, POST /invite/resend/:userId, POST /invite/revoke/:userId, POST /invite/suspend/:userId, POST /invite/unsuspend/:userId, POST /invite/admin/student/:studentId | Status badge + state-aware text buttons (Resend / Revoke / Suspend / Unsuspend / Send Login Invite) positioned under the class/level metadata strip alongside the ENROLLED badge — NOT in the export-actions row at top-right. Belongs with student identity, not page actions. |
| Student detail — Guardians sub-table | /dashboard/school/[tenantId]/students/[studentId]?tab=guardians | Same as All Students list | Per-guardian status badge + icon actions in the guardian-relationship table, so admins can manage that one student's guardians' invites without leaving the page. |
| Invitations dashboard (NEW screen) | /dashboard/school/[tenantId]/students/invitations /dashboard/school/[tenantId]/students/invitations/students /dashboard/school/[tenantId]/students/invitations/guardians | GET /invite/admin/list?persona=student|guardian, plus all bulk + per-user invite endpoints | Single page at /students/invitations with two tabs (Students / Guardians) — tab clicks change the URL to the sub-paths above. Single ManagedDataTable per tab: Name / Contact (email or phone) / Invitation Status (badge) / Last sent / Actions (icons). Status filter chip (All / Uninvited / Pending / Accepted / Suspended / Revoked) + name/email/phone search. Bulk toolbar follows the filter-first rule: Filter = Uninvited → Bulk Invite, Filter = Pending → Bulk Resend + Bulk Revoke, Filter = Active → Bulk Suspend, Filter = Suspended → Bulk Unsuspend, Filter = Revoked → Bulk Resend, Filter = All → no bulk actions. Sidebar entry "Invitations" under Students, between Sibling Groups and Class Placement (or wherever fits the existing nav order). |
Backend deliverables (deployed): InviteModule with InviteService + InviteTokenService + AuthentikAdminService; InviteToken Prisma model + 2 enums; hooks in src/stulce/services/guardian.service.ts, src/stame/services/staff.service.ts, src/adme/services/enrollment.service.ts (Trigger #3 — enrolApplicant); new RBAC permissions user-invite:invite.{send, resend, revoke, suspend, read, bulk}; NSE master templates (parent / staff / student + 3 _existing variants) in EN + FR with content for 5 channels (email / sms / whatsapp / telegram / inApp); seed CLI src/invite/seeds/run-seeds.ts; phone-identity migration (User.email nullable, User.phone added with @unique); suspend audit fields on User (suspendedAt, suspendedReason, suspendedBy, suspendedSource); 2,033 endpoints total (was 2,029; +4 today from POST /auth/signup, POST /auth/signup/school, POST /auth/forgot-password, POST /invite/admin/reset-password/:userId).
Public auth surface (deployed 2026-05-10): Academia-hosted compact sign-in card at /auth/sign-in (Continue with Email button → themed Authentik handoff; 4 colored brand icons for Google / Microsoft / Apple / Facebook with hover tooltips; persona Sign up link; Register New School button + Start a Free Trial subtext; Terms / Privacy footer). Persona signup form at /auth/sign-up, school self-signup form at /signup, forgot-password at /auth/forgot-password (all Academia-hosted, all i18n EN+FR). Authentik themed brand (DB-applied + captured declaratively in blueprints/academia.yaml): Academia text wordmark via inline-SVG data URI (theme-responsive via prefers-color-scheme), WebP background on 6 user-facing flows, RedirectStage on default-invalidation-flow at order 10 → Academia /auth/sign-in, meta_launch_url = /auth/sign-in, Brand default_application = academia-v21. Federated sign-out (lib/auth/federated-sign-out.ts) kills both NextAuth + Authentik sessions in one click via OIDC /end-session/ endpoint, lands user back on Academia compact card. Husky pre-push hook replaced (next build → tsc --noEmit) — push cycle ~30s instead of 5–6 min, no regression in type safety. Production-reproducible: Authentik blueprint + MinIO bootstrap script + assets/branding/sign-in-bg.webp all in git; scripts/bootstrap-minio-branding.sh + docs/architecture/BACKEND_AUTH_BOOTSTRAP_RUNBOOK.md capture the one-time setup steps. Drift fix: 20260511213229_add_password_reset_invite_purpose baseline migration recorded the PASSWORD_RESET enum value that had been added direct-to-DB; npx prisma migrate status reports clean.
Backend additions still pending for the realignment: GET /invite/admin/status-batch?userIds=u1,u2,… (single round-trip status map for list-row badges, eliminates N+1) and GET /invite/admin/list?persona=student|guardian&status=…&page=…&limit=… (paginated list scoped to one persona for the Invitations dashboard). Plus the SMTP / SES / Resend / Postmark provider classes flagged in docs/architecture/BACKEND_NSE_TODO.md — not blocking the realignment but required for schools that want to bring their own mail server.
Frontend realignment scope (in flight): extract <InviteStatusBadge>, <InviteRowActions> (icon variant), <BulkInviteToolbar> (filter-first); plumb into All Students list, Guardians & Family list, Student detail Guardians sub-table; relocate the student-detail affordances from top-right action row to under the class/level metadata strip; build the Invitations dashboard with two tabs; add the "Invitations" sidebar entry; delete the stale standalone /students/pending-invites route built earlier (wrong shape — replaced by this amended spec). i18n keys EN+FR for all new copy.
7. Phase 2 — Core School Operations
7.0 Student 360 Dashboards Cross-Engine — federates 15+ engines 100% coverage 🆕 NEW SECTION ✅ Sprints 1+2+3+4 shipped
Patched 2026-05-02 per PATCH_7.0_STUDENT_DASHBOARDS.md. NEW SECTION
— 2 dashboards aggregating real-time data across StuLCE, GME, ATME,
SBME, AwardsPME, ACCTE, SHME, LME, HME, SCIE, SCME, NSE, DTGE, ASME,
ICME. Zero new endpoints introduced for the dashboards
themselves (reuses existing endpoints — already counted in their owner
sections). Sprint 4 added 3 new persona-aware StuLCE endpoints (GET /stulce/students/me, GET /stulce/me/students, GET /stulce/students/:studentId/my-relationship) plus 8 new GuardianRelationship.canView*
columns. Backend aggregation endpoints flagged as deps in §28 for later
optimization. Auto-refresh polling now (30s per-student, 60s
school-wide); WebSocket push when NSE event bus exposed (Phase 6+). AI
Engine placeholder reserved for future Phase 9 build (ai_insights feature gate, default OFF).
Build status (2026-05-04):
✅ Sprint 1 (school dashboard MVP) · ✅ Sprint 2 (gender×level matrix,
geo distribution, financial strip, risk panel, 4-per-row layout) · ✅
Sprint 3 (per-student Critical Alerts, 6 stat cards w/ sparklines,
Activity Feed, Quick Links) · ✅ Sprint 4 (persona variants
admin/teacher/student-self/parent — 30-row visibility matrix, 8 new
guardian gates, ?as= override, /my-profile redirect via /auth/tenants,
Edit Guardian sheet engine-visibility toggles, audit/documents/behavior
service-level filters). ⏳ Parent Portal landing + child picker deferred
to Sprint 4b (depends on User Onboarding sprint for guardian login
flow).
| Page | Route | Federated Endpoints | UI Components |
| Per-Student Overview ("Student 360") (new Tab 1 of Student Profile, before drill-down tabs) ✅ DONE | /
students/[studentId]/ (admin/teacher) · /my-profile (student self — ✅
shipped, redirects via /auth/tenants) · Parent Portal → Child Overview
(parent w/ activeStudentId — ⏳ deferred to 4b) | Reuses
~12 endpoints across 15 engines: GET /stulce/students/:id/full
(StuLCE), GME transcript/GPA, GET /atme/students/:id/summary, GET
/sbme/summaries/student/:id + GET /sbme/ews/signals/:id, GET
/awardspme/students/:id/awards, GET /accte/students/:id/statement +
wallet balance, GET /shme/records/summary/:id (gated canViewHealthRecords),
GET /lme/circulation/patron/:patronId + holds + fines, GET
/hme/allocation/student/:id, GET /scie/timetable/student/:id, GET
/scme/awards/mine filtered, GET /nse/inbox filtered, ASME assignments,
DTGE documents | Hero strip (photo + name + ID +
GPA/attendance/balance/awards quick stats + Quick actions: Message
Parents, Generate ID Card, Print Transcript, Grant Award), Critical
Alerts banner (overdue invoice, EWS at-risk, sickbay active, library
overdue, behavior contract pending, AI Insight placeholder gated ai_insights),
6-card stat grid
(Academic/Attendance/Behavior/Awards/Financial/Wellness — each with
sparkline + drill link), Activity Feed (chronological mixed timeline
with filter chips), Quick Links panel (linked guardians, today's
schedule, scholarships, hostel allocation, clubs, documents). Persona variants
(per shell §17): Admin sees all; Teacher hides Financial; Student self
hides admin actions; Parent gated by 9 guardian permissions. Auto-refresh 30s. Skeleton loaders per zone. Drill-down: existing 11 Student Profile tabs render below the dashboard. |
| School Students Overview Dashboard (replaces bare student list at /students; existing list moves to /students/all-students) ✅ DONE | /students/ (Dashboard B — replaces previous list landing) | Reuses
existing endpoints across StuLCE, ACCTE/FME, SBME, AwardsPME, ADME,
SHME, PME. Frontend orchestrates 6-8 parallel queries until backend
aggregation endpoint built (GET /stulce/school-overview flagged in §28). | Sticky
filter bar (Level, Programme, Class, Gender, Age slider, Boarding
status, Status, Fee status, Date range), Top Stat Cards (Total Active w/
delta, By Level mini-stack, Gender ratio donut, Avg Age, Boarders %,
Pending Admissions), Analytics Grid 2×2 (Enrollment Trend 12mo line,
Gender × Level matrix, Age Distribution histogram, Geographic
Distribution if address tracked), Financial Overview Strip (Total Owing,
Top Defaulters list, On Payment Plans — gated finance:read), Risk Panel (EWS At-Risk by severity, Open Behavior Contracts, Health Flags — gated health:read), AI Predictions panel (gated ai_insights
placeholder), Recent School Activity feed
(admissions/withdrawals/graduations/transfers/imports/major awards).
Every stat + chart segment is click-to-drill → routes to /students/all-students with filter pre-applied via URL params. Auto-refresh 60s. |
7.0.1 AI Engine Placeholder
ai_insights
feature gate (default OFF — future Phase 9 engine). When enabled,
renders predictive panels: per-student at-risk scoring with suggested
intervention; school-wide predicted dropouts/fee defaults; cross-engine
narratives ("Grades dropped 15% after sickbay admission"). Backend AI
engine not built — frontend reserves space, ships zero functionality until backend exists.
7.0.2 Real-Time Strategy
- Today (MVP): TanStack Query
staleTime + refetchInterval (30s per-student, 60s school-wide). Visual "refreshed Xs ago" indicator. Manual refresh button per panel.
- Future (Phase 6+): when NSE generic
/events WebSocket namespace ships, layer push events on top of TanStack Query cache invalidation. Polling remains as fallback.
7.1 Students Module StuLCE — 66 endpoints 100% coverage
Patched
2026-04-16 per PATCH_7.1_STUDENTS.md. All 66 Swagger endpoints mapped,
zero stale refs, zero super-admin endpoints (StuLCE is fully
school-scoped). Per-student dashboard "Overview" tab + school-wide
dashboard added per §7.0 (2026-05-02).
| Page | API Endpoints | UI Components |
Student List (route moved to /students/all-students; /students is now Dashboard B per §7.0) | GET /stulce/students (query: page, limit, levelId, programmeId, status, search, gender, ageMin, ageMax, boarding, feeStatus) | TanStack
Table, Select filters, SearchInput, Badge (status), bulk action
toolbar. URL params hydrate from Dashboard B click-throughs. |
| Student Profile (tabbed: Overview (new Tab 1 — see §7.0), Identity, Guardians, Class History, Groups, Awards (was "Achievements"), Appointments, Pastoral Notes, Documents, Custom Values, Status, Transfers) | GET /stulce/students/:id, GET .../full, PUT .../:id, POST .../archive, GET .../guardians, Awards tab now uses AwardsPME (see §12.5 Screen 14):
GET /awardspme/students/:id/awards, POST /awardspme/students/:id/awards
(replaces legacy GET/POST /stulce/students/:id/achievements — kept for
back-compat but new builds should use AwardsPME federation read). Other
tabs: GET .../appointments, GET/POST .../pastoral-notes, GET/POST
.../documents, GET/PUT .../custom-values, POST
/stulce/students/:id/status, GET .../status-history | Tabs, Card,
Breadcrumb. Archive action in overflow menu (soft-delete, retains
records). ISCED: Guardian tab prominent for ISCED 0-4, minimal for 5+. Awards tab:
card grid via AwardsPME federation read with source badges + prize
chips + "Grant Award" right-side sheet (Sprint 1 deliverable per
PATCH_12.5_AWARDS.md). |
| Add Student | POST /stulce/students | Multi-step Form (react-hook-form + Zod), Dialog for guardian add |
| Bulk Import Students | POST /stulce/students/import | Dropzone
(CSV/Excel), preview table with validation errors per row, commit
button, progress bar, post-import summary (created/failed/skipped) |
| Guardians (list + bulk) | POST /
stulce/students/:id/guardians, PUT/DELETE
/stulce/guardian-relationships/:id, PUT .../pickup, POST
/stulce/guardians/import | TanStack Table (guardians across
school), Sheet (add guardian to student), Select (relationship type),
Switch (pickup authorized), Dropzone (CSV import). Per-student view
embedded as tab in Student Profile |
| Sibling Groups 🆕 | POST /stulce/sibling-groups, DELETE /stulce/sibling-groups/:id/members/:studentId | TanStack
Table (sibling group list with member count), Dialog (create group —
pick students), Button (unlink sibling). Used for sibling fee discount
eligibility and family messaging |
| Class Placement (2 tabs: Roster by class, Bulk assignment wizard) | POST /stulce/class-assignments/bulk, GET /stulce/classes/:id/roster, POST /stulce/students/:id/class | Roster
view (DnD between classes), Bulk wizard (filter students → select
target class → apply), Select (level/class). Per-student class change
also available from Student Profile |
| Student Groups | GET/POST /stulce/groups, POST/DELETE /stulce/groups/:id/members | Card grid, Sheet (create group + add members), Badge (group type). Membership changes via bulk add/remove |
| Transfers | POST /stulce/transfers, POST /stulce/transfers/inter-org, POST /stulce/transfers/:id/accept, GET /stulce/transfers/:id/package | TanStack
Table (inbound + outbound), Dialog (initiate intra-org vs inter-org),
Badge (status: pending/accepted/declined), Button (fetch transfer
package). Acceptance workflow for inbound inter-org |
| ID Cards (3 tabs: Single generate, Bulk generate, Template config) | POST /stulce/students/:id/id-card, POST /stulce/id-cards/bulk-generate, PUT /stulce/config/id-card-template | Tab
1 — Select student(s), preview, generate. Tab 2 — Filter students
(level/class/programme) → bulk generate PDF. Tab 3 — Template editor
(logo, fields, colors). Gate: student_id_cards |
Public ID Card Verify 🆕 (route /verify/id-card/[token] outside admin shell) | GET /stulce/id-cards/verify/:token | Public page (no auth) — scanned via QR code. Shows: photo, name, status (active/revoked), school, validity |
| Clearance List (active clearances) | POST /stulce/clearances, GET /stulce/clearances/:studentId | List
of students with active clearance, status per department, Button to
initiate (exit workflow). Badge (pending/cleared). Gate: student_clearance |
| Clearance Detail 🆕 | POST /stulce/clearances/:id/sign-off, GET /stulce/clearances/:studentId/check | Per-
student checklist with department sign-off actions, readiness check (all
depts clear?), final release button. Timeline of sign-off events |
| Custom Fields Definitions | GET/POST /stulce/custom-fields | TanStack
Table, Dialog (field builder), Select (field type:
text/number/date/enum/bool). Field values per student live in Student
Profile (Custom Values tab) |
| Re-enrollment | POST /stulce/students/:id/re-enroll, GET /stulce/students/:id/re-enrollment-eligibility | Student
picker, eligibility check (previous year status, fees cleared, no
holds), confirm re-enrollment into next level. Typically run end-of-year
via Bulk Status Change |
| Achievements Catalogue (school-level — legacy view; primary catalog is now AwardsPME §12.5 Award Catalogue) | GET /stulce/achievements, PUT/DELETE /stulce/achievements/:id | TanStack Table (legacy direct StuLCE rows). For new builds use GET /awardspme/awards (federation read)
which returns StuLCE achievements + SBME rewards + AwardsPME
orchestrations in unified shape. Keep this screen as a read-only legacy
view, or hide entirely if awards_management gate is on. |
| Appointments (prefect/monitor assignments) | GET/POST /stulce/appointments, POST /stulce/appointments/:id/revoke | TanStack
Table (active appointment holders: prefects, class monitors, house
captains), Dialog (assign), Button (revoke). Appointment types
configured in Settings. Per-student view in Student Profile |
| Pastoral Notes (feed view across students) | GET/PUT/DELETE /stulce/pastoral-notes/:id | Timeline
view (recent notes across school for counselors), Filter by
student/severity/author, Detail drawer (with edit/delete). Per-student
add + list in Student Profile |
| Documents Compliance 🆕 | GET /stulce/documents/compliance, POST /stulce/documents/:id/verify | School-
wide compliance report: list of students missing required documents
(birth cert, medical, etc.), verify/reject action per document. Badge
(verified/pending/rejected) |
| Bulk Status Change 🆕 | POST /stulce/students/bulk-status | Multi-
select student list, Select (target status), Confirm dialog (shows which
will succeed/fail per transition rules), Result summary. Used at
end-of-year for mass transitions (e.g., WITHDRAWN) |
| Settings | GET/PUT /stulce/config, POST /stulce/config/adopt-template, PUT /stulce/config/id-format, PUT /stulce/config/appointment-types | Form
with sections: General Config, Adopt Seed Template, Student ID Format,
Appointment Types. Form (react-hook-form), Switch toggles, Card
sections, Button (adopt template from platform seed) |
7.2 Admissions Module ADME — 62 endpoints 100% coverage
Patched
2026-04-16 per PATCH_7.2_ADMISSIONS.md. 62/62 Swagger endpoints mapped.
3 scopes: school admin (47ep, 17 screens), applicant portal (11ep, 7
screens), super admin (4ep, 2 screens). Platform shell per
shelldesigns/PLATFORM_SHELL_ARCHITECTURE.md.
7.2.1 School Admin (/dashboard/school/[tenantId]/admissions/...)
| Page | API Endpoints | UI Components |
| Admission Dashboard | GET /adme/admissions | Recharts funnel, stat Cards, Badge (status) |
| Create Admission Session | POST /adme/admissions | Sheet (create wizard), DatePicker, Input (name, description) |
| Admission Session Detail | GET /
adme/admissions/:id, PUT /adme/admissions/:id, POST
/adme/admissions/:id/levels, GET /adme/admissions/:id/programmes, POST
/adme/admissions/:id/programmes | Tabs (overview, levels, programmes), Card, Sheet (add level/programme) |
| Application Config | GET /adme/application-config, PUT /adme/application-config/:id, POST /adme/application-config/adopt, GET /adme/templates | Form builder (adopted template sections), Dialog (browse + adopt from platform), Switch |
| Application List | GET /adme/applications | TanStack Table, Badge (status), bulk action toolbar |
| Application Review | POST /adme/applications/:id/review | Tabs (form data, documents, scores), Textarea (notes), Select (approve/reject/waitlist) |
| Merit Scoring | POST
/adme/scoring/trigger, POST /adme/scoring/cutoff, POST
/adme/scoring/shortlist, POST /adme/scoring/exam-score, GET
/adme/scoring/rankings | TanStack Table (ranked), Input (exam scores), Button (trigger/cutoff/shortlist) |
| Offers | GET /adme/offers, GET /adme/offers/:id, POST /adme/offers/:id/revoke | TanStack Table, Badge (status), Dialog (revoke confirm). Accept/decline on applicant side. |
| Enrollment Placements | POST /adme/enrollment/confirm, GET /adme/placements, GET /adme/placements/history/:studentId | Wizard Form, TanStack Table, Timeline (placement history), Badge |
| Cohort Progression | POST /adme/progression/cohort | Select (cohort, target level), Bulk summary, Confirm dialog. End-of-year. |
| Manual Placements List | GET /adme/manual-placements, POST /adme/manual-placements | TanStack Table, Sheet (create), Badge (DRAFT→SUBMITTED→APPROVED) |
| Manual Placement Detail | GET /
adme/manual-placements/:id, POST /adme/manual-placements/:id/submit,
POST /adme/manual-placements/:id/approve, POST
/adme/manual-placements/:id/reject, POST
/adme/manual-placements/:id/cancel, POST
/adme/manual-placements/:id/note | Card (detail), Timeline (action log + notes), Button group, Textarea (note) |
| Manual Placement Config | GET /adme/manual-placements/config, PUT /adme/manual-placements/config | Form (approval rules, level constraints), Switch toggles |
| Appeal Review Queue | GET /adme/appeals, POST /adme/appeals/:id/review | TanStack Table, Dialog (grant/deny), Textarea (decision rationale) |
| Transfers List | GET /adme/transfers, POST /adme/transfers | TanStack Table, Sheet (create), Badge (status) |
| Transfer Detail | POST
/adme/transfers/:id/submit, POST /adme/transfers/:id/review, POST
/adme/transfers/:id/approve, POST /adme/transfers/:id/reject, POST
/adme/transfers/:id/cancel, POST /adme/transfers/:id/documents | Card (detail), Stepper, Button group, Dropzone (documents) |
| Transfer Config | GET /adme/transfers/transfer-config, PUT /adme/transfers/transfer-config | Form (per-type config), Switch toggles |
7.2.2 Applicant Portal (/apply/[tenantId]/... public + /applicant/... auth'd)
| Page | Auth | API Endpoints | UI Components |
| Application Portal Entry | Public | (routing only) | School logo + name, Start / Resume CTAs |
| Start Application | Public | POST /adme/applications/start | Form (name, email, programme/level), returns credentials |
| Resume Application | Public | POST /adme/applications/resume, POST /adme/applications/verify | Form (email + credentials), OTP input, verify button |
| Application Fill & Submit | Applicant | PUT /
adme/applications/:id/sections/:key, GET /adme/applications/:id/fees,
POST /adme/applications/:id/submit, POST /adme/applications/:id/withdraw | Multi-section form, progress indicator, fees preview, Submit / Withdraw |
| Offer Response | Applicant | POST /adme/offers/:id/accept, POST /adme/offers/:id/decline | Card (offer terms), Button (Accept / Decline), Confirm dialog |
| Submit Appeal | Applicant | POST /adme/appeals/:id/submit | Textarea (rationale), Dropzone (supporting docs), Submit |
| Withdraw Placement | Applicant | POST /adme/placements/:id/withdraw | Card (placement info), Dialog (confirm, reason) |
7.2.3 Super Admin (/dashboard/platform/content/admission-templates/...)
Required role: CONTENT_ADMIN or SUPER_ADMIN.
| Page | API Endpoints | UI Components |
| Admission Template Library | GET /adme/admin/templates, POST /adme/admin/templates, POST /adme/admin/templates/seed | TanStack Table, Sheet (create), Button (seed defaults) |
| Admission Template Editor | PUT /adme/admin/templates/:id | Form builder (sections, fields, validation), Preview pane |
7.3 Staff Module StaME — 60 endpoints 100% coverage
Patched
2026-04-16 per PATCH_7.3_STAFF.md. 60/60 Swagger endpoints mapped. 2
scopes: school admin (56ep, 13 screens), staff self-service (4ep, 4
screens). Zero super-admin endpoints.
7.3.1 School Admin (/dashboard/school/[tenantId]/staff/...)
| Page | API Endpoints | UI Components |
| Staff Directory | GET /stame/staff | TanStack Table, Badge (role/status), Avatar, SearchInput |
| Staff Profile (tabbed: Identity, Contracts, Compensation, Qualifications, CPD, Appraisals, Documents, Onboarding, Status, Courses) | GET /
stame/staff/:id, GET .../full, PUT .../:id, GET/POST .../contracts,
GET/PUT /stame/contracts/:id, POST .../renew, GET .../compensation, PUT
.../allowances, PUT .../deductions, GET/POST .../qualifications, PUT
/stame/qualifications/:id/verify, POST .../cpd, GET .../cpd-summary,
GET/POST .../appraisals, PUT /stame/appraisals/:id, GET/POST
.../documents, PUT /stame/documents/:id/verify, POST .../status, GET
.../status-history, POST .../confirm-probation, POST .../courses, POST
.../courses/:courseId/remove | Tabs, Card, Breadcrumb. 27 endpoints — build as lazy-loaded tab components. |
| Register Staff | POST /stame/staff | Multi-step Form, DatePicker, Select (employment type, rank) |
| Bulk Import Staff | POST /stame/staff/import | Dropzone (JSON), preview table, commit, progress bar |
| Onboarding Checklist | GET /
stame/staff/:id/onboarding, POST /stame/staff/:id/onboarding, PUT
/stame/onboarding/:id/items/:code, POST /stame/clearances/:id/sign-off | Per-staff checklist, item completion toggle, department sign-off, progress bar |
| Exit Management (terminate + retire) | POST /stame/staff/:id/terminate, POST /stame/staff/:id/retire | Select (exit type), Form (reason, effective date), Dialog (confirm), Timeline |
| Transfer Management | POST /stame/staff/:id/transfer, POST /stame/transfers/:id/accept | TanStack Table (pending), Sheet (initiate), Dialog (accept inbound), Badge (status) |
| Payroll Register | GET /stame/payroll-register | TanStack Table (all staff, salary, allowances, deductions, net), DatePicker (period), Export CSV |
| Compliance (documents + qualifications) | GET /stame/compliance/documents, GET /stame/compliance/qualifications | 2 tabs: Documents (missing), Qualifications (unverified/expired). Badge, filter by department |
| Appraisal Summary | GET /stame/appraisal-summary | Recharts (scores by dept, completion rates), Card (cycle stats) |
| Staff ID Management | POST /
stame/staff/:id/generate-id, PUT /stame/staff/:id/government-id, PUT
/stame/staff/:id/rank, POST /stame/staff/bulk-generate-ids, GET
/stame/staff/by-category | TanStack Table (by category), Sheet (generate ID), Button (bulk), Input (govt reg #), Select (rank) |
| Reports | GET /stame/reports/staff-student-ratio, GET /stame/reports/workforce-summary | Recharts (workforce by category/status/rank), Card (staff-student ratio per level) |
| Settings | GET
/stame/config, PUT /stame/config, POST /stame/config/adopt-template, PUT
/stame/config/id-format, PUT /stame/config/onboarding, PUT
/stame/config/ranks, GET /stame/ranks | Form sections: General, Adopt Template, ID Format, Onboarding Template, Ranks. Switch toggles. |
7.3.2 Staff Self-Service (/staff-portal/...)
Same auth (NextAuth/Authentik), same tenant. Staff sees own data only. Needs Staff Portal Shell in PLATFORM_SHELL_ARCHITECTURE.md.
| Page | API Endpoints | UI Components |
| My Self-Assessment | POST /stame/appraisals/:id/self-assessment | Form (self-scoring per rubric), Textarea (reflection), Submit. Only during active appraisal cycle. |
| My Portfolio | GET /stame/staff/:id/portfolio | Card grid (teaching history, courses, quals, CPD, appraisal scores). Read-only. |
| Submit Resignation | POST /stame/staff/:id/resign | Form (effective date, reason, notice period), Dialog (confirm — irreversible) |
| Request Transfer | POST /stame/staff/:id/transfer-request | Form (target school/org, reason, preferred date), Submit button |
8. Phase 3 — Academic Engine Modules
8.1 Programmes PME — 46 endpoints 100% coverage
Patched
2026-04-16 per PATCH_8.1_PROGRAMMES.md. 46/46 Swagger endpoints mapped.
2 scopes: school admin (41ep, 12 screens), student self-service (5ep, 2
screens). Zero super-admin endpoints (PME templates are school-scoped;
platform-level PME bank in SAPE Phase 7).
8.1.1 School Admin (/dashboard/school/[tenantId]/academics/programmes/...)
| Page | API Endpoints | UI Components |
| Programme Templates | GET /pme/templates, POST /pme/templates, PUT /pme/templates/:id/deactivate | Card grid or TanStack Table, Badge (ISCED level), Select filters, Sheet (create/upsert) |
| Programme Lifecycle Builder | GET /
pme/lifecycles/:programmeId, POST /pme/lifecycles, POST
/pme/lifecycles/:id/levels, DELETE /pme/lifecycles/:id/levels/:levelId | Multi-step Form (programme info + level configs + term definitions), Select (ISCED, progression mode). maxCreditsPerSemester ISCED 5+ only |
| Curriculum Map Editor | GET /
pme/curriculum-maps, POST /pme/curriculum-maps, GET
/pme/curriculum-maps/:id, PUT /pme/curriculum-maps/:id, DELETE
/pme/curriculum-maps/:id | Visual tree (programme > level >
courses), Sheet (map course), Input (credits, resit/retake toggles).
Credit hours ISCED 5+ only |
| Progression Rules | GET /pme/progression-rules, POST /pme/progression-rules, GET /pme/progression-rules/:id, DELETE /pme/progression-rules/:id | TanStack Table (rules by programme), Sheet (create rule — level transition, GPA threshold, required courses), Dialog |
| Academic Calendar | GET /
pme/calendars, POST /pme/calendars, DELETE /pme/calendars/:id, POST
/pme/calendars/:id/terms, DELETE /pme/calendars/:calId/terms/:termId | TanStack Table (years), DatePicker (term dates), Card (current year), Sheet (add year / add term) |
| Cohorts | GET /pme/cohorts, POST /pme/cohorts, GET /pme/cohorts/:id, PUT /pme/cohorts/:id | TanStack Table (enrollment counts), Sheet (create/edit), Badge. ISCED-aware label: "Class of" / "Batch" / "Cohort" |
| Programme Enrollment | POST /pme/enrollment/admit, POST /pme/enrollment/bulk | Wizard Form (single admit), Dropzone (bulk CSV), TanStack Table (results) |
| Student Academic Path (admin view) | GET /pme/students/:studentId/path | Card (current programme + level), Timeline (level history), TanStack Table (course registrations with grades) |
| Progression Evaluation | POST /pme/progression/evaluate, POST /pme/progression/process, GET /pme/progression/history/:pathId | Card (result — promoted/repeated/graduated/dismissed), Dialog (confirm), Timeline (decision history) |
| Graduation | GET
/pme/graduation, GET /pme/graduation/:id, POST
/pme/graduation/check-eligibility, POST /pme/graduation/process, POST
/pme/graduation/revoke | TanStack Table, Card (eligibility check), Dialog (batch confirm + revoke). Criteria vary by ISCED |
| Specializations Catalogue | GET /pme/specializations, POST /pme/specializations, GET /pme/specializations/:id | TanStack Table, Sheet (define major/minor), Badge (type). ISCED 5+ only |
| Student Specializations (admin) | GET /pme/students/:studentId/specializations, POST /pme/specializations/complete | TanStack Table, Button (approve completion — validates credits). ISCED 5+ only |
8.1.2 Student Self-Service (/student-portal/...) — First Appearance
First student portal screens in the plan. Needs Student Portal Shell (§18 in shelldesigns/PLATFORM_SHELL_ARCHITECTURE.md) — architectural decision pending.
| Page | API Endpoints | UI Components |
| My Specializations (declare / withdraw) | POST /pme/specializations/declare, POST /pme/specializations/withdraw | Card grid (available), Dialog (declare/withdraw confirm — cannot withdraw if completed). ISCED 5+ only |
| My Course Registrations (resit / retake / drop) | POST /pme/enrollment/courses/resit, POST /pme/enrollment/courses/retake, DELETE /pme/enrollment/courses/:id | TanStack Table (current registrations), Buttons (resit / retake / drop — all gated by CurriculumMap flags + REGISTERED status) |
8.2 Courses CME — 77 endpoints 100% coverage
Patched
2026-04-16 per PATCH_8.2_COURSES.md. 77/77 Swagger endpoints mapped. 2
scopes: school admin (64ep, 12 screens), student self-service (13ep, 4
screens). Zero super-admin endpoints (adopt is school-scoped; SAPE Phase
7 provides platform bank).
8.2.1 School Admin (/dashboard/school/[tenantId]/academics/courses/...)
| Page | API Endpoints | UI Components |
| Course Catalogue (approve / deactivate / version) | PUT /cme/courses/:id/approve, PUT /cme/courses/:id/deactivate, PUT /cme/courses/:id/version | TanStack Table (derived from curriculum-map), Badge (status), SearchInput, Dialog |
| Course Offerings List | GET /cme/offerings, POST /cme/offerings | TanStack Table, Sheet (propose — auto offeringCode), Select (term filter) |
| Course Offering Detail (tabbed) | GET /
cme/offerings/:id, PUT /cme/offerings/:id, POST
/cme/offerings/:id/submit, POST /cme/offerings/:id/approve, POST
/cme/offerings/:id/cancel, POST /cme/offerings/:id/open, GET
/cme/offerings/:id/enrollment | Tabs (detail, enrollment + waitlist), Badge (DRAFT→PENDING→PUBLISHED→OPEN→CANCELLED), Button group (cannot approve own) |
| Curriculum Documents | GET /
cme/curriculum-documents, POST /cme/curriculum-documents, GET
/cme/curriculum-documents/:id, PUT /cme/curriculum-documents/:id, POST
/cme/curriculum-documents/:id/submit, POST
/cme/curriculum-documents/:id/approve | TanStack Table, Rich text editor, Badge (state), Button (submit/approve — cannot approve own) |
| Curriculum Map | GET
/cme/curriculum-map, POST /cme/curriculum-map, PUT
/cme/curriculum-map/:id, DELETE /cme/curriculum-map/:id, POST
/cme/curriculum-map/adopt, GET /cme/curriculum-map/elective-groups | Visual
tree (programme > level > course), Sheet (add), Dialog (adopt
from SAPE bank), Badge (compulsory/elective), Elective groups panel |
| Syllabus Management (tabbed: Detail, Topics, Learning Outcomes, Assessment Scheme, Amendments, History) | POST /
cme/syllabi, GET/PUT /cme/syllabi/:id, POST /cme/syllabi/:id/submit,
POST /cme/syllabi/:id/approve, POST /cme/syllabi/:id/publish, GET
/cme/syllabi/course/:courseId, GET
/cme/syllabi/course/:courseId/history, GET/POST
/cme/syllabi/:syllabusId/topics, PUT/DELETE /cme/topics/:id, GET/POST
/cme/syllabi/:syllabusId/outcomes, PUT/DELETE /cme/outcomes/:id,
GET/POST /cme/syllabi/:syllabusId/assessment-scheme, POST
/cme/amendments, GET /cme/amendments/syllabus/:syllabusId, POST
/cme/amendments/:id/approve | Tabs with lazy-loaded components (21
endpoints). Badge (DRAFT→SUBMITTED→APPROVED→PUBLISHED). Scheme
validates weights=100. Amendments for running syllabi |
| Course Materials | GET /cme/materials, POST /cme/materials, GET /cme/materials/:id, PUT /cme/materials/:id, DELETE /cme/materials/:id | TanStack Table, Dropzone (upload), Sheet (add metadata), Badge (type) |
| Course Registration (admin auto-enroll) | POST /cme/registration/auto-enroll | Select (student, level), Button (auto-enroll compulsory), Result card |
| Waitlist Admin | POST /cme/waitlist/process | Select (offering), Input (N seats), Button (process — notifies next N with 48h acceptance) |
| Major-Minor Links (admin) | GET /cme/minors/links, POST /cme/minors/links | TanStack Table (major↔minor matrix), Sheet (create link). ISCED 5+ only |
| Credit Recognition | GET /
cme/credit-recognition, POST /cme/credit-recognition, GET
/cme/credit-recognition/:id, POST /cme/credit-recognition/:id/review | TanStack Table (pending), Sheet (submit), Dialog (review — cannot review own) |
| Substitutions | GET
/cme/substitution-rules, POST /cme/substitution-rules, PUT
/cme/substitution-rules/:id, POST /cme/substitutions/apply, POST
/cme/substitutions/:id/approve, GET /cme/substitutions/student/:pathId | TanStack Table (rules), Sheet (create rule), Dialog (approve — cannot approve own), per-student view |
8.2.2 Student Self-Service (/student-portal/...)
Continues Student Portal Shell pattern from §8.1.2. Architecture still pending (§18 of PLATFORM_SHELL_ARCHITECTURE.md) — now blocking 6 screens across PME + CME.
| Page | API Endpoints | UI Components |
| My Course Registration | GET /
cme/registration/:studentId/available, POST
/cme/registration/:studentId/select-electives, GET
/cme/registration/:studentId/status | Card (credit tracker),
Checkbox group (electives per group), Badge. Validates prereqs +
per-group min/max + total credits. ISCED 5+ only |
| My Minor Selection | GET /
cme/registration/:studentId/available-minors, POST
/cme/registration/:studentId/select-minor, POST
/cme/registration/:studentId/change-minor | Card grid (available minors), Dialog (change — drops old, enrolls new). ISCED 5+ only |
| My Waitlist | POST /cme/waitlist/join, POST /cme/waitlist/leave, POST /cme/waitlist/accept | Card (position), Button group. Accept has 48h expiry. ISCED 5+ only |
| My Course Materials | GET /
cme/content/:offeringId/materials, GET
/cme/content/:offeringId/context/:studentId, GET
/cme/content/:offeringId/access/:studentId/:materialId, POST
/cme/content/log-access | Card grid (by topic), Badge (type), File viewer. Content Delivery endpoints called programmatically during render |
8.3 Master Syllabus MaSyE — 50 endpoints 100% coverage
Patched
2026-04-16 per PATCH_8.3_MASTER_SYLLABUS.md. 50/50 Swagger endpoints
mapped. 3 scopes: school admin (10ep, 3 screens), student self-service
(5ep, 3 screens), platform/authority (35ep, 6 screens). Introduces
AUTHORITY_ADMIN role for national exam boards.
8.3.1 School Admin (/dashboard/school/[tenantId]/academics/courses/master-syllabus/...)
| Page | API Endpoints | UI Components |
| Syllabus Adoption | GET /
masye/adoption/available, POST /masye/adoption/adopt, GET
/masye/adoption/status/:courseId, POST /masye/adoption/sync/:courseId,
POST /masye/adoption/detach/:courseId | Card grid (available masters), Button (adopt/sync/detach), Badge (adopted/stale/current) |
| Custom Syllabus Builder | POST /
masye/builder/create, POST /masye/builder/import-csv, GET
/masye/builder/quality/:syllabusId, POST
/masye/builder/submit/:syllabusId | Multi-step Form (full tree), Dropzone (CSV), Progress (quality 0-100), Submit for platform review |
| Syllabus Coverage | GET /masye/analytics/coverage | Card (% courses with adopted masters), Recharts (coverage by dept/level), Filter |
8.3.2 Student Self-Service (/student-portal/syllabi/...)
| Page | API Endpoints | UI Components |
| Browse Syllabi | GET /masye/student/syllabi, GET /masye/student/syllabi/:id | Card grid (filterable by subject/level/authority), Paywall (free: overview only, paid: full tree) |
| My Syllabus Progress | GET /masye/student/progress/:syllabusId, POST /masye/student/assess | Topic tree with progress %, Self-assess checkboxes per topic, Recharts (mastery over time) |
| Syllabus Purchase | POST /masye/student/purchase | Card (syllabus + price), Payment flow (ACCTE integration), Revenue shared with authority |
8.3.3 Platform / Authority (/dashboard/platform/content/master-syllabus/... + .../syllabus-authorities/...)
Roles: CONTENT_ADMIN (reviews submissions), AUTHORITY_ADMIN (national exam boards), SUPER_ADMIN (seeds + authority management).
| Page | Role | API Endpoints | UI Components |
| Master Syllabus Library | CONTENT_ADMIN, AUTHORITY_ADMIN, SUPER_ADMIN | GET /
masye/master, POST /masye/master, DELETE /masye/master/:id, PATCH
/masye/master/:id/status, POST /masye/master/:id/version, POST
/masye/master/seed | TanStack Table, Sheet (create), Badge (draft/published/archived), Button (version clone), Bulk seed (SUPER_ADMIN only) |
| Master Syllabus Editor (tabbed: Detail, Topics, Objectives, Papers, Weights) | CONTENT_ADMIN, AUTHORITY_ADMIN, SUPER_ADMIN | GET /
masye/master/:id, PUT /masye/master/:id, GET
/masye/master/:syllabusId/topics/tree, POST
/masye/master/:syllabusId/topics, PATCH
/masye/master/:syllabusId/topics/reorder, PUT /masye/master/topics/:id,
DELETE /masye/master/topics/:id, POST
/masye/master/topics/:topicId/objectives, PUT
/masye/master/objectives/:id, DELETE /masye/master/objectives/:id, GET
/masye/master/:syllabusId/papers, POST /masye/master/:syllabusId/papers,
PUT /masye/master/papers/:id, DELETE /masye/master/papers/:id, POST
/masye/master/:syllabusId/weights, PUT /masye/master/weights/:id, DELETE
/masye/master/weights/:id | Tabs with lazy-loaded components (17 endpoints). DnD topic tree with reorder. Weight sum validation (=100) |
| Review Pipeline | CONTENT_ADMIN, SUPER_ADMIN | GET /
masye/review/queue, GET /masye/review/:id, POST
/masye/review/:id/approve, POST /masye/review/:id/reject, POST
/masye/review/:id/promote, POST /masye/review/merge | TanStack Table (submitted queue), Detail preview, Button group (approve/reject/promote/merge) |
| Syllabus Authorities | SUPER_ADMIN | GET /masye/authority, POST /masye/authority, PUT /masye/authority/:id | TanStack Table (WAEC, GCE Board, etc.), Sheet (register), Form (profile + contact + revenue share %) |
| Authority Analytics & Revenue | AUTHORITY_ADMIN (own), SUPER_ADMIN (any) | GET /masye/authority/:id/analytics, GET /masye/authority/:id/revenue | Recharts (adoption trends, purchases over time), Card (revenue, pending payouts), Table (syllabus-level) |
| Platform Syllabus Analytics | SUPER_ADMIN | GET /masye/analytics/platform | Recharts (platform-wide metrics: counts by status, adoption rates, revenue totals) |
8.4 Grading GME — 103 endpoints 100% coverage
Patched
2026-04-18 per PATCH_8.4_GRADING.md. 103/103 Swagger endpoints mapped.
Biggest module in Phase 3. 4 scopes: school admin (91ep, 14 screens),
student self-service (8ep, 2 screens), super admin (3ep, 1 screen),
public (1ep, 1 screen).
8.4.1 School Admin (/dashboard/school/[tenantId]/grading/...)
| Page | API Endpoints | UI Components |
| Assessments List | GET /gme/assessments, POST /gme/assessments, DELETE /gme/assessments/:id | TanStack Table, Sheet (create), DELETE (no scores required) |
| Assessment Detail (tabbed: Detail, Scores, Stats, Contestations, Lifecycle) | GET /
gme/assessments/:id, PUT /gme/assessments/:id, POST
/gme/assessments/:id/publish, POST /gme/assessments/:id/start-scoring,
POST /gme/assessments/:id/submit-review, POST
/gme/assessments/:id/approve-release, POST /gme/assessments/:id/release,
POST /gme/assessments/:id/finalize, POST /gme/assessments/:id/reopen,
GET /gme/assessments/:id/scores, POST /gme/assessments/:id/scores, POST
/gme/assessments/:id/scores/import, GET /gme/assessments/:id/stats, GET
/gme/assessments/:id/contestations, PUT /gme/scores/:id, POST
/gme/contestations/:id/resolve | Tabs with lazy-loaded components
(16 endpoints). Badge
(DRAFT→ACTIVE→SCORING→UNDER_REVIEW→RELEASED→FINALIZED). Approve-release
cannot approve own |
| Grade Computation | POST /
gme/compute/term-grades, POST /gme/compute/term-grades/batch, POST
/gme/compute/year-grades, POST /gme/compute/student-summary, POST
/gme/compute/cumulative-gpa, POST /gme/compute/academic-standing, POST
/gme/compute/class-ranking, POST /gme/compute/finalize-term, POST
/gme/compute/graduation-eligibility | Button group, Card (results), Progress bar for batch |
| Grades Viewer (tabbed: Term, Year, Cumulative, Student Summaries) | GET /
gme/term-grades, GET /gme/term-grades/:id, GET /gme/year-grades, GET
/gme/cumulative-records, GET /gme/cumulative-records/:id, GET
/gme/student-summaries | Tabs, TanStack Table per tab, drill-through to detail |
| Grading Configuration (tabbed: School, Programme, Course, Adopt Template) | GET /
gme/config/school, PUT /gme/config/school, GET
/gme/config/programme/:programmeId, PUT
/gme/config/programme/:programmeId, GET /gme/config/course/:courseId,
PUT /gme/config/course/:courseId, POST /gme/templates/adopt | 3-level hierarchy (school → programme → course) with inheritance, Button (adopt from platform) |
| Grade Scales | GET
/gme/grade-scales, POST /gme/grade-scales, PUT /gme/grade-scales/:id,
GET /gme/grade-scales/:id/entries, POST /gme/grade-scales/:id/entries,
PUT /gme/grade-scale-entries/:id, DELETE /gme/grade-scale-entries/:id | TanStack Table, per-scale entries panel (letter/min/max/GPA). ISCED-aware: primary 0-10, secondary A-E, tertiary 0.0-4.0 |
| Assessment Categories | GET /
gme/assessment-categories, POST /gme/assessment-categories, PUT
/gme/assessment-categories/:id, DELETE /gme/assessment-categories/:id | TanStack Table, Sheet (create with weight), Badge (%). Sum should = 100 |
| Sequences [ISCED 2-3] | GET /gme/sequences, POST /gme/sequences, GET /gme/sequences/:id, PUT /gme/sequences/:id, DELETE /gme/sequences/:id | TanStack Table (1st/2nd/3rd sequence), Form. ISCED 2-3 only |
| Graduation Management | POST /
gme/graduation/check-eligibility, POST
/gme/graduation/check-eligibility/batch, POST
/gme/graduation/finalize-promotion, POST
/gme/graduation/progress-cohort, POST /gme/graduation/dismiss, GET
/gme/graduation/academic-standing, GET /gme/graduation/honors-list, GET
/gme/graduation/promotion-status | Card (eligibility), Dialog
(batch + cohort with double-signal guard), TanStack Table
(honors/standing). Signals ADME for level exit |
| OEE Sessions List | GET /gme/oee/sessions, POST /gme/oee/sessions | TanStack Table, Sheet (links QBE paper + Assessment) |
| OEE Session Detail (tabbed: Detail, Results, Analytics, Integrity, Grading Queue, Lifecycle) | GET /
gme/oee/sessions/:id, PUT /gme/oee/sessions/:id, POST
/gme/oee/sessions/:id/schedule, POST /gme/oee/sessions/:id/activate,
POST /gme/oee/sessions/:id/cancel, POST /gme/oee/sessions/:id/close,
POST /gme/oee/sessions/:id/auto-submit-expired, POST
/gme/oee/sessions/:id/push-scores, POST
/gme/oee/sessions/:id/release-results, GET
/gme/oee/sessions/:id/grading-queue, GET
/gme/oee/sessions/:id/integrity-report, GET
/gme/oee/sessions/:id/analytics, GET /gme/oee/sessions/:id/results | Tabs (13 endpoints). Lifecycle: draft→scheduled→active→closed. Integrity: tab switches, fast completion, IP clusters |
| OEE Admin Grading | POST /
gme/oee/attempts/:id/flag, POST /gme/oee/attempts/:id/grade, POST
/gme/oee/attempts/batch-grade, POST /gme/oee/responses/:id/grade | Attempt viewer, grading form per response ($transaction), batch workflow |
| Report Cards | POST
/gme/reports/report-card, POST /gme/reports/report-cards/batch, GET
/gme/reports/report-cards, POST /gme/reports/report-cards/:id/publish | TanStack Table, Button (generate/batch), Badge (published). Calls DTGE for PDF |
| Transcripts [ISCED 5+] | POST /gme/reports/transcript, GET /gme/reports/transcripts, POST /gme/reports/transcripts/:id/publish | TanStack Table, Button (generate — CGPA required). ISCED 5+ only |
8.4.2 Student Self-Service (/student-portal/exams/... + /student-portal/grades)
| Page | API Endpoints | UI Components |
| My Exams (list + take + review) | GET /
gme/oee/sessions/:id/student-view, POST /gme/oee/attempts/start, POST
/gme/oee/attempts/:id/save, POST /gme/oee/attempts/:id/submit, GET
/gme/oee/attempts/:id/status, GET /gme/oee/attempts/:id | Card (session), Timer, Radio/Checkbox (MCQ), Textarea (essay), auto-save 30s, Submit dialog. Post-release: full attempt review |
| My Scores (view + contest) | GET /gme/students/:studentId/scores, POST /gme/scores/:scoreId/contest | TanStack Table, Button (contest released score), Dialog (reason) |
8.4.3 Super Admin / Platform (/dashboard/platform/content/grading-templates/...)
| Page | API Endpoints | UI Components |
| Grading Templates Library | GET /gme/templates, POST /gme/templates, PUT /gme/templates/:id | TanStack Table, Sheet (create), Form (scales + categories + config). Schools adopt via row 5 |
8.4.4 Public (/verify/grading-document/[dacCode])
| Page | API Endpoints | UI Components |
| Public Grading Document Verify (QR scan) | GET /gme/reports/verify/:dacCode | Public
page (no auth), QR-scanned from report card/transcript. Shows
student/school/document type/issue date/authenticity. May share route
with DTGE /verify/ |
8.5 Question Bank QBE — 20 endpoints 100% coverage
Patched
2026-04-18 per PATCH_8.5_QUESTION_BANK.md. 20/20 Swagger endpoints
mapped. Fully school-scoped (students interact via OEE). Feature-gated
by question_bank.
8.5.1 School Admin (/dashboard/school/[tenantId]/grading/question-bank/...)
| Page | API Endpoints | UI Components |
| Question Bank List | GET /qbe/questions, POST /qbe/questions, POST /qbe/questions/bulk-import, GET /qbe/questions/stats | TanStack Table, Sheet (create), Dropzone (bulk import with preview), Card (stats by type/difficulty/topic) |
| Question Detail / Editor | GET /
qbe/questions/:id, PUT /qbe/questions/:id, POST
/qbe/questions/:id/clone, POST /qbe/questions/:id/retire, POST
/qbe/questions/:id/visibility | Form, Version history panel (diff highlight), Button group (clone, retire, visibility: private → dept → school) |
| Exam Papers List | GET /qbe/papers, POST /qbe/papers | TanStack Table, Sheet (create draft), Badge (status) |
| Exam Paper Detail / Editor (tabbed: Detail, Questions, Auto-Generate, Preview) | GET /
qbe/papers/:id, PUT /qbe/papers/:id, POST /qbe/papers/:id/auto-generate,
POST /qbe/papers/:id/questions, DELETE
/qbe/papers/:id/questions/:questionId, POST /qbe/papers/:id/publish, GET
/qbe/papers/:id/printable, GET /qbe/papers/:id/marking-guide | Tabs
(8 endpoints). DnD question ordering, Form (auto-gen with warnings),
Button (Staff Preview, Printable Student View, Marking Guide — all audit
logged). Publish locks questions |
| Audit Logs | GET /qbe/audit-logs | TanStack Table (read-only, immutable), Badge (action type) |
8.6 Attendance ATME — 28 endpoints 100% coverage
Patched
2026-04-18 per PATCH_8.6_ATTENDANCE.md. 28/28 Swagger endpoints mapped.
2 scopes: school admin (27ep, 6 screens), super admin platform seed
(1ep, 1 screen). Feature-gated by attendance_management.
8.6.1 School Admin (/dashboard/school/[tenantId]/attendance/...)
| Page | API Endpoints | UI Components |
| Mark Attendance | POST
/atme/lesson, POST /atme/school-day, POST /atme/hostel, POST
/atme/staff, POST /atme/activity, POST /atme/refectory, GET
/atme/lesson/:slotId/students | Checkbox grid (per student from lesson-students), Select (event type, status), DatePicker. 6 event types |
| Attendance Reports & Stats | GET /atme/records, GET /atme/stats/:studentId | Recharts (attendance rate), TanStack Table, Card (per-student stats) |
| Alert Rules | GET /atme/alert-rules, POST /atme/alert-rules, PUT /atme/alert-rules/:id, DELETE /atme/alert-rules/:id | TanStack Table, Sheet (create rule), Select (trigger condition), Dialog (delete confirm) |
| Devices | GET
/atme/devices, POST /atme/devices, GET /atme/devices/:id, PUT
/atme/devices/:id, GET /atme/vendors, GET /atme/device-models, POST
/atme/ingest | TanStack Table, Sheet (register — uses vendors + models), Detail view, Badge (status), Button (test ingest) |
| Grading Bridge | POST
/atme/grading/compute, GET /atme/grading/bridges, GET
/atme/grading/exam-eligibility/:studentId, POST
/atme/grading/exam-gate-override | TanStack Table, Button (compute), Badge (eligible/blocked), Dialog (override with required reason — audit logged) |
| Attendance Settings | GET /atme/config, PUT /atme/config, GET /atme/event-definitions | Form with tabs per event type, Switch toggles, TanStack Table (event definitions read-only) |
8.6.2 Super Admin / Platform (/dashboard/platform/seed/attendance-events)
| Page | API Endpoints | UI Components |
| Attendance Event Definitions Seed | POST /atme/event-definitions/seed | Button (seed default event types), Result card. Typically run once at platform bootstrap |
8.7 Assignments ASME — 21 endpoints 100% coverage
Patched
2026-04-18 per PATCH_8.7_ASSIGNMENTS.md. 21/21 Swagger endpoints
mapped. 2 scopes: school admin (17ep, 2 screens), student self-service
(4ep, 1 screen). Feature-gated by assignment_management. Final module of Phase 3.
8.7.1 School Admin (/dashboard/school/[tenantId]/assignments/...)
| Page | API Endpoints | UI Components |
| Assignments List | GET /asme/assignments, POST /asme/assignments | TanStack Table, Badge (DRAFT→PUBLISHED→CLOSED→RELEASED→FINALIZED→GRADED), SearchInput, Sheet (create draft) |
| Assignment Detail (tabbed: Detail, Submissions, Stats, Contestations, Scoring, Lifecycle) | GET /
asme/assignments/:id, PUT /asme/assignments/:id, DELETE
/asme/assignments/:id, POST /asme/assignments/:id/transition, POST
/asme/assignments/:id/release, POST /asme/assignments/:id/finalize, POST
/asme/assignments/:id/reopen, POST /asme/assignments/:id/push-to-gms,
GET /asme/assignments/:id/submissions, POST /asme/submissions/:id/score,
POST /asme/assignments/:id/bulk-score, POST
/asme/assignments/:id/auto-score, GET /asme/assignments/:id/stats, GET
/asme/assignments/:id/contestations, POST
/asme/contestations/:id/resolve | Tabs with lazy-loaded components
(15 endpoints). Spreadsheet-style scoring. Lifecycle:
transition/release/finalize/reopen/push-to-gms. Cannot delete if
submissions exist |
8.7.2 Student Self-Service (/student-portal/assignments/...)
| Page | API Endpoints | UI Components |
| My Assignments (list + submit + contest) | GET /
asme/submissions/mine/:assignmentId, POST /asme/assignments/:id/submit,
PUT /asme/submissions/:id, POST /asme/submissions/:id/contest | Card (assignment + due), Dropzone, Editor, Button (update before deadline), Dialog (contest with reason — validates window) |
9. Phase 4 — Financial & Administrative
9.1 Fees & Billing ACCTE/FME — 98 endpoints 100% coverage
Patched
2026-04-18 per PATCH_9.1_FEES_BILLING.md. 98/98 Swagger endpoints
mapped. 3 scopes: school admin (55ep, 11 screens), platform (29ep, 7
screens — biggest platform finance surface), public (14ep, 2 screens).
Feature-gated by fee_management.
9.1.1 School Admin (/dashboard/school/[tenantId]/finance/...)
| Page | API Endpoints | UI Components |
| Finance Dashboard | GET /accte/dashboard, GET /accte/finance/revenue, GET /accte/finance/transactions | Recharts (revenue/collection), stat Cards, TanStack Table (transactions) |
| Fee Categories | GET /accte/fee-categories, POST /accte/fee-categories, PUT /accte/fee-categories/:id | TanStack Table, Sheet (create/edit), Badge (active) |
| Fee Schedules | GET
/accte/fee-schedules, POST /accte/fee-schedules, GET
/accte/fee-schedules/:id, PUT /accte/fee-schedules/:id, POST
/accte/fee-schedules/:id/publish | TanStack Table, Sheet (create/edit), Badge (DRAFT/PUBLISHED), Button (publish) |
| Billing (Invoices + Student Statement) | GET /
accte/invoices, GET /accte/invoices/:id, POST /accte/invoices/generate,
POST /accte/invoices/custom, POST /accte/invoices/:id/cancel, POST
/accte/invoices/:id/finalize, POST /accte/invoices/:id/fee-selections,
GET /accte/invoices/:id/optional-items, GET
/accte/students/:studentId/statement | TanStack Table, Button (batch generate), Sheet (custom invoice), Badge, Parent fee-selections UI for optional items |
| Payments (record + pay links) | GET /
accte/payments, POST /accte/payments/initiate, POST
/accte/payments/manual, POST /accte/payments/bank-deposit, POST
/accte/payments/:id/verify, POST /accte/payments/:id/refund, POST
/accte/payments/:id/allocate, GET /accte/payments/:id/receipt, POST
/accte/pay-links, POST /accte/pay-links/:id/revoke | TanStack Table, Sheet (manual/bank recording), Dialog (receipt/refund/allocate), Pay link generator |
| Installments | GET /accte/installments, POST /accte/installments, POST /accte/installments/:id/pay, POST /accte/installments/:id/cancel | TanStack Table, Sheet (create plan), Progress (payment progress) |
| Waivers | GET /accte/waivers, POST /accte/waivers, POST /accte/waivers/:id/revoke, POST /accte/waivers/scholarship-credits | TanStack Table, Sheet (create waiver), Badge (active/revoked), Button (apply scholarship credits) |
| Discount Configuration | GET /accte/discount-config, POST /accte/discount-config, PUT /accte/discount-config/:id, DELETE /accte/discount-config/:id | TanStack Table, Sheet (create rule), Select (sibling/staff-child) |
| Debt Management | GET
/accte/debt, GET /accte/debt/clearance/:studentId, POST
/accte/debt/:id/write-off, GET /accte/debt/config, PUT
/accte/debt/config | TanStack Table, Form (config), Badge (hold type), Dialog (write-off), Per-student clearance view |
| Tax Configuration | GET /accte/tax-config, POST /accte/tax-config, PUT /accte/tax-config/:id, DELETE /accte/tax-config/:id | TanStack Table, Sheet (create), Select (inclusive/exclusive) |
| Auto-Enroll on Payment | GET /
accte/auto-enroll-config, POST /accte/auto-enroll-config, PUT
/accte/auto-enroll-config/:id, DELETE /accte/auto-enroll-config/:id | TanStack Table, Sheet (create rule), Select (fee category → service) |
9.1.2 Super Admin / Platform (/dashboard/platform/finance/...)
Required role: FINANCE_ADMIN or SUPER_ADMIN. Biggest platform finance surface in the project.
| Page | API Endpoints | UI Components |
| Platform Finance Dashboard | GET /accte/dashboard/platform | Recharts (platform-wide metrics), stat Cards |
| Payment Gateways | GET
/accte/admin/gateways, POST /accte/admin/gateways, PUT
/accte/admin/gateways/:id, POST
/accte/admin/gateways/:id/activate-country, POST
/accte/admin/gateways/:id/test, POST /accte/admin/payments/initiate | TanStack Table, Sheet (register), Country activation matrix, Button (test + test payment) |
| Exchange Rate & Revenue Metrics | POST /accte/admin/exchange-rate, GET /accte/admin/revenue, GET /accte/admin/revenue-by-country, GET /accte/admin/payment-metrics | Form (exchange rate), Recharts (revenue over time / by country), stat Cards (metrics) |
| Transactions & Wallet Balances | GET /accte/admin/transactions, GET /accte/admin/wallet-balance, GET /accte/admin/wallet-balances | TanStack Table (cross-tenant), Card (single wallet query), Table (all school balances) |
| Settlements | POST /accte/admin/settlement, POST /accte/admin/settlement/request | Button (initiate, request), Status tracking |
| Platform Invoices (platform-to-school) | GET /
accte/admin/platform-invoices, GET /accte/admin/platform-invoices/:id,
POST /accte/admin/platform-invoices/:id/waive, POST
/accte/admin/platform-invoices/batch-generate, POST
/accte/admin/platform-invoices/generate, POST
/accte/admin/platform-invoices/payment | TanStack Table, Detail view, Button (waive/batch/single generate/record payment), Badge (status) |
| Revenue Share Management | GET /
accte/admin/rev-share, POST /accte/admin/rev-share, PUT
/accte/admin/rev-share/:id, GET /accte/admin/rev-share/ledger, POST
/accte/admin/rev-share/school-override, GET
/accte/admin/rev-share/school-overrides, GET /accte/admin/standing | TanStack Table (configs + overrides), Sheet (create + override), Ledger view (revenue flow), Per-school standing |
9.1.3 Public
| Page | API Endpoints | UI Components |
| Gateway Webhook Registry (backend receivers — no UI) | POST /
accte/webhooks/airtel-money, flutterwave, generic, mpesa, mtn-momo,
orange-money, ozow, paypal, paystack, stripe; POST /accte/admin/webhook;
GET /accte/demo-pay/confirm (dev-only) | 12 inbound webhook
receivers (no frontend UI). URLs documented for gateway dashboard
configuration. demo-pay must be disabled before production |
| Public Pay Link (parent-facing) | GET /accte/pay-links/invoice/:token, POST /accte/pay-links/pay/:token | Public page /pay/[token]: Card (invoice from token), Payment form (no auth — token + amount), Success/failure page |
9.2 Student Wallet ACCTE/WME — 53 endpoints 100% coverage
Patched
2026-04-18 per PATCH_9.2_WALLET.md. 53/53 Swagger endpoints mapped. 3
scopes: school admin (44ep, 11 screens), parent self-service (7ep, 4
screens — first Parent Portal appearance), platform (2ep, 1 screen). Feature-gated by student_wallet. Parent Portal Shell architecture pending in PLATFORM_SHELL_ARCHITECTURE.md §19.
9.2.1 School Admin (/dashboard/school/[tenantId]/wallet/...)
| Page | API Endpoints | UI Components |
| Wallets List | GET /accte/wallet, POST /accte/wallet | TanStack Table, Sheet (create), Stat Cards (active/frozen/total) |
| Wallet Detail (tabbed: Overview, Transactions, Limits, Actions) | GET /
accte/wallet/:studentId, GET /accte/wallet/:studentId/balance, GET
/accte/wallet/:studentId/transactions, POST
/accte/wallet/:walletId/freeze, POST /accte/wallet/:walletId/unfreeze,
PUT /accte/wallet/:walletId/limits | Tabs, Stat Cards (balance/hold/available), TanStack Table (transactions), Dialog (freeze/unfreeze), Form (limits) |
| Admin Adjustments (credit/debit/suspend) | POST /
accte/wallet/admin/credit, POST /accte/wallet/admin/debit, POST
/accte/wallet/admin/suspend/:walletId, POST
/accte/wallet/admin/unsuspend/:walletId | Sheet (credit/debit with reason), Dialog (suspend confirm), Badge (active/suspended) |
| School Float & Reports | GET /
accte/wallet/admin/float, GET /accte/wallet/reports/spending, GET
/accte/wallet/reports/top-ups, GET
/accte/wallet/reports/merchant-revenue, GET
/accte/wallet/reports/wallet-summary | Stat Card (float balance), Recharts (spending/top-ups/merchant-revenue), TanStack Table (wallet summary) |
| Cash Exchange Requests (admin review) | GET /
accte/wallet/admin/exchange-requests, POST
/accte/wallet/admin/exchange-request/:id/approve, POST
/accte/wallet/admin/exchange-request/:id/paid, POST
/accte/wallet/admin/exchange-request/:id/reject | TanStack Table, Badge (pending/approved/paid/rejected), Dialog (approve/paid/reject with notes) |
| Parent Funding Admin (verify deposits + cash top-up) | POST /
accte/wallet/funding/top-up-cash, POST
/accte/wallet/funding/bank-deposit/:id/verify, POST
/accte/wallet/funding/bank-deposit/:id/reject, GET
/accte/wallet/funding/bank-deposits/pending | TanStack Table (pending deposits), Sheet (cash top-up), Dialog (verify/reject with proof view) |
| Merchant Points | GET
/accte/wallet/merchants, POST /accte/wallet/merchants, GET
/accte/wallet/merchants/:id, PUT /accte/wallet/merchants/:id, DELETE
/accte/wallet/merchants/:id, POST
/accte/wallet/merchants/:id/operators/:operatorId, DELETE
/accte/wallet/merchants/:id/operators/:operatorId | TanStack Table, Sheet (create/edit), Badge (type: canteen/stationery/etc.), Dialog (delete), Operator manager |
| Merchant Catalogue | GET /
accte/wallet/merchants/:merchantId/catalogue, POST
/accte/wallet/merchants/:merchantId/catalogue, PUT
/accte/wallet/merchants/:merchantId/catalogue/:itemId, DELETE
/accte/wallet/merchants/:merchantId/catalogue/:itemId | TanStack Table, Sheet (add/edit item), Input (price), Dialog (delete) |
| POS (purchases + refunds + history) | POST /
accte/wallet/pos/purchase, POST /accte/wallet/pos/refund/:purchaseId,
GET /accte/wallet/pos/merchant/:merchantPointId, GET
/accte/wallet/pos/student/:studentId | Sheet (purchase — cart builder), Dialog (refund), TanStack Table (merchant + student history) |
| Fee Bridge (pay invoice from wallet) | GET /accte/wallet/fee-bridge/check/:walletId/:invoiceId, POST /accte/wallet/fee-bridge/pay | Card (pre-check), Button (pay from wallet), Badge (sufficient/insufficient) |
| Wallet Settings | GET /accte/wallet/config, PUT /accte/wallet/config | Form (react-hook-form), Input (exchange rate, points label, anti-fraud thresholds) |
9.2.2 Parent Self-Service 🆕 (/parent-portal/wallet/...)
First Parent Portal appearance. Architecture pending in PLATFORM_SHELL_ARCHITECTURE.md
§19 "Parent Portal Shell". Open questions: auth strategy (NextAuth
parent type vs separate), multi-tenant parent accounts, Parent = StuLCE
Guardian?
| Page | API Endpoints | UI Components |
| My Parent Account (view + link students) | GET /
accte/wallet/funding/parent-account/:parentId, POST
/accte/wallet/funding/parent-account, POST
/accte/wallet/funding/parent-account/:accountId/link-student | Card (account balance), TanStack Table (linked students), Sheet (link student with invite/verification) |
| Top-Up Wallet (parent-to-student + parent account top-up) | POST /
accte/wallet/funding/top-up (gateway to student wallet), POST
/accte/wallet/funding/parent-account/:accountId/top-up (fund parent
account) | Sheet (top-up — gateway integration), Select (student wallet vs family pot), Input (amount), Badge (gateway) |
| Submit Bank Deposit (proof of bank transfer) | POST /accte/wallet/funding/bank-deposit | Form (deposit details), Dropzone (proof upload), Badge (pending verification) |
| Request Cash Exchange (convert points back to cash) | POST /accte/wallet/admin/exchange-request | Sheet (exchange request), Card (rate + conversion preview), Badge (submitted/pending) |
9.2.3 Super Admin / Platform (/dashboard/platform/finance/wallet-config)
Required role: FINANCE_ADMIN or SUPER_ADMIN. Platform-wide wallet defaults (exchange rates, hold periods, anti-fraud thresholds).
| Page | API Endpoints | UI Components |
| Wallet Platform Config | GET /accte/wallet/admin/platform-config, PUT /accte/wallet/admin/platform-config | Form (react-hook-form), Input (default exchange rate, hold period, anti-fraud thresholds) |
9.3 Scheduling & Timetable SCIE — 160 endpoints, 17 tags 100% coverage
Patched
2026-04-18 per PATCH_9.3_SCHEDULING.md. 160/160 Swagger endpoints
mapped. 4 scopes: school admin (141ep, 22 screens), self-service (16ep, 4
screens — student + staff portals), public (1ep, 1 screen), platform
(2ep, 1 screen). Biggest module in the platform. Feature-gated by scheduling_timetable with 6 sub-gates. Staff Portal Shell pending in PLATFORM_SHELL_ARCHITECTURE.md §17.
9.3.1 School Admin (/dashboard/school/[tenantId]/scheduling/...)
Calendar & Events (3 screens, 19 endpoints)
| Page | API Endpoints | UI Components |
| Academic Calendar (events + closures + holidays view) | GET /
scie/calendar, GET /scie/events, POST /scie/events, PUT
/scie/events/:id, POST /scie/events/:id/publish, POST
/scie/events/:id/cancel, POST /scie/closures, GET /scie/holidays | Calendar view (month/week), Card (event), Badge (type), DatePicker |
| Event Categories | GET /scie/categories, POST /scie/categories, PUT /scie/categories/:id, DELETE /scie/categories/:id | TanStack Table, Sheet (create/edit), Badge (system/custom) |
| Notification Rules | GET /
scie/notification-rules, GET /scie/notification-rules/:id, POST
/scie/notification-rules, PUT /scie/notification-rules/:id, DELETE
/scie/notification-rules/:id, POST /scie/notification-rules/evaluate,
POST /scie/notification-rules/:id/test | TanStack Table, Sheet (rule builder), Button (Run Now / Test) |
Event RSVP (1 screen, 9 endpoints)
| Page | API Endpoints | UI Components |
| Event RSVP Management (tabbed: Invites, Attendees, Check-In, Report) | POST /
scie/events/:id/rsvp/invite, POST /scie/events/:id/rsvp/remind, GET
/scie/events/:id/rsvp, GET /scie/events/:id/rsvp/summary, GET
/scie/events/:id/attendees, DELETE /scie/events/:id/rsvp/:userId, POST
/scie/events/:id/check-in, POST /scie/events/:id/check-in/bulk, GET
/scie/events/:id/attendance-report | Tabs, TanStack Table (attendees), Badge (accepted/declined/tentative), Button (invite/remind), Barcode scanner (check-in) |
Class Timetable (3 screens, 25 endpoints)
| Page | API Endpoints | UI Components |
| Timetable Builder (tabbed: Grids, Slots, Lifecycle) | GET /
scie/timetable/grids, GET /scie/timetable/grids/:id, POST
/scie/timetable/grids, PUT /scie/timetable/grids/:id, DELETE
/scie/timetable/grids/:id, POST /scie/timetable/grids/:id/submit, POST
/scie/timetable/grids/:id/approve, POST /scie/timetable/clone-grid, GET
/scie/timetable/slots, POST /scie/timetable/slots, PUT
/scie/timetable/slots/:id, DELETE /scie/timetable/slots/:id, POST
/scie/timetable/slots/:id/override, POST /scie/timetable/submit, POST
/scie/timetable/approve, POST /scie/timetable/publish, POST
/scie/timetable/clone, POST /scie/timetable/upload | Grid view (day × period), DnD (dnd-kit), Badge (DRAFT→SUBMITTED→APPROVED→PUBLISHED), Select (level/term), Dropzone (upload CSV) |
| Bell Schedule | GET /scie/timetable/bell-schedule, POST /scie/timetable/bell-schedule, PUT /scie/timetable/bell-schedule/:id | Form (period builder), TimePicker, TanStack Table |
| Timetable Lookups (staff availability + student/staff schedule lookups) | GET /
scie/timetable/template, GET /scie/timetable/staff/:id/availability, GET
/scie/timetable/staff/:staffId/schedule, GET
/scie/timetable/student/:studentId | Select (staff/student), Card (availability), Weekly grid (schedule) |
Timetable Operations (5 screens, 25 endpoints)
| Page | API Endpoints | UI Components |
| Timetable Conflicts | GET /
scie/timetable/conflicts, GET /scie/timetable/conflicts/summary, GET
/scie/timetable/conflicts/:id, GET
/scie/timetable/conflicts/:id/proposals, POST
/scie/timetable/conflicts/check, POST
/scie/timetable/conflicts/:id/accept-proposal, POST
/scie/timetable/conflicts/:id/override, POST
/scie/timetable/conflicts/:id/dismiss | TanStack Table, Badge (severity: hard/soft), Dialog (accept proposal / override / dismiss) |
| Substitutions Needed (timetable-level sub finder) | GET /
scie/timetable/substitutions/needed, GET
/scie/timetable/substitutions/suggestions, POST
/scie/timetable/substitutions/assign | TanStack Table, Sheet (assign substitute), Badge (covered/uncovered) |
| Slot Swap Admin (board + approvals) | GET /
scie/timetable/swap, GET /scie/timetable/swap/board, POST
/scie/timetable/swap/:id/approve, POST /scie/timetable/swap/:id/rollback | TanStack Table, Board view (pending swaps), Dialog (approve/rollback) |
| Auto-Generate (algorithmic + AI) | POST /
scie/timetable/generate, POST /scie/timetable/generate/ai, POST
/scie/timetable/generate/ai/optimize, GET
/scie/timetable/generate/status/:id, POST
/scie/timetable/generate/accept/:id, POST
/scie/timetable/generate/reject/:id | Form (constraints), Button (generate), Progress (polling), Card (proposal review), Dialog (accept/reject) |
| Export & Share Admin (PDF/iCal/share links) | GET /scie/timetable/export/pdf, GET /scie/timetable/export/ical, POST /scie/timetable/share, DELETE /scie/timetable/share/:token | Button (download PDF/iCal), Dialog (share link), Input (share URL), TanStack Table (active tokens) |
Exam Timetable (1 screen, 13 endpoints)
| Page | API Endpoints | UI Components |
| Exam Timetable (tabbed: Slots, Invigilators, Accommodations, Board Registrations, Clashes) | GET /
scie/exams/timetable, POST /scie/exams/slots, PUT /scie/exams/slots/:id,
DELETE /scie/exams/slots/:id, POST /scie/exams/slots/:id/publish, GET
/scie/exams/:id/invigilators, POST /scie/exams/invigilators, DELETE
/scie/exams/invigilators/:id, GET /scie/exams/accommodations, POST
/scie/exams/accommodations, GET /scie/exams/board-registrations, POST
/scie/exams/board-registration, GET /scie/exams/clash-report | Tabs, TanStack Table, Sheet (create slot), Select (room/invigilator), Badge (published), Card (clash report) |
Facilities (1 screen, 8 endpoints)
| Page | API Endpoints | UI Components |
| Facilities Management (tabbed: Facilities, Bookings) | GET /
scie/facilities, GET /scie/facilities/available, GET
/scie/facilities/:id/schedule, POST /scie/facilities, PUT
/scie/facilities/:id, POST /scie/facilities/:id/maintenance, POST
/scie/bookings, POST /scie/bookings/:id/cancel | TanStack Table, Calendar (availability), Sheet (book/maintain), Badge (type) |
Staff Leave Management (1 screen, 8 endpoints)
| Page | API Endpoints | UI Components |
| Staff Leave Management (tabbed: Requests, Substitutions, Workload) | GET /
scie/leave/requests, POST /scie/leave/:id/approve, POST
/scie/leave/:id/reject, GET /scie/substitutions, POST
/scie/substitutions, POST /scie/substitutions/:id/confirm, GET
/scie/staff/:id/workload, PUT /scie/staff/:id/workload | Tabs, TanStack Table (requests), Dialog (approve/reject), Sheet (assign sub), Form (workload) |
Scheduling Admin (1 screen, 4 endpoints)
| Page | API Endpoints | UI Components |
| Scheduling Admin (templates + global conflicts + availability check) | GET /scie/admin/bell-templates, POST /scie/admin/adopt-bell-template, GET /scie/availability/check, GET /scie/conflicts | Card grid (platform templates), Button (adopt), Form (availability query), TanStack Table (conflicts) |
Sports & Activities (1 screen, 9 endpoints)
| Page | API Endpoints | UI Components |
| Sports & Activities (tabbed: Activities, Events, Participants) | GET /
scie/activities, POST /scie/activities, PUT /scie/activities/:id, GET
/scie/activities/:id/schedule, POST /scie/activities/events, PUT
/scie/activities/events/:id, POST /scie/activities/events/:id/cancel,
POST /scie/activities/events/:id/participants, DELETE
/scie/activities/events/:eventId/participants/:userId | Tabs, TanStack Table, Sheet (create activity/event), Calendar (schedule), Badge (active) |
Academic Deadlines (1 screen, 6 endpoints)
| Page | API Endpoints | UI Components |
| Academic Deadlines | GET /
scie/deadlines, GET /scie/deadlines/overdue, POST /scie/deadlines, POST
/scie/deadlines/:id/extend, POST /scie/deadlines/:id/cancel, POST
/scie/deadlines/:id/mark-passed | TanStack Table, DatePicker, Badge (active/passed/cancelled/overdue) |
Additional Domains (4 screens, 15 endpoints)
| Page | API Endpoints | UI Components |
| Boarding Events | GET /scie/boarding/events, POST /scie/boarding/events, PUT /scie/boarding/events/:id | TanStack Table, Sheet (create/edit), Badge (type) |
| PTA Bookings (Parent-Teacher Appointments) | GET /scie/pta/available, POST /scie/pta/book, POST /scie/pta/generate, POST /scie/pta/:id/cancel | TanStack Table, Sheet (book slot), Button (generate slots), Badge (booked/available) |
| Staff Events | GET /scie/staff-events, POST /scie/staff-events, PUT /scie/staff-events/:id, POST /scie/staff-events/:id/cancel | TanStack Table, Sheet (create/edit), Badge (status), Dialog (cancel) |
| Trips (school trips + field trips) | GET /scie/trips, POST /scie/trips, PUT /scie/trips/:id, POST /scie/trips/:id/cancel | TanStack Table, Sheet (create/edit), DatePicker (date range), Dialog (cancel) |
9.3.2 Self-Service (Student Portal + Staff Portal 🆕)
Shared screens render in both portals. Same endpoints; backend filters by role. First Staff Portal appearance — architecture pending in PLATFORM_SHELL_ARCHITECTURE.md §17.
| Page | Portal | API Endpoints | UI Components |
| My Timetable (today + week + export) | Student + Staff | GET /
scie/timetable/my, GET /scie/timetable/my/today, GET
/scie/timetable/my/week, GET /scie/timetable/export/pdf/my, GET
/scie/timetable/export/ical/my | Weekly grid (read-only), Card (today), Button (download PDF/iCal) |
| My Invitations (RSVP responses) | Student + Staff | GET /scie/my-invitations, PUT /scie/events/:eventId/rsvp | TanStack Table, Dialog (respond: accept/decline/tentative) |
| My Leave (submit + balance + cancel) | Staff only | POST /scie/leave/request, GET /scie/leave/balance/:staffId, POST /scie/leave/:id/cancel | Card (balance), Sheet (submit request), Dialog (cancel) |
| My Slot Swaps (request + respond + claim + cancel) | Staff only | GET /
scie/timetable/swap/my, POST /scie/timetable/swap/request, POST
/scie/timetable/swap/open, POST /scie/timetable/swap/claim/:id, POST
/scie/timetable/swap/:id/respond, POST /scie/timetable/swap/:id/cancel | TanStack Table (my swaps), Board view (open swaps), Sheet (request/claim), Dialog (respond/cancel) |
9.3.3 Public (/public/timetable/[token])
| Page | API Endpoints | UI Components |
| Public Timetable View (via share token) | GET /scie/timetable/share/:token | Weekly grid (read-only), no auth. Token generated by admin in Export & Share. Revocable. |
9.3.4 Super Admin / Platform (/dashboard/platform/scheduling/seed-templates)
Required role: SUPER_ADMIN or PLATFORM_OPS. One-time ops during country/region onboarding.
| Page | API Endpoints | UI Components |
| Platform Bell & Holiday Seed | POST /scie/admin/seed-bell-templates, POST /scie/admin/seed-holidays | Button (seed with confirmation), Card (seeded counts) |
9.4 Documents DTGE — 38 endpoints, 5 tags 100% coverage
Patched
2026-04-18 per PATCH_9.4_DOCUMENTS.md. 38/38 Swagger endpoints mapped. 3
scopes: school admin (36ep, 5 screens), public verify page (1ep, 1
screen), platform (1ep, 1 screen). Feature-gated by document_generation with sub-gates document_verification and custom_report_templates. No parent/student self-service — student/parent access via public verify URL. Final module of Phase 4.
9.4.1 School Admin (/dashboard/school/[tenantId]/documents/...)
| Page | API Endpoints | UI Components |
| Templates Manager (document template library) | GET /dtge/templates, POST /dtge/templates, PUT /dtge/templates/:id, DELETE /dtge/templates/:id, POST /dtge/templates/clone/:id | TanStack Table, Sheet (create/edit), HTML editor (CodeMirror/Monaco), Variable picker, Badge (system/custom) |
| Report Card Templates (school report card builder) | GET /
dtge/report-templates, GET /dtge/report-templates/:id/preview, POST
/dtge/report-templates, PUT /dtge/report-templates/:id, POST
/dtge/report-templates/:id/deactivate, POST /dtge/report-templates/seed | TanStack Table, Form (zones/config), Dialog (preview), Badge (active/inactive), Button (seed defaults) |
| Document Generation (generate + bulk + lifecycle) | GET /
dtge/documents, GET /dtge/documents/:id, POST /dtge/generate, POST
/dtge/bulk-generate, POST /dtge/preview, POST /dtge/publish, POST
/dtge/documents/:id/regenerate, POST /dtge/documents/:id/void | TanStack
Table, Button (generate/batch/publish), Dialog (preview), Badge
(pending/ready/published/voided), Destructive confirm (void) |
| Admin Verification Workflow (initiate + authorize + complete + reject + log) | POST /
dtge/verify/initiate, GET /dtge/verify/status/:id, POST
/dtge/verify/authorize/:id, POST /dtge/verify/complete/:id, POST
/dtge/verify/reject/:id, GET /dtge/verify/log | TanStack Table (log), Sheet (initiate), Progress (status polling), Dialog (authorize/reject/complete with notes), Badge (state) |
| Document Settings (tabbed: Document, Report, Pricing, Signatories) | GET /
dtge/config/document, PUT /dtge/config/document, GET
/dtge/config/report, PUT /dtge/config/report, GET /dtge/config/pricing,
POST /dtge/config/pricing, GET /dtge/config/signatories, POST
/dtge/config/signatories, PUT /dtge/config/signatories/:id, POST
/dtge/config/signatories/:id/deactivate, POST
/dtge/config/signatories/reorder | Tabs, Form (react-hook-form),
Dropzone (logo/signature image), TanStack Table (pricing/signatories),
DnD (reorder signatories), Toggle (deactivate) |
9.4.2 Public (/verify/[documentId]/[shortHash])
| Page | API Endpoints | UI Components |
| Public Document Verification (no auth — short-hash token) | GET /dtge/verify/:documentId/:shortHash | Public
page, no auth. Card (verification result: document metadata, issuing
authority, issued-to, issue date, validity), Badge
(valid/voided/revoked). Rate-limited on backend. |
9.4.3 Super Admin / Platform (/dashboard/platform/documents/platform-templates)
Required role: CONTENT_ADMIN or SUPER_ADMIN.
| Page | API Endpoints | UI Components |
| Platform Template Library (platform-wide templates all tenants can clone) | POST /dtge/templates/platform | Sheet (create platform template), HTML editor, Variable picker, Badge (platform) |
10. Phase 5 — Student Welfare & Operations
10.1 Health SHME — 72 endpoints, 12 tags 100% coverage
Patched
2026-04-18 per PATCH_10.1_HEALTH.md. 72/72 Swagger endpoints mapped.
School admin only (72ep, 14 screens) — student/parent self-service
reuses admin reads via role-filtered nav per shell architecture §17.
Feature-gated by health_management with 6 sub-gates. First module of Phase 5.
10.1.1 Health Records Management (2 screens, 30 endpoints)
| Page | API Endpoints | UI Components |
| Verification Queue (admin reviews pending records) | GET /shme/records/verification-queue, POST /shme/records/:id/verify, POST /shme/records/:id/reject | TanStack Table, Badge (pending/verified/rejected), Dialog (verify/reject with notes) |
| Student Health Record (tabbed: Summary, Allergies, Dietary, Medications, Immunizations, Growth) | Summary (5):
GET /shme/records/:studentId, GET /shme/records/summary/:studentId,
POST /shme/records, PUT /shme/records/:id, POST
/shme/records/refectory-alerts. Allergies (5): GET
/shme/records/:healthRecordId/allergies, POST
/shme/records/:healthRecordId/allergies, PUT /shme/allergies/:id, DELETE
/shme/allergies/:id, POST /shme/allergies/:id/verify. Dietary (4):
GET /shme/records/:healthRecordId/dietary, POST
/shme/records/:healthRecordId/dietary, PUT /shme/dietary/:id, DELETE
/shme/dietary/:id. Medications (5): GET
/shme/medications/record/:healthRecordId, POST /shme/medications, PUT
/shme/medications/:id, PATCH /shme/medications/:id/deactivate, POST
/shme/medications/:id/authorize. Immunizations (5): GET
/shme/immunizations/record/:healthRecordId, GET
/shme/immunizations/compliance/:studentId, POST /shme/immunizations, PUT
/shme/immunizations/:id, POST /shme/immunizations/:id/verify. Growth (3):
GET /shme/records/:healthRecordId/growth, GET
/shme/records/:healthRecordId/growth/chart, POST
/shme/records/:healthRecordId/growth | Tabs, Sheet (create/edit
per tab), TanStack Table (lists), Recharts (growth chart), Badge
(severity/status), Button (Send Refectory Alerts) |
10.1.2 Clinical Workflow (5 screens, 22 endpoints)
| Page | API Endpoints | UI Components |
| Clinic Visits (tabbed: Active, All, Follow-ups) | GET /
shme/clinic/visits, GET /shme/clinic/visits/:id, GET
/shme/clinic/visits/active, GET /shme/clinic/visits/follow-ups, POST
/shme/clinic/visits, PUT /shme/clinic/visits/:id, PATCH
/shme/clinic/visits/:id/outcome | Tabs, TanStack Table, Sheet (log visit), Select (triage/disposition), Badge (severity) |
| Health Incidents | GET /shme/incidents, POST /shme/incidents, PUT /shme/incidents/:id | TanStack Table, Sheet (report incident), Badge (severity) |
| Lab Requests & Results | GET /shme/lab/requests, POST /shme/lab/requests, POST /shme/lab/results | TanStack Table, Sheet (request lab), Dialog (enter results), Badge (pending/complete) |
| Screenings (vision/hearing/dental/etc.) | GET /shme/screening, POST /shme/screening, POST /shme/screening/:id/results | TanStack Table, Sheet (create screening), Dialog (enter results), Select (screening type) |
| Sickbay (tabbed: Beds, Admissions) | GET /
shme/sickbay/beds, POST /shme/sickbay/beds, GET
/shme/sickbay/admissions, POST /shme/sickbay/admissions, POST
/shme/sickbay/admissions/:id/discharge, POST
/shme/sickbay/admissions/:id/monitor | Tabs, Card grid (beds), Badge (occupied/available), Dialog (admit/discharge/monitor) |
10.1.3 Pharmacy (2 screens, 8 endpoints)
| Page | API Endpoints | UI Components |
| Pharmacy Inventory (items + stock) | GET /shme/pharmacy/items, POST /shme/pharmacy/items, GET /shme/pharmacy/stock, POST /shme/pharmacy/stock | TanStack Table, Sheet (add item/stock), Badge (stock level) |
| Pharmacy Dispensing (prescriptions + dispense + sales + log) | POST /shme/pharmacy/prescriptions, POST /shme/pharmacy/dispense, POST /shme/pharmacy/sales, GET /shme/pharmacy/dispensing-log | Sheet (create prescription), Dialog (dispense/sale), TanStack Table (log), Input (quantity) |
10.1.4 Health Extensions (3 screens, 8 endpoints)
| Page | API Endpoints | UI Components |
| Referrals (incl. mental health) | GET /shme/referrals/pending, POST /shme/referrals, PUT /shme/referrals/:id/follow-up, POST /shme/mental-health | TanStack Table, Sheet (create referral), Dialog (follow-up), Sub-permission gate (health:mental-health.read) |
| Sports Clearance | GET /shme/sports-clearance/:studentId, POST /shme/sports-clearance | Form (clearance check), Card (status), Badge (cleared/restricted) |
| Health Analytics & Ministry Reports | GET /shme/analytics/dashboard, GET /shme/analytics/ministry-report | Recharts (dashboard panels), Stat Cards, Button (export ministry report) |
10.1.5 Enrollment Gate & Config (2 screens, 4 endpoints)
| Page | API Endpoints | UI Components |
| Enrollment Gate Check (medical clearance lookup) | GET /shme/enrollment-gate/:studentId, GET /shme/config/enrollment-check/:studentId | Form (student lookup), Card (gate status), Badge (pass/fail), List (failing checks) |
| Health Config | GET /shme/config, PUT /shme/config | Form (react-hook-form), Input (capacity/hours), Switch toggles, Select (ministry report format) |
10.2 Behavior & EWS SBME — 88 endpoints, 12 tags 100% coverage
Patched
2026-04-18 per PATCH_10.2_BEHAVIOR.md. 88/88 Swagger endpoints mapped. 3
scopes: school admin (82ep, 16 screens), student self-service (3ep, 3
screens), parent self-service (3ep, 1 screen). Feature-gated by behavior_management with 10 sub-gates. Biggest Phase 5 module. Parent screen blocked on new guardian permission canViewBehavior.
10.2.1 Behavior Core (3 screens, 14 endpoints)
| Page | API Endpoints | UI Components |
| Behavior Dashboard & Analytics | GET /sbme/dashboard, GET /sbme/summaries/student/:studentId, GET /sbme/summaries/class/:classId, GET /sbme/analytics | Recharts (trends, category breakdown), stat Cards, TanStack Table (recent events) |
| Behavior Events (record + bulk + void + history) | POST /sbme/events, POST /sbme/events/bulk, GET /sbme/events/:id, GET /sbme/events/student/:studentId, POST /sbme/events/:id/void | TanStack Table, Sheet (record event), Student picker, Select (category/polarity), Badge (positive/negative), Dropzone (evidence) |
| Behavior Categories | GET /
sbme/categories, POST /sbme/categories, PUT /sbme/categories/:id, PUT
/sbme/categories/:id/toggle, POST /sbme/categories/seed | TanStack Table, Sheet (create), Switch (active toggle), Badge (polarity) |
10.2.2 Early Warning System (2 screens, 11 endpoints)
| Page | API Endpoints | UI Components |
| EWS Dashboard & Signals | GET /
sbme/ews/dashboard, GET /sbme/ews/dashboard/trends, GET
/sbme/ews/signals/:studentId, POST /sbme/ews/detect, POST
/sbme/ews/detect/:studentId | Recharts (signal trends), stat Cards (by severity), Badge (WATCH/CONCERN/CRITICAL), Button (Run Detection) |
| EWS Rules (rules CRUD + templates + reset) | GET /
sbme/ews/rules, GET /sbme/ews/rules/templates, PUT /sbme/ews/rules/:id,
PUT /sbme/ews/rules/templates/:id, POST /sbme/ews/rules/reset, POST
/sbme/ews/rules/seed-templates | TanStack Table, Sheet (edit rule), Button (reset/seed) |
10.2.3 Interventions (5 screens, 30 endpoints)
| Page | API Endpoints | UI Components |
| At-Risk Alerts & Conduct Grades | GET /
sbme/at-risk/alerts, POST /sbme/at-risk/detect, POST
/sbme/at-risk/evaluate/:studentId, POST
/sbme/at-risk/alerts/:id/acknowledge, POST
/sbme/at-risk/alerts/:id/resolve, POST /sbme/conduct-grades/calculate | TanStack Table, Badge (severity), Dialog (acknowledge/resolve), Button (Calculate Term Conduct Grades) |
| Counseling Referrals | GET /
sbme/counseling-referrals, POST /sbme/counseling-referrals, POST
/sbme/counseling-referrals/:id/accept, POST
/sbme/counseling-referrals/:id/close, POST
/sbme/counseling-referrals/:id/sessions, PUT
/sbme/counseling-referrals/:id | TanStack Table, Sheet (create referral/session), Badge (PENDING→ACCEPTED→IN_PROGRESS→COMPLETED), Sub-permission gate (behavior:mental-health.read) |
| Peer Reports (Admin Review) (triage + resolve + stats) | GET /sbme/peer-reports, GET /sbme/peer-reports/stats, POST /sbme/peer-reports/:id/resolve, PUT /sbme/peer-reports/:id/triage | TanStack Table, Dialog (triage/resolve), Badge (anonymous/identified), Recharts (stats) |
| Restorative Actions | GET /
sbme/restorative-actions/pending, GET
/sbme/restorative-actions/student/:studentId, POST
/sbme/restorative-actions, POST /sbme/restorative-actions/:id/complete,
PUT /sbme/restorative-actions/:id | TanStack Table, Sheet (assign action), Badge (pending/completed), Dialog (complete with notes) |
| Escalations & Hearings (tabbed: Pathways, Active) | GET /
sbme/escalation-pathways, POST /sbme/escalation-pathways, PUT
/sbme/escalation-pathways/:id, GET /sbme/escalations/student/:studentId,
POST /sbme/escalations, POST /sbme/escalations/:id/submit-defense, POST
/sbme/escalations/:id/schedule-hearing, POST
/sbme/escalations/:id/hearing-outcome, POST
/sbme/escalations/:id/appeal, POST /sbme/escalations/:id/resolve | Tabs,
TanStack Table, Sheet (escalate/defense), Dialog (schedule hearing,
outcome, appeal, resolve), Timeline view, Badge (status) |
10.2.4 Positive Reinforcement (2 screens, 8 endpoints)
| Page | API Endpoints | UI Components |
| Behavioral Contracts (Admin) | GET /sbme/contracts/student/:studentId, POST /sbme/contracts, PUT /sbme/contracts/:id, POST /sbme/contracts/:id/review | TanStack Table, Sheet (create contract), Dialog (review), Badge (unsigned/active/completed), Checkbox (conditions) |
| Recognition & Rewards (Admin) (legacy operator UI; primary catalog is now AwardsPME §12.5 — SBME rewards mirror in via POST /awardspme/seed/sbme-mirror) | GET /sbme/rewards/recognition-board, POST /sbme/rewards, PUT /sbme/rewards/:id, POST /sbme/rewards/:id/award | Card grid (recognition board), Sheet (create reward/award to student), Badge (milestone). Recommendation: keep for behavior-specific reward CRUD; for unified catalog + multi-prize bundles + auto-derivation use AwardsPME. |
10.2.5 Config, Houses, Groups, Templates (4 screens, 18 endpoints)
| Page | API Endpoints | UI Components |
| Behavior Config | GET /sbme/config, PUT /sbme/config | Form (react-hook-form), Switch toggles |
| Houses & Leaderboard | GET /
sbme/houses, GET /sbme/houses/leaderboard, POST /sbme/houses, PUT
/sbme/houses/:id, POST /sbme/houses/:id/assign, POST
/sbme/houses/:id/bulk-assign, POST /sbme/houses/reset-term-points, POST
/sbme/houses/reset-year-points | TanStack Table, Leaderboard view (ranked cards), Sheet (create/assign), Button (reset term/year), Dialog (bulk assign) |
| Behavior Groups | GET
/sbme/groups, POST /sbme/groups, PUT /sbme/groups/:id, POST
/sbme/groups/:id/add-students, POST /sbme/groups/:id/remove-students | TanStack Table, Sheet (create group), Multi-select (add/remove students) |
| Behavior Templates | GET /sbme/templates, GET /sbme/templates/:code/preview, POST /sbme/templates/:code/apply | TanStack Table, Dialog (preview), Button (apply to tenant) |
10.2.6 Student Self-Service 🆕 (3 screens, 3 endpoints)
Role-filtered nav for activeRole=student per shell architecture §17.
| Page | Portal | API Endpoints | UI Components |
| Submit Peer Report | Student | POST /sbme/peer-reports | Form
(categories: bullying/harassment/etc.), Toggle (anonymous — default on
for bullying), Textarea (description), Attachment picker |
| My Behavior Contract (view + sign) | Student | POST /sbme/contracts/:id/sign (reads contract via own GET /contracts/student/:studentId) | Card (contract terms), Checkbox (acknowledge each condition), Button (Sign), Badge (signed/unsigned) |
| My Rewards (legacy SBME-only view; unified self-service is AwardsPME §12.5 Screen 14 "Student Awards") | Student | GET /sbme/rewards/student/:studentId (with own studentId) | Card grid (SBME-only rewards). Recommendation:
deprecate in favor of AwardsPME GET /awardspme/students/:id/awards
which federates StuLCE + SBME + AwardsPME into a single timeline. |
10.2.7 Parent Self-Service 🆕 (1 screen, 3 endpoints)
Role-filtered nav for activeRole=parent + activeStudentId per shell architecture §19. Gated by new guardian permission canViewBehavior.
| Page | API Endpoints | UI Components |
| Child's Behavior (tabbed: Feed, Digest, Transcript) | GET /sbme/parent-feed/:studentId, GET /sbme/parent-digest/:studentId, POST /sbme/transcripts/:studentId | Tabs, Timeline (feed), Card (digest summary), Button (Generate Transcript — triggers DTGE template render) |
10.3 Library LME — 95 endpoints, 14 tags 100% coverage
Patched
2026-04-18 per PATCH_10.3_LIBRARY.md. 95/95 Swagger endpoints mapped. 3
scopes: school admin (88ep, 21 screens), student self-service (7ep, 5
screens), parent self-service (reuses student screens with
activeStudentId). Feature-gated by library_management with 7 sub-gates. Parent screens gated on new guardian permission canViewLibrary.
10.3.1 Reports Suite (6 screens, 6 endpoints)
Dedicated screen per report — each has distinct data shape and audience.
| Page | API Endpoints | UI Components |
| Library Dashboard | GET /lme/reports/dashboard | Stat Cards (in-circulation, overdue, holds), Recharts (high-level trends) |
| Circulation Report | GET /lme/reports/circulation | Recharts (checkout/return trends over time), Select (date range) |
| Collection Report | GET /lme/reports/collection | TanStack Table, Recharts (by category/condition), filter controls |
| Most-Borrowed Report | GET /lme/reports/most-borrowed | Ranked list (top-N), Badge (category), Card (book detail) |
| Overdue Report | GET /lme/reports/overdue | TanStack Table, Badge (days overdue), Button (send reminder) |
| Patron Activity Report | GET /lme/reports/patron-activity | TanStack Table (ranked patrons), Recharts (activity distribution) |
10.3.2 Catalogue (1 screen, 7 endpoints)
| Page | API Endpoints | UI Components |
| Catalogue (bibliographic records) | GET /
lme/catalogue, GET /lme/catalogue/:id, GET /lme/catalogue/isbn/:isbn,
POST /lme/catalogue, POST /lme/catalogue/import, PUT /lme/catalogue/:id,
PUT /lme/catalogue/:id/withdraw | TanStack Table, Sheet (add/edit), ISBN lookup input, Dropzone (bulk import), Badge (type), Dialog (withdraw) |
10.3.3 Physical Holdings (2 screens, 13 endpoints)
| Page | API Endpoints | UI Components |
| Inventory (Copies) (physical book copies — tabbed: List, Barcode Scanner) | GET /
lme/copies, GET /lme/copies/:id, GET /lme/copies/barcode/:barcode, POST
/lme/copies, POST /lme/copies/bulk, PUT /lme/copies/:id, PUT
/lme/copies/:id/mark-lost, PUT /lme/copies/:id/transfer, PUT
/lme/copies/:id/withdraw | Tabs, TanStack Table, Barcode scanner (camera API + keyboard emulation), Sheet (add/bulk), Dialog (mark-lost/transfer/withdraw) |
| Locations (library sections/shelves) | GET /lme/locations, POST /lme/locations, PUT /lme/locations/:id, DELETE /lme/locations/:id | TanStack Table, Sheet (create/edit), Dialog (delete) |
10.3.4 Circulation & Holds (3 screens, 21 endpoints)
| Page | API Endpoints | UI Components |
| Circulation (checkout/return/renew/overdue) | GET /
lme/circulation/:id, GET /lme/circulation/overdue, POST
/lme/circulation/checkout, POST /lme/circulation/return, POST
/lme/circulation/bulk-checkout, POST /lme/circulation/bulk-return, PUT
/lme/circulation/:id/renew | TanStack Table, Sheet (checkout/return: scan barcode), Bulk checkout UI, Badge (status), Card (patron summary) |
| Holds (book reservations) | GET /
lme/holds/item/:catalogueItemId, POST /lme/holds, POST
/lme/holds/process-expired, PUT /lme/holds/:id/cancel, PUT
/lme/holds/:id/fulfill | TanStack Table, Sheet (create hold), Badge (WAITING/READY/FULFILLED), Button (fulfill/cancel), Button (process expired) |
| Library Cards (patron card management) | GET /
lme/cards, GET /lme/cards/:id, POST /lme/cards, POST
/lme/cards/activate-on-payment, POST /lme/cards/:id/suspend, POST
/lme/cards/:id/lift-block, POST /lme/cards/:id/renew, POST
/lme/cards/:id/replace, POST /lme/cards/:id/revoke | TanStack
Table, Sheet (issue card), Badge (ACTIVE/SUSPENDED/REVOKED), Dialog
(card actions with notes), Toggle (Activate on Payment flag) |
10.3.5 Fines & Stock-Take (2 screens, 12 endpoints)
| Page | API Endpoints | UI Components |
| Fines (Admin) (summary + manual + waive + reconcile) | GET /lme/fines/summary, POST /lme/fines, POST /lme/fines/calculate, PUT /lme/fines/:id/waive, POST /lme/fines/:id/reconcile | Stat Cards (summary), Sheet (manual fine), Button (calculate fines), Dialog (waive with reason), Badge (PENDING/PAID/WAIVED) |
| Stock-Take (periodic physical audit — phased: start → scan → reconcile → complete) | POST /
lme/stock-take, POST /lme/stock-take/:id/scan, POST
/lme/stock-take/:id/bulk-scan, POST /lme/stock-take/:id/reconcile, PUT
/lme/stock-take/:id/complete, GET /lme/stock-take/:id/progress, GET
/lme/stock-take/:id/report | Wizard (phases), Progress bar
(scanned/expected), Input (barcode scan), Bulk scan mode, Dialog
(reconcile differences), Button (complete), TanStack Table (final
report) |
10.3.6 Textbooks (2 screens, 13 endpoints)
| Page | API Endpoints | UI Components |
| Textbook Distributions (term-level distribution campaigns) | GET /
lme/textbooks/distributions, GET /lme/textbooks/distributions/:id, GET
/lme/textbooks/distributions/:id/dashboard, POST
/lme/textbooks/distributions, PUT /lme/textbooks/distributions/:id, PUT
/lme/textbooks/distributions/:id/complete | TanStack Table, Sheet (create distribution), Dashboard (per-distribution stats), Button (complete distribution) |
| Textbook Assignments (per-student textbook issuance) | GET /
lme/textbooks/condition-report, GET /lme/textbooks/student-ratio, POST
/lme/textbooks/assign, POST /lme/textbooks/bulk-assign, POST
/lme/textbooks/return, POST /lme/textbooks/bulk-return, PUT
/lme/textbooks/assignments/:id/report-lost | TanStack Table, Bulk assign UI (class picker), Sheet (individual assign), Dialog (return/report-lost), Condition report view |
10.3.7 Digital + Reading + Clearance + Config (5 screens, 16 endpoints)
| Page | API Endpoints | UI Components |
| Digital Resources (e-books, journals) | GET /lme/digital, GET /lme/digital/:id/access, POST /lme/digital, POST /lme/digital/:id/checkout, PUT /lme/digital/:id | TanStack Table, Sheet (add resource), Button (get access — signed URL), Reader component (react-pdf/epub.js) |
| Reading Lists (curated lists) | GET /
lme/reading-lists, GET /lme/reading-lists/:id, POST /lme/reading-lists,
PUT /lme/reading-lists/:id, PUT /lme/reading-lists/:id/publish | TanStack Table, Sheet (create list), Book picker, Button (publish), Badge (draft/published) |
| Reading Leaderboard (public-facing recognition board) | GET /lme/reading/leaderboard | Ranked cards (top readers), Badge (levels/milestones), Public-display mode (for classroom screens) |
| Clearance (graduation library clearance check) | GET /lme/clearance/:studentId, GET /lme/clearance/:studentId/record | Student lookup form, Card (clearance status), Badge (cleared/blocked), List (outstanding items) |
| Library Config | GET /lme/config, POST /lme/config, PUT /lme/config | Form (react-hook-form), Switch toggles, Input (loan days, max items, fine rates) |
10.3.8 Student Self-Service 🆕 (5 screens, 7 endpoints)
Role-filtered nav for activeRole=student per shell architecture §17. Parent reuses via activeRole=parent + activeStudentId.
| Page | Portal | API Endpoints | UI Components |
| OPAC — Public Catalogue Search | Student + Parent + Public | GET /lme/catalogue/search (@Public) | Search input, TanStack Table (results), Card (book detail), Button (place hold) |
| My Borrowings | Student + Parent | GET /lme/circulation/patron/:patronId, GET /lme/circulation/patron/:patronId/status | Card (current borrowings), Badge (due dates), Button (renew), Card (patron status: can borrow / blocked) |
| My Holds | Student + Parent | GET /lme/holds/patron/:patronId | Card list (active holds), Badge (WAITING/READY), Button (cancel) |
| My Fines | Student + Parent | GET /lme/fines/patron/:patronId | Card (outstanding fines), Badge (PENDING/PAID/WAIVED), Button (Pay from Wallet → ACCTE fee-bridge) |
| My Reading (tabbed: Stats, Goals) | Student | GET /lme/reading/stats/:patronId, POST /lme/reading/goals | Stat Cards (books read, minutes, level), Form (set goal), Progress bar (toward goal), Badge (milestones) |
10.4 Hostel HME — 57 endpoints, 9 tags 100% coverage
Patched
2026-04-19 per PATCH_10.4_HOSTEL.md. 57/57 Swagger endpoints mapped. 3
scopes: school admin (54ep, 10 screens), student self-service (3ep, 3
screens), parent self-service (reuses student screens with
activeStudentId). Feature-gated by hostel_management with 6 sub-gates. Parent screens gated on new guardian permission canViewHostel.
10.4.1 Operations (1 screen, 6 endpoints)
| Page | API Endpoints | UI Components |
| Operations Dashboard (tabbed: Occupancy, Allocation Summary, Exeat Summary, Inspection Summary, Roll Call) | GET /
hme/ops/dashboard/occupancy, GET /hme/ops/dashboard/allocation-summary,
GET /hme/ops/dashboard/exeat-summary, GET
/hme/ops/dashboard/inspection-summary, GET /hme/ops/roll-calls, POST
/hme/ops/roll-call | Tabs, Recharts (occupancy %), Stat Cards (by dashboard), TanStack Table (roll call sessions), Sheet (new roll call) |
10.4.2 Infrastructure (3 screens, 16 endpoints)
Hostel → Rooms → Beds hierarchy. Separate screens for deep-linking.
| Page | API Endpoints | UI Components |
| Hostels (list + detail + occupancy + rooms-in-hostel) | GET /
hme/infra/hostels, GET /hme/infra/hostels/:hostelId, POST
/hme/infra/hostels, PUT /hme/infra/hostels/:hostelId, DELETE
/hme/infra/hostels/:hostelId, GET
/hme/infra/hostels/:hostelId/occupancy, GET
/hme/infra/hostels/:hostelId/rooms | TanStack Table, Sheet (create/edit), Card (occupancy %), Dialog (delete), Badge (status) |
| Rooms (room CRUD + beds-in-room) | GET /
hme/infra/rooms/:roomId, POST /hme/infra/rooms, PUT
/hme/infra/rooms/:roomId, DELETE /hme/infra/rooms/:roomId, GET
/hme/infra/rooms/:roomId/beds | TanStack Table, Sheet (create/edit), Dialog (delete), Select (parent hostel) |
| Beds (bed CRUD) | GET /hme/infra/beds/:bedId, POST /hme/infra/beds, PUT /hme/infra/beds/:bedId, DELETE /hme/infra/beds/:bedId | TanStack Table, Sheet (create/edit), Dialog (delete), Select (parent room), Badge (occupied/available) |
10.4.3 Allocations & Exeat (2 screens, 13 endpoints)
| Page | API Endpoints | UI Components |
| Allocations (manual + auto + preferences + reassign + end) | GET /
hme/allocation, GET /hme/allocation/preferences, POST
/hme/allocation/assign, POST /hme/allocation/auto-allocate, PUT
/hme/allocation/:allocationId/reassign, PUT
/hme/allocation/:allocationId/end | TanStack Table, Sheet (manual
assign), Switch (dryRun), Button (auto-allocate with preview), Dialog
(reassign/end), Badge (ACTIVE/VACATED) |
| Exeat Admin (approve/reject/cancel/confirm-return + overdue) | GET /
hme/exeat, GET /hme/exeat/:exeatId, GET /hme/exeat/overdue, PUT
/hme/exeat/:exeatId/approve, PUT /hme/exeat/:exeatId/reject, PUT
/hme/exeat/:exeatId/cancel, PUT /hme/exeat/:exeatId/confirm-return | TanStack
Table (tabbed: Pending, Approved, Overdue), Dialog (approve/reject with
notes), Button (confirm return), Badge
(PENDING→APPROVED→RETURNED/OVERDUE) |
10.4.4 Inspections & Visitors (2 screens, 8 endpoints)
| Page | API Endpoints | UI Components |
| Inspections (schedule + findings) | GET /hme/inspections, GET /hme/inspections/:inspectionId, POST /hme/inspections, PUT /hme/inspections/:inspectionId/findings | TanStack Table, Sheet (schedule), Form (findings — rating + notes + attachments), Badge (PASS/FAIL/PENDING) |
| Visitors (sign-in + active + log) | GET /hme/visitors, GET /hme/visitors/active/:hostelId, POST /hme/visitors/sign-in, PUT /hme/visitors/:visitorLogId/sign-out | TanStack
Table (log), Card (active visitors per hostel), Sheet (sign-in with
photo), Button (sign-out), Badge (signed-in/signed-out) |
10.4.5 Staff & Fees (2 screens, 11 endpoints)
| Page | API Endpoints | UI Components |
| Hostel Staff (tabbed: Managers, Captains) | GET /
hme/staff/managers, POST /hme/staff/managers, PUT
/hme/staff/managers/:managerId, DELETE /hme/staff/managers/:managerId,
POST /hme/staff/captains, PUT /hme/staff/captains/:captainId, DELETE
/hme/staff/captains/:captainId | Tabs, TanStack Table, Sheet (assign), Dialog (remove with confirmation), Badge (role: manager=staff, captain=student prefect) |
| Hostel Fees (cascade configs by hostel/room/bed) | GET /hme/fees/config, GET /hme/fees/config/:configId, POST /hme/fees/config, PUT /hme/fees/config/:configId | TanStack Table, Sheet (set fee), Select (cascade level: bed/room/hostel), Input (amount + currency) |
10.4.6 Student Self-Service 🆕 (3 screens, 3 endpoints)
Role-filtered nav for activeRole=student per shell architecture §17. Parent reuses via activeRole=parent + activeStudentId.
| Page | Portal | API Endpoints | UI Components |
| My Hostel Allocation (view own allocation + room + bed) | Student + Parent | GET /hme/allocation/student/:studentId (with own studentId) | Card (allocation detail: hostel, room, bed, roommates), Badge (active/vacated) |
| My Hostel Preferences (submit preferences before allocation) | Student | POST /hme/allocation/preferences | Form (preferred hostel/room/roommate), Lock indicator (preference window open/closed), Button (submit) |
| Submit Exeat (request leave — exit permission) | Student + Parent | POST /hme/exeat | Sheet (exeat form: destination, reason, dates, guardian), DatePicker (start/end), Badge (status after submit) |
10.5 Canteen RCM — 32 endpoints, 1 tag 100% coverage
Patched
2026-04-20 per PATCH_10.5_CANTEEN.md. 32/32 Swagger endpoints mapped. 3
scopes: school admin (31ep, 10 screens), student self-service (1ep, 1
screen), parent self-service (reuses student screen with
activeStudentId). Feature-gated by canteen_management with 5 sub-gates. Parent screen gated on new guardian permission canViewCanteen.
10.5.1 Meal Planning (3 screens, 14 endpoints)
| Page | API Endpoints | UI Components |
| Meal Plans Catalogue (plan templates CRUD + assign) | GET /
rcm/meal-plans, GET /rcm/meal-plans/:id, POST /rcm/meal-plans, PATCH
/rcm/meal-plans/:id, DELETE /rcm/meal-plans/:id, POST
/rcm/meal-plans/:id/assign | TanStack Table, Sheet (create/edit), Select (meal types, days), Input (price), Button (assign to students) |
| Student Plan Assignments (per-student plan + suspend/resume/end) | GET /
rcm/students/:studentId/meal-plans, POST
/rcm/students/:studentId/meal-plans/bulk-assign, PATCH
/rcm/student-meal-plans/:id/suspend, PATCH
/rcm/student-meal-plans/:id/resume, PATCH
/rcm/student-meal-plans/:id/end | TanStack Table, Button (bulk assign boarders), Badge (ACTIVE/SUSPENDED/ENDED), Dialog (suspend/resume/end with reason) |
| Menu Schedule (weekly/monthly menu planning) | GET /rcm/menu-schedule, POST /rcm/menu-schedule, PATCH /rcm/menu-schedule/:id | Grid (day × meal type), DnD (menu items to slots), Sheet (create schedule), Badge (active period) |
10.5.2 Meal Service (2 screens, 7 endpoints)
| Page | API Endpoints | UI Components |
| Meal Sessions (session CRUD + open/close lifecycle) | GET /rcm/sessions, GET /rcm/sessions/:id, POST /rcm/sessions, PATCH /rcm/sessions/:id/open, PATCH /rcm/sessions/:id/close | TanStack Table, Badge (SCHEDULED→OPEN→CLOSED), Button (open/close), Sheet (create session) |
| Check-In (student check-in at session) | POST /rcm/sessions/:sessionId/check-in, GET /rcm/sessions/:sessionId/check-ins | TanStack
Table (check-ins), Barcode scanner input, Badge
(entitlement/wallet/complimentary), Alert (dietary/allergy from SHME
refectory-alerts) |
10.5.3 Tables (1 screen, 5 endpoints)
| Page | API Endpoints | UI Components |
| Tables (dining tables + student assignments) | GET /
rcm/tables, POST /rcm/tables, PATCH /rcm/tables/:id, POST
/rcm/tables/:tableId/assign, DELETE
/rcm/tables/:tableId/assign/:studentId | TanStack Table, Sheet (create table), Input (capacity), Dialog (assign/unassign student) |
10.5.4 Reports Suite (3 screens, 3 endpoints)
| Page | API Endpoints | UI Components |
| Meal Attendance Report | GET /rcm/reports/meal-attendance | Recharts (attendance trends), TanStack Table (per-session), Select (date range) |
| Plan Uptake Report | GET /rcm/reports/plan-uptake | Recharts (plan distribution), Card (stats per plan), TanStack Table |
| Dietary Summary Report | GET /rcm/reports/dietary-summary | Stat Cards (halal/vegetarian/allergies), TanStack Table (per-student dietary flags) |
10.5.5 Config (1 screen, 2 endpoints)
| Page | API Endpoints | UI Components |
| Canteen Config | GET /rcm/config, PUT /rcm/config | Form (react-hook-form), Select (default charge source: entitlement/wallet/cash), Switch (toggle features) |
10.5.6 Student Self-Service 🆕 (1 screen, 1 endpoint)
Role-filtered nav for activeRole=student per shell architecture §17. Parent reuses via activeRole=parent + activeStudentId.
| Page | Portal | API Endpoints | UI Components |
| My Meal History | Student + Parent | GET /rcm/students/:studentId/meal-history (with own studentId) | Timeline view (meal sessions attended), Badge (entitlement/wallet/complimentary), Filter (date range) |
10.6 Transport TME — 62 endpoints, 10 tags 100% coverage
Patched
2026-04-20 per PATCH_10.6_TRANSPORT.md. 62/62 Swagger endpoints mapped.
3 scopes: school admin (61ep, 16 screens), student self-service (1ep, 1
screen), parent self-service (reuses student screen with
activeStudentId). Feature-gated by transport_management with 6 sub-gates. Parent screen gated on new guardian permission canViewTransport. Final module of Phase 5.
10.6.1 Analytics Suite (4 screens, 4 endpoints)
| Page | API Endpoints | UI Components |
| Fleet Analytics | GET /tme/analytics/fleet | Recharts (fleet utilization), Stat Cards (active/maintenance/idle) |
| Routes Analytics | GET /tme/analytics/routes | Recharts (route usage trends), TanStack Table (per-route stats) |
| Maintenance Due Report | GET /tme/analytics/maintenance-due | TanStack Table (vehicles due for service), Badge (overdue/due-soon) |
| Safety Analytics | GET /tme/analytics/safety | Recharts (incident trends), Stat Cards (by severity) |
10.6.2 Fleet & People (2 screens, 11 endpoints)
| Page | API Endpoints | UI Components |
| Vehicles (fleet registry) | GET /tme/vehicles, GET /tme/vehicles/:id, POST /tme/vehicles, PUT /tme/vehicles/:id, DELETE /tme/vehicles/:id | TanStack Table, Sheet (register), Badge (status), Input (capacity, registration) |
| Drivers (registry + timetable) | GET /
tme/drivers, GET /tme/drivers/:id, GET /tme/drivers/:id/timetable, POST
/tme/drivers, PUT /tme/drivers/:id, DELETE /tme/drivers/:id | TanStack Table, Sheet (create), Dropzone (license upload), Weekly grid (timetable) |
10.6.3 Routes & Operations (5 screens, 26 endpoints)
| Page | API Endpoints | UI Components |
| Routes (route CRUD) | GET /tme/routes, GET /tme/routes/:id, POST /tme/routes, PUT /tme/routes/:id, DELETE /tme/routes/:id | TanStack Table, Sheet (create route), Badge (active), Map preview |
| Stops (per-route stops + reorder) | GET /
tme/routes/:routeId/stops, POST /tme/routes/:routeId/stops, PUT
/tme/routes/stops/:stopId, DELETE /tme/routes/stops/:stopId, PATCH
/tme/routes/:routeId/stops/reorder | TanStack Table, DnD (dnd-kit for stop ordering), Sheet (add/edit stop), Map marker view |
| Schedules (recurring schedules + auto-generate trips) | GET /
tme/schedules, GET /tme/schedules/:id/trips, POST /tme/schedules, PUT
/tme/schedules/:id, DELETE /tme/schedules/:id, POST
/tme/schedules/:id/generate-trips | TanStack Table, Sheet (create), Button (generate trips — dry-run + commit), Progress (polling) |
| Trips (lifecycle: create → start → delay → complete) | GET /
tme/trips, GET /tme/trips/:id, POST /tme/trips, PUT /tme/trips/:id,
PATCH /tme/trips/:id/start, PATCH /tme/trips/:id/delay, PATCH
/tme/trips/:id/complete | TanStack Table, Sheet (log trip), DatePicker, Badge (SCHEDULED/IN_PROGRESS/DELAYED/COMPLETED), Action buttons by state |
| Vehicle Assignments (driver↔vehicle) | GET /
tme/drivers/vehicle-assignments, POST /tme/drivers/vehicle-assignments,
DELETE /tme/drivers/vehicle-assignments/:assignmentId | TanStack Table (assignment matrix), Sheet (assign), Badge (primary/backup) |
10.6.4 Enrollment & Fees (2 screens, 7 endpoints)
| Page | API Endpoints | UI Components |
| Student Enrollment (enroll + route capacity check) | GET /
tme/enrollment, POST /tme/enrollment, PUT /tme/enrollment/:id, DELETE
/tme/enrollment/:id, GET /tme/enrollment/route/:routeId/capacity | TanStack Table, Sheet (enroll student), Card (route capacity: X of Y seats), Select (route/stop) |
| Transport Fees Config | GET /tme/enrollment/fees/config, POST /tme/enrollment/fees/config | Form (react-hook-form), Input (fee per route / per km / flat), Select (billing cycle) |
10.6.5 Service Operations (3 screens, 13 endpoints)
| Page | API Endpoints | UI Components |
| Transport Attendance (bulk/single record + per-trip) | POST /tme/attendance/record, POST /tme/attendance/bulk-record, GET /tme/attendance/trip/:tripId | Mobile-first UI, Barcode/QR scanner, Per-stop tap list, Offline mode, TanStack Table (per-trip roster) |
| Incidents (report + resolve) | GET /tme/incidents, GET /tme/incidents/:id, POST /tme/incidents, PUT /tme/incidents/:id/resolve | TanStack
Table, Sheet (report), Dialog (resolve with outcome), Textarea
(description), Select (type: accident/behavior/mechanical/medical),
Badge (severity) |
| Maintenance & Inspections (tabbed: Maintenance Log, Insurance, Inspections) | POST /
tme/maintenance, GET /tme/maintenance/vehicle/:vehicleId, GET
/tme/maintenance/due-soon, GET /tme/maintenance/insurance-expiring, GET
/tme/maintenance/inspections/vehicle/:vehicleId, POST
/tme/maintenance/inspections | Tabs, TanStack Table, Sheet (log
maintenance — create-only, immutable), Sheet (log inspection),
DatePicker, Badge (due/overdue/expiring) |
10.6.6 Student Self-Service 🆕 (1 screen, 1 endpoint)
Role-filtered nav for activeRole=student per shell architecture §17. Parent reuses via activeRole=parent + activeStudentId.
| Page | Portal | API Endpoints | UI Components |
| My Transport Attendance | Student + Parent | GET /tme/attendance/student/:studentId (with own studentId) | Timeline (trips attended), Badge (on-time/late/absent), Filter (date range) |
11. Phase 6 — Communication & Collaboration
11.1 Notifications NSE — 34 endpoints, 7 tags 100% coverage
Patched
2026-04-21 per PATCH_11.1_NOTIFICATIONS.md, expanded 2026-05-08 (admin
analytics + audience options). 34/34 Swagger endpoints
mapped (notification surface — excludes 41 messaging sub-endpoints in
11.2). 2 scopes: school admin (25ep, 6 screens), all-persona
self-service (9ep, 3 screens). Feature-gated by notifications_system (always on).
11.1.1 School Admin — Operations (2 screens, 14 endpoints)
| Page | API Endpoints | UI Components |
| Notification Templates | GET /
nse/templates, POST /nse/templates, PUT /nse/templates/:id, DELETE
/nse/templates/:id, POST /nse/templates/:id/preview, POST
/nse/templates/:id/reset, POST /nse/admin/master-templates/seed | TanStack Table, Sheet (create/edit), Tabs (email/SMS/push/inApp preview), Button (reset), Button (seed masters) |
| Notifications Analytics (tabbed: Stats / Conversations / Messages search) | GET /nse/logs, GET /nse/logs/analytics, GET /nse/logs/sms-costs, GET /nse/messaging/admin/stats, GET /nse/messaging/admin/timeseries, GET /nse/messaging/admin/top, GET /nse/messaging/admin/audience-options | Recharts (area chart for daily volume, pie for type breakdown), TanStack Table (logs + conversations), Top senders / Top conversations / Top auto-post sources cards, Card (cost report) |
11.1.2 School Admin — Channels & Providers (3 screens, 10 endpoints)
| Page | API Endpoints | UI Components |
| Channels (outbound: email/WhatsApp/push) | GET /nse/channels, POST /nse/channels, DELETE /nse/channels/:id, POST /nse/channels/:id/test | TanStack Table, Sheet (configure), Select (type), Button (test — sends to admin's inbox) |
| SMS Gateways (multi-gateway country routing) | GET /nse/sms-gateways, POST /nse/sms-gateways, DELETE /nse/sms-gateways/:id | TanStack Table, Sheet (configure), Country coverage matrix |
| Provider Registry (platform providers + schema + test) | GET /nse/providers, GET /nse/providers/:code/schema, POST /nse/providers/:code/test | Card grid (Twilio/SendGrid/FCM/etc.), Badge (configured/not), Dialog (schema view), Button (live test) |
11.1.3 School Admin — User Preferences Admin (1 screen, 1 endpoint)
| Page | API Endpoints | UI Components |
| User Notification Preferences Admin (support view) | GET /nse/preferences/user/:userId | User picker, Read-only Form (channel toggles for that user) |
11.1.4 All-Persona Self-Service 🆕 (3 screens, 9 endpoints)
Top-level routes visible to every logged-in user (student, staff, teacher, parent, admin, super-admin).
| Page | Route | API Endpoints | UI Components |
| Inbox (in-app notifications center) | /inbox | GET /nse/inbox, GET /nse/inbox/count, POST /nse/inbox/:id/read, POST /nse/inbox/read-all | TanStack Table, Badge (unread count), Button (mark all read), Infinite scroll |
| Notification Preferences (channel toggles per event) | /settings/notifications | GET /nse/preferences/me, PUT /nse/preferences/me | Form (per-channel switches per event type), Note (email/inApp cannot be disabled) |
| My Devices (push notification tokens) | /settings/devices | GET /nse/devices/me, POST /nse/devices, DELETE /nse/devices/:id | Card list (registered devices), Button (Revoke), Badge (current device) |
11.2 Messaging MSGE — 41 endpoints, 7 tags, under /nse/messaging/ 100% coverage
Patched 2026-04-21 per PATCH_11.2_MESSAGING.md, expanded 2026-05-08 (broadcast audience builder + scheduled broadcasts). 41/41 Swagger endpoints mapped. Critical plan correction: MSGE lives at /nse/messaging/..., not /msge/....
MSGE is a subsystem of NSE. 3 scopes: all-persona self-service (25ep, 4
screens), school admin moderation (8ep, 3 screens), school admin broadcast & scheduling (8ep, 2 screens). Feature-gated by messaging_system.
WebSocket gateway (verified in code): Socket.IO at wss://api.academia.vivabox.net/messaging, Authentik JWT on handshake, rooms per conversation (conversation:${id}). Client events: message:send, message:typing, message:read. Server events: message:new, user:online/offline, user:typing, read:receipt.
11.2.1 All-Persona Self-Service Messaging 🆕 (4 screens, 25 endpoints)
Top-level routes at /messages/ (not nested under /dashboard/school/...). Reason: parent with kids at multiple schools needs unified inbox across tenants.
| Page | Route | API Endpoints | UI Components |
| Conversations (list + create + view + archive + delete) | /messages | GET /
nse/messaging/conversations, GET /nse/messaging/conversations/:id, POST
/nse/messaging/conversations, PUT /nse/messaging/conversations/:id, POST
/nse/messaging/conversations/:id/archive, DELETE
/nse/messaging/conversations/:id | List sidebar + chat panel (resizable-panels), Avatar, Badge (unread via WS), Sheet (new conversation), Dialog (archive/delete) |
| Topics (sub-threads within conversation) | /messages/[conversationId]/topics | GET /
nse/messaging/conversations/:conversationId/topics, POST
/nse/messaging/conversations/:conversationId/topics, PUT
/nse/messaging/conversations/:conversationId/topics/:slug, POST
/nse/messaging/conversations/:conversationId/topics/:slug/archive, POST
/nse/messaging/conversations/:conversationId/topics/:topicId/mute | Tabs (per topic), Badge (write permission), Button (archive/mute), Select (permission level) |
| Messages (read/compose/edit/delete/pin within topic) | /messages/[conversationId]/topics/[slug] | GET /
nse/messaging/conversations/:conversationId/topics/:slug/messages, POST
/nse/messaging/conversations/:conversationId/topics/:slug/messages, PUT
/nse/messaging/conversations/:conversationId/messages/:messageId, DELETE
/nse/messaging/conversations/:conversationId/messages/:messageId, POST
/nse/messaging/conversations/:conversationId/messages/:messageId/pin,
GET /nse/messaging/conversations/:conversationId/topics/:slug/pinned,
GET /nse/messaging/conversations/:conversationId/unread, POST
/nse/messaging/conversations/:conversationId/topics/:slug/read | Message list (cursor pagination), Textarea (compose), Button (send — emits WS message:send), WebSocket listener (message:new), Edit/delete (permission-gated), Pin (admin/owner) |
| Participants (manage members + mute + leave) | /messages/[conversationId]/participants | GET /
nse/messaging/conversations/:conversationId/participants, POST
/nse/messaging/conversations/:conversationId/participants, PUT
/nse/messaging/conversations/:conversationId/participants/:userId,
DELETE
/nse/messaging/conversations/:conversationId/participants/:userId, POST
/nse/messaging/conversations/:conversationId/participants/:userId/mute,
POST /nse/messaging/conversations/:conversationId/participants/leave | TanStack Table, Sheet (add participant), Select (role: OWNER/ADMIN/MEMBER/READONLY), Button (mute/leave/remove) |
11.2.2 School Admin — Moderation & Config (3 screens, 8 endpoints)
| Page | Route | API Endpoints | UI Components |
| Messaging Admin (tabbed: Stats / Conversations / Messages search) | /dashboard/school/[tenantId]/messaging/admin | GET /nse/messaging/admin/conversations, GET /nse/messaging/admin/messages, GET /nse/messaging/admin/stats, GET /nse/messaging/admin/timeseries, GET /nse/messaging/admin/top | Tabs, SearchInput, TanStack Table, Stat Cards, Recharts area chart (14-day timeseries), Pie (type breakdown), Top senders / conversations / source modules |
| Auto-Post Config (events that auto-post into conversations) | /dashboard/school/[tenantId]/messaging/auto-post | GET /
nse/messaging/auto-post-config, PUT
/nse/messaging/auto-post-config/:eventKey, POST
/nse/messaging/auto-post-config/seed-templates, POST
/nse/messaging/auto-post-config/reset | Cards grouped by source engine, Switch per event key, Button (seed defaults / reset), Search |
11.2.3 School Admin — Broadcast & Scheduling 🆕 (2 screens, 8 endpoints) — BUILT 2026-05-08
Major UX upgrade from the v2.0 plan: replaced the legacy single-UUID broadcast with a full audience builder. Resolves to userIds via the same engine used by Tenant Groups (§11.3). Recipients pane shows live name list with manual exclude. Scheduled broadcasts dispatched by @nestjs/schedule cron worker every minute.
| Page | Route | API Endpoints | UI Components |
| Broadcast (audience builder + recipients pane + send-now / schedule) | /dashboard/school/[tenantId]/messaging/broadcast | POST /nse/messaging/admin/broadcast/preview, POST /nse/messaging/admin/broadcast/send, POST /nse/messaging/admin/broadcast/schedule, POST /nse/messaging/admin/broadcast/recipients, POST /nse/messaging/admin/users/resolve | 3-column AudienceBuilder (16 sources: Everyone, Saved Groups, Student Groups, Faculties, Programmes, Levels, Classes, Staff Roles/Categories/Individuals, Demographics, Outstanding Fees, At-Risk EWS, Hostel Residents, Recent Enrollments, Individual People), RecipientsPane (paginated names with per-row exclude/include + breakdown by cohort), AudienceSpec preview chips, Save-as-Group dialog (creates a Tenant Group), Send-now / Schedule tabs, datetime-local picker |
| Scheduled Broadcasts 🆕 (list pending / sent / failed / cancelled with cancel action) | /dashboard/school/[tenantId]/messaging/scheduled | GET /nse/messaging/admin/broadcast/scheduled, DELETE /nse/messaging/admin/broadcast/scheduled/:id | Sectioned by status, Status badges, AlertDialog (cancel confirm), Auto-refresh every 60s |
Backend RBAC keys (verified in controllers): messaging:admin.audit, messaging:admin.moderate, messaging:broadcast.send, messaging:conversation.{create,archive,delete,manage}, messaging:participant.manage, messaging:topic.{create,manage}.
11.3 Tenant Groups (Saved Audience Definitions) 🆕 9 endpoints, 1 tag, under /tenant/groups BUILT 2026-05-08
NEW first-class tenant feature. Saved cross-feature audience definitions reusable across messaging broadcasts, future targeted notifications, future cohort reports. Filter-defined membership (resolved dynamically); separate from the explicit-list StudentGroup entity at /students/groups. Future GROUPME engine will handle richer group lifecycle (executives, meetings, treasury — like a school's Maths Club). 4 screens at /dashboard/school/[tenantId]/groups/... + 2 placeholder pages for Staff/Admin groups (ship with their respective modules).
| Page | Route | API Endpoints | UI Components |
| Groups Dashboard (KPIs across all group types) | /dashboard/school/[tenantId]/groups | GET /tenant/groups/dashboard | 4 nav cards (one per group type), 3 KPI cards (active / suspended / student groups), Most Used list, Recently Created list, Top Tags cloud |
| School-Wide Groups List (table with sort + filter + actions) | /dashboard/school/[tenantId]/groups/tenant | GET /tenant/groups?includeSuspended=true, DELETE /tenant/groups/:id, POST /tenant/groups/:id/suspend, POST /tenant/groups/:id/restore | ManagedDataTable (Name, Tags, Status, Use count, Last used, Created), 4 row actions (View / Edit / Suspend↔Restore / Delete), Search, Pagination, Column visibility, Status badge (Active / Suspended) |
| Group Detail (audience summary + live member list) | /dashboard/school/[tenantId]/groups/tenant/[id] | GET /tenant/groups/:id, GET /tenant/groups/:id/preview, POST /nse/messaging/admin/broadcast/recipients | Status header, Action bar (Edit / Suspend / Delete), Audience filter summary (human-readable), 4 metric cards (use count / last used / created / updated), Live RecipientsPane on right |
| Create / Edit Group (right-side Sheet — opened from list or detail) | — (Sheet, not a route) | POST /tenant/groups, PUT /tenant/groups/:id | Name + tags chips + description + role-type toggles ([Students][Parents][Staff][Admins]) + embedded AudienceBuilder + live RecipientsPane |
| Staff Groups (placeholder) | /dashboard/school/[tenantId]/groups/staff | — (placeholder) | Coming soon — ships with Staff Module (Phase 7) |
| Admin Groups (placeholder) | /dashboard/school/[tenantId]/groups/admin | — (placeholder) | Coming soon — ships with Admin Module enhancements |
AudienceSpec schema (used by Tenant Groups + Broadcast): supports everyone, roleTypes, tenantGroupIds, studentGroupIds, faculties, programmes, levels, classes, staffIds, staffRoles, staffCategories, gender, ageMin/Max, nationality[], studentStatuses[], outstandingFees, atRiskSeverities[], inHostel, recentEnrollmentDays, includeUserIds[], excludeUserIds[]. Resolver is single source of truth — same logic used by broadcast send, broadcast preview, group detail, and (future) targeted notifications.
12. Phase 7 — Advanced & Cross-Engine
12.1 Scholarships SCME — 91 endpoints, 10 tags 100% coverage
Patched
2026-04-21 per PATCH_12.1_SCHOLARSHIPS.md. 91/91 Swagger endpoints
mapped (verified against VPS controllers). 4 scopes: school admin (69ep,
17 screens), student/applicant (6ep, 1 screen), parent (3ep, 1 screen),
NEW Donor/Sponsor Portal (13ep, 4 screens). Feature-gated by scholarship_management with 7 sub-gates. Donor persona modeling pending — recommend extending UADE partner role-card.
12.1.1 School Admin — Programs & Applications (3 screens, 17 endpoints)
| Page | API Endpoints | UI Components |
| Programs & Pools (tabbed: Programs, Pools) | GET /scme/programs, POST /scme/programs, PUT /scme/programs/:id, GET /scme/pools, POST /scme/pools | TanStack Table, Sheet (create), Form (eligibility criteria), Badge (active/closed) |
| Applications & Committee Review (tabbed: Applications, Committees, Reviews) | GET /
scme/applications, POST /scme/applications/:id/finalize, GET
/scme/committees, POST /scme/committees, POST
/scme/committees/:id/reviewers, GET /scme/reviews, POST /scme/reviews | Tabs, TanStack Table, Form (scoring), Badge (quorum met/not), Button (Finalize) |
| Awards Admin (lifecycle: reserve → cancel/revoke/suspend) | GET /
scme/awards, POST /scme/awards/reserve, POST /scme/awards/:id/cancel,
POST /scme/awards/:id/revoke, POST /scme/awards/:id/suspend | TanStack Table, Sheet (reserve), Badge (state), Dialog (cancel/revoke/suspend with reason) |
12.1.2 School Admin — Renewals & Disbursements (2 screens, 7 endpoints)
| Page | API Endpoints | UI Components |
| Renewals (queue + per-award review) | GET /scme/renewals, GET /scme/renewals/queue, POST /scme/renewals/:awardId/review | TanStack Table, Dialog (review with notes), Badge (renewed/not-renewed) |
| Disbursements (schedules + records) | GET /
scme/disbursements/schedules, POST /scme/disbursements/schedules, GET
/scme/disbursements/records, POST /scme/disbursements/record | TanStack Table, Progress (installments paid), Sheet (create schedule), Button (record disbursement) |
12.1.3 School Admin — Funding (3 screens, 11 endpoints)
| Page | API Endpoints | UI Components |
| Donors & Donations | GET /scme/donors, POST /scme/donors, PUT /scme/donors/:id, GET /scme/donations, POST /scme/donations | TanStack Table, Sheet (create donor), Form (record donation), Badge (donor type) |
| Funds (scholarship funds + endowment) | GET /scme/funds, POST /scme/funds, PUT /scme/funds/:id | TanStack Table, Sheet (create), Input (amount), Badge (type: endowment/annual) |
| Sponsorship Payments & Retroactive | GET /scme/sponsorship-payments, POST /scme/retroactive/apply | TanStack Table (payments), Button (apply retroactive — admin warning), Dialog (reason) |
12.1.4 School Admin — Marketplace (2 screens, 7 endpoints)
| Page | API Endpoints | UI Components |
| Marketplace — Requests Admin | GET /scme/requests, POST /scme/requests, POST /scme/requests/:id/publish, POST /scme/requests/:id/close | TanStack Table, Sheet (create request), Badge (DRAFT→PUBLISHED→FUNDED/CLOSED), Button (publish/close) |
| Marketplace — Pledges & Proposals Oversight | GET /scme/pledges, GET /scme/proposals, POST /scme/proposals/:id/review | Tabs, TanStack Table, Dialog (review proposal), Badge (status) |
12.1.5 School Admin — Sponsorship & Partnerships (4 screens, 14 endpoints)
| Page | API Endpoints | UI Components |
| Sponsorship Profiles (student profiles for sponsor matching) | GET /
scme/sponsorship-profiles, POST /scme/sponsorship-profiles, POST
/scme/sponsorship-profiles/:id/publish, POST
/scme/sponsorship-profiles/:id/unpublish, GET
/scme/sponsorship-profiles/:id/progress | TanStack Table, Sheet
(create profile), Card (preview), Badge (published/anonymized), Warning
(require parent consent before publish) |
| Sponsorships Admin (donor↔student matches) | GET /
scme/sponsorships, POST /scme/sponsorships, POST
/scme/sponsorships/:id/activate, POST /scme/sponsorships/:id/cancel,
POST /scme/sponsorships/:id/suspend | TanStack Table, Sheet (create match), Badge (active/cancelled/suspended), Dialog (state change) |
| Partnerships (Corporate) | GET /scme/partnerships, POST /scme/partnerships, POST /scme/partnerships/:id/activate | TanStack Table, Sheet (create partnership), Badge (active/inactive) |
| Consent Admin (overview of all parent consents) | GET /scme/consent | TanStack Table, Badge (consented/revoked), Filter (per-student) |
12.1.6 School Admin — Progress Reports & Honors (2 screens, 8 endpoints)
| Page | API Endpoints | UI Components |
| Progress Reports Admin (generate + send to sponsors) | POST /scme/progress-reports/generate, POST /scme/progress-reports/:id/send | Button (generate per term), TanStack Table (drafts), Dialog (review/send) |
| Academic Honors (tabbed: Types, Compute, Certificates) | GET /
scme/honors, GET /scme/honors/types, POST /scme/honors/types, PUT
/scme/honors/types/:id, POST /scme/honors/compute, POST
/scme/honors/:id/certificate | Tabs, TanStack Table, Sheet (create type), Form (threshold criteria), Button (compute), Button (generate certificate via DTGE) |
12.1.7 School Admin — Reporting (1 screen, 6 endpoints)
| Page | API Endpoints | UI Components |
| Reports & Donor Reports (tabbed: Awards, Funds, Summary, Donor Reports) | GET /
scme/reports/awards, GET /scme/reports/fund-utilization, GET
/scme/reports/summary, GET /scme/donor-reports, POST
/scme/donor-reports/generate, POST /scme/donor-reports/:id/send | Tabs, Recharts (funnel, disbursement), Stat Cards, Button (generate report), Dialog (send to donor) |
12.1.8 Student/Applicant Self-Service 🆕 (1 screen, 6 endpoints)
Top-level route at /scholarships/my — applicant may apply pre-enrollment.
| Page | Route | API Endpoints | UI Components |
| My Scholarships (tabbed: Applications, Awards) | /scholarships/my | POST /
scme/applications, GET /scme/applications/mine, PUT
/scme/applications/:id, POST /scme/applications/:id/submit, POST
/scme/applications/:id/withdraw, GET /scme/awards/mine | Tabs, Sheet (apply), Badge (DRAFT/SUBMITTED/AWARDED/REJECTED), Button (Submit/Withdraw), Card (award detail) |
12.1.9 Parent Self-Service 🆕 (1 screen, 3 endpoints)
Role-filtered nav for activeRole=parent + activeStudentId per shell §19. Gated by new guardian permission canViewSponsorship.
| Page | API Endpoints | UI Components |
| Sponsorship Consent (for Child) | POST /scme/consent, POST /scme/consent/:id/revoke, GET /scme/consent/student/:studentId | Form (grant consent), Dialog (revoke consent), Badge (consented/revoked), Privacy notice |
12.1.10 Donor/Sponsor Portal 🆕 (4 screens, 13 endpoints)
NEW persona scope. Top-level routes at /donor-portal/.... Used by individual donors and corporate partners. Persona modeling pending — recommend extending UADE partner role-card to cover both individual + corporate.
| Page | Route | API Endpoints | UI Components |
| Browse Opportunities | /donor-portal/browse | GET /scme/sponsorship-profiles/available, GET /scme/requests/available | Card grid, Filter (region/age/programme/need), Badge (verified school) |
| My Pledges | /donor-portal/pledges | GET /scme/pledges/mine, POST /scme/pledges, POST /scme/pledges/:id/confirm, POST /scme/pledges/:id/withdraw | TanStack Table, Sheet (pledge), Badge (PENDING/CONFIRMED/WITHDRAWN), Button (confirm/withdraw) |
| My Proposals | /donor-portal/proposals | GET /scme/proposals/mine, POST /scme/proposals, POST /scme/proposals/:id/submit, PUT /scme/proposals/:id | TanStack Table, Sheet (create proposal), Form (proposal detail), Button (submit) |
| My Sponsorships | /donor-portal/sponsorships | GET /scme/sponsorships/mine, POST /scme/sponsorship-payments, GET /scme/progress-reports/mine | TanStack Table, Card (per-sponsorship), Button (make payment), Timeline (progress reports) |
12.2 Oversight OvME — 82 endpoints
| Page | API Endpoints | UI Components |
| Jurisdiction | POST /ovme/jurisdiction, GET .../subtree, .../country-tree, POST .../assign-schools, GET .../stats | Tree view (iterative BFS), TanStack Table (schools), stat Cards, DnD (school assignment) |
| Oversight Bodies | POST /ovme/bodies, POST .../officers, POST /ovme/access/grant, POST .../revoke | TanStack Table, Sheet (create), Select (access level: VIEWER/ADMIN), Badge (active) |
| Dashboard | GET /ovme/dashboard/overview/:jurisdictionId, .../attendance, .../academic, .../enrollment, .../finance | Tabs (9 views), Recharts (per-school comparison), stat Cards, TanStack Table |
| Compliance | POST /ovme/compliance/frameworks, POST .../categories, POST .../items | Accordion (framework > category > items), Sheet (create), Input (maxScore), Switch (isRequired) |
| Inspections | POST/PUT /ovme/inspections, POST .../advance-status, POST .../findings, POST .../corrective-actions | TanStack Table, Sheet (schedule), Form (findings), Badge (SCHEDULED→IN_PROGRESS→CLOSED), Timeline (actions) |
| Analytics | GET /ovme/analytics/compare-schools, .../gender-analysis, .../rankings, .../outliers | Recharts (comparison bar, GPI), TanStack Table (rankings), Badge (outlier) |
| Alerts | GET /ovme/alerts, POST .../acknowledge, POST .../escalate, POST .../threshold | TanStack Table, Badge (severity), Dialog (acknowledge/escalate), Form (threshold config) |
12.3 School Provisioning SAPE — 109 endpoints
| Page | API Endpoints | UI Components |
| Provisioning Status | POST /sape/provision, GET .../status | Card (route 1/2/3 status), Progress (steps completed), Badge (complete/pending) |
| Academic Structure | POST /
sape/academic/faculties, GET .../faculties, POST .../departments,
.../subjects, .../programmes, .../levels, .../courses, .../assign-dean,
.../assign-hod, .../subject-teachers | Accordion (faculty >
dept > subject > course tree), Sheet (create each level), Select
(dean/HOD/teacher), TanStack Table |
| Calendar & Terms | POST /sape/calendar/years, GET .../years, POST .../terms, POST .../term-enrolments | TanStack Table, Sheet (create year/term), DatePicker (start/end), Badge (current) |
| Grading & Assessment | POST /sape/grading/grade-scales, GET .../grade-scales, POST .../assessment-categories | TanStack Table, Sheet (create), Input (grade entries: letter, min, max, points) |
| Facilities | POST /sape/facilities/bell-schedules, .../hostels, PUT .../report-config, POST .../document-templates, .../verification-pricing | TanStack Table, Sheet (create), Form (bell schedule times), Dropzone (logo) |
| Course Proposal | GET /sape/course-proposal, POST .../confirm, GET .../additional | Card grid (grouped by programme > level), Checkbox (select subjects), Button (confirm) |
| Template Banks | GET
/sape/banks/subjects, POST .../import, GET .../grading, POST .../adopt,
GET .../report-cards, POST .../clone, GET .../calendars, POST .../import | TanStack Table (browse), Button (adopt/import/clone), Badge (adopted), Dialog (confirm) |
| Platform Seed | POST /sape/seed/subjects, POST .../profiles, POST .../grading | Button (seed), TanStack Table (results), Badge (seeded) — platform admin only |
12.4 Organisation Portal OrgPE — 25 endpoints
NOTE: This is a SEPARATE dashboard context from the school dashboard, accessed from UADE via /dashboard/org/[orgId]/.
| Page | API Endpoints | UI Components |
| Access Dashboard | GET /org/access-dashboard | Card grid (schools + orgs), stat Cards (school count, member count) |
| Context Switch | POST /org/switch-context | Select (school/org), Badge (role in each) |
| Org Overview | GET /org/organizations/:id, GET .../dashboard | stat Cards, TanStack Table (schools), Badge (KYC status) |
| Organisation CRUD | POST/GET/PUT /org/organizations | TanStack Table, Sheet (create), Form (name, slug, settings) |
| School List | GET /org/organizations/:id/schools, POST .../schools | TanStack Table, Sheet (add school), Badge (status) |
| School Access | POST /org/school-access/grant, .../revoke, GET .../school-access, PUT .../role | TanStack Table, Sheet (grant), Select (role), Dialog (revoke confirm) |
| CC Members | POST /org/cc-access/invite, .../request, .../approve/:id, .../revoke/:id, GET .../:orgId | TanStack Table, Sheet (invite), Badge (PENDING/ACTIVE), Dialog (approve/revoke) |
| KYC | POST /org/kyc/submit, GET .../status/:orgId, POST .../review/:orgId | Form (document upload), Badge (UNDER_REVIEW/APPROVED/REJECTED), Dropzone (documents) |
| School Transfers | POST /org/schools/:tenantId/detach, POST .../attach | Dialog (confirm detach/attach), Badge (independent/attached) |
| Onboarding | POST /org/onboard (@Public), GET /org/status/:orgId | Multi-step wizard Form (6 steps), Progress, Badge (status) |
12.5 Awards & Prize Management AwardsPME — 59 endpoints, 11 controller groups 100% coverage 🆕 NEW MODULE ✅ 11/17 screens shipped
Patched
2026-04-30 per PATCH_12.5_AWARDS.md. NEW MODULE — 59/59 Swagger
endpoints mapped (verified after Leaderboard + Yearbook addition
2026-04-30). 4 scopes: school admin (55ep, 11 screens), student/parent
self-service (2ep, 1 shared component), public opt-in (2ep, 2 screens). Cross-engine orchestrator — owns catalog, rules, prize lifecycle; calls into StuLCE, SBME, GME, ATME, PME, DTGE, ACCTE, SCME, NSE. Adopts backend's FRONTEND_AWARDSPME_PROPOSAL.md with 4 amendments: route placement (top-level /awards/...), endpoint count, Awards Coordinator as RBAC permission set, single self-service component per shell §17.
Build status (2026-05-02):
8 of 14 planned screens shipped + 3 new Detail pages added during build
(single-page Card layout, print-friendly, Edit-via-sheet). Plus admin
UX additions: Help button, dismissible Welcome card, 11-step guided
Walkthrough, themed Seed Pack picker with ISCED-localized labels.
Pending: Award Detail (per-orchestration), Award Rules, Prize
Fulfillment Queue, Yearbook (Admin), Public Leaderboard, Public
Yearbook.
12.5.1 School Catalogue & Lifecycle (3 screens, 7 endpoints)
| Page | Status | API Endpoints | UI Components |
| Award Catalogue (federation read — all awards in tenant) | ✅ DONE | GET /awardspme/awards | Granted tab on /students/achievements with TanStack Table (<ManagedDataTable>),
filter bar (year/definition/source/approval/engine), inline Approve /
Reject (reason prompt) / Archive actions, XLS+PDF export. |
| Award Detail (per-orchestration view + edit + soft-delete + restore) | ⏳ PENDING | GET /
awardspme/awards/:orchestrationId, PUT
/awardspme/awards/:orchestrationId, DELETE
/awardspme/awards/:orchestrationId, POST
/awardspme/awards/:orchestrationId/restore | Card layout, Right-side sheet (edit), Dialog (delete/restore confirm), Audit timeline |
| Pending Approvals (filtered catalogue + approve/reject) | ✅ DONE | POST /awardspme/awards/:orchestrationId/approve, POST /awardspme/awards/:orchestrationId/reject | Integrated
into Granted tab: filter chip "Status = PENDING", per-row Approve +
Reject (reason via window.prompt) buttons. Bulk approve and sidebar
notification badge are deferred. |
12.5.2 Catalog Management (3 screens + 3 new Detail pages, 23 endpoints + 3 new stats endpoints)
| Page | Status | API Endpoints | UI Components |
| Categories (recognition categories: Academic, Sports, Behavioral, etc.) | ✅ DONE | GET /
awardspme/categories, GET /awardspme/categories/:id, POST
/awardspme/categories, PUT /awardspme/categories/:id, DELETE
/awardspme/categories/:id, POST /awardspme/categories/:id/restore | Categories tab on /students/achievements/categories with <ManagedDataTable>, clickable name → Category Detail page, right-side sheet (create/edit), Badge (system/custom), ISCED level CSV input. |
| Category Detail 🆕 (added during build) | ✅ DONE | GET /awardspme/categories/:id/stats (new) + reuses listAwardCategories + listAwardDefinitions(?categoryId) | Single-
page no-tabs layout: header with Back/Edit/Print buttons, Stats row
(definitionCount/active/totalGranted/thisYear), Identity Card,
Definitions in Category table (clickable through to definition detail).
Print-friendly via print:hidden on chrome. |
| Award Definitions & Prizes (tabbed: Definitions, Prizes per definition) | ✅ DONE | Definitions (7):
GET /awardspme/definitions, GET /awardspme/definitions/:id, POST
/awardspme/definitions, PUT /awardspme/definitions/:id, DELETE
/awardspme/definitions/:id, POST /awardspme/definitions/:id/restore,
POST /awardspme/definitions/:id/clone. Prizes (4): GET
/awardspme/definitions/:definitionId/prizes, POST
/awardspme/definitions/:definitionId/prizes, PUT /awardspme/prizes/:id,
DELETE /awardspme/prizes/:id | Catalog tab (= /students/achievements) with <ManagedDataTable>, clickable name → Award Definition Detail page. Right-side AwardDefinitionSheet with all 20+ fields and inline PrizesPanel (attach/remove via useAppForm). Per-row inline icons: Edit, Clone, Archive/Restore. |
| Award Definition Detail 🆕 (added during build) | ✅ DONE | GET /awardspme/definitions/:id/stats (new) + reuses getAwardDefinition + listSchoolAwards(?definitionId) + definitionPrizes | Single-
page no-tabs Card layout: Stats row
(totalGranted/thisYear/thisTerm/pending), Identity, Scoping, Visibility
& Notifications, Attached Prizes, Top Recipients, Granted History
(paginated table). Print-friendly. Edit-via-sheet from header. |
| Prize Types (fulfillment channels: Cash, Trophy, Certificate, Scholarship, Fee Credit, Voucher) | ✅ DONE | GET /
awardspme/prize-types, GET /awardspme/prize-types/:id, POST
/awardspme/prize-types, PUT /awardspme/prize-types/:id, DELETE
/awardspme/prize-types/:id, POST /awardspme/prize-types/:id/restore | Prize
Types tab on /students/achievements/prize-types, clickable name → Prize
Type Detail page, right-side sheet, fulfillment channel select. |
| Prize Type Detail 🆕 (added during build) | ✅ DONE | GET /awardspme/prize-types/:id/stats (new), GET /awardspme/prize-types/:id/used-by (new), GET /awardspme/prize-types/:id/events (new) | Single-
page no-tabs Card layout: Stats row
(usedByCount/totalIssued/completed/pending), Monetary Total card (when
channel is monetary), Identity & Defaults, Used by Definitions
table, Recent Fulfillment Events table, Status Breakdown. |
12.5.3 Rules — Auto-Derivation (1 screen, 10 endpoints)
| Page | Status | API Endpoints | UI Components |
| Award Rules (tabbed: List, Detail with DSL editor + Run/Preview/Reevaluate + Evaluations) | ⏳ PENDING | GET /
awardspme/rules, GET /awardspme/rules/:id, POST /awardspme/rules, PUT
/awardspme/rules/:id, DELETE /awardspme/rules/:id, POST
/awardspme/rules/:id/restore, POST /awardspme/rules/:id/preview, POST
/awardspme/rules/:id/run, POST /awardspme/rules/:id/reevaluate, GET
/awardspme/rules/:id/evaluations | TanStack Table, Right-side
sheet (create/edit rule), Monaco editor (JSON DSL with autocomplete —
Sprint 4), Source engine select (GME/ATME/SBME/PME), Trigger select
(TERM_CLOSE/SCHEDULED/MANUAL_RUN/EVENT_DRIVEN), Cron input (if
SCHEDULED), Preview modal (qualifiers table), Result drawer ("X new, Y
archived, Z unchanged"), Evaluation history timeline |
12.5.4 Prize Fulfillment (1 screen, 6 endpoints)
| Page | Status | API Endpoints | UI Components |
| Prize Fulfillment Queue (status filter chip + transition + retry + cancel + audit timeline) | ⏳ PENDING | GET /
awardspme/prize-records, GET /awardspme/prize-records/:id, GET
/awardspme/prize-records/:id/events, POST
/awardspme/prize-records/:id/transition, POST
/awardspme/prize-records/:id/cancel, POST
/awardspme/prize-records/:id/retry-fulfillment | TanStack Table
with status filter chip
(PENDING/IN_PROGRESS/FULFILLED/FAILED/CANCELLED), Filter bar
(channel/student/definition/term/date), Per-row "Mark handed over"
(PENDING manual), "Retry" (FAILED with diagnostic tooltip), Bulk
actions, Side drawer (PrizeFulfillmentEvent timeline) |
12.5.5 Setup & Config (2 screens, 7 endpoints)
| Page | Status | API Endpoints | UI Components |
| Seed Installer (one-click defaults + per-bucket + SBME mirror) | ✅ DONE 🆕 enhanced | GET /
awardspme/seed/preview, POST /awardspme/seed/install, POST
/awardspme/seed/categories, POST /awardspme/seed/prize-types, POST
/awardspme/seed/sbme-mirror, GET /awardspme/seed/packs (new), GET /awardspme/seed/packs/:id (new), POST /awardspme/seed/packs/:id/install (new), GET /awardspme/seed/isced-labels (new) | Themed Seed Pack Picker
on Settings tab + as empty-state on Catalog/Categories/PrizeTypes tabs +
inline in Grant Award sheet. 6 packs (Universal Starter, Primary,
Secondary Excellence, Sports & Co-curricular, Behaviour &
Citizenship, Tertiary). Each card shows ISCED chip + "Who can use this
pack? ▾" Popover with per-system breakdown localised to tenant's countryCode+educationSystemCodes. |
| AwardsPME Settings (engine config — incl. public showcase toggles 🆕) | ✅ DONE | GET /awardspme/config, PUT /awardspme/config | Form (useAppForm()), Switch toggles (publicLeaderboardEnabled, yearbookEnabled, yearbookPublicEnabled), Inputs (publicLeaderboardLimit, publicLeaderboardTagline, yearbookCertificateTemplateCode), Multi-select via CSV (publicLeaderboardCategoryCodes), Toggle (publicLeaderboardShowFullName privacy). Plus Tour card with Restart button. |
12.5.6 Yearbook (Admin) 🆕 (1 screen, 2 endpoints)
| Page | Status | API Endpoints | UI Components |
| Yearbook (Admin) (per-academic-year compilation + PDF generation) | ⏳ PENDING | GET /awardspme/yearbook/:academicYear, POST /awardspme/yearbook/:academicYear/generate-pdf | Card layout, Year selector, Button (Generate PDF — uses DTGE template via yearbookCertificateTemplateCode), Progress indicator, Preview, Download link |
12.5.7 Self-Service 🆕 (1 shared component, 2 endpoints — admin/teacher/student/parent role-filtered per shell §17)
| Page | Status | Routes | API Endpoints | UI Components |
| Student Awards (federation read for one student + grant action) | ✅ DONE (admin/teacher; student/parent role variants pending) | Admin/Teacher: /students/[studentId]/achievements (replaced legacy disabled "Add"). Student self: /awards/my (pending). Parent: Parent Portal → Child's Awards (pending). | GET /awardspme/students/:studentId/awards, POST /awardspme/students/:studentId/awards | StudentAwardsView + StudentAwardCard + GrantAwardSheet.
Card grid, source badge (Academic/Behavior), prize chips coloured by
fulfillment status, Pending badge, hover-revealed Approve/Archive icons,
"Grant Award" right-side sheet (useAppForm) with
definition Combobox + date/year/awarding body/position/notes, filter
chips (All/Academic/Behavior/Pending). Empty state shows compact Seed
Pack Picker when catalog is empty. |
12.5.8 Public Scope 🆕 (2 screens, 2 endpoints — no auth, opt-in via tenant config)
| Page | Status | Route | API Endpoints | UI Components |
| Public Leaderboard (top award recipients per category) | ⏳ PENDING | /public/leaderboard/[tenantSlug] | GET /awardspme/public/leaderboard/:tenantSlug | Public page (no auth), Banner (publicLeaderboardTagline), Ranked list (limited to publicLeaderboardLimit, names per publicLeaderboardShowFullName), Category tabs (filtered by publicLeaderboardCategoryCodes), Badge (medal/trophy icons) |
| Public Yearbook (per-tenant per-academic-year showcase) | ⏳ PENDING | /public/yearbook/[tenantSlug]/[academicYear] | GET /awardspme/public/yearbook/:tenantSlug/:academicYear | Public page (no auth), Year selector, Card grid (recipients with photos), Category sections, Download PDF link (if generated) |
12.5.9 Admin UX (3 components, 0 endpoints) 🆕 (added during build)
| Component | Status | Notes |
| Help Button (top-right of every awards page) | ✅ DONE | Labelled <Button> in layout header. Dropdown: "Show welcome card" (un-dismisses + reloads) and "Start guided tour". |
| Welcome Card (dismissible explainer) | ✅ DONE | Wrapped in <Card> primitive with explicit yellow tokens (bg-yellow-500/5 dark:bg-yellow-500/10)
for proper light/dark contrast. 3-part explainer (Categories, Prize
Types, Awards) with numbered circles. Dismissed state persisted to localStorage per tenant. |
| Guided Tour (11-step walkthrough, no external dep) | ✅ DONE | Custom
dimmed-backdrop overlay with hole-punched SVG mask around the
highlighted target element. Steps: welcome → tabs intro → 5 per-tab
steps (Catalog/Granted/Categories/Prize Types/Settings) → starter pack →
new award → student profile → restart hint. Skip/Prev/Next/Finish
controls. Completion persisted to localStorage. |
Sprint phasing:
Sprint 1 = per-student tab upgrade (1-week unblock); Sprint 2 = catalog
mgmt; Sprint 3 = school catalogue + approval + fulfillment; Sprint 4 =
rule engine UI; Sprint 5 (optional) = parent portal + visual rule
builder + Yearbook + Public Showcase + FR translation.
13. Phase 8 — Platform Infrastructure & Settings
13.1 Audit Trail Platform — 8 endpoints
| Page | API Endpoints | UI Components |
| Audit Log | GET /audit/entries (query: userId, entityType, engine, action, startDate, endDate, page, limit), GET .../:id | TanStack Table, Select filters (engine, action, date range), Badge (action type), DatePicker |
| Audit Stats | GET /audit/stats | Recharts (by engine, by action), stat Cards (total today) |
| Audit Config | GET/PUT /audit/config | Form (retention days, excluded engines), Note (platform minimum enforced) |
| Platform Audit | GET/PUT /audit/platform-config, GET /audit/platform/entries | Same as above but cross-tenant (super admin only) |
13.2 Data Privacy & Compliance Platform — 15 endpoints
| Page | API Endpoints | UI Components |
| Consent Policies | GET/POST/PUT /privacy/policies, POST .../seed | TanStack Table, Sheet (create), Badge (mandatory/optional), Switch (active) |
| Consent Records | POST /privacy/consent, GET .../student/:studentId, GET .../status | TanStack Table, Badge (granted/declined/needs re-consent), Switch (grant/revoke) |
| Deletion Requests | POST /privacy/deletion-request, GET .../deletion-requests, PUT .../approve, PUT .../reject | TanStack Table, Badge (PENDING/PROCESSING/COMPLETED/REJECTED), Dialog (approve — shows blockers) |
| Data Export | POST /privacy/export-request, GET .../export-requests, GET .../download | TanStack Table, Button (request export), Badge (PROCESSING/READY/EXPIRED), Link (download) |
| Compliance Dashboard | GET /privacy/dashboard, GET .../compliance-report | stat Cards (consent rate, pending deletions), Recharts (per-policy rates), Card (avg deletion response time) |
13.3 Outbound Webhooks Platform — 12 endpoints
| Page | API Endpoints | UI Components |
| Subscriptions | POST/GET/PUT/DELETE /webhooks/subscriptions, GET .../:id, POST .../test | TanStack Table, Sheet (create — HTTPS URL, events), Button (test), Badge (active/paused), Switch (enable) |
| Delivery Logs | GET /webhooks/subscriptions/:id/logs (query: success, page, limit), POST .../retry | TanStack Table, Badge (success/failed), Button (retry), Badge (attempt count) |
| Event Catalogue | GET /webhooks/events | Card grid (15 event types + wildcard), Badge (category) |
| API Keys | POST /webhooks/api-keys, GET .../api-keys, POST .../revoke | TanStack Table, Button (generate — show once dialog), Badge (active/revoked) |
13.4 RBAC & Role Management RBAC — 15 endpoints
| Page | API Endpoints | UI Components |
| Permissions | GET /rbac/permissions, GET .../me, POST .../check | Accordion (grouped by module), Badge (permission key), SearchInput |
| Roles | GET/POST/PUT/DELETE /rbac/roles | TanStack Table, Sheet (create), Checkbox group (permissions), Badge (system/custom) |
| Assignment | PUT /rbac/users/:userId/role, POST /rbac/roles/bulk-assign | Select (role), Button (assign), TanStack Table (user list), Dialog (bulk assign) |
13.5 Subscription & Billing SBE — 37 endpoints
| Page | API Endpoints | UI Components |
| Current Plan | GET /sbe/tenant-subscriptions, POST .../change-tier | Card (current plan details), Badge (active), Button (change tier) |
| Feature Gates | GET /sbe/feature-gates, POST .../seed-status, PUT .../toggle | TanStack Table, Switch (toggle), Badge (active/inactive), stat Cards (seed status) |
| Tiers | GET/POST /sbe/subscription-tiers | Card grid (tier comparison), Badge (current), Button (upgrade) |
| Overrides | GET/POST /sbe/feature-overrides | TanStack Table, Sheet (create override), Select (GRANT/REVOKE), Badge (override type) |
| School Self-Service | GET /sbe/school/gates, POST .../request-upgrade, POST .../change-tier | Card grid (available gates), Button (request), Badge (enabled/locked) |
| Dashboard | GET /sbe/dashboard/overview, GET .../mrr | Recharts (MRR, gate adoption), stat Cards (subscribers, revenue) |
| Enforcement | POST /sbe/enforcement/check, POST .../invalidate-cache | Button (check gate), Badge (result), Button (invalidate cache) |
13.6 Branding & Theme Studio AppThemeEngine — 30 endpoints, 6 controller groups 100% backend coverage 🆕 NEW MODULE ✅ 10/12 screens shipped 2026-05-04→05
| Page | API Endpoints | UI Components |
| Theme Studio Shell | GET /branding/me | 3-pane layout, ResizablePanelGroup (editor↔preview drag, autoSaveId persists), sticky top bar with breadcrumb + name input + scope badge + Cancel / Save / Save As ▾, viewport guard < 1280px → empty state, PermissionGate branding:theme.author |
| Theme Library Rail | GET /themes?isActive=true&scope=..., DELETE /themes/:id, POST /themes/:id/restore | Platform + My School sections, search, filter chips (All / In use / Editable), 4-band swatch strip per row (primary/secondary/accent/background), ⋯ row menu (Open / Duplicate / Set active / Archive), Allowed-for-users Switch (per-row toggle of allowedPresetIds), collapsible icon-only mode (48px) |
| Color Editor (5 tabs) | GET /themes/:id, POST /themes/validate (debounced 500ms), GET /branding/fonts | Tabs (Colors / Typography / Shape & Shadow / Charts / Sidebar), Light / Dark toggle, Sync-linked-colors master switch, Validation banner (errors + warnings + Show me jump-to-tab), Accordion groups (Surface / Brand / Feedback / Borders / Charts / Sidebar), TokenRow w/ contrast chip, Sync dark from light, Style presets (None / Soft / Sharp / Brutal / Glow), Sliders (radius, shadow primitives), Match main palette, Generate charts from primary, Live typography sample (sans + serif + mono in their actual chosen families) |
| Color Picker (shared component) | — | Popover, 2D Saturation / Value panel (240×140 with draggable pin, keyboard arrow nav), Hue strip (full spectrum, draggable), HEX + OKLCH text inputs (auto-canonicalize), native EyeDropper API, Theme-presets quick-pick row (primary / secondary / accent / destructive / chart-1..5) |
| Bulk Color Update Dialog | — (purely client-side) | On color commit (picker close / input blur), scan tokens for siblings sharing previous value; Dialog with checkbox list of siblings (excluding non-color tokens), "Update N selected" / "Just this one", Select all / none, master toggle in editor header to disable feature |
| Live Preview Pane | POST /themes/:id/preview-derived-shadow (optional; local mirror of backend deriveShadowScale used by default) | Device toggle (Web / Mobile / Both side-by-side), Page picker (Components / Overview / List / Form / Settings), data-theme-preview scoped wrapper injects all 47 CSS vars, font slots resolve from FontCatalog at preview time, samples exercise font-sans + font-serif + font-mono visibly, ScrollArea with horizontal scrollbar for Both mode |
| Save / Save As Sheet + Apply flows | POST /themes, POST /themes/:id/duplicate, PUT /themes/:id, GET /themes/:id/consumers, PUT /branding/draft, POST /branding/publish | TanStack Form right-side Sheet, prefilled name on Duplicate from rail, Scope toggle (Tenant / Platform — visible to super admin), "Apply to my school after save" Switch, Cascade-warning AlertDialog when scope=PLATFORM && consumerCount > 0, cookie auto-swap (setActiveTheme) on Set-as-active so palette dropdown reflects new theme immediately |
| Tour Overlay | — | 8-step guided walkthrough (Pick theme → Colors → Typography → Shape → Charts → Sidebar → Preview → Save), spotlight cutout via 4 dimmed rectangles + ring around target anchor (data-tour-anchor), floating card with Next / Back / Finish, fires onEnter side-effects (auto tab-switching), "?" help button in top bar starts tour, doesn't cover preview pane |
| Theme Selector dropdown (header palette icon) | GET /themes (cached from rail) | DropdownMenu reading runtime catalog, falls back to bundled THEMES const outside school context, filtered by BrandingProfile.allowedPresetIds when set, hidden entirely when allowUserChoice=false, single check on cookie-match (the rendering theme), small "School" tag on tenant-active option |
| Runtime CSS injection (BrandingProvider) | GET /branding/me (5min cache) | Synthesizes <style id="branding-runtime-{slug}"> with [data-theme="{slug}"] { ... } + .dark[data-theme="{slug}"] { ... } blocks (47 token CSS vars × 2 variants) for non-bundled tenant presets — closes the "skeleton" gap when applying a custom theme. useBrandingOptional / useSchoolContextOptional helpers for components rendered outside the school dashboard tree. |
| Branding Settings page ⏳ Sprint 3 | GET/PUT /branding/draft, POST /branding/publish, GET /branding/history, POST /branding/rollback/:version, POST /branding/assets/logo | NOT YET BUILT — Logo upload (light + dark + favicon), display name, app short name, support email/phone, privacy/terms URLs, dark mode policy (AUTO / LIGHT / DARK / USER), history list with rollback action, "Customize a theme" button → Theme Studio (J1 entry point) |
| Super Admin Themes Studio ⏳ Sprint 3 | All /themes/* (super admin scope) + GET /admin/branding/profiles + GET /admin/branding/themes/:id/full-cascade | NOT YET BUILT — /dashboard/super/themes/studio route, platform-scope authoring without tenant context, Conflict diff modal (J6 in spec — token-by-token side-by-side), promote tenant theme → platform, archive force=true for system presets |
14. Module-to-Engine Mapping (Full Data)
| Frontend Module | Engine | Endpoints | Tags | Permission Namespace | ISCED Filter | Feature Gate |
| Students | StuLCE | 66 | 16 | student:* | All | Core (carve-outs: student_id_cards, student_clearance) |
| Admissions | ADME | 62 | 9 | admission:* | All | admission_management |
| Staff | StaME | 60 | 9 | staff:* | All | Core |
| Programmes | PME | 46 | 7 | programme:* | All | Core |
| Courses | CME | 77 | 16 | course:* | All (registration: 5+) | Core |
| Syllabus | MaSyE | 50 | 11 | syllabus:* | All | syllabus_management |
| Grading | GME | 103 | 9 | grading:* | All (GPA: 5+) | grading_management |
| Online Exams | QBE + GME/OEE | 45 | 4 | exam:*, qbank:* | All | online_examination + question_bank |
| Attendance | ATME | 28 | 5 | attendance:* | All | attendance_management |
| Assignments | ASME | 21 | 2 | assignment:* | All | assignment_management |
| Fees & Billing | ACCTE/FME | 98 | 13 | fee:*, finance:* | All | fee_management |
| Student Wallet | ACCTE/WME | 53 | 9 | wallet:* | All (essential: 5+) | student_wallet |
| Scheduling | SCIE | 160 | 17 | schedule:* | All | scheduling |
| Library | LME | 95 | 14 | library:* | All | library_management |
| Health | SHME | 72 | 12 | health:* | All | student_health |
| Behavior & EWS | SBME | 88 | 12 | behavior:* | All | student_behavior |
| Canteen | RCM | 32 | 1 | rcm:* | Boarding/mixed | refectory |
| Hostel | HME | 57 | 8 | hostel:* | Boarding only | hostel_management |
| Transport | TME | 62 | 10 | transport:* | All (more relevant 0-3) | transport_management |
| Documents | DTGE | 38 | 5 | document:* | All | document_generation |
| Notifications | NSE | 30 | 7 | notification:* | All | Core |
| Messaging | MSGE | 33 | 6 | messaging:* | All | messaging |
| Scholarships | SCME | 91 | 10 | scholarship:* | All | scholarships |
| Oversight | OvME | 82 | 12 | oversight:* | All | Core |
| Provisioning | SAPE | 109 | 8 | admin:* | All | Core |
| Org Portal | OrgPE | 25 | 7 | org-level RBAC | All | Core (CC gated by KYC) |
| Subscriptions | SBE | 37 | 7 | platform:* | All | Core |
| Audit | Platform | 8 | 1 | audit:* | All | Core |
| Privacy | Platform | 15 | 1 | privacy:* | All | Core |
| Webhooks | Platform | 12 | 1 | webhook:* | All | outbound_webhooks |
| RBAC | RBAC | 15 | 1 | core:* | All | Core |
| Awards & Prizes 🆕 | AwardsPME | 59 | 11 | award:*, prize:* | All (definitions can be ISCED-scoped) | awards_management |
15. RBAC & Permission Surface
15.1 Permission Files (21 files, 511 lines)
Top files by line count: programme.permissions.ts (96), grading.permissions.ts (60), messaging.permissions.ts (45), admission.permissions.ts (34), fee.permissions.ts (30), exam.permissions.ts (26), partner.permissions.ts (17), behavior.permissions.ts (15), core.permissions.ts (14), scheduling.permissions.ts (13), scholarship.permissions.ts (12), plus 10 more.
15.2 4-Scope RBAC Architecture
| Scope | Mechanism | Guard | Decorator |
| School | UserSchoolProfile → Role → permissions[] | RbacGuard | @RequirePermission() |
| Platform | User.platformRole string field | PlatformRbacGuard | @RequirePlatformRole() |
| Partner | PartnerAccess → static PARTNER_ROLE_PERMISSIONS | PartnerRbacGuard | @RequirePartnerPermission() |
| Organisation | OrgAccess → role (hierarchy: viewer < admin < owner) | OrgRbacGuard | @RequireOrgRole() |
15.3 Permission Inheritance
module.manage grants all actions. create/edit/approve imply view. submit implies view+create. publish implies view+approve.
15.4 How RBAC Drives Navigation
User clicks school card →
GET /uade/permissions/:tenantId →
returns { role: "Principal", permissions: ["grading:*", "student:*", "fee:*", ...] }
→ frontend filters sidebar items:
if permissions.some(p => p.startsWith("grading:")) → show Grading menu
if permissions.some(p => p.startsWith("fee:")) → show Finance menu
if permissions.includes("*") → show everything (super admin)
15.5 System Roles (20 pre-defined)
6 system roles: Super Admin, School Admin, Teacher, Accountant, Student, Parent
14 suggested roles: Principal, Vice Principal, Dean
of Studies, Head of Department, Registrar, Admissions Manager, Bursar,
Counselor, IT Administrator, Librarian, Hostel Warden, Canteen Manager,
Nurse/Health Officer, Sports Master
16. Feature Gate Matrix
Feature gates are enforced by the FEATURE_MAP in src/rbac/constants/feature-map.ts. If a school's subscription tier does not include the gate, the API returns 403 and the frontend should hide the module.
16.1 Top-Level Gates (30)
| Gate Code | Feature | Engines Affected | Category |
| grading_management | Grading & report cards | GME | Academic |
| assignment_management | Assignments | ASME | Academic |
| online_examination | Online exam delivery | GME/OEE | Academic |
| question_bank | Question bank | QBE | Academic |
| attendance_management | Attendance tracking | ATME | Academic |
| syllabus_management | Syllabus management | MaSyE | Academic |
| fee_management | Fee & billing | ACCTE/FME | Finance |
| student_wallet | Student wallet & micropayments | WME | Finance |
| scholarships | Scholarship management | SCME | Finance |
| student_behavior | Behavior management | SBME | Operations |
| admission_management | Full admission management | ADME | Operations |
| scheduling | Timetable & calendar | SCIE | Operations |
| document_generation | Document generation | DTGE | Platform |
| hostel_management | Hostel operations | HME | Operations |
| transport_management | Transport management | TME | Operations |
| library_management | Library management | LME | Operations |
| student_health | General student health | SHME | Operations |
| refectory | Canteen management | RCM | Operations |
| messaging | Two-way messaging | MSGE | Communication |
| outbound_webhooks | Webhook integrations | Platform | Platform |
| student_id_cards | ID card generation | StuLCE | Platform |
| student_clearance | Student clearance | StuLCE | Platform |
| awards_management | Awards & prize management (catalog + rules + fulfillment) 🆕 | AwardsPME | Operations |
16.2 Sub-Gates (within top-level gates)
| Sub-Gate Code | Parent Gate | Feature |
| admission_portal | admission_management | Online application portal |
| admission_merit | admission_management | Merit scoring |
| admission_transfers | admission_management | Transfer admissions |
| clinic_management | student_health | School clinic |
| pharmacy_management | student_health | School pharmacy |
| health_screening | student_health | Health screening |
| messaging_broadcast | messaging | Broadcast channels (premium) |
| awards_rules | awards_management | Rule engine + auto-derivation (enterprise) 🆕 |
| awards_marketplace_prizes | awards_management | Multi-prize bundles 🆕 |
| awards_scholarship_prize | awards_management | SCHOLARSHIP_GRANT prize channel (gated by SCME) 🆕 |
| awards_fee_credit_prize | awards_management | FEE_CREDIT prize channel (gated by ACCTE) 🆕 |
| awards_seed_catalog | awards_management | Adopt platform-seeded catalog 🆕 |
| awards_visual_rule_builder | awards_management | Visual rule builder (vs JSON DSL — future) 🆕 |
| awards_public_showcase | awards_management | Public Leaderboard + Public Yearbook (per-tenant opt-in) 🆕 |
16.3 Frontend Implementation
const { featureGates } = useSchoolContext();
// Hide entire sidebar module
{featureGates.includes("library_management") && <LibraryNavItem />}
// Hide sub-feature within a module
{featureGates.includes("admission_merit") && <MeritScoringTab />}
// Premium sub-gate
{featureGates.includes("messaging_broadcast") && <BroadcastButton />}
17. Frontend Architecture Decisions
17.1 Technology Stack (Already Established)
| Layer | Technology | Notes |
| Framework | Next.js 14+ (App Router) | Server components for initial loads, client components for interactivity |
| UI Library | shadcn/ui + Tailwind CSS | Consistent with existing UADE dashboard |
| State Management | TanStack Query v5 | Already wired for UADE. Server state only — no Redux. |
| Forms | React Hook Form + Zod | Already used in existing form components |
| Tables | TanStack Table | For all data tables |
| Auth | NextAuth.js + Authentik | JWT bearer token flow, already working |
| API Client | Custom apiClient() / serverApiClient() | Already built in src/lib/api-client.ts. Injects Bearer + X-Tenant-Id. |
| Routing | Next.js App Router | [tenantId] dynamic segment for tenant scoping |
| URL State | nuqs (NuqsAdapter) | For filter/pagination/search state in URL |
| Command Palette | KBar | Already wired |
| Real-time | WebSocket (Socket.io) | For messaging (MSGE gateway at /messaging namespace) |
17.2 Key Architectural Patterns
Tenant Context Provider
/dashboard/school/[tenantId]/layout.tsx
→ TenantProvider (fetches permissions, iscedLevels, features)
→ SchoolSidebar (RBAC-filtered + feature-gated)
→ SchoolTopBar (tenant switcher)
→ {children}
Feature Module Pattern (per engine)
src/features/<engine>/
api/
queries.ts ← TanStack Query options (queryKey, queryFn, staleTime)
mutations.ts ← useMutation hooks for POST/PUT/DELETE
types.ts ← TypeScript interfaces matching backend DTOs
service.ts ← apiClient() calls (raw fetch wrappers)
components/
<engine>-list.tsx ← Data table with filters, search, pagination
<engine>-detail.tsx ← Detail/edit view
<engine>-form.tsx ← Create/edit form
<engine>-dashboard.tsx ← Module overview/stats
hooks/
use-<engine>.ts ← Custom hooks combining queries + mutations
constants/
columns.tsx ← Table column definitions
schemas/
<engine>.schema.ts ← Zod validation schemas
ISCED-Aware Rendering
const { iscedLevels } = useSchoolContext();
const isTertiary = iscedLevels.some(l => l >= 5);
const isSecondary = iscedLevels.some(l => l >= 2 && l <= 4);
// Conditional field
{isTertiary && <GpaDisplay studentId={id} />}
// Conditional label
<Label>{isTertiary ? "Semester" : "Term"}</Label>
// Conditional column in table
const columns = [
...baseColumns,
...(isTertiary ? [creditHoursColumn, gpaColumn] : []),
];
18. ISCED-Conditional Rendering Map
Complete map of every UI element that changes based on ISCED level:
| Module | Component | ISCED 0-2 (Primary) | ISCED 3-4 (Secondary) | ISCED 5-8 (Tertiary) |
| Programmes | Level label | "Class" / "Grade" | "Form" / "Year" | "Year" / "Level" |
| Programmes | Progression mode | Auto-promote | Exam-gated | Credit-accumulation |
| Programmes | Specializations | Hidden | Hidden | Visible (major/minor) |
| Courses | Credit hours column | Hidden | Hidden | Visible |
| Courses | Course registration | Hidden | Hidden | Full self-service |
| Courses | Waitlist / Minor / Credit recognition | Hidden | Hidden | Visible |
| Grading | Grade display | Marks /10 or /20 | Marks + letter (A-E) | GPA 0.0–4.0 |
| Grading | CGPA panel | Hidden | Hidden | Visible |
| Grading | Sequences tab | Hidden | Visible (1st, 2nd, 3rd) | Hidden |
| Grading | Graduation check | Age/completion | National exam results | CGPA + credit threshold |
| Score Entry | Score format | Numeric (0-10/20) | Numeric (0-20) | Numeric + letter grade |
| Report Cards | Format | Simple marks sheet | Marks + class rank + conduct | Transcript + GPA + credits |
| Attendance | Granularity | Per-day (full class) | Per-period (per-subject) | Per-lecture (optional) |
| Fees | Structure | Flat annual/termly | Flat + exam fees | Per-credit differential |
| Timetable | Complexity | Simple grid (1:1) | Subject rotation | Multi-section + labs |
| Student List | Guardian column | Prominent | Visible | Minimal/hidden |
| Student List | GPA column | Hidden | Hidden | Visible |
| Library | Features | Basic lending | + textbooks | + digital + reserves |
| Hostel | Visibility | Hidden (unless boarding) | Visible (if boarding) | Visible |
| Transport | Visibility | Prominent | Visible | Hidden |
| Term label | Label | "Term 1, 2, 3" | "Term 1, 2, 3" | "Semester 1, 2" |
| EWS signals | Academic signals | Minimal | 8 rules (ISCED 3-4) | 11 rules (ISCED 5-8) |
19. Route Map
Complete Next.js App Router route structure (~190 page.tsx files):
/dashboard/school/[tenantId]/
+-- page.tsx → School Overview
+-- layout.tsx → TenantProvider + SchoolSidebar + TopBar
|
+-- students/
| +-- page.tsx → Student List
| +-- [studentId]/page.tsx → Student Profile (tabbed)
| +-- new/page.tsx → Add Student Form
| +-- import/page.tsx → CSV/Excel Import
| +-- guardians/page.tsx → Guardian List
| +-- class-placement/page.tsx → Class Placement Board
| +-- groups/ | transfers/ | id-cards/ | clearance/
| +-- achievements/ | appointments/ | pastoral-notes/ | documents/
| +-- re-enrollment/ | settings/page.tsx
|
+-- admissions/
| +-- page.tsx → Admission Dashboard (funnel)
| +-- applications/page.tsx → Application List
| +-- applications/[id]/page.tsx → Application Review
| +-- config/ | merit/ | offers/ | enrollment/ | manual/ | appeals/ | transfers/
|
+-- staff/
| +-- page.tsx | [staffId]/page.tsx | new/ | contracts/ | qualifications/ | appraisals/ | documents/ | config/ | reports/
|
+-- academics/
| +-- programmes/ (page, [id], new, enrollment, progression, graduation, specializations)
| +-- courses/ (page, [id], offerings, registration, curriculum-map, curriculum-docs, substitutions)
| +-- syllabus/ (page, adoption, custom, review)
| +-- calendar/page.tsx | templates/page.tsx
|
+-- timetable/ (page, my-schedule, slots, conflicts, substitutions, swaps, generate, export, exam, bell-schedule, settings)
+-- grading/ (page, assessments, assessments/[id], scores, computation, report-cards, sequences, gpa, graduation, config, online-exams/)
+-- attendance/ (page, reports, alerts, devices, grading-bridge, config)
+-- assignments/ (page, [id], new, settings)
+-- finance/ (page, fee-structure, billing, payments, installments, waivers, discounts, debts, revenue, tax, auto-enroll, config)
+-- wallet/ [if gate] (page, wallets, funding, merchants, catalogue, pos, fee-bridge, reports, config)
+-- calendar/ (page, events, rsvp, deadlines, leave, activities, facilities, settings)
+-- messaging/ (page, conversations, [conversationId], auto-post, admin, settings)
+-- library/ [if gate] (page, catalogue, circulation, holds, cards, textbooks, digital, reading-lists, inventory, fines, clearance, reports, config)
+-- health/ [if gate] (page, records, records/[studentId], clinic, sickbay, immunizations, allergies, dietary, medications, pharmacy, growth, config)
+-- behavior/ [if gate] (page, events, at-risk, ews, counseling, hearings, contracts, restorative, peer-reports, rewards, parent-feed, config)
+-- canteen/ [if gate] (page, meal-plans, student-plans, sessions, check-in, tables, menu, reports, config)
+-- hostel/ [boarding] (page, infrastructure, allocations, exeat, inspections, visitors, operations, staff, fees, config)
+-- transport/ [if gate] (page, routes, vehicles, drivers, enrollment, schedules, trips, attendance, incidents, maintenance, analytics, settings)
+-- documents/ (page, report-templates, generate, verify, config)
+-- notifications/ (page, templates, channels, providers, devices, preferences, analytics, settings)
+-- scholarships/ [if gate] (page, programs, applications, committee, awards, disbursement, donors, marketplace, sponsorship, honors, reports, settings)
+-- awards/ [if awards_management gate] 🆕 (page=Catalogue, [orchestrationId]/page.tsx, pending/page.tsx, catalog/categories/page.tsx, catalog/definitions/page.tsx, catalog/prize-types/page.tsx, rules/page.tsx, rules/[ruleId]/page.tsx, fulfillment/page.tsx, yearbook/[academicYear]/page.tsx, seed/page.tsx, settings/page.tsx)
+-- settings/ (page, academic, template-banks, calendar, grading, facilities, course-proposal, roles, subscription, features, privacy, audit, webhooks, notifications)
/dashboard/org/[orgId]/ → Organisation Dashboard (separate)
+-- page.tsx | schools/ | members/ | kyc/ | access/ | settings/
/shared/ → Public routes (no auth)
+-- timetable/[token]/page.tsx → Public Timetable View
+-- verify/[code]/page.tsx → Public Document Verification (QR)
/public/ → AwardsPME public routes (no auth, opt-in via tenant config) 🆕
+-- leaderboard/[tenantSlug]/page.tsx → Public Leaderboard (per §12.5 Screen 12)
+-- yearbook/[tenantSlug]/[academicYear]/page.tsx → Public Yearbook (per §12.5 Screen 13)
/awards/my/ → Student Portal — My Awards (federation read, role-filtered) 🆕
Total new routes: ~190 page.tsx files across 22 top-level sections + 1 org context + public routes.
20. Delivery Approach Options
Option A — Full Manual Build (Claude + Developer)
Method: Build every module by hand — feature module, API layer, components, forms, tables, ISCED logic.
~25 modules
~185 pages
~500+ components
Enterprise-grade, full control over every line
Best for: When quality and customization matter more than speed.
Option B — Lovable-Generated + Manual Wiring
Method: Use Lovable to rapidly generate page shells and components from mockups/descriptions, then manually wire them to the real API.
Best for: When speed of visual delivery matters most. Governance rules already in place.
Option C — Hybrid (Recommended)
- Phase 1 (Shell) — built manually. The tenant context provider, RBAC navigation, and school layout are architectural foundation. Must be built right.
- Phases 2-8 (Feature modules) — Lovable generates, developer wires.
Feed Lovable the Swagger spec + mockup. Lovable generates layouts,
table columns, form fields. Developer wires to real API, adds
ISCED/RBAC/gate logic, QAs against live data.
Best for: Delivering a demoable product quickly while maintaining enterprise-grade API integration.
21. Risk Register
R01Feature gate enforcement missing
Schools see modules their subscription doesn't include.
@RequireFeature() guard decorator needs to be written and deployed before frontend launches.
R02ISCED rendering untested
No real university tenant exists to test ISCED 5+ features.
Create test tenants at different ISCED levels with representative data.
R03Performance at scale
Data tables with 1,000+ rows may lag.
All list endpoints support ?page=&limit= — use server-side pagination.
R04Multi-tenant data leaks
Bug in tenant context causes cross-school exposure.
X-Tenant-Id header enforced on every backend endpoint. Frontend must always set it.
22. Success Criteria
01School admin can enter dashboard — UADE enterRoute works, school overview renders with real data
02RBAC-filtered navigation — Users only see what their role permits
03Feature-gate filtered modules — Disabled gates hide modules
04Student CRUD end-to-end — Create, read, update, search, filter, paginate
05Admission pipeline flows — Apply → review → score → offer → accept → enroll
06Grading for ISCED 2 + ISCED 6 — Score entry, computation, report cards for secondary; GPA/CGPA for university
07Fee collection works — Structure → invoice → payment → receipt
08ISCED-conditional rendering — Same dashboard renders differently for primary vs. university
09Mobile-responsive — Works on tablet (1024px) and mobile (375px)
10All data tables handle scale — Server-side pagination, no client-side lag
23. Internationalization (i18n)
All user-facing text in the frontend MUST use next-intl translation functions. No hardcoded English strings in components.
23.1 Reference Document
See frontend/planning/TRANSLATION_PROTOCOL.md v1.0: next-intl + Zustand locale persistence, ICU message format for plurals/interpolation, EN + FR launch languages.
23.2 Implementation (Proof of Concept Complete)
UADE proof of concept deployed: src/i18n/config.ts, src/i18n/messages/en.json + fr.json, src/stores/locale-store.ts, src/components/language-switcher.tsx. All UADE components use useTranslations() — zero hardcoded strings.
23.3 Rules for New Modules
- Add translation keys to
en.json and fr.json under its namespace
- Import
useTranslations from next-intl in every component that renders text
- Use
t('key') for all labels, buttons, headings, placeholders, tooltips
- Use
useFormatter() for dates, numbers, currencies — never hardcode locale strings
- Use ICU format for plurals:
{count, plural, one {# item} other {# items}}
// Pattern for every component:
import { useTranslations, useFormatter } from 'next-intl';
export function StudentList() {
const t = useTranslations('students');
const tc = useTranslations('common');
const format = useFormatter();
return (
<div>
<h1>{t('title')}</h1>
<Button>{tc('actions.add')}</Button>
<span>{format.dateTime(date, { dateStyle: 'long' })}</span>
</div>
);
}
24. API Client Configuration
24.1 File Location
src/lib/api-client.ts — custom fetch wrapper used by all TanStack Query hooks.
24.2 How It Works
// Every request automatically includes:
// 1. Authorization: Bearer {accessToken} — from NextAuth session
// 2. X-Tenant-Id: {tenantId} — from TenantProvider context (Zustand)
// 3. Accept-Language: {locale} — from locale store (for backend i18n)
// 4. Content-Type: application/json
const apiClient = async (path: string, options?: RequestInit) => {
const session = await getSession();
const { tenantId } = useTenantStore.getState();
const { locale } = useLocaleStore.getState();
const res = await fetch(`${NEXT_PUBLIC_API_URL}${path}`, {
...options,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${session?.accessToken}`,
'X-Tenant-Id': tenantId ?? '',
'Accept-Language': locale,
...options?.headers,
},
});
if (res.status === 401) {
signIn('authentik');
throw new Error('Session expired');
}
if (!res.ok) {
const error = await res.json().catch(() => ({}));
throw new Error(error.message || `API error: ${res.status}`);
}
return res.json();
};
24.3 Environment Variables
| Variable | Value | Purpose |
| NEXT_PUBLIC_API_URL | https://api.academia.vivabox.net | Backend API base URL |
| NEXTAUTH_URL | https://app.academia.vivabox.net | Frontend URL for NextAuth callbacks |
| AUTH_SECRET | (secret) | NextAuth encryption key |
25. Feature Gate Frontend Implementation
25.1 Gate Check in Sidebar Navigation
const navItems = [
{ label: t('nav.students'), href: '/students', icon: Icons.student, gate: null }, // core — always shown
{ label: t('nav.library'), href: '/library', icon: Icons.library, gate: 'library_management' },
{ label: t('nav.health'), href: '/health', icon: Icons.health, gate: 'student_health' },
// ...
].filter(item => !item.gate || featureGates.includes(item.gate));
25.2 Gate Check on Page Load
export default function LibraryPage() {
const { featureGates } = useSchoolContext();
if (!featureGates.includes('library_management')) {
return <FeatureLockedPage gate="library_management" />;
}
return <LibraryDashboard />;
}
25.3 Sub-Gate Check for Features Within a Module
// Show merit scoring only if the sub-gate is active:
{featureGates.includes('admission_merit') && (
<TabsTrigger value="merit">{t('admissions.meritScoring')}</TabsTrigger>
)}
// Premium messaging broadcast:
{featureGates.includes('messaging_broadcast') && (
<Button onClick={sendBroadcast}>{t('messaging.broadcast')}</Button>
)}
25.4 FeatureLockedPage Component
function FeatureLockedPage({ gate }: { gate: string }) {
const t = useTranslations('settings');
return (
<div className="flex flex-col items-center justify-center py-20 text-center space-y-4">
<Icons.lock className="size-12 text-muted-foreground" />
<h2 className="text-xl font-semibold">{t('featureGates')}</h2>
<p className="text-muted-foreground max-w-md">
This feature requires the <Badge>{gate}</Badge> subscription gate.
</p>
<Button variant="outline" asChild>
<Link href="/settings/subscription">View Subscription</Link>
</Button>
</div>
);
}
26. State Handling Patterns
26.1 Loading State (Skeleton)
function StudentListSkeleton() {
return (
<div className="space-y-4">
<Skeleton className="h-10 w-64" /> {/* search bar */}
<Skeleton className="h-8 w-full" /> {/* table header */}
{Array.from({ length: 5 }).map((_, i) => (
<Skeleton key={i} className="h-12 w-full" />
))}
</div>
);
}
26.2 Error State
function ErrorBanner({ error }: { error: Error }) {
const t = useTranslations('common');
return (
<Alert variant="destructive">
<AlertTitle>{t('error.title')}</AlertTitle>
<AlertDescription>{error.message}</AlertDescription>
<Button variant="outline" onClick={() => window.location.reload()}>
{t('actions.refresh')}
</Button>
</Alert>
);
}
26.3 Empty State
function EmptyState({ title, description, action }) {
return (
<div className="flex flex-col items-center justify-center py-16 text-center space-y-3">
<div className="bg-muted rounded-full p-4">
<Icons.inbox className="size-8 text-muted-foreground" />
</div>
<h3 className="text-lg font-semibold">{title}</h3>
<p className="text-muted-foreground text-sm max-w-md">{description}</p>
{action && <Button onClick={action.onClick}>{action.label}</Button>}
</div>
);
}
26.4 Permission Denied
function PermissionDenied() {
const t = useTranslations('common');
return (
<div className="flex flex-col items-center justify-center py-16 text-center space-y-3">
<Icons.shield className="size-12 text-muted-foreground" />
<h3>{t('error.permissionDenied')}</h3>
<p>{t('error.permissionDeniedDescription')}</p>
</div>
);
}
27. Data Table Column Specifications (Top 10 Pages)
27.1 Student List (/students)
| Column | Sortable | Filterable | Default Visible |
| Name (givenName + familyName) | Yes | Search | Yes |
| Student ID | No | No | Yes |
| Programme | Yes | Select dropdown | Yes |
| Level | Yes | Select dropdown | Yes |
| Status | Yes | Select dropdown | Yes |
| Gender | No | Select dropdown | Yes |
| Guardian | No | No | Yes (ISCED 0-4), Hidden (ISCED 5+) |
| GPA | Yes | No | Hidden (ISCED 0-4), Yes (ISCED 5+) |
| Enrollment Date | Yes | Date range | No (column toggle) |
Default sort: givenName ASC | Bulk actions: Export CSV, Change Status, Assign Group
27.2 Staff Directory (/staff)
| Column | Sortable | Filterable | Default Visible |
| Name | Yes | Search | Yes |
| Employee ID | No | No | Yes |
| Role | Yes | Select | Yes |
| Department | Yes | Select | Yes |
| Status | Yes | Select | Yes |
| Phone | No | No | Yes |
| Hire Date | Yes | Date range | No |
Default sort: givenName ASC | Bulk actions: Export CSV
27.3 Application List (/admissions/applications)
| Column | Sortable | Filterable | Default Visible |
| Applicant Name | Yes | Search | Yes |
| Programme | Yes | Select | Yes |
| Level | Yes | Select | Yes |
| Status | Yes | Select (AS_DRAFT, AS_SUBMITTED, AS_SHORTLISTED, etc.) | Yes |
| Merit Rank | Yes | No | Yes |
| Submitted At | Yes | Date range | Yes |
| Reviewer | No | Select | No |
Default sort: createdAt DESC | Bulk actions: Shortlist, Reject, Export
27.4 Invoice List (/finance/billing)
| Column | Sortable | Filterable | Default Visible |
| Invoice # | Yes | Search | Yes |
| Student | Yes | Search | Yes |
| Amount | Yes | No | Yes |
| Balance | Yes | No | Yes |
| Status | Yes | Select (DRAFT, SENT, PARTIALLY_PAID, PAID, CANCELLED) | Yes |
| Due Date | Yes | Date range | Yes |
| Programme | No | Select | No |
Default sort: createdAt DESC | Bulk actions: Send reminders, Export, Cancel
27.5 Assessment List (/grading/assessments)
| Column | Sortable | Filterable | Default Visible |
| Title | Yes | Search | Yes |
| Course | Yes | Select | Yes |
| Type | Yes | Select (CA, MIDTERM, FINAL) | Yes |
| Status | Yes | Select (DRAFT→FINALIZED) | Yes |
| Max Score | No | No | Yes |
| Scores Entered | No | No | Yes (progress bar) |
| Created At | Yes | No | No |
Default sort: createdAt DESC | Bulk actions: Activate, Release, Finalize
27.6 Timetable Slots (/timetable/slots)
| Column | Sortable | Filterable | Default Visible |
| Day | Yes | Select | Yes |
| Period | Yes | Select | Yes |
| Course | Yes | Select | Yes |
| Lecturer | Yes | Select | Yes |
| Room | Yes | Select | Yes |
| Level/Class | Yes | Select | Yes |
| Status | Yes | Select (DRAFT/APPROVED/PUBLISHED) | Yes |
Default sort: dayOfWeek ASC, periodIndex ASC | Bulk actions: Submit, Approve, Publish
27.7 Attendance Records (/attendance)
| Column | Sortable | Filterable | Default Visible |
| Student | Yes | Search | Yes |
| Date | Yes | Date range | Yes |
| Event Type | Yes | Select (LESSON, SCHOOL_DAY, etc.) | Yes |
| Status | Yes | Select (PRESENT, ABSENT, LATE, EXCUSED) | Yes |
| Course/Period | No | Select | Yes |
| Marked By | No | No | No |
Default sort: date DESC | Bulk actions: Export
27.8 Library Catalogue (/library/catalogue)
| Column | Sortable | Filterable | Default Visible |
| Title | Yes | Search | Yes |
| ISBN | No | Search | Yes |
| Author(s) | Yes | No | Yes |
| Type | Yes | Select (BOOK, JOURNAL, DIGITAL) | Yes |
| Copies (Total/Available) | Yes | No | Yes |
| Status | Yes | Select (ACTIVE, WITHDRAWN) | Yes |
Default sort: title ASC | Bulk actions: Import, Withdraw
27.9 Behavior Events (/behavior/events)
| Column | Sortable | Filterable | Default Visible |
| Student | Yes | Search | Yes |
| Category | Yes | Select | Yes |
| Polarity | Yes | Select (POSITIVE/NEGATIVE) | Yes |
| Points | Yes | No | Yes |
| Date | Yes | Date range | Yes |
| Recorded By | No | Select | No |
| Voided | No | Select | No |
Default sort: createdAt DESC | Bulk actions: Void, Export
27.10 Scholarship Applications (/scholarships/applications)
| Column | Sortable | Filterable | Default Visible |
| Applicant | Yes | Search | Yes |
| Programme | Yes | Select | Yes |
| Status | Yes | Select (SUBMITTED, SHORTLISTED, AWARDED, REJECTED) | Yes |
| Applied At | Yes | Date range | Yes |
| GPA | Yes | No | Yes |
| Committee Score | Yes | No | No |
Default sort: createdAt DESC | Bulk actions: Shortlist, Reject
28. Backend Dependencies — What the Frontend Needs from Backend
Purpose:
Single-source list of backend changes the frontend plan depends on.
Aggregated from all module patch documents (Phase 2-5). Maintained as
modules are patched. Legend: 🔴 Blocking frontend build · 🟡 Blocking specific screen · 🟢 Nice-to-have
28.1 Guardian Permissions (ChildCard.metadata)
Backend must extend ChildCard.metadata (exposed via UADE /uade/dashboard)
with granular access flags. Each controls what parent can see in Parent
Portal screens. Without these, parent screens cannot be exposed.
| Permission | Purpose | Consumer Module | Patch Ref | Status |
| canViewGrades | Parent views child's grades | GME (existing) | — | ✅ Shipped |
| canViewAttendance | Parent views child's attendance | ATME (existing) | — | ✅ Shipped |
| canCommunicateWithTeachers | Parent messaging channel | NSE (existing) | — | ✅ Shipped |
| canViewHealthRecords | Parent views child's health tabs | SHME | 10.1 | 🟡 Needed |
| canViewMentalHealth | Sensitive subset — mental-health referrals | SHME | 10.1 | 🟡 Needed |
| canAuthorizeMedication | Parent sign-off prescription for minor | SHME | 10.1 | 🟡 Needed |
| canViewBehavior | Parent Feed, Digest, Transcript | SBME | 10.2 | 🟡 Needed |
| canViewLibrary | Borrowings, holds, fines, reading | LME | 10.3 | 🟡 Needed |
| canViewHostel | Allocation, exeat status | HME | 10.4 | 🟡 Needed |
| canViewCanteen | Meal history | RCM | 10.5 | 🟡 Needed |
| canViewTransport | Transport attendance | TME | 10.6 | 🟡 Needed |
| canViewSponsorship | View child's sponsorship consent + status | SCME | 12.1 | 🟡 Needed |
| canViewAwards | View child's awards (federated from StuLCE/SBME/AwardsPME) | AwardsPME | 12.5 | 🟡 Needed |
8 new flags pending. All are booleans on the Guardian record, returned in ChildCard.metadata per the existing pattern.
28.2 Admin Sub-Permissions
Finer-grained admin RBAC for sensitive sub-workflows. Needed so not every school admin sees mental-health records, etc.
| Permission Key | Purpose | Module | Status |
| health:mental-health.read | Restrict SHME mental-health referrals to counselor role only | SHME | 🟡 Needed |
| behavior:mental-health.read | Restrict SBME counseling referrals | SBME | 🟡 Needed |
| behavior:hearings.conduct | Only principal/headmaster conducts formal escalation hearings | SBME | 🟡 Needed |
| behavior:contracts.sign-off | Review/approve behavioral contracts | SBME | 🟡 Needed |
| student:impersonate.view | Admin "view as student" support feature | Shell §19 | 🟢 Enhancement |
| awards_coordinator | RBAC permission set (not new persona): award:record.view + prize:record.view + prize:record.fulfill + prize:record.cancel + prize:record.retry. School admin assigns to staff who run prize fulfillment. | AwardsPME | 🟡 Needed |
28.3 Backend Workflow Triggers
Decisions or triggers backend needs to implement for frontend flows to work cleanly.
| Trigger | Expected Behavior | Module | Ref | Status |
| Guardian creation auto-invite | On
Guardian record creation (during student intake with email), auto-send
signup invite email. Parent clicks → account activated → Parent Portal
role card appears in UADE | StuLCE → Auth | Shell §19.3 (D7) | 🟡 Needed |
| User Onboarding sprint (full spec) 🆕 | Auto-invite primitive triggered by Guardian / Staff / Student-via-ADME-enrolment / Student-manual creation. Sends signed JWT invite email; recipient sets password, Authentik account activates, JWT strategy at src/auth/strategies/jwt.strategy.ts:89-105 auto-swaps placeholder authentikId on first login. Reuses existing PENDING + "pending_<ts>" placeholder pattern; no schema enum changes. Currently blocking Sprint 4 (Persona Variants) — frontend cannot test parent/teacher/student personas without real logins. | StuLCE + StaME + ADME + new Invite engine | Spec: docs/architecture/SPRINT_USER_ONBOARDING.md · Plan: §6.5 | 🔴 Blocking Sprint 4 — sprint estimated 18 days |
| Parent-initiated exeat approval | Decide: auto-approved (parent = authority) vs needs admin review. Backend distinguishes by caller role | HME | Patch 10.4 #2 | 🟡 Needs decision |
| LME fine payment reconciliation | When student pays LME fine via ACCTE-WME wallet, POS webhook must reconcile fine status in LME | LME ↔ ACCTE | Patch 10.3 #7 | 🟡 Needed |
| Peer report anonymization | POST /sbme/peer-reports with anonymous flag — backend strips reporter identity before exposure to admin | SBME | Patch 10.2 #10 | 🟡 Needed |
| SHME refectory alerts → RCM | POST /shme/records/refectory-alerts pushes allergy/dietary data; RCM Check-In reads aggregated alerts on student | SHME → RCM | Patch 10.1 #4, 10.5 #3 | 🟡 Needed |
| Conduct grade → GME term report | SBME POST /conduct-grades/calculate flows result to GME term report before finalization | SBME → GME | Patch 10.2 #4 | 🟡 Needed |
| Donor/Sponsor persona modeling | UADE has partner role-card; need to clarify if it covers individual donors too, or add new donor persona kind. Blocks Donor Portal screens 20-23 in SCME. | UADE → SCME | Patch 12.1 #1 | 🟡 Needs decision |
| Per-student dashboard aggregation endpoint 🆕 | GET /stulce/students/:id/overview
returns all 12 panel payloads in one call (currently frontend
orchestrates 12 parallel queries). Reduces network round-trips from 12
to 1. Frontend ships parallel-call MVP first. | StuLCE (cross-engine federation) | Patch 7.0 #1 | 🟡 Optimization needed |
| School-wide overview aggregation endpoint 🆕 | GET /stulce/school-overview?{filters}
returns all stat cards + analytics in one call (frontend currently
orchestrates 6-8 parallel queries with filters: level, programme,
classId, gender, ageMin/ageMax, boarding, status, feeStatus). | StuLCE | Patch 7.0 #2 | 🟡 Optimization needed |
| AI Engine 🆕 | Future Phase 9
backend engine for predictive insights. Per-student at-risk scoring,
school-wide dropout/fee-default predictions, cross-engine narratives.
Frontend reserves space via ai_insights feature gate (default OFF). No backend code yet. | AI Engine (future) | Patch 7.0 #4 | 🔴 Not built |
| NSE generic /events WebSocket namespace 🆕 | Currently only /messaging WS namespace exists. Need generic /events namespace that streams cross-engine events for live dashboard updates (replaces auto-refresh polling). | NSE | Patch 7.0 #5 | 🟢 Future enhancement (Phase 6+) |
| Sponsorship publish requires consent | POST /scme/sponsorship-profiles/:id/publish should fail if no parent consent exists for that student. Backend enforces; frontend shows warning. | SCME | Patch 12.1 #3 | 🟡 Needed |
28.4 Cross-Module Backend Contracts
Data flows between engines that frontend depends on. Backend must wire these.
| From | To | Purpose | Status |
| SCIE event check-in | ATME attendance | Event check-in (for mandatory events) creates attendance record | 🟡 Verify |
| TME fees config | ACCTE/FME | Transport fees → invoicing | 🟡 Verify |
| HME boarding status | RCM meal plans | Boarders auto-assigned meal plan on check-in | 🟡 Verify |
| LME graduation clearance | StuLCE graduation | Gate graduation on no outstanding library items | 🟡 Verify |
| SHME enrollment gate | StuLCE enrollment | Medical clearance required to enroll | 🟡 Verify |
| GME term report | DTGE template | Report card rendering pulls GME data | 🟡 Verify |
| SCME award | DTGE certificate | Scholarship certificate generation | 🟡 Verify |
| HME fees config | ACCTE/FME | Hostel fees → invoicing | 🟡 Verify |
28.5 Potential New Endpoints (Student/Parent Self-Service)
Places where frontend currently reuses admin endpoints with activeStudentId filter — backend may want to add explicit /my or /mine endpoints for cleaner row-level security.
| Expected Endpoint | Current Workaround | Module | Priority |
| GET /shme/records/mine | Reuse admin GET /records/:studentId with own ID | SHME | 🟢 Cleaner RLS |
| GET /lme/circulation/my | Reuse GET /circulation/patron/:patronId with own patronId | LME | 🟢 Cleaner |
| GET /lme/holds/my | Similar | LME | 🟢 Cleaner |
| GET /lme/fines/my | Similar | LME | 🟢 Cleaner |
Note: Current workaround works if backend has row-level security based on session.user.id + requested studentId/patronId match. If backend can't enforce that at query level, dedicated /my endpoints become 🔴 Blocking.
28.6 Maintenance
This section is updated as each module patch is applied. Last aggregate update: 2026-04-20 (after Phase 5 complete). When adding a new dependency to any patch doc's "Open Items" section, also add it here under the appropriate category. This is the contract with backend team.
Generated: 2026-04-15 · Last updated: 2026-05-02 | Academia V2.1 | School Admin Dashboard Build Plan v2.1
Source of truth: demofox VPS (77.237.247.146)
Backend (2026-05-02): 35+ engines, 1,980 endpoints across 291 Swagger tags, 401+ models — all tests green
Plan coverage: 1,712 of 1,980 endpoints (86.5%) across 441 screens. Pending: OvME, ICME, MarketPE, TransME, CFE.
Supersedes: v1.0 (2026-04-10) which was written against 1,548 endpoints and missed 7 entire modules