liberusoftware/notifications-filament
Filament integration for Liberu Software's notifications package. Adds ready-made admin and panel UI for composing, sending, and reviewing notifications, so Laravel teams can wire notification management into Filament apps with minimal configuration.
liberusoftware/notifications-filament is a presentation adapter, not a notification engine. The actual sending, storing, and recipient-resolution logic lives in its companion domain module (liberusoftware/module-notifications). Treat this package as the Filament-facing skin: resources, pages, widgets, and the panel plugin that wires them into your admin UI.
Minimal path to a working screen:
composer.json for the require block before running anything:
composer require liberusoftware/notifications-filament
If the core module isn't pulled transitively, add liberusoftware/module-notifications explicitly and read its README first. The adapter inherits the core module's data model, so that document is your real source of truth.vendor/liberusoftware/notifications-filament/database/migrations). Confirm what table it targets — see the Gotchas section, this is the most common first-run failure.app/Providers/Filament/AdminPanelProvider.php), typically:
->plugins([
\Liberusoftware\NotificationsFilament\NotificationsFilamentPlugin::make(),
])
Check src/ for the exact class name and whether the service provider self-registers via package discovery instead.php artisan filament:optimize-clear && php artisan about
Where to look first, in this order:
composer.json — required Filament major version (v3 vs v4 changes everything below) and the core module constraint.src/*ServiceProvider.php — what gets auto-registered, what config keys are read, what's publishable.src/Filament/ — the actual Resources / Pages / Widgets. This tells you whether the package manages notification records as a CRUD resource or only renders a bell/inbox.config/notifications-filament.php (if publishable) — toggle points for navigation, resources, and views.First use case to validate with: drop the package into an existing panel and confirm the notification bell / inbox page appears and reflects a record created through the core module's API (Notification::fake() in a tinker session or a test). If that round-trip works, the adapter's contract is intact; everything else is UI polish.
Separate the send path from the render path. Your application code should call the core module's notification classes (php artisan make:notification style, or whatever the domain module exposes). The Filament package should never be the thing that dispatches notifications — it observes them. Keeping that line clean means you can swap or drop the UI without touching business logic, and it makes Notification::fake() assertions in tests meaningful again.
Panel plugin vs. service provider. Two registration styles are common in Liberu modules, and this package may support both. Prefer the plugin (->plugins([...])) when you have multiple panels, because it lets you scope the UI:
// Admin panel: full resource + widget
->plugins([NotificationsFilamentPlugin::make()])
// Customer panel: bell only, no resource pages
->plugins([NotificationsFilamentPlugin::make()->resources(false)])
Verify the fluent methods exist in src/NotificationsFilamentPlugin.php — if they don't, gate access via canAccess() / shouldRegisterNavigation() overrides on the resource instead.
Extending shipped resources rather than editing vendor code. The standard Filament move applies: subclass the provided resource and re-register it.
class NotificationResource extends \Liberusoftware\NotificationsFilament\Filament\Resources\NotificationResource
{
public static function getNavigationGroup(): ?string { return 'System'; }
public static function table(Table $table): Table { /* add read_at filter, recipient column */ }
}
If the package resolves its resource class from a config key, override that key instead of fighting discovery.
Embedding the bell as a widget. Register it through the panel's render hook so it lands in the topbar next to the user menu:
->renderHook(
PanelsRenderHook::USER_MENU_BEFORE,
fn (): string => Blade::render('@livewire(\Liberusoftware\NotificationsFilament\Filament\Widgets\NotificationBell::class)'),
)
Add a poll interval (->poll('30s')) if real-time isn't wired — most adapters of this size ship polling, not broadcasting.
Multi-panel and multi-guard discipline. Notifications are guard-scoped. If your app has separate web and admin guards, confirm the adapter resolves the recipient from the current panel's guard rather than auth()->user(). This is the single most likely place a thin adapter breaks in a real app — assert it with a test that logs in as an admin and checks the inbox is empty for a customer's notifications.
Testing pattern. Two layers, tested separately:
// Domain layer — did we send?
Notification::fake();
$this->post('/orders')->assertRedirect();
Notification::assertSentTo($user, OrderShipped::class);
// Adapter layer — does it render?
Livewire::test(NotificationResource\Pages\ListNotifications::class)
->assertCanSeeTableRecords([$notification]);
If the Livewire test class isn't importable, the package is pinning a Filament version incompatible with your panel — caught early, before it wastes a day.
This package has zero dependents and zero stars. That is not a reason to avoid it, but it is a reason to pin the version exactly ("liberusoftware/notifications-filament": "1.2.*", not ^1.2) and to read the source before relying on it. Budget an hour for src/ review; it's likely small enough to read end-to-end, and you'll need that familiarity because there is no community to ask. Consider vendoring (Composer path repository + fork) if the project is long-lived.
The license is NOASSERTION. This means the package's composer.json / LICENSE file does not declare a recognized SPDX identifier. For internal tooling it's a footnote; for anything distributed or client-facing, resolve it with the maintainer before shipping. This is a genuine legal unknown, not a formatting nit.
Table collisions with Laravel's built-in notifications. Filament ships database notifications against Laravel's default notifications table; the core Liberu module may define its own model, table, and even its own Notification class name. Before migrating, run:
php artisan migrate --pretend
and grep the package for $table. If the adapter and the core module both migrate a notifications table, you'll get a duplicate-column error on the second run — fix by publishing the migration and editing it, or by disabling one side's migration in config.
Filament major version drift is the top integration risk. A package last touched in 2026-10 may target Filament v4 APIs (Filament\Schemas, ->schema() vs ->form()) while your panel is v3. Symptom: Call to undefined method ...::form() or a blank resource page with no error. Check composer.json constraints first, then composer why-not filament/filament.
Duplicate registration. If package discovery registers a provider and you've added the plugin manually, you can end up with the navigation item appearing twice or a widget rendering two Livewire instances. Run php artisan about and inspect the provider list — remove one side.
Navigation leaks into every panel. Filament resources appear in all panels unless gated. If the bell shows up in your public-facing panel, either scope the plugin per panel or override canAccess() to check the guard/role. Don't discover this in production.
Cache staleness after publishing. After vendor:publish, view and config changes silently don't apply until you clear:
php artisan optimize:clear && php artisan filament:optimize-clear
Filament caches component registration aggressively — this is the answer to 80% of "my widget disappeared" reports.
Extension points to check for, in order of usefulness: publishable Blade views (fastest cosmetic fix), a config key mapping resource/widget classes (cleanest override), container bindings for a recipient resolver interface (needed for multi-guard), and finally subclassing. If none of the first three exist, subclass and re-register — and note it as technical debt, because you're now coupled to internal class paths that a patch release can move.
Boundary confusion is the real cost. When something misbehaves, decide first which module owns the bug: does the record exist in the database (core module), or does it exist but not render (this adapter)? Query the table directly before touching Filament code. With a 0-dependent package, you are the QA team — that triage habit saves more time than any other single behavior.
How can I help you explore Laravel packages today?