Users can now control notification delivery channels independently:
- Email notifications
- In-app notifications
Category-level controls (marketing, security, team, billing) remain available and apply across enabled channels.
notification_preferences is stored as a JSON object with two top-level groups:
channelsemail(boolean)in_app(boolean)
categoriesmarketing(boolean)security(boolean)team(boolean)billing(boolean)
Legacy flat preferences are normalized automatically in the backend:
- Old shape (
marketing/security/team/billing) is mapped tocategories. - Missing
channelsdefaults to both enabled.
DataExportCompleted now uses channel + category checks:
- Security category disabled → no delivery.
- Email enabled → mail channel used.
- In-app enabled → database channel used.
Run targeted tests:
php artisan test --compact tests/Feature/Settings/NotificationPreferencesTest.php tests/Feature/Notifications/DataExportCompletedNotificationTest.php