Callers fire an event after their own state write succeeds; the dispatcher resolves recipients, applies the org grid and each person's personal mutes, renders any custom wording, and writes an in-app row, an email and a text as permitted. There are three entry points: notifyEvent (role-routed), notifyUsers (a named set of people) and notifyStageRecipients (the per-stage automation engine).
Also called: alerts · who gets told what · notification system · team alerts
- 1Recipients resolve in order, deduped by user id: roles in the org's preference row for this event, explicitly picked individuals, and every assignee of the project when the payload names one.
- 2The org roster comes from the org_members mirror in one indexed query, falling back to a Clerk scan if the mirror is not seeded.
- 3Channel gates come from the org's preference row, then the registry's per-event defaults, and can be hard-overridden per dispatch.
- 4Each person's own overrides can only QUIET a channel, never grant one.
- 5Failures are logged, never thrown — 'a notify hiccup doesn't break the user action'.
- 6Email routes through the org's own sender rather than a shared platform address.
The file header records the protocol it implements: 'customer-journey milestones (form submitted, contract signed, etc.) fire notifications only — never auto-start projects. The Start Project gate stays human-controlled.' The three entry points exist because rules implemented in only one of them silently did not apply to the others: 'That meant a builder who completed a stage still got their own "stage complete" email, and a person holding two accounts in the org got it twice.'
- Rules that applied to one dispatcher and not the others
- Recipient resolution scattered across emit sites
See it on your own jobs
Twenty minutes, your numbers, no slide deck. We’ll build one of your real buildings in front of you and send you the estimate link at the end — yours to keep either way.
or keep browsing features →