Milesoft Notifications SDK (notifications-sdk)

1. Overview

The Notifications SDK (notifications-sdk) provides a strongly-typed programmatic client for orchestrating cross-channel messaging and tenant communications inside the Milesoft platform. It supports managing user delivery preferences, issuing direct push notifications, publishing message payloads to broad topic cohorts, dispatching transactional emails via SMTP, and processing system events across different client-facing channels (Push, App persist, Email, Mobile).


2. Initialization

2.1 Dependency Installation

The notifications-sdk package is hosted in our secure Google Cloud Artifact Registry repository.

To consume notifications-sdk in your Spring Boot application, apply the Google Cloud Artifact Registry plugin and declare our secure repository in your build.gradle:

plugins {
    id "com.google.cloud.artifactregistry.gradle-plugin" version "2.2.5"
}

repositories {
    mavenCentral()
    maven { url "artifactregistry://us-west2-maven.pkg.dev/milesoft-repo/repo-maven" }
}

dependencies {
    // Declaring the standard notifications-sdk library dependency
    implementation "io.milesoft:notifications-sdk:2.1.0"
}

2.2 Central Spring Boot Configuration

Configure the underlying clients and NotificationService helper class inside your Spring configuration layer.

import io.milesoft.clients.PlatformClient;
import io.milesoft.clients.strategy.PlatformTokenProvider;
import io.milesoft.notifications.client.v2.EventClient;
import io.milesoft.notifications.client.v2.NotificationClient;
import io.milesoft.notifications.client.v2.PreferencesClient;
import io.milesoft.notifications.services.NotificationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class NotificationsSdkConfig {

    private final NotificationClient notificationClient;
    private final EventClient eventClient;
    private final PreferencesClient preferencesClient;
    private final NotificationService notificationService;

    @Autowired
    public NotificationsSdkConfig(PlatformClient platformClient, 
                                  @Value("${milesoft.notifications.baseUrl}") String baseUrl) {
        
        PlatformTokenProvider tokenProvider = new PlatformTokenProvider(platformClient);

        this.notificationClient = new NotificationClient(baseUrl, tokenProvider);
        this.eventClient = new EventClient(baseUrl, tokenProvider);
        this.preferencesClient = new PreferencesClient(baseUrl, tokenProvider);
        this.notificationService = new NotificationService(notificationClient, eventClient);
    }

    @Bean
    public NotificationClient notificationClient() { return notificationClient; }

    @Bean
    public EventClient eventClient() { return eventClient; }

    @Bean
    public PreferencesClient preferencesClient() { return preferencesClient; }

    @Bean
    public NotificationService notificationService() { return notificationService; }
}

3. Core SDK Clients & Method Specifications

Programmatic execution is managed across logical clients designed to completely abstract the underlying REST boundaries.

3.1 NotificationClient

Manages direct notifications and inboxes.

  • Notifications list(String cursor, Integer limit, Actor actor): Paginated fetch of the active user's notification inbox.
  • List<Notification> loadBulk(Ids payload, Actor actor): Loads specific notifications by their unique IDs.
  • Notification create(SaveNotification payload, Actor actor): Creates and delivers a direct notification to targeted recipients.
  • void markAsRead(Ids payload, Actor actor): Marks a batch of notifications as read.
  • void delete(String id, Actor actor): Deletes a specific notification.
  • void deleteBulk(Ids payload, Actor actor): Deletes multiple notifications in a single batch.
  • void pushToTopic(PushToTopic payload, Actor actor): Broadcasts a direct push notification to an FCM topic.

3.2 EventClient

Triggers audience-based platform system events.

  • boolean emit(EmitEvent payload, Actor actor): Emits an event to explicit recipients, letting preference matrices dictate channel routing.
  • boolean push(PushEvent payload, Actor actor): Broadcasts an event to a registered topic channel.

3.3 PreferencesClient

Tracks user device tokens and subscriptions.

  • Preferences load(Actor actor): Loads active caller's delivery channel configurations.
  • Preferences update(Preferences payload, Actor actor): Saves active user's FCM registration tokens and topic channel subscription mappings.

3.4 NotificationService

A high-level convenience helper aggregating notifications and events propagation acting under active user contexts.

  • List<Receipt> emit(Notification notification, Recipients recipients): Emits a notification to a specific cohort.
  • boolean emit(Event event, Recipients recipients): Emits an event to a targeted cohort.

