02 — User Personas (Search Module)
- 1. Admin / Principal
- 2. Receptionist / Front-office clerk
- 3. Teacher
- 4. Librarian
- 5. Parent (mobile companion)
(forward-looking) - 6. Operations lead (coaching module)
(planned) - 7. Anti-personas (explicitly out)
- Persona × entity matrix (what each persona mostly finds)
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 singlesearchpermission (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:
searchpermission +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:
searchpermission. - 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 (
$regexcase-insensitive on title/description/text/tags —search-index.repository.ts:36-50); Mongo$textneeds 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:
searchpermission. - 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,Bookrows. - Expectation: announcement search should find the latest copy; known gap:
only
AnnouncementCreated/Publishedare indexed, edits do not re-sync.
4. Librarian
- Access:
searchpermission. - 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/Deleted→Bookrows (search-indexer.service.ts:13,20,27). - Expectation: ISBN-style tokens; numeric tokens work through
text/tagsfields 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-19even namespaces cache keys per tenant, though search does not use Redis yet). - Unauthenticated user: 401 —
JwtAuthGuardon the controller (search.controller.ts:3,10).
Persona × entity matrix (what each persona mostly finds)
| Persona | User | Student | Teacher | Staff | Parent | Book | Organization | Lead | Announcement |
|---|---|---|---|---|---|---|---|---|---|
| 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).