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 Journey (Bulk Module)

End-to-end journeys through the bulk import/export flow. Screen references (SSn) resolve in 05_Screen_Inventory.md; exact API behaviour in 12_API_Mapping.md. Forward-looking client on top of the live API.


1. Journey map

#JourneyPersonaScreensOutcome
J1First-time bulk importAdmissions AdminSS1 → SS2 → SS3 → SS4All rows imported; report shown
J2Import with row errorsAdmissions AdminSS1 → SS2 → SS3 → SS4Partial success; error list reviewed
J3Fix and re-uploadAdmissions AdminSS4 → SS2 (corrected) → SS4Previously failed rows now import; successes not duplicated
J4Export roster / templateRegistrarSS5students.csv downloaded
J5Malformed / wrong fileany adminSS2 → SS1 (error)Clear failure, file not partially imported

J1 — First-time bulk import (happy path)

  1. Entry — Bulk/Import menu (client gate: admin-capable user, 02 §7).
  2. SS1 Upload — picks students.csv (file picker, .csv only); client parses in an isolate to render a preview (15 §4); "Next" enabled when headers match the contract (08 §1).
  3. SS2 Preview — header map (contract vs file), row count, sample rows; mismatches and missing required columns flagged before upload; "Import N rows" CTA.
  4. SS3 Confirm — reads the risk summary: "N rows will create N users and N student records. Duplicates and reference mismatches will be skipped."
  5. SS4 ResultPOST /bulk/import/students; indeterminate progress (sync request); on 200, report renders: imported/failed/total, per-row error table. All-success → celebratory summary + links (view students, download report).
  6. Exit — back to Students list; imported users/students are live immediately (synchronous create; no queue).

J2 — Import with row errors (partial success)

  1. Same entry through SS3.
  2. SS4 — report shows imported < totalRows, failed > 0; error table with row numbers and messages, e.g. Email "x" already registered. / Academic year "2026-27" not found. (08 §2).
  3. Error rows are grouped by cause (duplicates / missing refs / bad format) for fast triage; each row links to its line in the file.
  4. User downloads an error CSV (client-synthesized: original row + error column) for offline fixing — no server endpoint exists for this.

J3 — Fix and re-upload (idempotency)

  1. From SS4, "Fix errors" → re-upload the corrected file (SS2).
  2. Already-imported rows now fail as duplicates (admission number / email, students-import.adapter.ts:49-56) — expected and explained: report shows imported ≈ previously-failed rows, duplicates listed as duplicates.
  3. No duplicate users are created even if a race occurs — the create-time fallback reuses the existing user id (students-import.adapter.ts:72-75).
  4. Design copy must teach this: "duplicate" ≠ "problem" on re-upload (14_QA_Checklist.md §5).

J4 — Export roster / template

  1. SS5 Export — entity selector (students only today), "Download CSV".
  2. GET /bulk/export/studentstext/csv attachment students.csv (bulk.controller.ts:50-60).
  3. Content: admissionNumber, rollNumber, status, admissionDate (students-import.adapter.ts:92-97), sorted by admissionNumber (:90-91).
  4. Templating caveat (flagged): the export is a roster snapshot, not an import template — it lacks firstName/lastName/email/grade/section/ academicYear. UI copy must not claim "download a template from Export"; a true template is client-generated (forward-looking) (04 §6).

J5 — Malformed / wrong file (failure)

  1. Wrong entity offered (e.g. "teachers") → client blocks it (entity list is hard-coded students); if it slips through, server 404 No import adapter for entity "teachers". (bulk-import.service.ts:17-20) → SS4 error state.
  2. Malformed CSV (unclosed quote, bad encoding) → client preview fails first (isolate parse, 15 §4); if the file bypasses preview, server 400 Malformed CSV: could not parse file. (bulk-import.service.ts:31-33).
  3. Empty CSV (header only) → 400 CSV must include a header row and data. (:34-35).
  4. Missing file field → 400 CSV file is required (multipart field "file"). (bulk.controller.ts:43-46).
  5. Nothing is partially imported on any of these — parse happens before the first row is touched.

Cross-journey notes

  • No async queue exists — every journey above blocks on one HTTP request per upload; async workers with BullMQ progress/rollback are (planned) (IMPLEMENTATION_PLAN.md:172) and will later turn SS4's indeterminate bar into a progressed job (design keeps that seam open, 13 §4).
  • Large files (≥ 1000 rows): the journey is identical but slow; UI must pre-cap size (recommended 1000 rows / ~2 MB) and warn before upload (10 §6); server-side row limit (planned).
  • Events: every imported row emits UserCreated (in-app notification, event-queue-map.ts:10) and StudentCreated (in-app student-enrolled, event-queue-map.ts:28) — students/parents may react to onboarding notifications; the importing admin does not need to send anything manually.