4. Built-In SDK Capabilities

  • 🔒 Map Guardrails (@MapGuard): Generic payload and metadata contexts are validated at the gateway to protect parsing engines from heap-bloat and DoS vulnerabilities:
    • Maximum Key Count: 100 unique keys per map.
    • Maximum Nesting Depth: 5 nested levels.
    • Key Pattern: Must be alphanumeric matching ^[a-zA-Z0-9_\-]{1,256}$.
  • Intelligent Routing: Channels are evaluated dynamically. If a billing alert targets a cohort of 50 users, the engine parses each operator's customized Preferences map to resolve whether to dispatch via Push, App persist, or transactional Email.

5. Code Examples

5.1 Dispatching Direct Cohort Alerts

import io.milesoft.notifications.services.NotificationService;
import io.milesoft.notifications.domain.Notification;
import io.milesoft.notifications.domain.Recipients;
import io.milesoft.notifications.domain.Receipt;
import io.milesoft.primitives.actor.Actor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;

@Service
public class BillingNotificationService {

    private final NotificationService notificationService;

    @Autowired
    public BillingNotificationService(NotificationService notificationService) {
        this.notificationService = notificationService;
    }

    public void dispatchOverdueInvoiceAlert(Actor actor, String title, String description, List<String> clientUserIds) {
        // Construct targeted recipients
        Recipients recipients = Recipients.builder()
            .users(false)
            .admins(false)
            .includeIds(clientUserIds)
            .excludeIds(List.of())
            .build();

        // Construct notification payload
        Notification notification = Notification.builder()
            .type("billing_alert")
            .mail(true)
            .title(title)
            .description(description)
            .gotoUrl("/billing/invoices")
            .build();

        // Emit over the platform
        List<Receipt> receipts = notificationService.emit(notification, recipients);
        for (Receipt receipt : receipts) {
            System.out.println("Alert successfully delivered to user " + receipt.getUserId() + " via " + receipt.getMethod());
        }
    }
}

5.2 Emitting Platform System Events

import io.milesoft.notifications.services.NotificationService;
import io.milesoft.notifications.domain.Event;
import io.milesoft.notifications.domain.Recipients;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;

@Component
public class RewardEventEngine {

    private final NotificationService notificationService;

    public RewardEventEngine(NotificationService notificationService) {
        this.notificationService = notificationService;
    }

    public void triggerRewardUnlockedEvent(String userId, String rewardName, int pointsAmount) {
        Recipients recipients = Recipients.builder()
            .users(false)
            .admins(false)
            .includeIds(List.of(userId))
            .excludeIds(List.of())
            .build();

        Event event = Event.builder()
            .type("reward_unlocked")
            .payload(Map.of("reward", rewardName, "amount", pointsAmount))
            .build();

        boolean success = notificationService.emit(event, recipients);
        if (success) {
            System.out.println("System event successfully emitted over the platform.");
        }
    }
}

6. SDK Data Transfer Objects (DTOs)

SaveNotification

Structure used to submit/create a direct notification.

Field Type Description / Constraints
type String Semantic type/category of the notification (e.g., billing_alert). Required / Not Blank.
mail Boolean Indicates whether SMTP email delivery should also be executed. Required / Not Null.
title String The title heading of the notification. Required / Not Blank.
description String Longer description body of the notification.
gotoUrl String Deep-link redirection path triggered when a user clicks the notification.
emailExtra String Supplemental content parsed solely into the email template body.
payload Map<String, Object> Raw key-value context details linked to the notification. Subject to @MapGuard.
metadata Map<String, Object> Extra key-value metadata parameters. Subject to @MapGuard.
data MergeData Structured template variables for Liquid engine compilation.
recipients Recipients Targeted cohort filters mapping the intended recipients. Required / Not Null.

Notification

Schema representing a persistent notification record retrieved from the database.

Field Type Description / Constraints
id String The unique database identifier of the notification. Required / Not Blank.
type String The semantic category of the notification. Required / Not Blank.
mail Boolean Indicates whether email delivery was processed. Required / Not Null.
state NotificationState The reading status of the notification (New, Read). Required / Not Null.
title String The header title. Required / Not Blank.
description String The long description text. Required / Not Blank.
gotoUrl String Deep-link redirection target path.
metadata Map<String, Object> Key-value meta data fields. Subject to @MapGuard.
created ZonedDateTime Timestamp indicating creation. Required / Not Null.
updated ZonedDateTime Timestamp marking last state modification. Required / Not Null.

