Notifications & alerts.
A school generates a thousand small events a day — a mark posted, a fee overdue, a bus delayed, a child absent. Notifications decides which of them reaches which person, on which channel, in which language, without ever becoming noise. Per-category routing meets per-person preferences meets per-school quotas and a configured provider: the right news, on the right channel, every time. This handbook follows a single alert from the event that triggered it to the phone it lands on.
- 5delivery channels
- 13preference categories
- EN·FR·ARper recipient
- ≈10 minto read
Prologue
The nervous system of the school#
Every other module produces events; notifications carries them. A grade is posted, an invoice falls overdue, a club meeting is scheduled, a safeguarding flag is raised — each one becomes a notification, routed to exactly the people who should know, on exactly the channels they have chosen, and no further.
Three forces decide the path of every alert. The event has a category. The person has preferences. The school has quotas — and a configured provider per paid channel. The dispatcher resolves all of them for every recipient before it sends a single message. The rest of this handbook is those forces, one chapter at a time.
Chapter one
Everyone has an inbox#
The in-app inbox is the one channel that always delivers — it costs nothing and never runs out of quota. Parents and students read theirs at /portal/notifications, teachers at /teacher/notifications, and school staff at /dashboard/notifications. Each inbox shows messages newest-first, lets the reader filter by All, Unread, or a single category, and hides any category with no messages so the filter row stays scannable. (The teacher and staff views group by day — Today, Yesterday, then dated.)
The inbox is real-time. A new notification arrives over a live database subscription and surfaces as a toast the instant it is created — no refresh, no polling. The subscription is mounted once, in the notifications bell that rides the top bar, so every surface stays current without re-subscribing. Readers mark one notification read or mark all read (clicking one also carries them to whatever it points at); deleting a message from the inbox is a staff action on the admin surface.
Chapter two
Routing across the channels#
Beyond the in-app inbox, YESS reaches families on four external channels: push (to the mobile app), email, SMS, and WhatsApp — five channels in all. Every notification carries a category, and the category paired with each recipient's preferences decides which channels actually fire. The family-facing preference grid covers thirteen categories — academic, financial, communication, attendance, transport, admissions, LMS, social, incident, discipline, health, newsletter, and system — while the platform routes a few more event types behind the scenes (magic links, welcome, plan changes, and the like).
When an event occurs, the in-app copy is delivered immediately and the external channels are queued. There is one more gate before a paid channel can send: the school must have a configured provider for that channel (an email, SMS, WhatsApp, or push provider that is active and credentialed). If no provider is configured, the external copy is simply skipped and the in-app copy still lands — so a school with no SMS provider quietly falls back to in-app rather than failing.
Chapter three
Every person sets their own preferences#
A family controls exactly how the school reaches them at /portal/notifications/preferences. The page has two halves. The first is delivery settings that apply to everything: quiet hours (a window during which non-critical messages are held), a digest mode (off, a daily summary, or a weekly one), the language a message should arrive in (auto, English, French, or Arabic), and a read-receipts toggle.
The second half is the routing grid: for each of the thirteen categories, a master on/off switch and — when it is on — five channel toggles for in-app, push, email, SMS, and WhatsApp. Changes save the moment they are made. WhatsApp is special: a family must enter and confirm a phone number in international format before any WhatsApp message can be sent, and revoking consent clears the number instantly — a deliberate compliance gate, not an oversight.
Chapter four
Quotas and the dispatcher#
External channels cost money, so each school has a monthly quota per paid channel — email, SMS, WhatsApp, and push — seeded at signup (the starting allowances are generous: 100,000 email, 500,000 push, and 5,000 each for SMS and WhatsApp). The admin reads usage against limit on the Quotas tab of /dashboard/notifications; the bar warns past 80% and turns destructive at the limit. When a channel's monthly limit is reached, the dispatcher stops sending on it — the in-app copy still lands, so the message is never lost, only the paid channel pauses.
The same hub carries a Dispatcher view for the people who run delivery: queue-health tiles (pending, dispatched, partial, failed, skipped) and 24-hour volume, the oldest items still waiting, and recent failures. Delivery drains automatically — an edge function runs on a cron schedule — but a Send queue now button flushes it on demand. Every channel attempt is written to an immutable dispatch log with its own status (delivered, rate-limited, opted-out, no-provider, quiet-hours-deferred, or failed), so “did the parent get the SMS?” is answerable from the record rather than guessed.
Chapter five
Speaking to everyone#
Some news goes to the whole school at once — a closure, an event, a policy change. The Send notification tab on /dashboard/notifications composes a broadcast: a title, a body, the channels to use, and an audience picked by role. It can go out immediately with Send now or be scheduled for later. A broadcast fans out into individual notifications, so each recipient still receives it on their own enabled channels and in their own language, and the same quota, provider, and dispatch rules apply.
Broadcast history is kept with per-message counts — total recipients, how many were sent, how many failed — so a head can confirm a closure notice actually reached the school rather than hoping it did.
What makes notifications elite
- 1
Resolved on every send
Event category, recipient preference, school quota, and a configured provider are all resolved per recipient before a single message goes out — so routing is exact, not best-effort.
- 2
Consent-gated paid channels
No SMS or WhatsApp reaches a person who hasn't opted in, and WhatsApp requires a confirmed number in international format. Compliance is built into the send path, not bolted on.
- 3
Never lost, only paused
When a paid channel hits its quota or has no provider, the in-app copy still delivers and the attempt is logged. The message always arrives somewhere.
- 4
An answerable audit trail
Every channel attempt is written to an immutable dispatch log with its own delivery status, so 'did the parent get it?' is a lookup, not a guess.
- 5
One alert, each in their language
Each recipient's preferred language is resolved when the message is written, so a French-speaking family and an Arabic-speaking family read the same alert, each in their own tongue.
Adjacent modules
Where notifications connect#
Notifications is the downstream channel for nearly every other module — it carries the events they produce.
Adjacent modules
- 15Communication hubMessages, announcements, and broadcasts share the same delivery spine and the same inbox.
- 20Finance, fees & accountingOverdue invoices and receipts fire financial-category notifications on the family's chosen channels.
- 10Attendance engineAn absence raises an attendance alert routed to the parent in their language, in real time.
Tutorial
Do it step by step#
Set the school's reach, let a family tune their own, and send something to everyone. Six steps across the admin and the family side.
- 1
Check the school's quotas
On the Quotas tab of /dashboard/notifications, confirm the monthly limits for email, SMS, WhatsApp, and push (they are seeded at signup). This is the budget every alert draws on.If a paid channel runs out mid-month — or has no provider configured — messages don't fail: the in-app copy still lands and the attempt is logged.
- 2
A family tunes their preferences
At /portal/notifications/preferences, a parent sets quiet hours, a digest mode, and a language, then turns each category on or off and picks its channels. Changes save instantly. - 3
Confirm WhatsApp consent
To receive WhatsApp, the family enters a phone number in international format and confirms it. Until that consent exists, no WhatsApp message can be sent — and revoking it clears the number at once. - 4
Let an event route itself
When a module raises an event — an overdue invoice, an absence — the dispatcher resolves each recipient's channels for that category and sends accordingly. The recipient sees it in their inbox at /portal/notifications in real time. - 5
Broadcast to the whole school
For school-wide news, use the Send notification tab on /dashboard/notifications — title, body, channels, audience, send now or schedule. It fans out into individual notifications, each on its recipient's channels and in their language. - 6
Verify delivery
Open the Dispatcher tab to watch queue health, flush the queue on demand with Send queue now, and read the dispatch log to confirm exactly which channel reached which person.The dispatch log is immutable — it is the record you reach for when a family says they never got the message.
One event, resolved against category, preference, quota, and provider — and delivered on every channel the family chose, with a log that can prove it arrived.