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

03 — User Journeys (Timetable Module)

Five journeys mapped 1:1 to the implemented API. Endpoint citations: timetable.controller.ts:14-29, timetable.service.ts:16-69. (planned) = roadmap/documented but not in code.


Journey 1 — Create a timetable entry (Coordinator / Admin)

flowchart TD
    A[Class grid → tap empty slot] --> B[Entry editor sheet]
    B --> C[Pick class, subject, teacher, day, start/end time, room?, academic year]
    C --> D[Submit POST /timetable]
    D --> E{Server conflict check}
    E -->|409 Schedule conflict detected| F[Inline AppBanner: teacher/room already\n booked in overlapping period]
    E -->|400 VALIDATION_ERROR| G[Field errors per DTO]
    E -->|200| H[TimetableEntryCreated emitted]
    H --> I[Slot appears in grid, server-sorted]
    F --> J[Fix time/teacher/room → resubmit]
  • Body: CreateTimetableEntryDto (create-timetable-entry.dto.ts:5-38).
  • Conflict rule: query matches same-day entries sharing teacherId or roomId (timetable.service.ts:17-22); overlapping time (start1 < end2 && start2 < end1, timetable.service.ts:68) → 409.
  • Not checked: same-class overlap (OQ-1) — client may warn but server accepts.
  • Side-effect: TimetableEntryCreated (timetable.service.ts:33-44) — no queue routing exists (01 §6).

Journey 2 — View a class's weekly grid (all personas, read)

flowchart TD
    A[Nav 'Timetable' → pick class] --> B[GET /timetable?classId=<id>]
    B --> C[Entries sorted dayOfWeek, startTime]
    C --> D[Render 6-day grid Mon..Sat × time rows]
    D --> E[Tap slot → detail popover]
    D --> F[Empty day → dashed empty cell]
  • Server-sorted {dayOfWeek:1, startTime:1} (timetable.service.ts:48-53) — client renders, never re-sorts.
  • Day headers from DayOfWeek enum (timetable.schema.ts:7-14): Monday–Saturday.

Journey 3 — View a teacher's weekly grid (teacher self / coordinator)

flowchart TD
    A[Teacher detail → Schedule tab] --> B[GET /timetable?teacherId=<id>]
    B --> C[Grid sorted dayOfWeek, startTime]
    C --> D{Teacher role?}
    D -->|teacher self| E[Read-only grid, no editor affordances]
    D -->|coordinator/admin| F[Long-press slot → edit / duplicate entry]
  • Same sort contract (timetable.service.ts:55-60).
  • A teacher resolving "me" has no /timetable/me endpoint — client must know the teacher id (OQ-2, teachers 03 §5).

Journey 4 — Resolve a conflict (Coordinator / Admin)

flowchart TD
    A[Submit entry] --> B{409?}
    B -->|yes| C[Conflict banner: 'Teacher already booked\n 10:00-11:00 on Tuesday'\n or 'Room already in use']
    C --> D[Options: change time · change teacher ·\n change room · cancel]
    D --> E[Resubmit POST /timetable]
    E -->|200| F[Grid updates]
    E -->|409 again| C
  • Client can pre-flight conflicts locally: loaded grids per teacher/room let the editor warn before submit; server remains the source of truth (races possible).
  • No partial write: a 409 leaves the grid untouched.

Journey 5 — Room schedule view (Facilities Manager) — (planned)

flowchart TD
    A[Rooms module → room detail] --> B{RoomId filter exists?}
    B -->|no today| C[Client fetches GET /timetable?classId=\n for every class using the room\n and merges slots]
    B -->|planned| D[GET /timetable?roomId=<id>]
    C --> E[Render merged room grid, read-only]
    D --> E
  • No roomId query param on GET /timetable today (timetable.controller.ts:22-25) — the merged client view is a documented composition, not an invention of API surface; native filter is (planned) per IMPLEMENTATION_PLAN.md:226 ("conflicts… export" phase).

Failure exits (shared)

401 → silent refresh → sessionExpired; 429 → "try again in a moment", no auto-retry; 5xx → generic + requestId + retry (per 00-shared/07 §11).