|
5 | 5 | [](https://openjdk.org) |
6 | 6 | [](https://spring.io/projects/spring-boot) |
7 | 7 |
|
8 | | -> Notifications core library with email, SMS, and push notification service contracts and provider abstraction. |
| 8 | +> Reactive, provider-agnostic notifications core for Spring Boot — email, SMS and push ports with pluggable SendGrid, Resend, Twilio and Firebase adapters, FreeMarker templating, per-user channel preferences and built-in Micrometer metrics. |
9 | 9 |
|
10 | 10 | --- |
11 | 11 |
|
12 | 12 | ## Table of Contents |
13 | 13 |
|
14 | 14 | - [Overview](#overview) |
| 15 | + - [Modules](#modules) |
| 16 | + - [Provider Adapters](#provider-adapters) |
15 | 17 | - [Features](#features) |
16 | 18 | - [Requirements](#requirements) |
17 | 19 | - [Installation](#installation) |
|
23 | 25 |
|
24 | 26 | ## Overview |
25 | 27 |
|
26 | | -Firefly Framework Notifications provides the core service layer and provider contracts for sending email, SMS, and push notifications. It defines provider interfaces (`EmailProvider`, `SMSProvider`, `PushProvider`) that concrete notification providers implement, along with application services that orchestrate notification delivery. |
| 28 | +Firefly Framework Notifications is the **core notifications abstraction** for the Firefly platform. It defines the application services and outbound ports for sending notifications across three channels — **email**, **SMS** and **push** — and lets you swap concrete delivery providers without touching business logic. |
27 | 29 |
|
28 | | -The module is structured as a multi-module project with a core sub-module containing the service implementations, DTOs, and provider interfaces. The notification services delegate to the appropriate provider implementation, which is supplied by separate provider modules (SendGrid, Resend, Twilio, Firebase). |
| 30 | +The module follows a strict **hexagonal (ports & adapters)** design. Your code depends only on the channel services (`EmailService`, `SMSService`, `PushService`) and the outbound port interfaces (`EmailProvider`, `SMSProvider`, `PushProvider`). The actual integration with a SaaS provider lives in a **separate adapter module** (SendGrid, Resend, Twilio, Firebase) that you add as a dependency and select with a single property. Because the ports are the only contract, you can switch from, say, SendGrid to Resend by changing a dependency and one config line — no code changes. |
29 | 31 |
|
30 | | -This architecture allows applications to switch notification providers without changing business logic, as all providers implement the same standardized interfaces. |
| 32 | +Everything is **reactive end to end**: services and ports return Project Reactor `Mono` types, so notification dispatch composes naturally into WebFlux pipelines and never blocks request threads. On top of the raw send path the core adds two cross-cutting concerns out of the box: a **FreeMarker template engine** for rendering templated emails by ID, and a **notification preference service** so deliveries can respect per-user, per-channel opt-outs. A Spring Boot auto-configuration wires shared **Micrometer** instrumentation (`NotificationMetrics`) that every adapter reuses to emit consistent send/latency/error metrics tagged by channel and provider. |
| 33 | + |
| 34 | +This repository ships only the contracts, DTOs, services and observability — it has **no opinionated runtime provider of its own**. Pick one (or more) of the sibling adapter modules below to actually deliver messages. |
| 35 | + |
| 36 | +### Modules |
| 37 | + |
| 38 | +This is an aggregator (`pom` packaging) project. It currently contains a single submodule; the structure leaves room for additional core submodules without breaking coordinates. |
| 39 | + |
| 40 | +| Module | Artifact | Purpose | |
| 41 | +| --- | --- | --- | |
| 42 | +| Notifications Core | `fireflyframework-notifications-core` | Channel services (email/SMS/push), outbound provider ports, request/response DTOs, FreeMarker template engine, in-memory notification preference service, and Micrometer observability auto-configuration. | |
| 43 | + |
| 44 | +### Provider Adapters |
| 45 | + |
| 46 | +Concrete delivery is supplied by these **separate adapter repositories**, each implementing the matching port from this core and activating via a `firefly.notifications.<channel>.provider` property: |
| 47 | + |
| 48 | +| Adapter | Channel | Implements | Selecting property | |
| 49 | +| --- | --- | --- | --- | |
| 50 | +| [`fireflyframework-notifications-sendgrid`](https://github.com/fireflyframework/fireflyframework-notifications-sendgrid) | Email | `EmailProvider` | `firefly.notifications.email.provider=sendgrid` | |
| 51 | +| [`fireflyframework-notifications-resend`](https://github.com/fireflyframework/fireflyframework-notifications-resend) | Email | `EmailProvider` | `firefly.notifications.email.provider=resend` | |
| 52 | +| [`fireflyframework-notifications-twilio`](https://github.com/fireflyframework/fireflyframework-notifications-twilio) | SMS | `SMSProvider` | `firefly.notifications.sms.provider=twilio` | |
| 53 | +| [`fireflyframework-notifications-firebase`](https://github.com/fireflyframework/fireflyframework-notifications-firebase) | Push | `PushProvider` | `firefly.notifications.push.provider=firebase` | |
31 | 54 |
|
32 | 55 | ## Features |
33 | 56 |
|
34 | | -- `EmailService` with template-based email sending and attachments |
35 | | -- `SMSService` for SMS message delivery |
36 | | -- `PushService` for push notification delivery |
37 | | -- `EmailProvider` interface for pluggable email providers |
38 | | -- `SMSProvider` interface for pluggable SMS providers |
39 | | -- `PushProvider` interface for pluggable push notification providers |
40 | | -- DTOs for email requests/responses with attachment support |
41 | | -- DTOs for SMS requests/responses |
42 | | -- DTOs for push notification requests/responses |
43 | | -- Email status tracking enum |
| 57 | +- **Reactive channel services** — `EmailService`, `SMSService` and `PushService`, each returning `Mono<...ResponseDTO>` for non-blocking dispatch. |
| 58 | +- **Hexagonal outbound ports** — `EmailProvider`, `SMSProvider`, `PushProvider`. Add an adapter module and a config property to bind an implementation; no code changes to switch providers. |
| 59 | +- **Rich email model** — `EmailRequestDTO` with `from`/`to`, CC/BCC lists, plain-text and HTML bodies, Bean Validation (`@Email`, `@NotBlank`), and `EmailAttachmentDTO` for byte-content attachments with MIME type. |
| 60 | +- **Templated email** — `sendTemplateEmail(EmailTemplateRequestDTO)` renders a template by `templateId` with a variable map before delivery. Backed by the pluggable `NotificationTemplateEngine` SPI. |
| 61 | +- **FreeMarker template engine** — `FreemarkerNotificationTemplateEngine` loads `.ftl` templates from a configurable classpath prefix (default `/notification-templates`) and an optional filesystem directory; rendering runs on a bounded-elastic scheduler. |
| 62 | +- **Per-user channel preferences** — `NotificationPreferenceService` with a ready-to-use `InMemoryNotificationPreferenceService`; toggle email/SMS/push per user (with per-channel overrides) and check `isChannelEnabled(userId, channel)` before sending. |
| 63 | +- **Consistent response contracts** — `EmailResponseDTO` (with `EmailStatusEnum` SENT/FAILED and `success(...)`/`error(...)` factories), `SMSResponseDTO`, and `PushNotificationResponse`, each carrying message ID, status and error message. |
| 64 | +- **Built-in observability** — `NotificationObservabilityAutoConfiguration` registers a shared `NotificationMetrics` bean (when a `MeterRegistry` is present) emitting `firefly.notifications.sent`, `firefly.notifications.delivery.duration`, `firefly.notifications.errors` and `firefly.notifications.templates.rendered`, tagged by `channel`, `provider`, `status` and `template`. |
| 65 | +- **Reusable by every adapter** — adapters wrap their dispatch in `NotificationMetrics.timedDispatch(channel, provider, mono)` so all providers report metrics the same way. |
44 | 66 |
|
45 | 67 | ## Requirements |
46 | 68 |
|
47 | | -- Java 21+ |
| 69 | +- Java 21+ (Java 25 recommended) |
48 | 70 | - Spring Boot 3.x |
49 | 71 | - Maven 3.9+ |
| 72 | +- At least one provider adapter (SendGrid, Resend, Twilio, or Firebase) plus its account/API credentials to actually deliver notifications |
| 73 | +- A `MeterRegistry` (e.g. Micrometer + Actuator) on the classpath if you want notification metrics |
| 74 | +- FreeMarker on the classpath only if you use templated email (it is an optional dependency) |
50 | 75 |
|
51 | 76 | ## Installation |
52 | 77 |
|
| 78 | +The notifications core is consumed transitively by every provider adapter, so in most applications you simply add the adapter you need (see [Provider Adapters](#provider-adapters)). To depend on the core contracts directly: |
| 79 | + |
53 | 80 | ```xml |
54 | 81 | <dependency> |
55 | 82 | <groupId>org.fireflyframework</groupId> |
56 | | - <artifactId>fireflyframework-notifications</artifactId> |
57 | | - <version>26.02.07</version> |
| 83 | + <artifactId>fireflyframework-notifications-core</artifactId> |
| 84 | + <!-- Version is managed by the Firefly BOM / parent; omit it when inheriting fireflyframework-parent --> |
58 | 85 | </dependency> |
59 | 86 | ``` |
60 | 87 |
|
| 88 | +The version is governed by the Firefly Framework parent/BOM. When your project inherits `fireflyframework-parent` (or imports the Firefly BOM), you can omit the `<version>` entirely. |
| 89 | + |
61 | 90 | ## Quick Start |
62 | 91 |
|
| 92 | +**1. Add a provider adapter** (here: SendGrid for email). The adapter brings `fireflyframework-notifications-core` in transitively. |
| 93 | + |
| 94 | +```xml |
| 95 | +<dependency> |
| 96 | + <groupId>org.fireflyframework</groupId> |
| 97 | + <artifactId>fireflyframework-notifications-sendgrid</artifactId> |
| 98 | +</dependency> |
| 99 | +``` |
| 100 | + |
| 101 | +**2. Select and configure the provider** in `application.yml`: |
| 102 | + |
| 103 | +```yaml |
| 104 | +firefly: |
| 105 | + notifications: |
| 106 | + email: |
| 107 | + provider: sendgrid # binds the SendGrid EmailProvider adapter |
| 108 | + sendgrid: |
| 109 | + api-key: ${SENDGRID_API_KEY} |
| 110 | +``` |
| 111 | +
|
| 112 | +**3. Inject the channel service and send** — the `EmailProvider` adapter is auto-wired behind `EmailService`: |
| 113 | + |
63 | 114 | ```java |
64 | 115 | import org.fireflyframework.notifications.core.services.email.v1.EmailService; |
65 | 116 | import org.fireflyframework.notifications.interfaces.dtos.email.v1.EmailRequestDTO; |
| 117 | +import org.fireflyframework.notifications.interfaces.dtos.email.v1.EmailResponseDTO; |
| 118 | +import org.springframework.stereotype.Service; |
| 119 | +import reactor.core.publisher.Mono; |
66 | 120 |
|
67 | 121 | @Service |
68 | 122 | public class OrderNotificationService { |
69 | 123 |
|
70 | 124 | private final EmailService emailService; |
71 | 125 |
|
72 | | - public Mono<EmailResponseDTO> sendOrderConfirmation(Order order) { |
| 126 | + public OrderNotificationService(EmailService emailService) { |
| 127 | + this.emailService = emailService; |
| 128 | + } |
| 129 | +
|
| 130 | + public Mono<EmailResponseDTO> sendOrderConfirmation(String customerEmail, String orderId) { |
73 | 131 | EmailRequestDTO request = EmailRequestDTO.builder() |
74 | | - .to(order.getCustomerEmail()) |
75 | | - .subject("Order Confirmation - " + order.getId()) |
76 | | - .body("Your order has been confirmed.") |
77 | | - .build(); |
78 | | - return emailService.send(request); |
| 132 | + .from("orders@example.com") |
| 133 | + .to(customerEmail) |
| 134 | + .subject("Order Confirmation - " + orderId) |
| 135 | + .html("<h1>Thanks!</h1><p>Your order " + orderId + " is confirmed.</p>") |
| 136 | + .build(); |
| 137 | + return emailService.sendEmail(request); |
79 | 138 | } |
80 | 139 | } |
81 | 140 | ``` |
82 | 141 |
|
| 142 | +**Templated email** — provide a `NotificationTemplateEngine` bean (the FreeMarker engine renders `.ftl` files from `/notification-templates`) and call `sendTemplateEmail`: |
| 143 | + |
| 144 | +```java |
| 145 | +@Bean |
| 146 | +NotificationTemplateEngine notificationTemplateEngine() { |
| 147 | + return new FreemarkerNotificationTemplateEngine(); // classpath:/notification-templates |
| 148 | +} |
| 149 | +
|
| 150 | +// ... |
| 151 | +EmailTemplateRequestDTO request = EmailTemplateRequestDTO.builder() |
| 152 | + .from("welcome@example.com") |
| 153 | + .to(user.getEmail()) |
| 154 | + .subject("Welcome!") |
| 155 | + .templateId("welcome-email") // resolves welcome-email.ftl |
| 156 | + .templateVariables(Map.of("firstName", user.getFirstName())) |
| 157 | + .build(); |
| 158 | +return emailService.sendTemplateEmail(request); |
| 159 | +``` |
| 160 | + |
| 161 | +**Respect user preferences** before dispatching: |
| 162 | + |
| 163 | +```java |
| 164 | +return preferenceService.isChannelEnabled(userId, "email") |
| 165 | + .filter(Boolean::booleanValue) |
| 166 | + .flatMap(enabled -> emailService.sendEmail(request)); |
| 167 | +``` |
| 168 | + |
| 169 | +SMS and push follow the same pattern via `SMSService.sendSMS(SMSRequestDTO)` and `PushService.sendPush(PushNotificationRequest)`, selecting the Twilio and Firebase adapters respectively. |
| 170 | + |
83 | 171 | ## Configuration |
84 | 172 |
|
85 | | -Configuration is provided by the specific notification provider module (SendGrid, Resend, Twilio, Firebase). |
| 173 | +This core module exposes one auto-configuration toggle; the bulk of configuration (API keys, sender identities, provider selection) lives in the provider adapter you choose. |
| 174 | + |
| 175 | +```yaml |
| 176 | +firefly: |
| 177 | + notifications: |
| 178 | + # Provider selection — supplied by the adapter modules you add (see table below). |
| 179 | + email: |
| 180 | + provider: sendgrid # or: resend |
| 181 | + sms: |
| 182 | + provider: twilio |
| 183 | + push: |
| 184 | + provider: firebase |
| 185 | + observability: |
| 186 | + metrics: |
| 187 | + enabled: true # default; set false to skip NotificationMetrics registration |
| 188 | +``` |
| 189 | + |
| 190 | +| Property | Default | Description | |
| 191 | +| --- | --- | --- | |
| 192 | +| `firefly.notifications.email.provider` | _(none)_ | Selects the email `EmailProvider` adapter — `sendgrid` or `resend`. Defined by the adapter module. | |
| 193 | +| `firefly.notifications.sms.provider` | _(none)_ | Selects the SMS `SMSProvider` adapter — `twilio`. Defined by the adapter module. | |
| 194 | +| `firefly.notifications.push.provider` | _(none)_ | Selects the push `PushProvider` adapter — `firebase`. Defined by the adapter module. | |
| 195 | +| `firefly.observability.metrics.enabled` | `true` | When `true` (and a `MeterRegistry` is present), registers the shared `NotificationMetrics` bean used by all adapters. | |
| 196 | + |
| 197 | +Provider-specific keys (for example `firefly.notifications.sendgrid.*`, `firefly.notifications.twilio.*`, `firefly.notifications.firebase.*`) are documented in each adapter's README. |
| 198 | + |
| 199 | +**Template engine** — `FreemarkerNotificationTemplateEngine` is not auto-registered; declare it as a bean. Its constructor accepts a classpath prefix (default `/notification-templates`) and an optional filesystem directory for template overrides. Without a `NotificationTemplateEngine` bean, `sendTemplateEmail` fails fast with an `UnsupportedOperationException`. |
| 200 | + |
| 201 | +**Notification preferences** — `InMemoryNotificationPreferenceService` is suitable for development and single-instance deployments. For multi-instance/production usage, provide your own `NotificationPreferenceService` backed by R2DBC or a cache. |
86 | 202 |
|
87 | 203 | ## Documentation |
88 | 204 |
|
89 | | -No additional documentation available for this project. |
| 205 | +- [`ARCHITECTURE.md`](ARCHITECTURE.md) — in-depth hexagonal architecture guide: ports & adapters, layer responsibilities, dependency flow, and how to add a new provider. |
| 206 | +- [Firefly Framework Module Catalog](https://github.com/fireflyframework) — the full set of framework modules and adapters. |
| 207 | +- Adapter READMes: [SendGrid](https://github.com/fireflyframework/fireflyframework-notifications-sendgrid) · [Resend](https://github.com/fireflyframework/fireflyframework-notifications-resend) · [Twilio](https://github.com/fireflyframework/fireflyframework-notifications-twilio) · [Firebase](https://github.com/fireflyframework/fireflyframework-notifications-firebase). |
90 | 208 |
|
91 | 209 | ## Contributing |
92 | 210 |
|
|
0 commit comments