Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,22 @@ name: CI
on:
push:
branches: [develop]
paths-ignore:
- '**.md'
- 'docs/**'
- 'tutorials/**'
- 'examples/**/README.md'
- 'LICENSE'
- '.gitignore'
pull_request:
branches: [develop, main]
paths-ignore:
- '**.md'
- 'docs/**'
- 'tutorials/**'
- 'examples/**/README.md'
- 'LICENSE'
- '.gitignore'
workflow_dispatch:
inputs:
triggered-by:
Expand All @@ -13,10 +27,5 @@ on:
jobs:
build:
uses: fireflyframework/.github/.github/workflows/java-ci.yml@main
permissions:
packages: read
contents: read
actions: write
with:
java-version: '25'
secrets: inherit
293 changes: 60 additions & 233 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,272 +1,99 @@
# fireflyframework-notifications
# Firefly Framework - Notifications

[![CI](https://github.com/fireflyframework/fireflyframework-notifications/actions/workflows/ci.yml/badge.svg)](https://github.com/fireflyframework/fireflyframework-notifications/actions/workflows/ci.yml)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)
[![Java](https://img.shields.io/badge/Java-21%2B-orange.svg)](https://openjdk.org)
[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.x-green.svg)](https://spring.io/projects/spring-boot)

Firefly Notifications Library - A hexagonal architecture implementation for multi-channel notifications.
> Notifications core library with email, SMS, and push notification service contracts and provider abstraction.

## Overview
---

This library provides a clean, testable notification system for email, SMS, and push notifications using **Hexagonal Architecture** (Ports and Adapters pattern). The core domain logic is completely isolated from infrastructure concerns, making it easy to swap providers, test in isolation, and maintain over time.
## Table of Contents

### Architecture Layers
- [Overview](#overview)
- [Features](#features)
- [Requirements](#requirements)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Configuration](#configuration)
- [Documentation](#documentation)
- [Contributing](#contributing)
- [License](#license)

```
┌─────────────────────────────────────────────────────────────┐
│ Application Layer │
│ (EmailService, SMSService, PushService) │
└────────────────────┬────────────────────────────────────────┘
│ depends on
┌─────────────────────────────────────────────────────────────┐
│ Domain Layer (Ports) │
│ EmailProvider │ SMSProvider │ PushProvider │
│ (interfaces + DTOs) │
└─────────┬──────────────────────┬────────────────────┬───────┘
│ │ │
implemented by implemented by implemented by
│ │ │
▼ ▼ ▼
┌──────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Infrastructure │ │ Infrastructure │ │ Infrastructure │
│ (Adapters) │ │ (Adapters) │ │ (Adapters) │
├──────────────────┤ ├──────────────────┤ ├─────────────────┤
│ SendGrid Adapter │ │ Twilio Adapter │ │ Firebase Adapter│
│ Resend Adapter │ │ │ │ │
└──────────────────┘ └──────────────────┘ └─────────────────┘
```
## Overview

### Components
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.

#### Core Module (`fireflyframework-notifications-core`)
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).

**Domain Layer (Ports & DTOs):**
- `EmailProvider`, `SMSProvider`, `PushProvider` - Port interfaces defining contracts
- Request/Response DTOs for each notification type
- No infrastructure dependencies
This architecture allows applications to switch notification providers without changing business logic, as all providers implement the same standardized interfaces.

**Application Layer (Services):**
- `EmailService`, `SMSService`, `PushService` - Service interfaces and implementations
- Depend only on port interfaces, never on concrete adapters
- Contain business logic and orchestration
## Features

#### Adapter Modules (Infrastructure)
- `EmailService` with template-based email sending and attachments
- `SMSService` for SMS message delivery
- `PushService` for push notification delivery
- `EmailProvider` interface for pluggable email providers
- `SMSProvider` interface for pluggable SMS providers
- `PushProvider` interface for pluggable push notification providers
- DTOs for email requests/responses with attachment support
- DTOs for SMS requests/responses
- DTOs for push notification requests/responses
- Email status tracking enum

- **`fireflyframework-notifications-sendgrid`** - SendGrid email adapter
- **`fireflyframework-notifications-resend`** - Resend email adapter
- **`fireflyframework-notifications-twilio`** - Twilio SMS adapter
- **`fireflyframework-notifications-firebase`** - Firebase Cloud Messaging push adapter
## Requirements

Each adapter implements the corresponding port interface and handles provider-specific integration details.
- Java 21+
- Spring Boot 3.x
- Maven 3.9+

## Installation

Add the core library to your Spring Boot application:

```xml path=null start=null
<dependency>
<groupId>org.fireflyframework</groupId>
<artifactId>fireflyframework-notifications-core</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
```

Then add one or more adapter libraries based on your notification needs:

```xml path=null start=null
<!-- For email via SendGrid -->
<dependency>
<groupId>org.fireflyframework</groupId>
<artifactId>fireflyframework-notifications-sendgrid</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>

<!-- For email via Resend -->
```xml
<dependency>
<groupId>org.fireflyframework</groupId>
<artifactId>fireflyframework-notifications-resend</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>

<!-- For SMS via Twilio -->
<dependency>
<groupId>org.fireflyframework</groupId>
<artifactId>fireflyframework-notifications-twilio</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>

<!-- For push notifications via Firebase -->
<dependency>
<groupId>org.fireflyframework</groupId>
<artifactId>fireflyframework-notifications-firebase</artifactId>
<version>1.0.0-SNAPSHOT</version>
<groupId>org.fireflyframework</groupId>
<artifactId>fireflyframework-notifications</artifactId>
<version>26.01.01</version>
</dependency>
```

See individual adapter READMEs for configuration details.

## Configuration

This library uses Spring Boot relaxed property binding. Both kebab-case and camelCase property names are accepted (e.g., `api-key` or `apiKey`). The examples below use kebab-case; if your service uses camelCase (as seen in some projects), it will also work.

### Provider Selection

If you include multiple email providers, select one using:

```yaml path=null start=null
notifications:
email:
provider: resend # or sendgrid
```
## Quick Start

Only the selected email provider will be instantiated.
```java
import org.fireflyframework.notifications.core.services.email.v1.EmailService;
import org.fireflyframework.notifications.interfaces.dtos.email.v1.EmailRequestDTO;

### Provider Properties

Configure providers in your `application.yml`:

```yaml path=null start=null
# Twilio (SMS)
twilio:
config:
account-sid: ${TWILIO_ACCOUNT_SID}
auth-token: ${TWILIO_AUTH_TOKEN}
phone-number: "+1234567890"

# SendGrid (Email)
sendgrid:
api-key: ${SENDGRID_API_KEY}

# Resend (Email)
resend:
api-key: ${RESEND_API_KEY}
default-from: "noreply@example.com"
# base-url: https://api.resend.com # optional; override for testing

# Firebase (Push)
firebase:
project-id: ${FIREBASE_PROJECT_ID}
credentials-path: ${FIREBASE_CREDENTIALS_PATH} # optional; uses ADC if omitted
```

Notes:
- Use either kebab-case (recommended) or camelCase (e.g., `accountSid`, `authToken`, `phoneNumber`, `apiKey`, `projectId`, `credentialsPath`). Both are supported.
- Providers are conditionally loaded only when required properties are present.
- Avoid configuring more than one email provider at the same time unless `notifications.email.provider` is explicitly set.

## Usage

Inject the service interfaces from the core module. Spring automatically wires the adapter implementations you've added to your classpath.
@Service
public class OrderNotificationService {

### Email Example
private final EmailService emailService;

```java path=null start=null
@Service
public class UserNotificationService {

@Autowired
private EmailService emailService;

public void sendWelcomeEmail(String userEmail) {
public Mono<EmailResponseDTO> sendOrderConfirmation(Order order) {
EmailRequestDTO request = EmailRequestDTO.builder()
.from("noreply@example.com")
.to(List.of(userEmail))
.subject("Welcome to Firefly")
.html("<h1>Welcome!</h1><p>Thanks for signing up.</p>")
.text("Welcome! Thanks for signing up.")
.to(order.getCustomerEmail())
.subject("Order Confirmation - " + order.getId())
.body("Your order has been confirmed.")
.build();

emailService.sendEmail(request)
.subscribe(response -> {
if (response.isSuccess()) {
log.info("Email sent successfully: {}", response.getMessageId());
} else {
log.error("Failed to send email: {}", response.getError());
}
});
return emailService.send(request);
}
}
```

### SMS Example

```java path=null start=null
@Autowired
private SMSService smsService;

public void sendVerificationCode(String phoneNumber, String code) {
SMSRequestDTO request = SMSRequestDTO.builder()
.phoneNumber(phoneNumber)
.message("Your verification code is: " + code)
.build();

smsService.sendSMS(request)
.subscribe(response -> {
if (response.isSuccess()) {
log.info("SMS sent: {}", response.getMessageId());
}
});
}
```

### Push Notification Example

```java path=null start=null
@Autowired
private PushService pushService;

public void sendPushNotification(String deviceToken, String title, String body) {
PushNotificationRequest request = PushNotificationRequest.builder()
.token(deviceToken)
.title(title)
.body(body)
.data(Map.of("type", "alert", "priority", "high"))
.build();

pushService.sendPush(request)
.subscribe(response -> {
if (response.isSuccess()) {
log.info("Push sent: {}", response.getMessageId());
}
});
}
```
## Configuration

## Benefits of Hexagonal Architecture
Configuration is provided by the specific notification provider module (SendGrid, Resend, Twilio, Firebase).

1. **Provider Independence**: Switch from SendGrid to Resend without changing business logic
2. **Testability**: Mock port interfaces for unit tests without touching real providers
3. **Maintainability**: Clear separation between domain logic and infrastructure
4. **Flexibility**: Add new providers by simply implementing the port interface
5. **Domain Focus**: Business logic in services depends only on abstract interfaces
## Documentation

## Testing
No additional documentation available for this project.

Test your notification logic without real providers:
## Contributing

```java path=null start=null
@Test
public void testEmailNotification() {
// Mock the port interface
EmailProvider mockProvider = mock(EmailProvider.class);
when(mockProvider.sendEmail(any()))
.thenReturn(Mono.just(EmailResponseDTO.success("test-id")));

EmailServiceImpl service = new EmailServiceImpl();
service.emailProvider = mockProvider;

// Test without touching real email infrastructure
StepVerifier.create(service.sendEmail(someRequest))
.expectNextMatches(response -> response.isSuccess())
.verifyComplete();
}
```
Contributions are welcome. Please read the [CONTRIBUTING.md](CONTRIBUTING.md) guide for details on our code of conduct, development process, and how to submit pull requests.

## Documentation
## License

For detailed architecture documentation, see [ARCHITECTURE.md](ARCHITECTURE.md).
Copyright 2024-2026 Firefly Software Solutions Inc.

For adapter-specific configuration and usage:
- [SendGrid Adapter](../fireflyframework-notifications-sendgrid/README.md)
- [Resend Adapter](../fireflyframework-notifications-resend/README.md)
- [Twilio Adapter](../fireflyframework-notifications-twilio/README.md)
- [Firebase Adapter](../fireflyframework-notifications-firebase/README.md)
Licensed under the Apache License, Version 2.0. See [LICENSE](LICENSE) for details.
Loading