You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Production-grade, event-driven notification platform for reliable multi-channel communication.
Built with Java 23, Spring Boot 3.x, Apache Kafka, PostgreSQL, and Redis.
The Notification Platform is an event-driven microservice system that enables reliable, scalable, and auditable delivery of notifications across multiple channels - email, SMS, push notifications, and webhooks. It decouples notification production from delivery through asynchronous event streaming, ensuring resilience under load and providing built-in retry with idempotency guarantees.
Responsibilities
Ingest notification requests via REST API or Kafka events
De-duplicate incoming events within a configurable time window via Redis
Resolve & render notification templates via a dedicated template service
Dispatch through channel-specific adapters (email, SMS, push, webhook)
Track & audit every delivery attempt with full history
Retry failed deliveries with exponential backoff and distributed scheduling
Dead-letter events that exhaust all retry attempts for manual inspection
Template management, storage, and dynamic rendering
delivery-tracker
8003
Delivery attempt recording, history queries, and audit trail
notification-platform-common
-
Shared domain enums, exceptions, DTOs, and auto-configuration
High-Level Architecture
graph TD
A[Client / API Gateway] -->|REST| B(Notification Service)
B -->|Kafka: notification.transactional| C(Notification Service Consumer)
B -->|Kafka: notification.marketing| C
B -->|Kafka: notification.alerts| C
C --> D{Channel Dispatcher}
D -->|Internal API| E(Template Service)
E --> H[(PostgreSQL)]
D -->|"External APIs (Mocked)"| F(SendGrid, Twilio, FCM, Webhook)
D -->|Internal API| G(Delivery Tracker)
G --> H[(PostgreSQL)]
C --> I[(Redis - Deduplication)]
C --> J(ShedLock - Retry Scheduler)
J -->|Kafka: notification.retry| C
C -->|After retries exhausted| K(Kafka: notification.dlq)
Loading
Event Flow
sequenceDiagram
participant Client
participant NS as Notification Service
participant K as Kafka
participant TS as Template Service
participant CD as Channel Dispatcher
participant EX as External Channel (SendGrid/Twilio/FCM/Webhook)
participant DT as Delivery Tracker
participant R as Redis
Client->>NS: POST /api/v1/notifications
NS->>R: Check eventId in dedup cache
alt Event ID exists
R-->>NS: Event already processed
NS-->>Client: 200 OK (deduplicated)
else Event ID new
R-->>NS: Event not in cache
NS->>R: Store eventId in dedup cache (24h TTL)
NS->>K: Publish to notification.* topic
NS-->>Client: 202 Accepted
K->>NS: Consume NotificationEvent
NS->>TS: GET /templates/{templateId}
TS-->>NS: Rendered template content
NS->>CD: Dispatch to channels
CD->>EX: Send via channel API
EX-->>CD: Delivery result
CD->>DT: POST /delivery-attempts
DT-->>CD: 201 Created
CD-->>NS: Dispatch results
NS->>K: Publish result (or retry if failed)
end
Loading
Retry Flow
sequenceDiagram
participant NS_Consumer as Notification Service (Kafka Consumer)
participant NS_Scheduler as Retry Scheduler
participant ShedLock
participant K as Kafka
participant DT as Delivery Tracker
participant CD as Channel Dispatcher
participant EX as External Channel
NS_Consumer->>DT: Identify failed attempts
NS_Consumer->>K: Publish to notification.retry
K->>NS_Consumer: Consume retry event
NS_Scheduler->>ShedLock: Acquire lock
alt Lock acquired
ShedLock-->>NS_Scheduler: Lock granted
NS_Scheduler->>CD: Re-dispatch for failed channels
CD->>EX: Send message
EX-->>CD: Result
CD->>DT: POST /delivery-attempts
alt Success after retry
NS_Scheduler->>K: Publish success (optional)
else Exhausted retries
NS_Scheduler->>K: Publish to notification.dlq
end
NS_Scheduler->>ShedLock: Release lock
else Lock not acquired
ShedLock-->>NS_Scheduler: Lock denied
end
Loading
Template Resolution Flow
sequenceDiagram
participant NS as Notification Service
participant TS as Template Service
participant DB as PostgreSQL
NS->>TS: GET /api/v1/templates/{templateId}
TS->>DB: Query template by ID
DB-->>TS: TemplateEntity
TS->>TS: Render template with payload
TS-->>NS: Rendered content (HTML/text)
Loading
Delivery Tracking Flow
sequenceDiagram
participant CD as Channel Dispatcher
participant DT as Delivery Tracker
participant DB as PostgreSQL
participant Client
CD->>DT: POST /api/v1/delivery-attempts
DT->>DB: Insert DeliveryAttemptEntity
DB-->>DT: Persisted entity
DT-->>CD: 201 Created
Client->>DT: GET /api/v1/delivery-attempts/events/{eventId}
DT->>DB: Query by eventId
DB-->>DT: Attempts list
DT-->>Client: DeliveryAttemptResponse[]
Client->>DT: GET /api/v1/delivery-attempts/users/{userId}
DT->>DB: Query by userId
DB-->>DT: Attempts list
DT-->>Client: DeliveryAttemptResponse[]
# Health check
curl http://localhost:8001/actuator/health
curl http://localhost:8002/actuator/health
curl http://localhost:8003/actuator/health
# Swagger UIs
open http://localhost:8001/swagger-ui.html
open http://localhost:8002/swagger-ui.html
open http://localhost:8003/swagger-ui.html
Docker / Docker Compose
The docker-compose.yml at the project root provides the required event-streaming infrastructure:
Service
Image
Ports
Purpose
zookeeper
confluentinc/cp-zookeeper:7.5.0
2181
Kafka coordinator
kafka
confluentinc/cp-kafka:7.5.0
9092 (internal), 29092 (external)
Message broker
kafka-init
confluentinc/cp-kafka:7.5.0
-
Topic initialization
kafka-ui
provectuslabs/kafka-ui:latest
8080
Web UI for Kafka
Topics created automatically on startup (retention: 24 hours):
Topic
Partitions
notification.transactional
1
notification.marketing
1
notification.alerts
1
notification.retry
1
notification.dlq
1
# Start Kafka infrastructure
docker-compose up -d
# View Kafka UI
open http://localhost:8080
# Stop everything
docker-compose down
Select the local environment from the environment dropdown
Start sending requests!
The collection includes:
Folder
Requests
notification-service
Send notification, get delivery status, get attempts link
template-service
List templates, get template, render template, check template
delivery-tracker
Record attempt, get by ID, get by event, get by user, get failed
Build & CI
Maven Modules
# Compile all modules
mvn clean compile
# Run all tests
mvn test# Run tests for a specific module
mvn clean test -pl notification-service
# Build JARs
mvn package -DskipTests
# Full verify (includes tests)
mvn clean verify
CI Pipeline (GitHub Actions)
The repository uses a GitHub Actions workflow (.github/workflows/build.yml) that runs on every push/PR to main:
The platform is designed for local development and testing. Microservices run as standalone Spring Boot applications communicating via Kafka and REST. Infrastructure dependencies (Kafka, PostgreSQL, Redis) are managed outside the application containers.
Recommended Production Enhancements
Containerize each service with Docker and deploy to Kubernetes
Managed Kafka (Confluent Cloud, MSK, or Event Hubs)
Managed PostgreSQL (RDS, Cloud SQL, or Azure Database)
Managed Redis (ElastiCache, Redis Cloud, or Azure Cache for Redis)
API Gateway for unified entry point, authentication, rate limiting
Service Mesh (Istio/Linkerd) for observability, traffic management
Distributed Tracing (Jaeger/Zipkin) with OpenTelemetry