Skip to content

Repository files navigation

NotifyHub

An open-source, Go-based notification platform called NotifyHub for event-driven products.

This project is building toward a "Kubernetes for notifications" model: business systems publish notification intent, while the platform owns delivery orchestration, policy evaluation, retries, provider failover, callbacks, auditability, and observability.

clideo_editor_0ee5c18547ab4caab17b3099c1ae72d5.mp4

What It Does Today

The current platform already supports:

  • canonical notification intake through a REST API
  • asynchronous worker processing backed by Kafka
  • PostgreSQL-backed request, attempt, policy, and audit state
  • templates, routing policies, preference policies, and delivery policies
  • provider bindings with binding-set aware routing
  • pluggable email, sms, and webhook connectors
  • retry classification, dead-lettering, replay, and provider failover
  • provider health tracking and gobreaker-backed circuit breakers
  • provider callback normalization and outbound lifecycle webhooks
  • Prometheus/Grafana metrics, Kafka UI, and Adminer
    • local Docker observability stack
  • unit tests, live integration tests, and a basic CI workflow

For the build log and production-readiness checklist, see docs/project-status.md.

Mental Model

Your application decides:

  • why a notification should happen
  • who should receive it
  • what business event or template key it maps to

The control plane decides:

  • which channels should be used
  • which provider binding set should handle them
  • how templates are rendered
  • whether preferences suppress delivery
  • how retries, failover, DLQ, replay, and callbacks are handled

Core Components

  • api Control-plane API for requests, policies, templates, provider bindings, dead letters, and status queries.
  • worker Async reconciliation engine that evaluates policy, renders content, dispatches connectors, schedules retries, and manages circuit-breaker state.
  • callback-gateway Normalizes provider callbacks into delivery-attempt and request-status updates.
  • connector-email, connector-sms, connector-webhook, connector-push, connector-whatsapp Reference out-of-process provider adapters.
  • migrate Versioned SQL migration runner used by Docker and local commands.

Repo Layout

apps/
  api/
  callback-gateway/
  migrate/
  worker/
connectors/
  email/
  sms/
  webhook/
libs/
  contracts/
  core/
  messaging/
  observability/
  storage/
deployments/docker/
deployments/helm/
docs/
  api/
  architecture/
  project-status.md
migrations/
tests/
  integration/
  load/

Quick Start

Start the local stack:

make up

Run migrations directly:

make migrate

Inspect the stack:

  • API: http://localhost:8080/healthz
  • Worker: http://localhost:8081/healthz
  • Callback gateway: http://localhost:8082/healthz
  • Email connector: http://localhost:8091/healthz
  • SMS connector: http://localhost:8092/healthz
  • Webhook connector: http://localhost:8093/healthz
  • Kafka UI: http://localhost:8085
  • Adminer: http://localhost:8086
  • Prometheus: http://localhost:9090
  • Grafana: http://localhost:3000

Grafana default login:

  • user: admin
  • password: admin

Adminer default login:

  • system: PostgreSQL
  • server: postgres
  • username: postgres
  • password: postgres
  • database: notification_control_plane

Example Request

{
  "idempotency_key": "order-123-delayed",
  "event_name": "order.delayed",
  "template_key": "order-delayed-v1",
  "channels": ["email"],
  "recipient": {
    "user_id": "user-123",
    "email": "alice@example.com"
  },
  "variables": {
    "order_id": "ORD-123",
    "reason": "carrier_delay"
  },
  "priority": "high"
}

Submit it:

curl -s -X POST http://localhost:8080/v1/notification-requests \
  -H 'Content-Type: application/json' \
  -d @request.json

Testing

Run the normal Go suite:

make test

Check formatting:

make fmt-check

Run the live integration suite against the local stack:

make integration-test

Run the load test:

make load-test

API Docs

Example Client Integrations

Current Public API Surface

Key endpoints currently exposed by api:

  • POST /v1/notification-requests
  • GET /v1/notification-requests/{requestID}
  • GET /v1/provider-definitions
  • GET /v1/provider-accounts
  • GET /v1/provider-accounts/{providerAccountID}
  • GET /v1/provider-accounts/{providerAccountID}/status
  • POST /v1/provider-accounts
  • PATCH /v1/provider-accounts/{providerAccountID}
  • POST /v1/provider-accounts/{providerAccountID}/disable
  • GET /v1/provider-bindings
  • GET /v1/provider-bindings/{channel}
  • POST /v1/provider-bindings
  • GET /v1/provider-binding-health
  • GET /v1/provider-binding-health/{bindingID}
  • POST /v1/provider-binding-health/{bindingID}/reset
  • GET /v1/callback-routes
  • GET /v1/callback-routes/{providerKey}
  • POST /v1/callback-routes
  • GET /v1/routing-policies
  • GET /v1/preference-policies
  • GET /v1/templates
  • GET /v1/delivery-policies
  • GET /v1/webhook-subscriptions
  • GET /v1/dead-letters
  • POST /v1/dead-letters/{deadLetterID}/replay

Provider callbacks are received through callback-gateway:

  • POST /v1/providers/{provider}/{providerAccountId}/callbacks

Notes For Contributors

  • Add new schema changes as numbered files in migrations.
  • Keep connector-specific behavior behind connector processes rather than embedding provider logic into api or worker.
  • Prefer extending the unit and integration suites when changing worker decision logic, retries, or provider behavior.
  • Review architecture decisions in docs/adr before making large design changes.

Production Readiness

This is already a strong working platform foundation, but it is not yet finished as a production-ready OSS control plane. Remaining work includes broader operator docs, stronger multi-channel semantics, auth/RBAC, secret-manager integration, more CI/build automation, and deployment packaging beyond local Docker.

About

a notification control plane to send notifications

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages