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

05 — Screen Inventory (Staff Module)

Eleven screens across three route groups. All backend-facing behavior cited from src/modules/staff/**. Layout, copy, and client behaviors follow the shared tokens and components (00-shared/02, 03, 05). Screens are (planned) client-side; the API surface they map to is implemented.

S1 — Staff List (/staff)

  • Purpose: browse the non-teaching roster; entry to detail; quick actions.
  • Data: GET /staff?page=&limit= (staff.controller.ts:27-28); response data: Staff[], meta (staff.service.ts:64-76; envelope response-envelope.interceptor.ts:20-32,55-57).
  • List row: avatar (initials from user — staff profile has no name field; join with users for display, (proposed)), employeeNumber (title), department/designation (subtitle), status badge + overflow menu (staff.schema.ts:22-52).
  • Filters (proposed): client-side chips for status (exact enum staff.schema.ts:7-12) and employmentType (staff.schema.ts:14-19); search box maps to q param which the server accepts but ignores for staff (staff.service.ts:64-76, OQ-2) — label "filtering loaded results".
  • Pagination: page/limit controls (shared contract 00-shared/07 §5); infinite scroll on phone (proposed); meta drives controls (pagination-query.dto.ts:41-55).
  • Actions: FAB "Add staff" (staff.create), row menu: View, Edit, Deactivate (staff.delete).
  • Empty: "No staff yet" + CTA; with filters: "No staff match filters".

S2 — Staff Detail (/staff/:id)

  • Data: GET /staff/:id (staff.controller.ts:30-31); 404 → not-found empty-state (staff.service.ts:58-62).
  • Header: avatar, employee number, name (joined from users (proposed)), status badge, edit + deactivate actions.
  • Tabs (proposed): Overview | Employment | Metadata | Audit (see 06).
  • Related info: department and designation resolve via GET /departments/:id, GET /designations/:id — the detail payload does not embed them (staff.schema.ts:29-33; repositories store refs only).

S3 — Create Staff (/staff/new)

  • Data: POST /staff (staff.controller.ts:24-25).
  • Fields (exact from create-staff.dto.ts:4-38): userId (required picker), employeeNumber (required), departmentId (optional picker), designationId (optional picker), employmentType (optional dropdown — full_time/part_time/ contract/intern), joiningDate (optional date), salaryGrade (optional text).
  • Server defaults: status=active, employmentType=full_time (staff.service.ts:37-43) — surface as helper text, not editable.
  • Errors: 409 on duplicate employee number → inline field error (staff.service.ts:32-36); 400 validation → per-field (http-exception.filter.ts:103-107).

S4 — Edit Staff (/staff/:id/edit)

  • Data: PATCH /staff/:id (staff.controller.ts:33-34); prefilled from GET /staff/:id.
  • Extra field vs create: status (update-staff.dto.ts:35-38) and metadata (update-staff.dto.ts:40-42) — the only sanctioned way to change lifecycle state.
  • Send only changed fields; audit delta = changed keys (staff.service.ts:88).

S5 — Deactivate Flow (modal, from S1/S2)

  • Data: DELETE /staff/:id (staff.controller.ts:36-37).
  • Confirm dialog: warning that deactivation is permanent (soft-delete, no restore endpoint — base.repository.ts:68-74; OQ-8). 404 handled as already-gone.

S6 — Department List (/departments)

  • Data: GET /departments?page=&limit= (department.controller.ts:29-30).
  • Row: name, code badge, head (joined headId (proposed)), status.
  • Actions: FAB "Add department", row menu Edit / Deactivate.
  • Sort: server returns insertion order (department.service.ts:38-50); sort by name is client-side (proposed).

S7 — Department Detail (/departments/:id)

  • Data: GET /departments/:id (department.controller.ts:32-33); 404 handled.
  • Sections: name/code/head/status (schema department.schema.ts:9-19), member list (proposed) — computed client-side by fetching staff and filtering departmentId (no server endpoint returns members).
  • Head row: avatar + name via headIdGET /staff/:id (proposed); deleted head → "—".

S8 — Department Form (create + edit)

  • Data: POST /departments / PATCH /departments/:id (department.controller.ts:26-27,35-40).
  • Fields (exact from department.dto.ts:4-39): name (required), code (optional), headId (optional staff picker); edit adds status.
  • 409 duplicate name → inline (department.service.ts:23-25).

S9 — Designation List (/designations)

  • Data: GET /designations?page=&limit= (designation.controller.ts:29-30).
  • Row: name, level, department (joined departmentId (proposed)), status.
  • Display sort: by level ascending (proposed) — server returns insertion order (designation.service.ts:41-50).

S10 — Designation Detail (/designations/:id)

  • Data: GET /designations/:id (designation.controller.ts:32-33).
  • Sections: name/level/department/status (designation.schema.ts:9-19); staff holding the designation (proposed) — client-filtered list.

S11 — Designation Form (create + edit)

  • Data: POST /designations / PATCH /designations/:id (designation.controller.ts:26-27,35-40).
  • Fields (exact from designation.dto.ts:4-39): name (required), departmentId (optional), level (optional int, default 0); edit adds status.
  • 409 duplicate name → inline (designation.service.ts:25-28).

Cross-screen state rules (shared 00-shared/06 §3.1)

Every screen: Initial/Loading → AppSkeleton; Error → AppErrorState(code, retry); Success+empty → AppEmptyState; Success → content. Pull-to-refresh on all lists. 409 → inline duplicate message (00-shared/06 §5); 401 → refresh flow; 403 → permission screen/action hiding; 429 → backoff copy.