Recipients

Scoping criteria defining targeted user recipient groups.

Field Type Description / Constraints
users Boolean If true, targets all standard active tenant users. Required / Not Null.
admins Boolean If true, targets all tenant administrators. Required / Not Null.
supers Boolean If true, targets all system super-users. Required / Not Null.
includeIds List<String> Specific User IDs whitelist. Required / Not Null.
excludeIds List<String> Specific User IDs blacklist. Required / Not Null.

Preferences

User-specific configuration mapping messaging tokens and channel selections.

Field Type Description / Constraints
messagingToken String FCM device messaging token registered by mobile/web clients.
deliveries Map<String, DeliveryMethod> Map indexing notification types to delivery methods (None, Mobile, App, Email). Required / Not Null.
topics Map<String, Boolean> Map indexing topics to subscription statuses (True if subscribed). Required / Not Null.

Receipt

Delivery confirmation object generated for each successful dispatch channel attempt.

Field Type Description / Constraints
userId String Target user's system identifier. Required / Not Blank.
to String Channel endpoint used (e.g., email address, device token). Required / Not Blank.
method DeliveryMethod Channel mechanism executed (None, Mobile, App, Email). Required / Not Null.

Receipts

Wrapping container holding a list of delivery confirmations.

Field Type Description / Constraints
receipts List<Receipt> List of delivery confirmations. Required / Not Null.

EmitEvent

Specifies parameters to trigger an audience-based system event.

Field Type Description / Constraints
type String Semantic event identifier matching liquid templates. Required / Not Blank.
payload Map<String, Object> Raw key-value contextual data. Subject to @MapGuard.
data MergeData Template compilation merge values.
recipients Recipients Recipient audience definitions. Required / Not Null.

PushEvent

Specifies parameters to trigger a topic-wide system event broadcast.

Field Type Description / Constraints
topic String Active topic name to broadcast the event to. Required / Not Blank.
payload Map<String, Object> Raw key-value contextual data. Subject to @MapGuard.
data MergeData Template compile merge variables.

PushToTopic

Broadcasts a direct push notification to all users subscribed to a specific topic channel.

Field Type Description / Constraints
topic String Unique topic name. Required / Not Blank.
title String The push notification title text. Required / Not Blank.
gotoUrl String The redirection deep-link.
payload Map<String, Object> Key-value context payload. Subject to @MapGuard.
data MergeData Template merge fields.

Topic

Subscription mapping associating standard topic channels to the user.

Field Type Description / Constraints
type String Semantic topic identifier. Required / Not Blank.
subscribed Boolean Boolean registration status. Required / Not Null.

Delivery

Type mapping linking specific notification keys to preferred delivery methods.

Field Type Description / Constraints
type String Unique notification type identifier. Required / Not Blank.
method DeliveryMethod Preferred delivery method selection. Required / Not Null.

Ids

Utility request envelope payload packaging multiple document identifiers.

Field Type Description / Constraints
ids List<String> Collection of system identifiers. Required / Not Null.

MergeData

Template context package used by the template-compilation engines.

Field Type Description / Constraints
userId String Contextual user identifier.
contactId String Contextual contact identifier.
userQualifiers List<Qualifier> Qualifier-based routing filters for user attributes.
contactQualifiers List<Qualifier> Qualifier-based routing filters for contact attributes.
models List<Model> Nested list of rich objects loaded into template context.

Qualifier

Filtering parameter mapping within MergeData.

Field Type Description / Constraints
key String Filter identifier field. Required / Not Blank.
id String Filter argument value. Required / Not Blank.

Model

A data model object dictionary evaluated inside dynamic template frameworks.

Field Type Description / Constraints
key String Variable name inside template parsing (e.g., invoice). Required / Not Blank.
data Map<String, Object> Nested fields/properties of the target model object. Required / Not Null.

Enums

DeliveryMethod

The configured delivery mechanics supporting different dispatch options:

  • None: Triggers event-only emissions (no visual delivery).
  • Mobile: Sends push notifications directly to registered FCM mobile/web devices.
  • App: Sends push notifications to FCM and persists the notification inside the user's persistent inbox (Firestore database).
  • Email: Delivers via FCM push, persists in the user's inbox, and constructs/dispatches a transactional email via the SMTP connector.

NotificationState

Reflects reading status in user inboxes:

  • New
  • Read