02 — User Personas (Timetable Module)
- 1. Organization Admin
- 2. Academic Coordinator (scheduling operator)
- 3. Teacher (self — read-only)
- 4. Room / Facilities Manager (derived)
- 5. Persona → surface map
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_admin—permissions: ALL_PERMISSIONS(role.schema.ts:17-24), which includestimetable.readandtimetable.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
roomIdquery 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:
teacher—permissions: ['student.read','attendance.mark','attendance.edit'](role.schema.ts:26-32) — notimetable.*grant; "My schedule" is served byGET /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/medoes 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 /timetableonly filters byclassId/teacherId(timetable.controller.ts:22-25). The client merges per-class responses; a native room filter is(planned).
5. Persona → surface map
| Persona | Primary surfaces (this module) | Key endpoints |
|---|---|---|
| Org Admin | Class grid, entry editor, conflict banner | POST /timetable (timetable.controller.ts:14-18), GET /timetable?classId= (:23) |
| Academic Coordinator | Class grid, teacher grid, room view (planned), entry editor | POST /timetable, GET /timetable?classId=, GET /timetable?teacherId= (:26) |
| Teacher (self) | My schedule grid (read-only) | GET /timetable?teacherId=<me> (:26) |
| Room / Facilities Manager | Room schedule (planned) | composed from GET /timetable?classId=; native ?roomId= (planned) |