Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

02 — User Personas (Timetable Module)

Derived from blueprint/01-Product/USER_PERSONAS.md (tenant-level actors), the implemented RBAC permission catalog (src/modules/rbac/permissions.constants.ts:44-45), and the actual API surface (src/modules/timetable/**). Personas marked (derived) are role-level specializations inferred from module access patterns, not literal blueprint personas.


1. Organization Admin

  • Blueprint anchor: "Manages a single institution (tenant). Goals: Configure branches, invite staff, oversee operations. Access: Full tenant admin, configurable permissions." (USER_PERSONAS.md:20-25)
  • System role: org_adminpermissions: ALL_PERMISSIONS (role.schema.ts:17-24), which includes timetable.read and timetable.create (permissions.constants.ts:44-45).
  • Goals: a complete, conflict-free weekly timetable before term start; teachers and rooms never double-booked; changes applied fast during term (substitutions).
  • Pain points: there is no update/delete endpoint — fixing a mistake means recreating entries via the planned routes (OQ-2); class-vs-class overlaps are not detected server-side (timetable.service.ts:17-22), so the admin carries that check in their head.
  • Context: desktop-first, term-start bursts; the grid is the primary surface.
  • Success: full week built in one session with zero 409s on submit.

2. Academic Coordinator (scheduling operator)

  • Blueprint anchor: derived from Staff persona ("coordinators… read access across modules", USER_PERSONAS.md:34-39) — the person who actually builds the timetable from teacher availability and room inventory. (derived)
  • System role: custom role granted timetable.read + timetable.create (permissions.constants.ts:44-45) — client-side gating only, server is JWT-only (timetable.controller.ts:9, 01 §5).
  • Goals: lay out the weekly grid per class; balance teacher load; assign rooms; resolve conflicts as they appear (409 from timetable.service.ts:28).
  • Pain points: room view has no API (no roomId query param, timetable.controller.ts:20-29) — must compose it client-side from class grids (planned) for backend support; no bulk create (IMPLEMENTATION_PLAN.md:226).
  • Context: desktop; heavy keyboard + drag & drop usage (15 §8).

3. Teacher (self — read-only)

  • Blueprint anchor: "Delivers instruction. Goals: Mark attendance, assign homework, enter exam marks. Pain: Wants minimal clicks; mobile-friendly. Access: Own classes, own students." (USER_PERSONAS.md:27-32)
  • System role: teacherpermissions: ['student.read','attendance.mark','attendance.edit'] (role.schema.ts:26-32) — no timetable.* grant; "My schedule" is served by GET /timetable?teacherId=<me> (timetable.controller.ts:23-27) using the teacher's own id, read-only.
  • Goals: know where to be at any time, in < 10 s, on a phone; see today's classes and the whole week.
  • Pain points: no self-resolution endpoint (GET /timetable/me does not exist) — the client must know the teacher id; conflicts caused by others appear as double-booking in their grid with no resolution affordance (read-only).
  • Context: phone-first, during school hours; minimal interaction — view-only grid.

4. Room / Facilities Manager (derived)

  • Blueprint anchor: derived from Staff persona + the existence of the Rooms module (room.schema.ts:16-35, rooms.controller.ts:20-52). (derived)
  • System role: custom role with rooms.read (permissions.constants.ts:50).
  • Goals: see which room is free when; spot room overlaps; plan lab/hall usage.
  • Pain points: the API cannot answer "what's booked in room X" — GET /timetable only filters by classId/teacherId (timetable.controller.ts:22-25). The client merges per-class responses; a native room filter is (planned).

5. Persona → surface map

PersonaPrimary surfaces (this module)Key endpoints
Org AdminClass grid, entry editor, conflict bannerPOST /timetable (timetable.controller.ts:14-18), GET /timetable?classId= (:23)
Academic CoordinatorClass grid, teacher grid, room view (planned), entry editorPOST /timetable, GET /timetable?classId=, GET /timetable?teacherId= (:26)
Teacher (self)My schedule grid (read-only)GET /timetable?teacherId=<me> (:26)
Room / Facilities ManagerRoom schedule (planned)composed from GET /timetable?classId=; native ?roomId= (planned)