05 — Screen Inventory (Staff Module)
- S1 — Staff List (
/staff) - S2 — Staff Detail (
/staff/:id) - S3 — Create Staff (
/staff/new) - S4 — Edit Staff (
/staff/:id/edit) - S5 — Deactivate Flow (modal, from S1/S2)
- S6 — Department List (
/departments) - S7 — Department Detail (
/departments/:id) - S8 — Department Form (create + edit)
- S9 — Designation List (
/designations) - S10 — Designation Detail (
/designations/:id) - S11 — Designation Form (create + edit)
- Cross-screen state rules (shared 00-shared/06 §3.1)
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); responsedata: Staff[],meta(staff.service.ts:64-76; enveloperesponse-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),statusbadge + overflow menu (staff.schema.ts:22-52). - Filters
(proposed): client-side chips forstatus(exact enumstaff.schema.ts:7-12) andemploymentType(staff.schema.ts:14-19); search box maps toqparam 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);metadrives 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 fromGET /staff/:id. - Extra field vs create:
status(update-staff.dto.ts:35-38) andmetadata(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 filteringdepartmentId(no server endpoint returns members). - Head row: avatar + name via
headId→GET /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 addsstatus. - 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
levelascending(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, default0); edit addsstatus. - 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.