01 — Product Overview (Notifications Module)
- 1. Product Statement
- 2. Scope — In (v1, implemented)
- 3. Scope — Out (planned / forward-looking)
- 4. PRD Exclusion: Native Mobile App
- 5. How Notifications Are Created
- 6. Non-Goals (v1)
Single notification engine across all channels. Scope for this design pass: the in-app notification inbox as implemented in
src/modules/notifications/. Multi-channel dispatch (email, push, WhatsApp, WebSocket) is planned — seestudylyon-blueprint/04-Modules/Notifications.md:11-17.
1. Product Statement
StudyLyon users (students, teachers, parents, staff, org admins) receive a
persistent, per-tenant in-app notification inbox generated from system events
(account lifecycle today; homework/attendance/exams in the event pipeline). Each
notification is a small record: type, title, body, optional data payload,
and a readAt flag (notification.schema.ts:15-32). The inbox supports
list + pagination, single & bulk mark-read, and an unread-count badge.
2. Scope — In (v1, implemented)
| Area | Status |
|---|---|
| Persisted in-app notifications, tenant-scoped | ✅ src/modules/notifications/ |
Event-driven creation (EventBus fan-in) | ✅ notifications.handler.ts |
List w/ pagination + unreadOnly filter | ✅ GET /api/v1/notifications |
| Unread count | ✅ GET /api/v1/notifications/unread-count |
| Mark one read / mark all read | ✅ PATCH /api/v1/notifications/:id/read, PATCH /api/v1/notifications/read-all |
3. Scope — Out (planned / forward-looking)
| Area | Where |
|---|---|
| Email / Push / WhatsApp / WebSocket dispatch | Notifications.md:13; QUEUE.EMAILS / PUSH / WHATSAPP exist (queue.constants.ts:2-4) but no workers consume them for notifications |
POST /api/v1/notifications/send (internal send) | Notifications.md:24 — (planned) |
| Notification templates (i18n + interpolation) | Notifications.md:7 — (planned) |
| Per-user channel preferences | Notifications.md:7,27-28 — (planned) |
| Push/FCM device tokens | POST /api/v1/notifications/device-token (future) — docs/user-flows/END_TO_END_USER_FLOWS.md:788 — (forward-looking) |
| Push for coaching test reminders / DPP alerts / batch start | docs/IMPLEMENTATION_PLAN.md:769,859 — (forward-looking) |
Analytics events {module}.{screen}.{action} | (proposed) — SDK open, see 00-shared/10 §8 |
4. PRD Exclusion: Native Mobile App
Per docs/IMPLEMENTATION_PLAN.md:859 the mobile app is an open clarifying
question, not a v1 deliverable. The PRD scopes the web app + API first; this
design therefore covers the web/app-agnostic in-app inbox and keeps mobile
push behind the (forward-looking) markers above. Any native-app-specific screen
is out of scope.
5. How Notifications Are Created
- Any module emits a
DomainEventon the sharedEventBus. NotificationsHandlersubscribes viaeventBus.onAny(notifications.handler.ts:61) and maps event → notification config (handler.ts:8-31,33-50).- Recipient resolves from
payload.userId ?? payload.recipientId ?? actorId(handler.ts:76-79). - Persist happens inside a synthetic tenant context (
handler.ts:81-99). - Client reads via the four authenticated endpoints.
Today only four event types produce notifications (see 03_User_Journey and 12_API_Mapping for the list).
6. Non-Goals (v1)
- No read-receipt analytics or per-recipient delivery stats.
- No notification detail endpoint (
GET /:id) — detail is derived client-side from the list item +datapayload. - No server-side push to external providers.
- No admin-facing send UI (see 08_Form_Specifications).