ProductNotifications & Announcements

Notifications & Announcements

One-line: Reaches students, parents, and staff through in-app alerts, real-time streams, mobile push, and email — driven by reusable templates and school-wide announcements.

What it does

  • Templated notifications — business events (fee overdue, attendance marked, leave approved) render a reusable template with per-recipient context.
  • In-app notifications — every alert is stored and shown in a bell-icon inbox with an unread count, mark-as-read, and deep links.
  • Real-time SSE stream — the inbox updates live over a text/event-stream connection, with an optional sound chime on arrival.
  • Push to mobile — delivered to registered devices via Firebase Cloud Messaging (FCM) and Expo push for the Expo app.
  • Email — sent through the shared mailer using HTML templates.
  • School announcements — admins author broadcasts that land in the same inbox as everything else.

Who uses it

  • Admins / staff — send manual notifications, author and recall announcements, manage templates.
  • Parents / students / teachers — receive alerts in-app, on mobile, and by email.

Key concepts

  • Notification template — a named, event-triggered layout (subject, body_template) rendered with Jinja context; can target in_app, push, email, or a combination.
  • In-app notification — a stored record (title, message, type, action_url, is_read).
  • SSE stream — long-lived GET /api/notifications/stream pushing new items as they arrive.
  • Device registration / token — a mobile device registers its FCM/Expo token so push can reach it.
  • Push (Firebase / Expo) — device delivery via FCM HTTP v1 and the Expo push API.
  • Announcement — a sibling module (draft → scheduled → published → recalled) that fans out to the same inbox.
  • Mailer / email — shared email sender with reusable HTML templates.

How it works

Business event (e.g. fee marked overdue)
  -> dispatch template for the event, render with per-user context
  -> for each recipient:
       - create in-app Notification (also pushed over SSE)
       - send push to registered devices (FCM / Expo)
       - send email if the template has an email channel

Announcements are authored by admins; on publish, a fan-out task creates one parent notification plus recipient rows, so readers see them alongside normal alerts.

Rules & edge cases

  • Gated by the plan key notifications; permissions use the notification.* / announcement.* prefixes.
  • Everything is tenant-scoped — templates may be tenant-specific or platform-level (tenant_id null).
  • The SSE route calls db.session.remove() before streaming so a live connection never parks a DB pool slot; a keepalive (SSE_KEEPALIVE_SEC, default 15s) doubles as dead-client detection. On a single-worker deployment, long-lived SSE connections can consume worker threads, so thread count must be sized for expected concurrent streams.
  • Announcement attachments are S3-backed; unpublished draft attachments are swept after 24h.
  • Push requires Firebase service-account credentials; email in production runs through the deployment’s SMTP relay (AWS SES), which starts in sandbox mode until a sending limit is granted — see infrastructure.

Where it lives

  • server/modules/notifications/ — templates, dispatch, SSE, push
  • server/modules/devices/ — device token registration
  • server/modules/announcements/ — announcement authoring and fan-out
  • server/modules/mailer/ — email templates and sending
  • admin-web — bell inbox, dropdown, chime, template management
  • mobile client — device registration and push receipt
  • Plan key: notifications