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

12 — API Mapping (Notifications Module)

Exact contract for every endpoint. Base path /api/v1 (URI versioning, src/main.ts). All routes require a JWT (@UseGuards(JwtAuthGuard), notifications.controller.ts:16); success envelope via shared interceptor (common/interceptors/response-envelope.interceptor.ts), errors via common/filters/http-exception.filter.ts (see 00-shared/07).


1. Implemented Endpoints

1.1 GET /api/v1/notifications — List my notifications

  • Source: notifications.controller.ts:21-29service.findMyNotifications (notifications.service.ts:39-52)
  • Query: page (int ≥1, default 1), limit (int 1..100, default 20), unreadOnly (bool) — dto/list-notifications.dto.ts:6-25
  • Response 200:
    { "data": [ { "_id", "recipientId", "type", "title", "body",
                  "data": {}, "readAt": null, "createdAt", "updatedAt", "version" } ],
      "meta": { "page", "limit", "totalItems", "totalPages", "hasNext", "hasPrevious" } }
    
    meta shape from buildPaginationMeta (common/dto/pagination-query.dto.ts:41-55).
  • Ordering: createdAt desc (repository.ts:66). Filter: tenant + recipient + optional readAt: null (repository.ts:52-73).
  • Errors: 400 (bad query), 401 (no token).

1.2 GET /api/v1/notifications/unread-count — Unread count

  • Source: notifications.controller.ts:31-35service.getUnreadCount (service.ts:66-70) → repo.countUnreadByRecipient (repository.ts:31-35)
  • Response 200: { "count": 3 }

1.3 PATCH /api/v1/notifications/:id/read — Mark one read

  • Source: notifications.controller.ts:37-41service.markAsRead (service.ts:54-59)
  • Ownership: recipientId !== userId200 null (no-op, not 404).
  • Response 200: updated document (with readAt, version+1repository.ts:37-43); null for foreign/missing id.
  • Route note: two-segment :id/read cannot collide with read-all (single segment) — keep this ordering on any future param route.

1.4 PATCH /api/v1/notifications/read-all — Mark all read

  • Source: notifications.controller.ts:43-47service.markAllAsRead (service.ts:61-64) → bulk updateMany where readAt: null (repository.ts:45-50)
  • Response 200: {} (envelope with no payload).

2. Permissions

PermissionConstantsUsed by
notification.readpermissions.constants.ts:32list / unread-count (planned RBAC binding)
notification.updatepermissions.constants.ts:33mark-read endpoints (planned RBAC binding)
notification.send (internal)not in ALL_PERMISSIONSPOST /notifications/send(planned), blueprint Notifications.md:24,68-70
notification.preference.managenot in ALL_PERMISSIONSpreferences — (planned), blueprint Notifications.md:70

Note: no RBAC guard is attached today — only JwtAuthGuard; perms are declared-but-unenforced (gap, see 14 §D).

3. Planned / Forward-Looking Endpoints

EndpointStatusSource
POST /api/v1/notifications/send (internal)(planned)Notifications.md:24
GET /api/v1/notifications/preferences(planned)Notifications.md:27
PATCH /api/v1/notifications/preferences(planned)Notifications.md:28
GET /api/v1/notification-templates(planned)Notifications.md:29
POST /api/v1/notifications/device-token(future)(forward-looking)END_TO_END_USER_FLOWS.md:788

4. Event → Notification Creation Contract (no HTTP)

Domain EventNotificationTypeTitleSource
EmailVerifiedemail_verifiedEmail Verifiedhandler.ts:16-20
EmailVerificationResentverification_resentVerification Email Senthandler.ts:21-25
PasswordResetCompletedpassword_resetPassword Resethandler.ts:26-30
UserRegisteredwelcomeWelcome to StudyLyon (interpolates firstName, handler.ts:44-47)handler.ts:41-49

Recipient resolution: payload.userId ?? payload.recipientId ?? actorId (handler.ts:76-79). data = full event payload (handler.ts:96). NotificationCreatedEvent interface (events/notification-events.ts:1-10) is declared but never emitted (gap 14 §F).

5. Queue-Event Routing (infrastructure)

  • QUEUE.EMAILS/PUSH/WHATSAPP/IN_APP constants exist (queue.constants.ts:1-17).
  • event-queue-map.ts:6-43 routes events: emails (welcome/reset/invoice/receipt), in-app (UserCreated, OrganizationCreated, Homework*, ExamResultsPublished, Student/Teacher/Staff/ParentCreated, FeeStructureCreated), audit-write, etc.
  • Gap: no BullMQ worker consumes the in-app queue for notifications; NotificationsHandler listens on the in-process EventBus only (handler.ts:61). The map is the (planned) fan-out contract — see 14 §G.