PHPackages                             deegitalbe/laravel-trustup-io-notifications - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. deegitalbe/laravel-trustup-io-notifications

ActiveLibrary

deegitalbe/laravel-trustup-io-notifications
===========================================

Laravel client package for the Trustup IO Notifications system.

0.5.1(today)00MITPHPPHP ^8.2

Since Jul 27Pushed todayCompare

[ Source](https://github.com/deegitalbe/laravel-trustup-io-notifications)[ Packagist](https://packagist.org/packages/deegitalbe/laravel-trustup-io-notifications)[ RSS](/packages/deegitalbe-laravel-trustup-io-notifications/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (9)Versions (4)Used By (0)

Trustup IO Notifications (Laravel client)
=========================================

[](#trustup-io-notifications-laravel-client)

Drop-in Laravel client for the Trustup IO Notifications service. It lets a source application **send** notifications through Laravel's native notification system and **receive** delivery feedback (delivered, bounced, opened, clicked, ...), all over Kafka.

- Package name: `deegitalbe/laravel-trustup-io-notifications`
- Namespace: `Deegitalbe\TrustupIoNotificationsClient\`
- Requires: PHP 8.2+, Laravel 12, `mateusjunges/laravel-kafka`, and the contracts package `deegitalbe/laravel-trustup-io-notifications-contracts`.

The notification payloads and channel definitions live in the contracts package. See its README for how to define a `NotificationData` class, override channel rendering, and add a new notification type. This README covers wiring the client into an app and the send / receive flows.

---

1. Install
----------

[](#1-install)

```
composer require deegitalbe/laravel-trustup-io-notifications
```

The service provider is auto-discovered. It registers the config file and the two consume commands.

2. Configure
------------

[](#2-configure)

Publish the config if you want to edit defaults (optional; env vars are enough for most apps):

```
php artisan vendor:publish --provider="Deegitalbe\TrustupIoNotificationsClient\TrustupIoNotificationsClientServiceProvider"
```

Set the source and the Kafka broker. Everything else has working defaults.

```
# Which source this app is (tools | marketplace). Used as the default recipient source.
TRUSTUP_IO_NOTIFICATIONS_SOURCE=tools

# Kafka broker (mateusjunges/laravel-kafka config)
KAFKA_BROKERS=kafka:9092
```

Config keys (`config/trustup-io-notifications.php`):

KeyEnvDefaultPurpose`topics.request``TRUSTUP_IO_NOTIFICATIONS_TOPIC_REQUEST``notifications.request`Topic this app **publishes** send requests to.`topics.status``TRUSTUP_IO_NOTIFICATIONS_TOPIC_STATUS``notifications.status`Topic this app **consumes** delivery statuses from.`topics.engagement``TRUSTUP_IO_NOTIFICATIONS_TOPIC_ENGAGEMENT``notifications.engagement`Topic this app **consumes** engagement events from.`topics.dlq``TRUSTUP_IO_NOTIFICATIONS_TOPIC_DLQ``notifications.dlq`Dead-letter topic for both consumers.`source``TRUSTUP_IO_NOTIFICATIONS_SOURCE``null`Default `Source` when a recipient has none. If null and no source on the recipient → `MissingSourceException`.3. Send a notification (bare minimum)
-------------------------------------

[](#3-send-a-notification-bare-minimum)

Three pieces: a **notification** class, a **notifiable** that knows its recipient, and a `notify()` call.

### The notification

[](#the-notification)

The notification receives your own domain models and derives the `NotificationData` from them inside `toTrustupIoNotificationsData()`. You do not pass the data object in from the outside.

```
use App\Models\Comment;
use Illuminate\Notifications\Notification;
use Deegitalbe\TrustupIoNotificationsClient\Channel\TrustupIoNotificationsChannel;
use Deegitalbe\TrustupIoNotificationsClient\Concerns\InteractsWithTrustupIoNotifications;
use Deegitalbe\TrustupIoNotificationsClient\Contracts\SendsTrustupIoNotification;
use Deegitalbe\TrustupIoNotificationsContracts\Contracts\NotificationData;
use Deegitalbe\TrustupIoNotificationsContracts\Data\ToolsCommentNotificationData;

class CommentNotification extends Notification implements SendsTrustupIoNotification
{
    use InteractsWithTrustupIoNotifications;

    public function __construct(private Comment $comment) {}

    public function via(object $notifiable): array
    {
        return [TrustupIoNotificationsChannel::class];
    }

    public function toTrustupIoNotificationsData(): NotificationData
    {
        return new ToolsCommentNotificationData(
            product_url: $this->comment->product->url,
            product_name: $this->comment->product->name,
            body: $this->comment->body,
            attachment_details: $this->comment->attachmentDetails(),
            commenter_name: $this->comment->author->name,
            timestamp: $this->comment->created_at->toIso8601String(),
            action_url: $this->comment->url,
            notifications_url: route('notifications.index'),
            company_name: $this->comment->product->company->name,
            company_address: $this->comment->product->company->address,
        );
    }
}
```

- Implement `SendsTrustupIoNotification`; `toTrustupIoNotificationsData()` maps your models to the typed payload.
- `use InteractsWithTrustupIoNotifications` to get the default "all channels" behavior; without it you must implement `restrictTrustupIoNotificationsChannels()` yourself.
- Reference the channel by class in `via()`.
- The `NotificationData` class (`ToolsCommentNotificationData` here) comes from the contracts package; see its README to define your own.

### The notifiable

[](#the-notifiable)

Add Laravel's `Notifiable` (for `notify()`), implement the interface, and use the routing trait:

```
use Illuminate\Notifications\Notifiable;
use Deegitalbe\TrustupIoNotificationsClient\Concerns\RoutesTrustupIoNotifications;
use Deegitalbe\TrustupIoNotificationsClient\Contracts\NotifiableViaTrustupIoNotifications;
use Deegitalbe\TrustupIoNotificationsContracts\Enums\Source;
use Deegitalbe\TrustupIoNotificationsContracts\Request\Recipient;

class User extends Model implements NotifiableViaTrustupIoNotifications
{
    use Notifiable;
    use RoutesTrustupIoNotifications;

    public function toTrustupIoNotificationsRecipient(): Recipient
    {
        return Recipient::identified((string) $this->id);
    }
}
```

`Notifiable` is required (it provides `notify()`); the package does not include it for you. `RoutesTrustupIoNotifications` wires Laravel's routing convention to your `toTrustupIoNotificationsRecipient()`.

The recipient omits the source: the client fills it from `TRUSTUP_IO_NOTIFICATIONS_SOURCE` at publish time. Pass it explicitly (`Recipient::identified((string) $this->id, Source::Tools)`) only if this app sends for more than one source.

### Send it

[](#send-it)

```
$user->notify(new CommentNotification($comment));
```

That publishes the request to Kafka. The notifications service picks it up, resolves the recipient's coordinates, and delivers on each supported channel.

4. Receive delivery feedback
----------------------------

[](#4-receive-delivery-feedback)

The service publishes back onto the `status` and `engagement` topics. The client turns those into two Laravel events you listen to.

### Run the consumers + a queue worker

[](#run-the-consumers--a-queue-worker)

The consume commands are long-running Kafka consumers. They only **enqueue** jobs; the events fire from inside those queued jobs. So you need the consumers **and** a queue worker running:

```
php artisan trustup-io-notifications:consume-statuses
php artisan trustup-io-notifications:consume-engagements
php artisan queue:work            # or Horizon
```

Without a queue worker, statuses and engagements are consumed but the events never dispatch.

### Listen to the events

[](#listen-to-the-events)

```
use Illuminate\Support\Facades\Event;
use Deegitalbe\TrustupIoNotificationsClient\Events\TrustupIoNotificationStatusReceived;
use Deegitalbe\TrustupIoNotificationsClient\Events\TrustupIoNotificationEngagementReceived;

Event::listen(TrustupIoNotificationStatusReceived::class, function ($event) {
    $event->payload->sendId;         // string
    $event->payload->channel;        // NotificationChannel: email|sms|push
    $event->payload->status;         // NotificationStatus: pending|sent|delivered|error
    $event->payload->type;           // NotificationType
    $event->payload->data;           // hydrated NotificationData
});

Event::listen(TrustupIoNotificationEngagementReceived::class, function ($event) {
    $event->payload->kind;           // ChannelEventKind: delivered|bounced|spam_complaint|opened|clicked|...
    $event->payload->clickedUrl;     // ?string (set for clicks)
    $event->payload->sendId;
    $event->payload->channel;
});
```

The package defines **no listeners of its own** by design: it emits the events, your app decides what to do (update a local model, alert on bounce, track engagement, ...). Register as many listeners as you want, on either event. Dispatching with zero listeners is a no-op, not an error.

`StatusPayload` and `EngagementPayload` shapes are documented in the contracts README.

5. What must be running
-----------------------

[](#5-what-must-be-running)

ProcessRoleWhere`queue:work` / HorizonRuns the queued jobs that both send and receive rely onsource app`trustup-io-notifications:consume-statuses`Consumes delivery statuses → `TrustupIoNotificationStatusReceived`source app`trustup-io-notifications:consume-engagements`Consumes engagements → `TrustupIoNotificationEngagementReceived`source appKafka brokerTransport for all topicsshared infraThe notifications serviceConsumes `request`, delivers, publishes `status` / `engagement`separate serviceSending only needs a reachable Kafka broker. Receiving feedback needs the two consumers **and** a queue worker.

---

Customization
-------------

[](#customization)

### Restrict channels per notification

[](#restrict-channels-per-notification)

By default a notification goes out on every channel its data class supports. Override to narrow it:

```
use Deegitalbe\TrustupIoNotificationsContracts\Enums\NotificationChannel;

public function restrictTrustupIoNotificationsChannels(): ?array
{
    return [NotificationChannel::Email]; // email only, even if the data class also supports sms/push
}
```

`null` = all supported channels. `[]` is invalid and rejected (`InvalidEnvelopeException`).

### Anonymous recipients (no model)

[](#anonymous-recipients-no-model)

When there is no notifiable model, route on the fly with a `Recipient::anonymous(...)`:

```
use Illuminate\Support\Facades\Notification;
use Deegitalbe\TrustupIoNotificationsContracts\Request\Recipient;

Notification::route('trustup-io-notifications',
    Recipient::anonymous(email: 'a@b.com', phone: null, deviceTokens: [], locale: 'fr-BE')
)->notify(new CommentNotification($comment));
```

The routing key is the literal string `trustup-io-notifications`.

### Customize the payload / channels / rendering

[](#customize-the-payload--channels--rendering)

The notification's **content** (which template, which variables, SMS/push wording, translations) is controlled by the `NotificationData` class and its `Renders*` traits, all in the contracts package. See that README's "Capability interfaces and their default rendering" section for the overridable methods (`emailTemplate`, `emailVariables`, `emailTemplateLocaleGranularity`, `smsBody`, `pushTitle`, ...).

### Default source vs explicit source

[](#default-source-vs-explicit-source)

`Recipient::identified($id, Source::Tools)` sets the source explicitly. Built without a source (`Recipient::identified($id)` or any anonymous recipient), the client fills it from `config('trustup-io-notifications.source')` at publish time. Set `TRUSTUP_IO_NOTIFICATIONS_SOURCE` so this always resolves.

Errors
------

[](#errors)

ExceptionWhen`MissingTrustupIoNotificationContractException`The notification does not implement `SendsTrustupIoNotification`.`UnresolvableRecipientException`The notifiable exposes no recipient (missing method / on-demand route not a `Recipient`).`MissingSourceException`Recipient has no source and no `config('...source')` default.`MissingTopicConfigException`A required topic config key is null at publish time.`InvalidRecipientException` / `InvalidEnvelopeException`Invalid recipient coordinates or an empty channel list.

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance100

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity38

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

3

Last Release

0d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/24230736?v=4)[Mathieu Henrotay](/maintainers/henrotaym)[@henrotaym](https://github.com/henrotaym)

---

Top Contributors

[![trustup-foreman[bot]](https://avatars.githubusercontent.com/in/1802739?v=4)](https://github.com/trustup-foreman[bot] "trustup-foreman[bot] (3 commits)")

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/deegitalbe-laravel-trustup-io-notifications/health.svg)

```
[![Health](https://phpackages.com/badges/deegitalbe-laravel-trustup-io-notifications/health.svg)](https://phpackages.com/packages/deegitalbe-laravel-trustup-io-notifications)
```

###  Alternatives

[spatie/laravel-pdf

Create PDFs in Laravel apps

1.0k4.8M48](/packages/spatie-laravel-pdf)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3914.8k](/packages/rawilk-profile-filament-plugin)[harris21/laravel-fuse

Circuit breaker for Laravel queue jobs. Protect your workers from cascading failures.

45955.7k](/packages/harris21-laravel-fuse)[vormkracht10/laravel-mails

Laravel Mails can collect everything you might want to track about the mails that has been sent by your Laravel app.

24957.5k](/packages/vormkracht10-laravel-mails)[stephenjude/filament-jetstream

A Laravel starter kit built with Filament inspired by Jetstream.

17760.2k3](/packages/stephenjude-filament-jetstream)[lettermint/lettermint-laravel

Official Lettermint driver for Laravel

1190.2k1](/packages/lettermint-lettermint-laravel)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
