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

09 — User Behaviour (Communication Module)

Observed/targeted behavior patterns per persona; informs layout, frequency of actions, and failure modes. Backend constraints cited where they shape behavior.


1. Consumption behavior

PersonaCadenceSession typeCore action
Student (Zainab)2×/day (morning/evening)20-40 s skimopen feed → open unread → auto/explicit read
Parent (Mrs. Okoro)1×/day + event-triggered15 sdeep link → detail → read
Teacher (Daniel)3-5×/day around classes30-60 sfeed + compose class notices
Admin (Aisha)as events occur1-2 mincompose, publish, check receipts next day

Behavioral consequence: the feed must render usable in one hand, show unread at a glance (unread dot 07 §1), and open detail in ≤ 1 tap. Read action should feel free — no confirmation dialogs.

2. Composer behavior

  • Authors compose from templates in their head — no template backend ((planned), IMPLEMENTATION_PLAN.md:231); provide no template UI today.
  • Audience choice is the highest-friction step: authors think "my class" or "all teachers", not "grade: Grade 10, name lookup". The AudiencePicker must therefore offer the five types in plain words with a recipient-count preview (planned) — backend resolves counts only at publish (announcement.service.ts:68-93).
  • Draft habit: authors save-then-publish from mobile; publish-from-feed is a convenience (planned) (no such route today — publish requires :id after create).

3. Read-receipt behavior

  • Authors check receipts ~24 h after publish; expect a simple read/unread split.
  • The unread split is derivable but requires both payloads: readBy[] from GET /announcements/:id/reads and targetUserIds from the list (announcement.service.ts:104-107 + :42-43).
  • Known trap: AudienceType.ALL has targetUserIds = [] (announcement.service.ts:144-146) — receipts screen must degrade to "list of who read" without counts to avoid misleading "0 of 0 read".
  • Laggard follow-up (export/remind) (planned).

4. Messaging behavior (secondary)

  • 1:1 staff chat, quick question cadence; unread thread badge drives return visits.
  • Realtime expectation — WebSocket (planned), IMPLEMENTATION_PLAN.md:119; until then poll (forward-looking) is a fallback.

5. Failure modes & tolerance

FailureUser reactionMitigation in design
Feed emptyassumes nothing was announcedempty-state CTA for authors; no skeleton ghosting
Audience silently empty (typo name)believes everyone saw itrecipient preview (planned) + warning (06 §3.3)
Read tap errorsretries once, then ignoresidempotent $addToSet (announcement.repository.ts:20-33) makes retries safe; silent fire-and-forget + toast
Offline feedexpects cached last stateoffline banner + last-fetch cache (forward-looking)
Duplicate announcements (no edit route)deletes? can't — no delete routetolerate duplicates in feed; dedupe by _id client-side

6. Trust & privacy

  • Users believe announcements are private to the tenant — true at API level (BaseRepository tenant scope, announcement.repository.ts:12-18).
  • Users do not expect read receipts to show who read; admins do. Gate receipts UI by authorship (planned) — no RBAC exists yet (permissions.constants.ts has no communication.*), so the client hides it for non-authors by createdBy == me (announcement.schema.ts BaseSchema createdBy; announcement.service.ts:36).
  • Custom-audience picks expose user ids in payloads (create-announcement.dto.ts:18-26); never render raw ids, always display names (user lookup (forward-looking)).