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

02 — User Personas (Search Module)

Who uses global search, what they look for, and how the index serves them. Personas are grounded in the entities the indexer actually indexes (search-indexer.service.ts:7-32) and the single search permission (permissions.constants.ts:93). All personas are tenant-internal — the repository scopes every query to the JWT tenant (search-index.repository.ts:24-26).


1. Admin / Principal

  • Access: search permission + JwtAuthGuard (search.controller.ts:10,16).
  • Goal: find any person, document, or record fast from the dashboard search bar.
  • Typical queries: staff member by name, student by admission number, book by title.
  • Served by: index rows for User, Student, Teacher, Staff, Parent, Book, Organization, Announcement (search-indexer.service.ts:7-32).
  • Expectation: results in < 1 s; taps a result and lands on the entity detail.
  • Frustration risk: stale results for leads/announcements — no update/delete events are mapped for those types (search-indexer.service.ts:29-31).

2. Receptionist / Front-office clerk

  • Access: search permission.
  • Goal: locate a student or parent quickly when they arrive.
  • Typical queries: student name fragments, admission number (search-indexer.service.ts:71), parent email (:78).
  • Served by: substring-tolerant fallback ($regex case-insensitive on title/description/text/tags — search-index.repository.ts:36-50); Mongo $text needs word-ish tokens, so partial names rely on the fallback path.
  • Expectation: type-ahead with debounce; "see all" drill-down per entity type when many matches.

3. Teacher

  • Access: search permission.
  • Goal: find students in their class, locate colleagues, find announcements.
  • Typical queries: student name, announcement keyword (matched on body → description — search-indexer.service.ts:80), book title for the library.
  • Served by: Student, User, Announcement, Book rows.
  • Expectation: announcement search should find the latest copy; known gap: only AnnouncementCreated/Published are indexed, edits do not re-sync.

4. Librarian

  • Access: search permission.
  • Goal: check whether a title exists in the catalogue without opening the library module.
  • Typical queries: partial title, author in description.
  • Served by: BookCreated/Updated/DeletedBook rows (search-indexer.service.ts:13,20,27).
  • Expectation: ISBN-style tokens; numeric tokens work through text/tags fields since text search includes them.

5. Parent (mobile companion) (forward-looking)

  • Access: future read-only companion role — PRD Phase 3 (00-shared/12 A1).
  • Goal: find their child, school announcements, staff contacts.
  • Served by: the same endpoint (permission permitting) — no parent-specific search surface exists in code.
  • Expectation: results are tenant-scoped; parent must never see cross-tenant rows (base.schema.ts:9-31, repository scoped filter).

6. Operations lead (coaching module) (planned)

  • Goal: search batches, sessions, test series, DPP content.
  • Served by: plan-only index extension (docs/IMPLEMENTATION_PLAN.md:771) — not in code today.

7. Anti-personas (explicitly out)

  • Cross-tenant operator: impossible by construction — every read/write is tenant-scoped (search-index.repository.ts:84-89; redis-cache.service.ts:16-19 even namespaces cache keys per tenant, though search does not use Redis yet).
  • Unauthenticated user: 401 — JwtAuthGuard on the controller (search.controller.ts:3,10).

Persona × entity matrix (what each persona mostly finds)

PersonaUserStudentTeacherStaffParentBookOrganizationLeadAnnouncement
Admin
Receptionist
Teacher
Librarian
Parent (forward-looking)

Gaps this matrix exposes are the same event-mapping gaps: leads are create-only (search-indexer.service.ts:29), announcements never update (:30-31).