Notifications
Notifications owns in-app notifications, event preferences, email templates, delivery queue, send logs, and Resend webhook updates.
On this page
Where to look
| Area | Maintainer reference |
|---|---|
| Routes | Implementation referencesrc/app/(dashboard)/communications, /communications/outbound, /communications/outbound/settings, /communications/outbound/templates |
| Webhook | Implementation referencesrc/app/api/notifications/webhooks/resend |
| Event registry | Implementation referencesrc/features/notifications/shared/events/registry.ts |
| In-app | Implementation referencesrc/features/notifications/server/in-app, src/features/notifications/ui/bell.tsx, list.tsx |
| Delivery | Implementation referencesrc/features/notifications/server/delivery |
| Outbox | Implementation referencesrc/features/notifications/server/outbox, src/features/notifications/ui/outbox |
| Templates | Implementation referencesrc/features/notifications/server/templates, src/features/notifications/ui/templates |
| Settings | Implementation referencesrc/features/notifications/server/settings, src/features/notifications/ui/settings |
Implementation reference4 areas
These Product code locations explain how the documented behavior is implemented. Expand them when you are ready to customize or maintain this area.
Canonical event registry
Notification keys are defined once so templates, preferences, delivery, and webhook flows use the same vocabulary.
src/features/notifications/shared/events/registry.ts
Queue and dedupe
Product code queues work into notification_outbox, canonicalizes event keys, and treats unique dedupe conflicts as already queued.
src/features/notifications/server/delivery/queue/notify-queue.ts
Worker and retry behavior
The worker atomically claims rows, dispatches through the delivery registry, marks success or failure, and moves exhausted rows to dead letter.
src/features/notifications/server/outbox/services/worker.tssrc/features/notifications/server/events/dispatch.ts
Templates and provider updates
Template runtime code renders event-specific messages, while Resend webhooks update delivery status after provider callbacks arrive.
src/features/notifications/server/templates/services/runtime.tssrc/features/notifications/server/templates/services/render.tssrc/app/api/notifications/webhooks/resend/route.ts
Reference paths are relative to the Shipflash-Product checkout.
Notification delivery flow
- 1
Choose a canonical event key
Callers use a canonical event key for preferences and delivery logs. Application-owned events may also have editable templates; team.invite remains Supabase Auth-owned.
Relevant Product code
src/features/notifications/shared/events/registry.ts
- 2
Queue the work
The queue helper writes notification_outbox rows with recipient, payload, resource id, dedupe key, status, and next attempt time.
Relevant Product code
src/features/notifications/server/delivery/queue/notify-queue.ts
- 3
Claim atomically
The worker uses claim_notification_batch to avoid two workers sending the same queued message.
Relevant Product code
src/features/notifications/server/outbox/services/worker.tssupabase/migrations/20260426000000_init.sql
- 4
Dispatch, retry, or dead-letter
Delivery runs through the registry, records provider status, retries transient failures with backoff, and dead-letters exhausted rows.
Relevant Product code
src/features/notifications/server/outbox/services/worker.tssrc/features/notifications/server/events/dispatch.ts
Notification event registry
Use this example as a starting point, then adapt it to your product's rules and configuration.
This is the complete current registry. Add events here first, then explicitly decide whether delivery is Supabase Auth-owned or application-owned before adding an editable template.
export const NOTIFICATION_EVENT_KEY_VALUES = [
"lead.new",
"lead.contact.message",
"lead.contact.reply",
"team.invite",
"auth.signup.welcome",
"system.alert",
"operations.stripe.dispute.created",
"billing.invoice.payment_succeeded",
"billing.invoice.payment_failed",
"billing.subscription.started",
"billing.subscription.changed",
"billing.subscription.canceled",
"billing.subscription.expired",
"billing.subscription.expiring_soon",
"billing.refund.issued",
"billing.order.completed",
"billing.credit_pack.granted",
"billing.credit_balance.low",
"billing.usage.threshold_reached",
"billing.usage.summary",
] as const;Source reference
src/features/notifications/shared/events/registry.ts
Recipe: add an email event
Add a notification event that can be queued, templated, retried, and audited without sending from unrelated product code.
Implementation locations
Inspect
- src/features/notifications/shared/events/registry.ts
- src/features/notifications/server/events/dispatch.ts
- src/features/notifications/server/templates/services/runtime.ts
- src/features/notifications/server/outbox/services/worker.ts
Edit
- src/features/notifications/shared/events/registry.ts
- src/features/notifications/server/events/dispatch.ts
- src/features/notifications/shared/templates/defaults.ts
- src/features/notifications/shared/templates/constants.ts
Steps
- Add the event key to the registry.
- Add or update the default template and allowed variables.
- Add delivery handling through the registry.
- Queue the event from the product module using a dedupe key when duplicate source events are possible.
Verify
- pnpm run test:features
- pnpm run quality
- Trigger the event in test mode and confirm notification_outbox status changes.
Common mistakes
- Do not send provider email directly from billing, auth, team, or contact code.
- Do not invent event keys outside the registry.
- Do not hide retry errors from the outbox UI.
AI prompt: notification event
Add a notification event for <event>. Inspect the canonical event registry, delivery registry, template runtime, outbox worker, and the source module that queues the event. Keep provider sending inside the notification delivery boundary and preserve retry/dead-letter behavior.Inspect first
src/features/notifications/shared/events/registry.tssrc/features/notifications/server/events/dispatch.tssrc/features/notifications/server/outbox/services/worker.ts
Verify
- pnpm run test:features
- pnpm run quality
Delivery rules
- Queue provider delivery instead of sending from unrelated product code.
- Keep retry state and failure reason visible in the outbox.
- Use event keys from the registry so templates and preferences stay consistent.
- Handle Resend webhook updates without trusting raw payloads as application state.