09 — User Behaviour (Leave Module)
- 1. Requesting leave
- 2. Checking balance
- 3. Approving (org admin)
- 4. Substituting (substitute teacher)
- 5. Reading the calendar
- 6. Behavioural expectations
(proposed) - 7. Metrics
(proposed)
Observed and expected user behaviours around leave, mapped to what the API actually enforces. Behaviors are
(proposed)product expectations unless cited to source; metrics are analytics(proposed).
1. Requesting leave
- Frequency: teachers request a few times per term (sick + planned); admins configure once. High-trust, low-frequency writes.
- Pre-request ritual: users check balance first (
GET /leave/balance) because approval is balance-gated (leave.service.ts:188-189) — the client should surface balance inline on the request form(proposed)to collapse this step. - Date planning: users plan around weekends; the server counts them
(
leave.service.ts:310-312) — expect mismatch complaints; the request form shows the inclusive count up front (06 §2.4). - Overlap behavior: users may file overlapping pending requests (e.g.,
sick leave on top of planned leave). No server rule rejects this (gap —
createRequestleave.service.ts:126-156has no overlap check); a client warning on submit is the mitigation(proposed).
2. Checking balance
- Cadence: before each request; after each approval (deduction is
live-computed,
leave.service.ts:87-88— always fresh). - Mental model: users think "12 days/year" and forget carry-forward;
the card must visually separate
daysPerYear | carriedForward | daysUsed | daysRemaining(:66-74). - Year boundary: balance resets per calendar year with prev-year carry
(
:92-97,107-112) — Jan behavior surprises users; caption it.
3. Approving (org admin)
- Ritual: open queue, skim reasons, decide fast; self-approval is
impossible (
leave.service.ts:179-180) — admins delegate to a peer. - Balance surprise: approval of a request that exceeds balance 409s
(
:188-189); admin's mental model must be "reject or wait" — the UI offers reject-with-note as the fallback action. - Double-decision: second decision 409s (
:175-178) — UI refreshes and greys the row. - Batch desire: admins want batch approve
(proposed)— no server support (one PATCH per id,leave.controller.ts:49-53).
4. Substituting (substitute teacher)
- Discovery: substitute checks "My Substitutions" (
GET /leave/substitutions/teacher/:id,leave.controller.ts:79-83); no push today ((planned)notification,IMPLEMENTATION_PLAN.md:163). - Conflict avoidance: server rejects clashes at assign time
(
leave.service.ts:241-250); substitutes rely on admin accuracy — no accept/decline loop exists (gap). - No-show tracking:
completed/cancelledstates are schema-only (substitution.schema.ts:7-11); behavior tracking is(planned)via Timetable integration.
5. Reading the calendar
- Use: planning coverage, checking who is out before scheduling meetings —
calendar is approved-only (
leave.service.ts:290) and tenant-wide.
6. Behavioural expectations (proposed)
| Expectation | Design response |
|---|---|
| Users distrust stale balance | balance always refetched on screen open; RefreshIndicator; caption "live" |
| Fast approval | Approvals queue default filter pending; approve = 1 tap, reject = 2 taps max |
| Requesters check status often | status chips on list; (planned) push on decision event (events/leave-events.ts:10-18) |
| Admins never re-decide | after decision, row leaves pending view |
| Substitutes plan mornings | substitutions sorted by date asc (leave.service.ts:275-280), grouped by day |
7. Metrics (proposed)
leave.request.submit → decision time (median/P90); balance-check → submit
conversion; approval → substitution assignment rate; clash-rejection rate
(signal of poor coverage planning); reject-with-"insufficient balance" rate
(gap indicator for request-form balance preview).