Skip to content

Notifications

Reshape delivers notifications two ways at once: persisted to the database so they show up in a notification panel, and broadcast in real time over Laravel Reverb so they appear instantly without a page refresh.

The real-time notification panel

Writing a notification

A notification is a standard Laravel notification that opts into both channels — app/Notifications/CompanyMemberAddedNotification.php is the reference example:

php
// Deliver over both the database and Reverb...
$notification->via(object $notifiable) : array // ['database', 'broadcast']

// A stable string the frontend switches on to render this notification type...
$notification->broadcastType() : string
$notification->databaseType(object $notifiable) : string

toArray() is what's stored in the notifications table and what's broadcast — the frontend consumes exactly this payload. broadcastType()/databaseType() give the frontend a stable string to switch on when rendering different notification types.

This one is dispatched from an event listener triggered when someone is added to a company — see Companies. The pattern (event → queued listener → notification) is the one to follow for your own notifications.

Delivery

Notifications are queued (the database queue connection locally), so sending one never blocks the triggering request. Real-time delivery happens over a private, per-user channel:

Every user has a private broadcast channel, App.Models.User.{id} (routes/channels.php). Reverb must be running for broadcast delivery to work — php artisan reverb:start --port=9000 locally (see Development). Without it, notifications still land in the database and the frontend's panel will show them on next load; they just won't push instantly.

Reading and marking as read

A paginated list is available for the current user; viewing a single notification marks it read as a side effect. Users can also explicitly set a notification's read/unread state, or mark everything read at once.

In the frontend

The notification bell in web/src/components/layouts/sidebars/app-notification-sidebar.vue subscribes to App.Models.User.{id} with useEchoNotification and pushes incoming events straight into the TanStack Query cache, so the panel updates without a refetch. Transient, non-persistent toasts (form success/error, quick confirmations) are a separate, simpler system built on vue-sonner — not everything that flashes on screen is a Notification record.