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 Journeys (Communication Module)

End-to-end journeys mapped to backend flow. Backend behavior cited with file:line.


1. Author journey: Draft → Publish → Measure (Aisha, Daniel)

StepActionBackend callBackend behavior
1Open composerlocal form state (draft is client-side only)
2Title, body, audiencevalidated per CreateAnnouncementDto
(create-announcement.dto.ts:29-49)
3Save draftPOST /announcementscreates doc with published: false and
createdBy from tenant context (announcement.service.ts:31-37); emits
AnnouncementCreated (:39-51)
4PublishPOST /announcements/:id/publishidempotent — returns early if already
published (announcement.service.ts:68-70); resolves audience → targetUserIds
(:73-75,109-148); sets published: true, publishedAt (:76-78); emits
AnnouncementPublished (:80-91)
5MonitorGET /announcements/:id/readsreturns readBy[] receipts
(announcement.service.ts:104-107)
6Follow upmanual (no reminder automation)

Pain points: AudienceType.ALL resolves to [] (announcement.service.ts:144-146) — broadcast-all currently carries no resolved targets; unread-laggard export is a gap; expiry/priority (planned).

2. Recipient journey: Feed → Detail → Read (Zainab)

StepActionBackend callBackend behavior
1Open feedGET /announcementslist, sort: { createdAt: -1 }
(announcement.service.ts:56-60); optional ?audience= filter
2Client-side "For me"must match targetUserIds against own id locally;
ALL-type entries are always "for me" (forward-looking) — backend does not filter
(announcement.service.ts:56-60)
3Open detailGET /announcements/:idgap: no route; reuse list item payload
(forward-looking)
4Read + acknowledgePOST /announcements/:id/read$addToSet receipt
{userId, readAt} — idempotent (announcement.repository.ts:20-33)
5Check attachmentattachments: string[] stored on doc
(create-announcement.dto.ts:45-49)

3. Manager journey: Read-receipt audit (Aisha)

  • Open "My announcements" (list) → pick one → receipt breakdown: total targeted (targetUserIds.length), read count (readBy.length), unread (targetUserIds − readBy.userId). All derivable from GET /announcements/:id/reads
    • targetUserIds from list payload.
  • Note: reads returns receipts but not the target list; client needs both (announcement.service.ts:104-107).

4. Chatter journey: 1:1/group messaging (Samuel)

  • Threads list → open thread (GET /threads, GET /threads/:id) → send (POST /messages); realtime delivery via WebSocket (planned), docs/IMPLEMENTATION_PLAN.md:119. (Messages are secondary surface in this package; see 04_Information_Architecture.md.)

5. Error / exception paths

SituationBackend behaviorClient handling
Publish nonexistent idNotFoundException announcement.service.ts:64error snackbar
Mark read nonexistent idNotFoundException announcement.service.ts:100toast, refresh list
Audience name typo (grade/section)resolves [] targets silently
(announcement.service.ts:122,129)composer warns "0 recipients"
(planned) — backend does not validate
Duplicate read tap$addToSet no-op (announcement.repository.ts:27-31)idempotent UI