
Respect how people want to hear from you
People can choose their notification channels. Wildo applies those preferences to personal notifications while keeping role-addressed responsibilities and explicitly required notices distinct.
The in-app preference controls notification presentation without disabling live data updates.
Example — Quiet personal email, keep work current
A person switches off personal email notifications. Their open application continues to refresh records, and required security notices can still be delivered.
For engineers
Store choices through the preference resource
The user’s self-preferences record contains notification channel switches. The operation dispatcher loads them with recipient context and applies its delivery decision to personal email. The shared preference predicate also defines SMS and push switches; those operation-dispatch channels do not yet have sending implementations. The relevant gate is:
Selected from notifications-dispatcher.backend.service.ts; surrounding module configuration is omitted.
private recipientAcceptsNotificationChannel(
notification: UserNotificationDefinition,
recipientUserContext: { notificationChannelPreferences?: UserPreferences_Notifications } | undefined,
): boolean {
if (notification.alwaysDeliver === true) return true;
if (!userNotificationTargetIsSuppressibleByRecipientPreference(notification.target)) return true;
const preferences = recipientUserContext?.notificationChannelPreferences;
if (!preferences) return true;
switch (notification.channel) {
case CoreUserNotificationChannel.EMAIL:
return preferences.email !== false;
case CoreUserNotificationChannel.SMS:
return preferences.sms !== false;
case CoreUserNotificationChannel.PUSH:
return preferences.push !== false;
default:
// WEBSOCKET and FRONT_END_SUCCESS carry no switch of their own. The `inApp` preference
// governs the notification CENTRE, which is a frontend surface — `NotificationContext`
// honours it there, because suppressing the socket frame would also suppress the live
// UI updates that ride the same channel.
return true;
}
}
An absent preference record preserves delivery. alwaysDeliver explicitly bypasses personal suppression, and role-addressed targets are not treated as optional personal subscriptions. Use that distinction for a billing or security responsibility; do not mark every product message mandatory.
Keep in-app presentation separate
NotificationContext applies inApp to optional personal server messages before displaying a toast, notification-centre entry or celebration. Declarative frames carry their recipient target and alwaysDeliver flag through WebSocketEventBridge, so required notices and responsibility-addressed messages stay visible.
Local save confirmations keep their own behavior. The same websocket frame can still refresh lists and records even when its personal message is hidden.
Preference filtering does not implement a transport. Use the implemented email and in-app paths for this operation-notification flow. Direct email-by-address has no user preference record and follows its own delivery contract. Author the recipient target and obligation carefully before selecting a suppression policy.