Skip to Content
DocsHow Dawn worksNotifications

Notifications

Dawn notifications are code-defined transactional workflows. They are separate from conversational messages and run as listeners for domain events.

The first implementation borrows the durable workflow concepts used by Knock without adding a workflow editor or notification UI.

Concepts

ConceptDawn representation
WorkflowA typed entry in notifications/workflows.ts with a stable key
TriggerA key, idempotency key, recipients, tenant, actor, and typed data
Recipient runOne workflow execution result per recipient
Channel stepA condition, template, and provider-neutral channel name
PreferenceA resolver that can allow or skip each recipient and channel
MessageRendered content and a stable ID for one recipient and channel step
ReceiptThe sent or skipped result, including a provider message ID

Every current workflow is transactional. Workflow keys and trigger data are linked by NotificationWorkflowDataMap, so a trigger with missing or incorrect data fails typechecking.

Current workflows

Workflow keyDomain eventRecipientChannel
patient-welcomepatient.createdPatientconsole
appointment-confirmationappointment.createdPatientconsole

The event envelope contains identifiers only. A retryable notification step loads the patient or appointment from the domain stores before triggering its notification workflow.

domain mutation -> domain event -> Vercel event workflow -> retryable notification step -> transactional notification workflow -> channel

The event ID is the notification idempotency key. Run and message IDs are derived from the workflow key, event ID, recipient ID, and step reference so retries address the same logical delivery.

Console channel

The console channel is the only provider today. It writes one structured transactional.notification record with:

  • message, workflow, step, recipient, and tenant IDs
  • rendered subject and body

It does not write the recipient email address or phone number. Rendered content can still contain personal information and must be treated as application data.

Adding a workflow

  1. Add its key and data shape to NotificationWorkflowDataMap.
  2. Define its channel steps in notificationWorkflows.
  3. Add a typed trigger method to the transactional notification service.
  4. Call that trigger from a retryable event-listener step.

Keep domain event payloads small. Load mutable or sensitive context inside the notification step.

Adding a channel

Implement NotificationChannel behind a provider-neutral adapter, add its name to NotificationChannelName, and provide it when creating the engine. Templates and event listeners must not depend on a vendor SDK.

The engine already provides conditions, preference checks, channel capability checks, recipient fan-out, and delivery receipts. Delays, batching, cancellation, persisted message history, and real email or SMS providers are not implemented yet.

Last updated on