Background
SimpleModule has an Email module but no abstraction over notification channels. Laravel's Notification class lets a single notification flow across mail, database, broadcast, SMS, Slack, push, etc., with per-recipient channel routing. This is high-leverage: every other module (Users password reset, Orders confirmation, Admin alerts, BackgroundJobs failures) becomes a consumer.
Motivation
- One API to send across many channels
- Per-user opt-in/out per channel (stored in
Settings) - The database channel powers the in-app bell-icon UI (mark-as-read, unread count)
- Decouples what to send from how to send
Design sketch
New module modules/Notifications (Contracts + Impl + Tests):
publicinterfaceINotification{string[]Via(IUseruser);// ["mail", "database", "slack"]MailMessage?ToMail(IUseruser)=>null;object?ToDatabase(IUseruser)=>null;SlackMessage?ToSlack(IUseruser)=>null;SmsMessage?ToSms(IUseruser)=>null;}publicinterfaceINotifier{TaskSendAsync<T>(IUseruser,Tnotification,CancellationTokenct=default)whereT:INotification;TaskSendNowAsync<T>(IUseruser,Tnotification,CancellationTokenct=default)whereT:INotification;}publicinterfaceINotificationChannel{stringName{get;}TaskSendAsync(IUseruser,INotificationnotification,CancellationTokenct);}- Channels shipped:
MailChannel (uses Email module), DatabaseChannel (persists Notification { Id, UserId, Type, Data (json), ReadAt, CreatedAt }) - Optional channels (separate packages):
SlackChannel, WebPushChannel, SmsChannel - Async dispatch goes through
BackgroundJobs; SendNowAsync is synchronous - Settings entries per channel:
Notifications.Channel.{Name}.Enabled (per-user override) - Inertia bell-icon component in admin shell consumes
/api/notifications (list/unread-count/mark-read endpoints)
Acceptance criteria
References
Background
SimpleModule has an
Emailmodule but no abstraction over notification channels. Laravel'sNotificationclass lets a single notification flow across mail, database, broadcast, SMS, Slack, push, etc., with per-recipient channel routing. This is high-leverage: every other module (Users password reset, Orders confirmation, Admin alerts, BackgroundJobs failures) becomes a consumer.Motivation
Settings)Design sketch
New module
modules/Notifications(Contracts + Impl + Tests):MailChannel(uses Email module),DatabaseChannel(persistsNotification { Id, UserId, Type, Data (json), ReadAt, CreatedAt })SlackChannel,WebPushChannel,SmsChannelBackgroundJobs;SendNowAsyncis synchronousNotifications.Channel.{Name}.Enabled(per-user override)/api/notifications(list/unread-count/mark-read endpoints)Acceptance criteria
modules/Notificationsscaffolded viasm new module Notificationsand follows ConstitutionINotifierresolvable from any module via DISettingsNotifications_Send/docsReferences
modules/Email