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

09 — User Behaviour (Teachers Module)

Rules of engagement: what the UI may/must not do, derived strictly from backend behaviour. Contradictions with PLAN.md / flow docs are flagged, not resolved by invention.


1. Global behaviours

RuleSource
Every list is tenant-scoped automatically; client never sends tenantIdbase.repository.ts:20-30,33-35
Every request carries Bearer JWT; 401 → single-flight refresh → sessionExpired00-shared/06 §3.6
Deleted (soft) records are invisible to the client — 404, not a flag in payloadbase.repository.ts:20-30
success:false never renders raw message for 5xx — generic + requestId; 4xx business text allowed00-shared/07 §11
Server returns raw ObjectIds for refs — client joins names from catalogs; missing ref = "—"teacher.schema.ts:22-26,44-48

2. List screen (S1)

  • Search input debounced 300 ms (AppSearchBar); since q is ignored server-side (teacher.service.ts:66-78), client filters loaded pages locally and shows "Searching across loaded page only" helper when filter active + more pages exist (OQ-3).
  • Filter chips re-run local filter on loaded items; server-side filters don't exist — never claim otherwise in copy.
  • Pagination: infinite scroll; meta.hasNext stops loader (pagination-query.dto.ts:41-55).
  • Pull-to-refresh resets page 1 + bypasses cache (00-shared/06 §3.3).
  • Empty states per 04 §7.

3. Detail screen (S2–S4)

  • Tabs keep state; switching year in Assignments refetches matrix (server keyed by academicYearIdsubject-assignment.service.ts:26-31).
  • If detail fetch 404 → user deleted concurrently → leave detail, snackbar "Teacher removed".
  • Edit navigates to S6 with prefill; back from form → refresh detail.

4. Create/Edit forms (S5/S6)

  • Never optimistic — create/update are server-confirmed writes (00-shared/06 §3.5).
  • On 409: keep form values; show AppBanner + focus related field.
  • On 400: map details[].field → inline field errors; focus first invalid (09_Accessibility_Baseline.md §10).
  • On 5xx/network: keep form values, AppErrorState inline with Retry (idempotent because create duplicate → 409 guard, update → idempotent $set).
  • Offline: form entry blocked with AppOfflineBanner (no offline queue for teachers, 00-shared/06 §3.7).

5. Assignment editor (S7)

  • Add = server-confirmed (no optimistic row).
  • Client duplicate check runs on picker selection AND on submit (race between two admins possible — server accepts both; see QA-3).
  • Remove: confirm dialog (destructive) → server 200 → row removed; 404 → row already gone → remove locally + snackbar.
  • Year switch in S3 discards in-progress editor (sheet closes).

6. Deactivate (S8)

  • Server-confirmed, never optimistic (irreversible).
  • Confirm button pending state; haptic heavyImpact(); on 200 → back + snackbar.
  • No guard server-side on active assignments/timetable (OQ-5) — dialog warns: "Existing assignments and schedule entries are not modified."

7. Teacher self (S9/S10, (planned))

  • Read-only; no create/edit/remove affordances for teacher role.
  • On on_leave/inactive: banner on My Teaching; schedule still visible.
  • No server "me" endpoint — client resolves own teacher id via stored session mapping (see OQ-2; documented, not invented).

8. Error copy table (module)

CodeScreenClient message (i18n key)
409 userF1teachers.create.conflict.user — "A teacher profile already exists for this user."
409 empF1teachers.create.conflict.employeeNumber — "Employee number already exists."
404S2/S3/S8teachers.notFound — "Teacher not found or removed."
404 assignmentS3 removeassignments.notFound — "Assignment already removed."
400F1/F2/F3per-field from details
429allerrors.rateLimited — "Too many requests. Try again in a moment."
5xxallerrors.server + requestId

9. Behavioural edge cases (derived)

  • POST /teachers with userId already having a profile → 409 (create path only; update cannot change userId).
  • PATCH employeeNumber → no uniqueness 409 (only create checks; teacher.service.ts:32-38 vs 80-93) — client pre-check is best-effort.
  • Assignment lists keyed by academicYearId return [] when param missing (subject-assignment.service.ts:26-31) — client always sends it.
  • Timetable by teacher id returns entries sorted dayOfWeek, startTime (timetable.service.ts:55-60) — client must not re-sort by date.