Shipflash logoDocs

Notifications

Notifications owns in-app notifications, event preferences, email templates, delivery queue, send logs, and Resend webhook updates.

On this page

Where to look

AreaPaths
Routessrc/app/(dashboard)/communications, /communications/outbound, /communications/outbound/settings, /communications/outbound/templates
Webhooksrc/app/api/notifications/webhooks/resend
Event registrysrc/features/notifications/server/notification-events.ts
In-appsrc/features/notifications/server/in-app, src/features/notifications/ui/bell.tsx, list.tsx
Deliverysrc/features/notifications/server/delivery
Outboxsrc/features/notifications/server/outbox, src/features/notifications/ui/outbox
Templatessrc/features/notifications/server/templates, src/features/notifications/ui/templates
Settingssrc/features/notifications/server/settings, src/features/notifications/ui/settings

Code-backed notifications map

Canonical event registry

Notification keys are defined once so templates, preferences, delivery, and webhook flows use the same vocabulary.

  • src/features/notifications/server/notification-events.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.ts
  • src/features/notifications/server/delivery/registry.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.ts
  • src/features/notifications/server/templates/services/render.ts
  • src/app/api/notifications/webhooks/resend/route.ts

Notification delivery flow

  1. 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.

    • src/features/notifications/server/notification-events.ts
  2. 2

    Queue the work

    The queue helper writes notification_outbox rows with recipient, payload, resource id, dedupe key, status, and next attempt time.

    • src/features/notifications/server/delivery/queue/notify-queue.ts
  3. 3

    Claim atomically

    The worker uses claim_notification_batch to avoid two workers sending the same queued message.

    • src/features/notifications/server/outbox/services/worker.ts
    • supabase/migrations/20260426000000_init.sql
  4. 4

    Dispatch, retry, or dead-letter

    Delivery runs through the registry, records provider status, retries transient failures with backoff, and dead-letters exhausted rows.

    • src/features/notifications/server/outbox/services/worker.ts
    • src/features/notifications/server/delivery/registry.ts

Notification event registry

Source: src/features/notifications/server/notification-events.ts

Add events here first, then explicitly decide whether delivery is Supabase Auth-owned or application-owned before adding an editable template.

ts
export const NOTIFICATION_EVENT_KEY_VALUES = [
  "lead.new",
  "lead.contact.message",
  "team.invite",
  "auth.signup.welcome",
  "system.alert",
  "operations.stripe.dispute.created",
  "billing.invoice.payment_succeeded",
  "billing.invoice.payment_failed",
  "billing.subscription.expiring_soon",
] as const;

Recipe: add an email event

Add a notification event that can be queued, templated, retried, and audited without sending from unrelated product code.

Inspect

  • src/features/notifications/server/notification-events.ts
  • src/features/notifications/server/delivery/registry.ts
  • src/features/notifications/server/templates/services/runtime.ts
  • src/features/notifications/server/outbox/services/worker.ts

Edit

  • src/features/notifications/server/notification-events.ts
  • src/features/notifications/server/delivery/registry.ts
  • src/features/notifications/server/templates/shared/defaults.ts
  • src/features/notifications/server/templates/shared/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

AI prompt
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/server/notification-events.ts
  • src/features/notifications/server/delivery/registry.ts
  • src/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.