System design

One request becomes many controlled delivery decisions.

NotifyHub is built as a control plane: client authentication, routing policy, template resolution, provider selection, callback verification, delivery tracking, and outbound webhooks are all handled centrally.

Request path

What happens when a client sends a request

NotifyHub request flow A left-to-right flow from client request to API, worker, connector, provider, callback gateway, and downstream webhooks. Client service API key + canonical request Notification API Auth, validation, policy Kafka + worker Queue, claim, expand Connector + provider Provider wire format Callback gateway Verify route, decode payload Update attempts and events Lifecycle webhooks Forward normalized events No provider-specific format Observability Prometheus, Grafana, logs Operational feedback loop
Why this shape matters It keeps the service boundary stable for clients while letting providers, retries, and channel behavior evolve independently.
Data model

Core tables and records

Record Purpose
Notification client Which upstream service is allowed to send and which channels it may use
Template Per-channel, per-language render source stored in the control plane
Routing policy Maps event names to channels and binding sets
Preference policy Suppresses channels a user has opted out of
Provider account Stores provider config and secret references separately
Callback route Defines how provider callbacks are verified and accepted
Delivery attempt Stores each connector call, response, and final status
Lifecycle

Request and attempt states are separate on purpose

Request state

Tracks the whole notification request across all channels: accepted, processing, dispatched, delivered, suppressed, failed, unsupported, or expired.

Delivery attempt state

Tracks the one provider call that happened for a specific channel and binding: pending, accepted, delivered, failed, suppressed, or unsupported.

Callbacks

Inbound callbacks and outbound lifecycle webhooks

Provider callbacks

Providers call the callback gateway, which verifies the route, decodes the payload, updates delivery attempts, and stores normalized channel events.

Outbound webhooks

Webhook subscriptions let downstream services receive normalized lifecycle events without knowing the original provider format.

Verification modes

The callback route can use no verification, a shared secret, or HMAC-based verification. Providers that do not need verification still work with the none mode.

Failure handling

Invalid or missing verification details are rejected early so provider traffic does not update the wrong route.

Scale

Retries, fallback, and observability are first-class

Retries

Channel delivery policies define retry count and backoff. The worker records retries instead of hiding them inside connector code.

Fallback

Bindings and provider health let the worker skip unhealthy accounts and continue through the configured binding set.

Observability

API, worker, callback gateway, connectors, Kafka, and storage all emit metrics so operators can see acceptance, delivery, callback, and retry behavior separately.