Looking to hire Laravel developers? Try LaraJobs

laravel-notification-system maintained by abdogoda

Description
Production-ready, highly extensible multi-channel notification package for Laravel by Abdulrhman Goda.
Last update
2026/08/10 10:45 (dev-main)
License
Downloads
0

Comments
comments powered by Disqus

Laravel Notification System

Latest Version on Packagist License: MIT Developer Website

A production-ready, highly extensible, multi-channel notification framework for Laravel applications developed by Abdulrhman Goda. Designed for single and multi-authentication, unlimited guards, customizable recipients, delivery tracking, localization, queued channels, and built-in Blade/Tailwind admin dashboard components.


Requirements

  • PHP 8.2+
  • Laravel 10, 11, 12, or 13

Features

  • Multi-Channel Architecture: Native support for Database, Mail, FCM Push Notifications, WhatsApp (BULQ API), and extensible custom channels.
  • Fluent Notification Builder: Clean API (NotificationSystem::make()->title(...)->to(...)->send()).
  • Dynamic Recipient Resolution: Pass Eloquent models, collections, query builders, arrays, or guard names.
  • Immutable DTO Layer: Strong type safety with NotificationData, RecipientData, ChannelData, AttachmentData, and MailData.
  • Delivery Logging: Detailed logging table (notification_logs) tracking status, attempts, response payload, exception trace, and duration.
  • Event-Driven Lifecycle: Event hooks (NotificationCreating, NotificationSending, NotificationSent, NotificationFailed, ChannelSending, ChannelSent, ChannelFailed).
  • Queued & Async Delivery: Asynchronous queued delivery with configurable backoff, retry, and per-channel queue names.
  • Recipient Localization: Automatic locale detection from recipient preferences with fallback.
  • Admin Panel & Blade Components: Ready-to-use Blade components (<x-notification-card>, <x-notification-table>, <x-notification-form>, <x-recipient-selector>, <x-channel-selector>, <x-statistics-widget>).
  • REST API Endpoints: Production API controllers for mobile and SPA clients.

Installation

1. Require via Composer

composer require abdogoda/laravel-notification-system

2. Publish Configuration & Migrations

# Publish everything
php artisan vendor:publish --provider="NotificationSystem\NotificationSystemServiceProvider"

# Or publish individually
php artisan vendor:publish --tag=notification-system-config
php artisan vendor:publish --tag=notification-system-migrations
php artisan vendor:publish --tag=notification-system-views
php artisan vendor:publish --tag=notification-system-translations
php artisan vendor:publish --tag=notification-system-assets

3. Run Migrations

php artisan migrate

Quick Start

Basic Fluent Builder

use NotificationSystem\Facades\NotificationSystem;

NotificationSystem::make()
    ->title('Welcome to the Platform!')
    ->body('Thank you for joining our academy.')
    ->channels(['database', 'mail', 'fcm'])
    ->to($user)
    ->locale('ar')
    ->data([
        'action_url' => '/dashboard',
        'type' => 'welcome_onboarding'
    ])
    ->send();

Sending to Multiple Guards / Audiences

NotificationSystem::make()
    ->title('Scheduled Maintenance Alert')
    ->body('The system will undergo scheduled maintenance tonight at 12:00 AM.')
    ->channels(['database', 'fcm'])
    ->to(['students', 'teachers', 'merchants'])
    ->send();

Synchronous Delivery (Skip Queue)

NotificationSystem::make()
    ->title('Urgent Alert')
    ->body('Action required immediately.')
    ->to($user)
    ->sendNow();

Queued with Delay

NotificationSystem::make()
    ->title('Reminder')
    ->body('Your appointment is in 1 hour.')
    ->to($user)
    ->queue(true, delaySeconds: 3600)
    ->send();

Email with Attachments

NotificationSystem::make()
    ->title('Invoice Ready')
    ->body('Your invoice is attached.')
    ->email(send: true, greeting: 'Dear Customer')
    ->attach('/path/to/invoice.pdf', name: 'Invoice.pdf', mime: 'application/pdf')
    ->to($user)
    ->send();

Configuration Reference

After publishing, the config file is at config/notification-system.php:

Default Channels

'default_channels' => ['database'],

Locale

'default_locale' => 'ar',
'locale_column'  => 'lang',  // Model attribute for preferred locale

Queue Settings

'queue' => [
    'enabled'       => true,
    'connection'    => env('NOTIFICATION_QUEUE_CONNECTION', 'default'),
    'queue_name'    => env('NOTIFICATION_QUEUE_NAME', 'notifications'),
    'backoff'       => [5, 15, 60],      // Retry backoff in seconds
    'max_tries'     => 3,
    'channel_queues' => [                // Per-channel queue names
        'mail'     => 'emails',
        'fcm'      => 'push-notifications',
        'whatsapp' => 'whatsapp',
    ],
],

Guards Setup

Map guard names to Eloquent models. These are resolved when you pass guard strings to ->to():

