Skip to main content
Schoolyi
School librarian arranging books and planning cards in a bright library

Browse docs

Communication

Notifications workflow

What Schoolyi actually delivers - in-app alerts and SMTP email - plus the event registry, per-user preferences, role-aware deep links, and the dead-letter queue for failed sends.

Communication guide for day and boarding schools.

Last updated August 29, 2026

What actually delivers

Before you design a communication policy around this module, be clear about which channels leave the server. An in-app notification is a database row that appears at /notifications and in the bell count, and it always works because it needs no external service. Email is sent through one shared nodemailer SMTP transport, so if SMTP is healthy, email works everywhere, and if it is not, nothing sends anywhere. Those are the two real channels.

SMS and WhatsApp appear in the code and in some settings, and neither transmits a message. The SMS provider shipped with the product writes the message to the server log and returns success, and no real provider is registered anywhere in the codebase, so counters and status fields that say sent mean logged. WhatsApp is a wa.me link builder: the fee dunning ladder stores that link inside an in-app notification for a person to open manually. Do not promise parents an SMS.

ChannelReal?What happens
In-appYesA Notification row keyed to a recipient, read at /notifications with an unread count
EmailYes, with SMTPOne shared nodemailer transport; per-module HTML templates
SMSNoLog-only provider writes the text to the server log and reports success
WhatsAppNoBuilds a wa.me chat URL stored in a notification for manual follow-up
Push / mobileNoNot implemented; the bell polls the unread count about every 90 seconds

Prerequisites

  1. Configure SMTP and FROM_EMAIL, then send a test from /settings/email-test until it passes.
  2. Check per-user defaults at /settings/notifications. Each user, including parents and students, owns their own preferences.
  3. Review the reusable copy at /settings/message-templates. Three categories ship: fees, admissions, and general.
  4. Configure exam mail separately at /settings/exam-notifications if the school runs formal exam sessions.
  5. Confirm guardians are linked to students at /parents, because family notifications resolve recipients through active parent links with a portal user.

The event registry is the source of truth

Every notification type is declared once in lib/notifications/event-registry.ts with its preference key, audience, whether it is mandatory, the channels it may use, a deep link, and a retry policy. An unknown event key throws in development and in CI, and in production it is logged and downgraded to the general event, so a typo cannot silently create an unclassified notification. Mandatory events - absence alerts, fee reminders, exam schedule changes, transport boarding and incidents, published report cards - carry a longer retry budget of five attempts than the three given to optional ones.

  • Absence alerts are declared for email, SMS and in-app, and in practice deliver as in-app plus email.
  • Fee reminders, fee generation, exam schedules and results, published report cards and notices are email plus in-app.
  • Grade published, homework due reminders, library events, committee actions, leave status and exam paper workflow are in-app only.
  • Transport boarding is email plus in-app and mandatory; trip started, delay and waitlist events are in-app, while a transport incident also emails.

Preferences, and which of them are honoured

A user saves preferences at /settings/notifications and they are stored on the user record: email on or off, SMS on or off, fee due reminders and a reminder day count, attendance alerts, grade published, leave status, general notices, and a digest mode. Be honest with staff about the reach of these switches. Notice publishing reads the general notices, email and SMS flags. Most other senders check only the registry channel list for the event, not the individual preference, so an absence alert or a dunning email goes out regardless of the switch. Digest mode is stored but nothing batches, so delivery is always immediate, and the fee reminder window is fixed at seven days rather than taken from the saved day count.

  • Links are built by role through lib/notifications/notification-deep-links.ts so the same event lands somewhere useful for each audience.
  • Grades: /my-grades for a student, /parent-dashboard/grades with a childId for a parent, /grades for staff.
  • Fees: the learner fee page for students and parents, /fees/collections for staff.
  • Attendance, transport, leave and syllabus follow the same pattern, with the parent variant carrying childId.
  • Change the route, change the helper. A notification stores the href it was created with, so old rows keep pointing at the old path.

When email fails: the dead-letter queue

  • Failed sends are written as files under uploads/notification-dead-letter, overridable with NOTIFICATION_DEAD_LETTER_DIR, so a failure is visible without a schema change.
  • The count appears on /ops as email dead letters, and the list is available at GET /api/notifications/dead-letter to Platform Admin, Principal, Vice Principal and Admin.
  • An item can be retried or dismissed. Retry records another attempt and the next retry time, and dismisses it once the budget is exhausted - it does not resend the message. Recovery is to resend from the module that owns it, for example a receipt from /fees/receipts.
  • The alert threshold is five open items, owned by the Platform Admin and escalating to the Vice Principal.

Limits

  • No SMS, WhatsApp or push delivery, and no third-party provider integration to enable them.
  • No digest, quiet hours or rate limiting. Every triggered event is written or sent immediately.
  • No automatic redelivery. Nothing polls the dead-letter queue.
  • No delivery receipts or open tracking. A successful SMTP handoff is all the product knows.

Common questions

Quick answers in plain language.

Does Schoolyi send SMS or WhatsApp messages to parents?+

No. The bundled SMS provider only writes the message to the server log and reports success, and no real gateway is wired in, so any sent count or SENT status for SMS means logged. WhatsApp is a wa.me link stored in a notification for a staff member to open. Only in-app notifications and SMTP email actually leave the server.

What still works if SMTP is not configured?+

In-app notifications work normally, because they are database rows. Every email attempt throws instead, and the caller records it: notice sends land on the dead-letter queue, fee payments show [RECEIPT_EMAIL:FAILED], and admission notifications are stored with emailStatus FAILED. Test the configuration at /settings/email-test, which Platform Admin and Admin can use.

Why did a parent receive an email after turning email notifications off?+

Only notice publishing consults the per-user email and general notices switches. Other senders, including absence alerts and the fee dunning ladder, check the channels declared for the event in the notification registry rather than the individual preference. Treat mandatory events such as absence alerts and fee reminders as always-on.

How does an administrator see notifications that failed to send?+

Open /ops and look at the email dead letters count, or call GET /api/notifications/dead-letter as Platform Admin, Principal, Vice Principal or Admin. Items can be retried or dismissed, but retry is bookkeeping only - to actually get the message out, resend it from the owning module.

Related searches

School leaders and IT teams often search for: how to notifications workflow in school management software, best parent communication app schools for K-12 schools, Schoolyi notifications workflow guide, notifications workflow step by step, school notice board software, school announcement system, and parent messaging platform schools.