emuniq/filament-browser-notifications
Automatically turns every Filament database notification into a browser push notification, no code changes required. Installs VAPID keys, migrations, and the User trait in one command, then auto-registers across all panels with a subscription prompt and profile section.
Architecture fit. The package is well-suited to the shape of a Filament-heavy Laravel application. It attaches to Laravel's DatabaseNotification::created Eloquent event, so it exploits a framework lifecycle point that every existing notification already crosses — no per-notification wiring, no channel registration, no service worker publishing. Delivery is deferred to a queued job, which keeps the request path (and the notification write) decoupled from push latency and provider failures. VAPID-only is a meaningful architectural simplification: no Firebase dependency, no third-party WebSocket infrastructure, no new secrets beyond a key pair. The design is genuinely "zero-config by default, opt-out when needed," which is the correct posture for an internal admin tool where notification fatigue is the primary adoption risk.
Integration feasibility. Installation is a single artisan command that generates VAPID keys, runs the push_subscriptions migration, injects the HasPushSubscriptions trait into User, and auto-registers the plugin across all Filament panels. The one thing a TPM must flag: the installer writes to your app/Models/User.php source file. That is convenient and auditable (it degrades gracefully to printed manual instructions when the file is read-only, per 1.1.1), but it is an inherently fragile operation — the 1.1.1 changelog shows exactly this class of bug (trait imported but not applied when Notifiable sat alongside other traits). Plan to verify the trait is actually on the class body in a staged environment, not just trust the exit code.
Technical risk.
DatabaseNotification::created fires for every database notification in the app, including ones outside the Filament panel. Throttling (5s default grouping) and silent via ->viewData(['silent' => true]) are the only escape hatches, and the silent path itself required a v5 fix and a non-obvious viewData() workaround. Expect to audit existing notification classes and mark noisy ones silent.oklch() handling, ActionGroup resolution, and openUrlInNewTab respect are all version-sensitive heuristics that have already needed point fixes.Key questions to take to the maintainer / internal review.
silent?Stack fit. Laravel 10+, PHP 8.1+, Filament 3+, plus laravel-notification-channels/webpush underneath. This is a clean fit for any team already running a Filament panel with sendToDatabase() in production. Teams without a queue worker, or on HTTP-only internal deployments, are not a fit until those are resolved.
Migration path. Additive and reversible. The only schema change is push_subscriptions; the only code change is a trait on User plus optional config publishing. No existing notification classes need editing. Rollback is removing the package and the trait — dead subscriptions simply stop being used.
Compatibility. Confirm your exact Filament minor (v3 vs v4 vs v5) and your PHP/Laravel versions against the requirements block. Test in staging across the panels you intend to enable, because auto-registration applies to all panels by default — if you have separate admin and customer-facing panels, verify the prompt and profile section behave sensibly on each (config override in PanelProvider is the lever here).
Sequencing.
browser-notifications:test {id} --sync reaches a real browser.queue:work monitored.User.php; add manually if the installer skipped it.queue_connection/queue_name to your operational queues — do not leave it on default in a busy system.silent before enabling the prompt.Maintenance. The upstream cadence is active (v1.0 → v1.2 with meaningful fixes in a short window) but entirely dependent on one consultancy. Treat this as a small, fork-friendly dependency: read the source before adopting, and budget for the possibility of in-housing maintenance if the project stalls. MIT license makes that legally trivial. Keep an eye on the underlying webpush channel package — that is the real operational dependency and the more likely source of breakage.
Support. No SLA, no dependents, GitHub issues only. Your support surface is: prompt appearing/not appearing, push not arriving (invariably queue or HTTPS), and iOS users not receiving anything (PWA not installed). The test command and profile section status/device count are good first-line diagnostics — put those in your runbook.
Scaling. Each database notification triggers one queued job; the throttle groups bursts within the configured window so a notification storm becomes one "You have N new notifications" push rather than N. Set throttle_seconds to 0 only if you genuinely want one push per notification. Subscription rows grow with devices per user; 410 Gone cleanup keeps the table honest. Push fan-out ultimately hits the browser vendors' push services (FCM, APNs, Mozilla), so volume is bounded by device count, not by your infrastructure.
Failure modes to instrument.
.env, and test after any rotation.BadMethodCallException at runtime. Fixed in 1.1.1, but verify on every fresh container build.ActionGroup and removed hardcoded /admin, but this heuristic remains the most likely source of "wrong page opened" feedback.throttle_seconds: 0) or lost individual context (grouped pushes).Ramp-up. Low for engineers — one install command, one test command, one config file. The real ramp-up cost is operational literacy: understanding the service worker route, the auto-generated manifest.json, the iOS PWA flow, and where the listener fires. Half a day of reading the source pays for itself the first time someone asks "why did this notification push and that one didn't?"
How can I help you explore Laravel packages today?