'guards' => [
    'admin' => [
        'model' => \App\Models\Admin::class,
        'label' => 'Admins',
    ],
    'student' => [
        'model' => \App\Models\Student::class,
        'label' => 'Students',
    ],
],

Channel Credentials

'channels' => [
    'whatsapp' => [
        'api_url' => env('BULQ_WHATSAPP_API_URL'),
        'token'   => env('BULQ_WHATSAPP_TOKEN'),
        'template_name' => env('BULQ_WHATSAPP_TEMPLATE', 'login_otp'),
    ],
    'fcm' => [
        'driver_class' => env('NOTIFICATION_FCM_DRIVER', null),
    ],
    'mail' => [
        'from_address' => env('MAIL_FROM_ADDRESS', 'noreply@example.com'),
        'from_name'    => env('MAIL_FROM_NAME', 'Laravel'),
    ],
],

Delivery Logging

'table_name'         => 'notification_logs',
'logging_enabled'    => true,
'log_retention_days' => 90,  // Set to null to keep forever

Custom Channels

You can register custom channels that implement ChannelInterface:

use NotificationSystem\Contracts\ChannelInterface;
use NotificationSystem\DTOs\NotificationData;
use NotificationSystem\DTOs\RecipientData;

class SlackChannel implements ChannelInterface
{
    public function send(RecipientData $recipient, NotificationData $notification): array|bool
    {
        // Your Slack sending logic here
        return ['status' => 'sent'];
    }
}

Register it in a service provider:

use NotificationSystem\Facades\NotificationSystem;

NotificationSystem::extend('slack', SlackChannel::class);

Then use it:

NotificationSystem::make()
    ->title('Hello Slack!')
    ->channels(['database', 'slack'])
    ->to($user)
    ->send();

FCM Setup

To use FCM push notifications, implement FcmDriverInterface and configure it:

use NotificationSystem\Contracts\FcmDriverInterface;

class MyFcmDriver implements FcmDriverInterface
{
    public function sendNotification(string $token, string $title, string $body, array $data = []): void
    {
        // Your Firebase sending logic
    }
}

Register in a service provider:

$this->app->bind(FcmDriverInterface::class, MyFcmDriver::class);

Or set via config/env:

NOTIFICATION_FCM_DRIVER=App\Services\MyFcmDriver

Events

The package dispatches events throughout the notification lifecycle. Listen to them in your EventServiceProvider:

Event Fired When
NotificationCreating Before recipients are resolved
NotificationSending Before delivery starts for a recipient
NotificationSent After all channels deliver for a recipient
NotificationFailed If the entire delivery process throws
ChannelSending Before a specific channel sends
ChannelSent After a specific channel succeeds
ChannelFailed After a specific channel fails

Example Listener

use NotificationSystem\Events\NotificationSent;

class LogNotificationDelivery
{
    public function handle(NotificationSent $event): void
    {
        logger()->info('Notification delivered', [
            'notification_id' => $event->notification->id,
            'recipient_id'    => $event->recipient->id,
            'channels'        => array_keys($event->channelResults),
        ]);
    }
}

REST API Endpoints

All routes are configurable via notification-system.routes.api:

Method Endpoint Description
GET /api/v1/notifications List paginated notifications
GET /api/v1/notifications/unread-count Get unread count
POST /api/v1/notifications/mark-all-read Mark all as read
POST /api/v1/notifications/{id}/mark-read Mark one as read
DELETE /api/v1/notifications/{id} Delete a notification
DELETE /api/v1/notifications Clear all notifications

Blade Components

Available components (all prefixed with notification-system):

<x-notification-system-notification-card :notification="$notification" :is-unread="true" />
<x-notification-system-notification-table :notifications="$notifications" />
<x-notification-system-notification-form />
<x-notification-system-recipient-selector :guards="$guardModels" />
<x-notification-system-channel-selector :selected-channels="['database', 'mail']" />
<x-notification-system-statistics-widget :total="100" :unread="5" :delivered="90" :failed="5" />

Delivery Logging

Every send attempt is logged to the notification_logs table with:

  • notification_id — Links to the notification
  • channel — Which channel was used
  • statuspending, sending, delivered, or failed
  • duration_ms — How long the channel took
  • response — JSON response from the channel
  • exception — Error message if failed

Query Log Scopes

use NotificationSystem\Models\NotificationLog;

NotificationLog::delivered()->count();
NotificationLog::failed()->forChannel('mail')->get();
NotificationLog::forRecipient('App\Models\User', 1)->recent(30)->get();
NotificationLog::olderThan(90)->delete(); // Prune old logs

Testing

composer test

Or:

vendor/bin/phpunit

The test suite uses SQLite in-memory via Orchestra Testbench.


Credits & Author

Developed with ❤️ by Abdulrhman Goda.


Contributing

Please see CONTRIBUTING.md for details.

Security

If you discover a security vulnerability, please see SECURITY.md.

License

The MIT License (MIT). Copyright © 2026 Abdulrhman Goda. Please see License File for more information.