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.

Writing a notification
A notification is a standard Laravel notification that opts into both channels — app/Notifications/CompanyMemberAddedNotification.php is the reference example:
// 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) : stringtoArray() 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.