A scalable, extensible notification system built with Spring Boot following SOLID principles and design patterns. Features comprehensive test coverage with 272+ unit and integration tests.
- β Multi-Channel Support: Email, SMS, Push Notifications, WhatsApp, Slack
- β User Management: Registration, preferences, channel configuration
- β Priority Levels: HIGH, MEDIUM, LOW priority notifications
- β Scheduling: Immediate, scheduled, and recurring notifications
- β Batch Processing: Efficient bulk notification handling
- β Retry Mechanism: Exponential backoff with configurable retry attempts
- β Failure Tracking: Comprehensive history and audit trail
- β RESTful APIs: Complete API suite with JSON payloads
- β Validation: Comprehensive input validation with Jakarta Bean Validation
- β Testing: 272 tests including unit, integration, and API tests
-
Single Responsibility Principle (SRP)
- Each service class handles one specific concern
NotificationService- notification lifecycleNotificationRetryService- retry logic onlyNotificationSchedulerService- scheduling onlyNotificationBatchService- batch processing only
-
Open/Closed Principle (OCP)
- New notification channels can be added without modifying existing code
- Simply implement
NotificationChannelStrategyinterface - Factory pattern manages channel creation
-
Liskov Substitution Principle (LSP)
- All channel strategies are interchangeable
- Any
NotificationChannelStrategyimplementation works with the system
-
Interface Segregation Principle (ISP)
- Clean, focused interfaces (e.g.,
NotificationChannelStrategy) - Clients depend only on methods they use
- Clean, focused interfaces (e.g.,
-
Dependency Inversion Principle (DIP)
- Services depend on abstractions (interfaces), not concrete implementations
NotificationServicedepends onNotificationChannelStrategyinterface- Spring's dependency injection enforces this principle
-
Strategy Pattern
NotificationChannelStrategyinterface with multiple implementations- Allows runtime selection of notification delivery strategy
-
Factory Pattern
NotificationChannelFactorycreates appropriate channel strategies- Centralizes channel strategy instantiation
-
Repository Pattern
- JPA repositories abstract data access layer
- Clean separation between business logic and data persistence
-
Builder Pattern
- DTOs and entities use Lombok's
@Builderfor clean object creation
- DTOs and entities use Lombok's
-
DTO Pattern
- Separates API layer from domain layer
NotificationRequest,NotificationResponsefor API communication
src/
βββ main/
β βββ java/com/notification/
β β βββ NotificationSystemApplication.java
β β βββ channel/ # Strategy Pattern - Channel implementations
β β β βββ NotificationChannelStrategy.java (Interface)
β β β βββ NotificationChannelFactory.java
β β β βββ DeliveryResult.java
β β β βββ impl/
β β β βββ EmailChannelStrategy.java
β β β βββ SmsChannelStrategy.java
β β β βββ PushNotificationChannelStrategy.java
β β β βββ WhatsAppChannelStrategy.java
β β β βββ SlackChannelStrategy.java
β β βββ controller/ # REST API Layer
β β β βββ UserController.java
β β β βββ NotificationController.java
β β βββ domain/ # Domain Model
β β β βββ entity/
β β β β βββ User.java
β β β β βββ Notification.java
β β β β βββ NotificationHistory.java
β β β βββ enums/
β β β β βββ NotificationChannel.java
β β β β βββ NotificationPriority.java
β β β β βββ NotificationStatus.java
β β β β βββ ScheduleType.java
β β β β βββ RecurrenceFrequency.java
β β β βββ model/
β β β βββ NotificationContent.java
β β β βββ ScheduleConfig.java
β β β βββ RetryConfig.java
β β βββ dto/ # Data Transfer Objects
β β β βββ NotificationRequest.java
β β β βββ NotificationResponse.java
β β β βββ BulkNotificationRequest.java
β β βββ exception/ # Exception Handling
β β β βββ GlobalExceptionHandler.java
β β β βββ ErrorResponse.java
β β βββ repository/ # Data Access Layer
β β β βββ UserRepository.java
β β β βββ NotificationRepository.java
β β β βββ NotificationHistoryRepository.java
β β βββ service/ # Business Logic Layer
β β β βββ NotificationService.java
β β β βββ NotificationSchedulerService.java
β β β βββ NotificationBatchService.java
β β β βββ NotificationRetryService.java
β β β βββ NotificationQueueService.java
β β β βββ AsyncNotificationProcessor.java
β β β βββ UserService.java
β β βββ validation/ # Custom Validators
β β βββ ScheduledTimeValidator.java
β βββ resources/
β βββ application.yml
β βββ application-test.yml
βββ test/ # Comprehensive Test Suite
βββ java/com/notification/
βββ channel/impl/ # Channel Tests (37 tests)
βββ controller/ # Controller Tests (21 tests)
βββ service/ # Service Tests (87 tests)
βββ domain/ # Domain Tests (82 tests)
β βββ entity/ # Entity Tests (47 tests)
β βββ enums/ # Enum Tests (35 tests)
βββ exception/ # Exception Handler Tests (9 tests)
βββ integration/ # Integration Tests (29 tests)
βββ NotificationFlowIntegrationTest.java
βββ RestApiIntegrationTest.java
βββ ValidationIntegrationTest.java
- Java 17 or higher
- Maven 3.6 or higher
mvn clean installmvn spring-boot:runThe application will start on http://localhost:8080
Run all tests (272 tests):
mvn testRun specific test suites:
# Service layer tests
mvn test -Dtest=*ServiceTest
# Integration tests
mvn test -Dtest=*IntegrationTest
# REST API tests
mvn test -Dtest=RestApiIntegrationTest
# Validation tests
mvn test -Dtest=ValidationIntegrationTestRegister a user:
curl -X POST http://localhost:8080/api/users \
-H "Content-Type: application/json" \
-d '{
"username": "john.doe",
"email": "john@example.com",
"phoneNumber": "+1234567890",
"preferredChannels": ["EMAIL", "SMS"]
}'Create a notification:
curl -X POST http://localhost:8080/api/notifications \
-H "Content-Type: application/json" \
-d '{
"userId": 1,
"channel": "EMAIL",
"subject": "Welcome!",
"body": "Welcome to our notification system",
"priority": "HIGH"
}'Schedule a notification:
curl -X POST http://localhost:8080/api/notifications \
-H "Content-Type: application/json" \
-d '{
"userId": 1,
"channel": "EMAIL",
"subject": "Scheduled Reminder",
"body": "Your meeting is tomorrow",
"priority": "MEDIUM",
"scheduleType": "SCHEDULED",
"scheduledTime": "2026-02-10T10:00:00"
}'POST /api/users- Register new userGET /api/users/{userId}- Get user by IDGET /api/users- Get all usersPUT /api/users/{userId}/preferences- Update channel preferencesPUT /api/users/{userId}/channels/{channel}- Update channel contact infoPATCH /api/users/{userId}/channels/{channel}- Enable channelDELETE /api/users/{userId}/channels/{channel}- Disable channelDELETE /api/users/{userId}- Deactivate user
POST /api/notifications- Create single notificationPOST /api/notifications/bulk- Create bulk notificationsPOST /api/notifications/{id}/send- Send notification immediatelyGET /api/notifications- Get all notificationsGET /api/notifications/{id}- Get notification detailsGET /api/notifications/user/{userId}- Get user notificationsGET /api/notifications/{id}/history- Get notification history
DELETE /api/notifications/{id}/schedule- Cancel scheduled notificationPUT /api/notifications/{id}/schedule- Reschedule notification
POST /api/notifications/{id}/retry- Manual retryPOST /api/notifications/{id}/reset- Reset for retry
POST /api/notifications/batch- Process batch notificationsGET /api/notifications/statistics/batch- Batch statistics
POST /api/notifications/queue/process- Process notification queuePOST /api/notifications/queue/priority- Process by priorityGET /api/notifications/statistics/retry- Retry statistics
Key configuration properties in application.yml:
spring:
application:
name: notification-system
datasource:
url: jdbc:h2:mem:notificationdb
driver-class-name: org.h2.Driver
jpa:
hibernate:
ddl-auto: create-drop
show-sql: false
h2:
console:
enabled: true
notification:
retry:
max-attempts: 3 # Maximum retry attempts
initial-interval: 1000 # Initial retry delay (ms)
multiplier: 2.0 # Exponential backoff multiplier
max-interval: 10000 # Maximum retry delay (ms)
batch:
size: 100 # Batch processing size
scheduling:
enabled: true # Enable scheduled processingThe system includes comprehensive validation:
- Email: Must be valid format (
@Email) - Username: 3-50 characters, alphanumeric with dots/underscores/hyphens only
- Phone Number: E.164 format (e.g.,
+1234567890) - WhatsApp Number: E.164 format
- Push Token: Max 255 characters
- Slack Handle: 1-100 characters
- User ID: Must be positive number
- Subject: 1-200 characters
- Body: 1-5000 characters
- Scheduled Time: Must be in future (for SCHEDULED type)
- Recurrence End Time: Must be after start time
- Max Occurrences: 1-1000 for recurring notifications
ScheduledTimeValidator: Validates scheduling constraints- Ensures SCHEDULED notifications have future times
- Validates RECURRING notifications have proper end conditions
- Prevents scheduling notifications in the past
- Create a new strategy class implementing
NotificationChannelStrategy:
@Component("whatsappChannel")
public class WhatsAppChannelStrategy implements NotificationChannelStrategy {
@Override
public DeliveryResult send(Notification notification, User user) {
// Implement WhatsApp sending logic
}
@Override
public boolean canDeliver(User user) {
return user.getWhatsappNumber() != null;
}
@Override
public String getChannelName() {
return "WHATSAPP";
}
}- Add the channel to the
NotificationChannelenum - No changes needed to existing code! β¨
- User information and contact details
- Channel preferences
- Personalization variables
- Notification content and metadata
- Status tracking
- Scheduling information
- Retry configuration
- Audit trail of all notification attempts
- Error tracking
- Delivery status history
The project includes comprehensive test coverage with 272 tests:
- Channel Tests (37 tests): All 5 channel strategy implementations
- Service Tests (87 tests): Core business logic validation
- NotificationService: Creation, sending, validation
- NotificationRetryService: Retry logic and exponential backoff
- NotificationSchedulerService: Scheduling and recurring notifications
- NotificationBatchService: Batch processing
- NotificationQueueService: Queue management
- AsyncNotificationProcessor: Async processing
- UserService: User management
- Controller Tests (21 tests): REST API endpoints with MockMvc
- Domain Entity Tests (47 tests):
- User: JPA lifecycle, channel validation
- Notification: Business logic, status transitions
- NotificationHistory: Audit trail
- Enum Tests (35 tests): All 5 enum types with business methods
- Exception Handler Tests (9 tests): Global exception handling
- NotificationFlowIntegrationTest (9 tests): End-to-end workflows
- Complete user β notification β send lifecycle
- Priority ordering validation
- Bulk operations
- Recurring notifications
- Retry mechanisms
- RestApiIntegrationTest (11 tests): JSON-based REST API testing
- User registration with JSON payloads
- Notification creation via HTTP
- Scheduling and rescheduling
- Bulk notifications
- Error scenarios
- ValidationIntegrationTest (18 tests): Input validation
- Email/phone format validation
- Username constraints
- Subject/body length limits
- Scheduled time validation
- Recurring notification rules
- Bulk request validation
- JUnit 5: Testing framework
- Mockito: Mocking dependencies
- Spring Test: Integration testing with @SpringBootTest
- MockMvc: REST API testing
- H2 Database: In-memory database for integration tests
- @Transactional: Automatic test data cleanup
# All tests
mvn test
# Specific test class
mvn test -Dtest=NotificationServiceTest
# Test pattern
mvn test -Dtest=*IntegrationTest
# With coverage report
mvn clean test jacoco:report-
H2 In-Memory Database: Used for development and testing. Can be easily replaced with PostgreSQL/MySQL for production by updating
application.yml. -
Scheduled Tasks: Using Spring's
@Scheduledfor periodic processing of scheduled/recurring notifications and retry mechanisms. Runs every 60 seconds. In production, consider using a distributed scheduler like Quartz with clustering. -
Simulated Delivery: Channel implementations simulate network delays and occasional failures (10% for email, 5% for SMS, 3% for push) to demonstrate retry mechanisms. Replace with actual provider integrations for production.
-
Batch Size: Configurable via properties (default: 100). Adjust based on system capacity and requirements.
-
Priority Queue: Implemented via database query ordering (
findByStatusAndPriorityOrderByCreatedAtAsc). For high-scale systems, consider Redis or RabbitMQ with priority queues. -
Validation Layer: Jakarta Bean Validation at DTO level + custom validators at service level. Catches invalid data early and returns HTTP 400 with clear error messages.
-
Async Processing: Uses
@Asyncwith separate thread pool for non-blocking notification processing. Configure thread pool size based on load. -
Transactional Boundaries: Service methods use
@Transactionalfor consistency. Each notification creation/update is atomic. -
Audit Trail: Every notification attempt is logged in
NotificationHistoryfor compliance and debugging. -
Test Strategy: Comprehensive pyramid approach - many unit tests, fewer integration tests, ensuring fast feedback and high confidence.
For production deployment, consider:
- β Use persistent database (PostgreSQL, MySQL) - update datasource config
- β
Implement actual notification providers:
- Email: SendGrid, AWS SES, Mailgun
- SMS: Twilio, AWS SNS, Vonage
- Push: Firebase Cloud Messaging (FCM), Apple Push Notification Service (APNS)
- WhatsApp: WhatsApp Business API
- Slack: Slack Web API
- β Use message queues (Kafka, RabbitMQ) for high-volume scenarios
- β Implement distributed caching (Redis) for user preferences and rate limiting
- β Add authentication and authorization (Spring Security with JWT)
- β Implement rate limiting per user/channel
- β Encrypt sensitive data (phone numbers, push tokens)
- β Use HTTPS for all endpoints
- β Add API keys for external integrations
- β Add metrics collection (Micrometer + Prometheus)
- β Set up dashboards (Grafana)
- β Implement distributed tracing (Jaeger, Zipkin)
- β Centralized logging (ELK stack: Elasticsearch, Logstash, Kibana)
- β Add health checks and readiness probes
- β Configure alerts for failures, high retry rates, queue backlogs
- β Containerize with Docker
- β Orchestrate with Kubernetes
- β Use horizontal pod autoscaling
- β Implement connection pooling
- β Add circuit breakers (Resilience4j) for external services
- β Consider event-driven architecture for high throughput
- β Set up CI/CD pipelines (GitHub Actions, Jenkins)
- β Implement blue-green or canary deployments
- β Add automated testing in pipeline
- β Use infrastructure as code (Terraform, Helm charts)
- β Implement proper secret management (Vault, AWS Secrets Manager)
- β Database indexing on frequently queried fields
- β Query optimization and pagination
- β Async processing for all I/O operations
- β Bulk operations for batch processing
- β Connection pooling (HikariCP)
- β Load testing and capacity planning
- Java 17 - Programming language
- Spring Boot 3.2.0 - Application framework
- Spring Data JPA - Data persistence
- Hibernate - ORM
- H2 Database - In-memory database (dev/test)
- Maven - Build tool
- Lombok - Boilerplate reduction
- JUnit 5 - Testing framework
- Mockito - Mocking framework
- Spring Test - Integration testing
- Jakarta Bean Validation - Input validation
- Total Lines of Code: ~8,000+
- Test Coverage: 272 tests covering all layers
- Services: 9 service classes
- Controllers: 2 REST controllers
- Repositories: 3 JPA repositories
- Domain Entities: 3 entities
- Enums: 5 enums with business logic
- Channel Strategies: 5 implementations
- DTOs: 3 data transfer objects
- Custom Validators: 1 scheduling validator
This is an educational/portfolio project demonstrating enterprise software design principles and patterns.
Built with β€οΈ using Spring Boot, following SOLID principles and design patterns