Lesson 11 of 15Notification Preferences

Notification Preferences

A notification system that ignores preferences becomes a spam system. Preferences are not just UI settings. They are part of the delivery decision.

Channels and Categories

Channels:

Email
SMS
Push
WhatsApp
In-app

Categories:

Security
Transactional
Product activity
Marketing
Promotional
System maintenance

The preference question is not "email on or off." It is "Can this user receive this category on this channel?"

Preference Matrix

Category          Email     SMS              Push      In-app
Security          required  optional urgent  required  required
Transactional     enabled   optional         enabled   enabled
Product activity  optional  disabled         optional  enabled
Marketing         optional  disabled         optional  optional

Security alerts may be mandatory. Marketing must be optional. Product activity is often configurable.

Schema

CREATE TABLE notification_preferences (
  user_id UUID NOT NULL,
  category TEXT NOT NULL,
  channel TEXT NOT NULL,
  enabled BOOLEAN NOT NULL,
  source TEXT NOT NULL DEFAULT 'user',
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  PRIMARY KEY (user_id, category, channel)
);

Use source to distinguish user action, admin policy, legal import, or default.

Decision Function

async function canSendNotification(input: {
  userId: string;
  category: string;
  channel: string;
}) {
  if (input.category === "security") return true;

  const preference = await getPreference(
    input.userId,
    input.category,
    input.channel
  );

  return preference?.enabled ?? defaultPreference(input.category, input.channel);
}

Defaults should be conservative for marketing and practical for transactional messages.

Fallback Channels

Fallback is not always good. If push fails for marketing, do not automatically send SMS. If push fails for a suspicious login, SMS fallback may be appropriate.

Marketing push failed -> no fallback
Security push failed -> try email + SMS
Invoice email failed -> retry email, then support queue

Preference UI

The UI should map to categories users understand:

Security alerts
Order and payment updates
Product activity
Tips and marketing

Do not expose internal event names like PaymentSuccessV2.

Preference design is product design. Clear language reduces support tickets and legal risk.

Caching Preferences

Preference reads happen often. Cache carefully.

Cache key: notification_preferences:user_123
TTL: 5 minutes
Invalidate when user updates preferences

Never cache forever. A user unsubscribe should take effect quickly.

Common Mistakes

  1. One global unsubscribe switch for every message type.
  2. Sending fallback SMS for marketing.
  3. Ignoring preference changes due to stale cache.
  4. Exposing internal event names to users.
  5. Not auditing preference changes.

Interview Questions

  1. Which notification categories can be mandatory?
  2. How would you model per-channel preferences?
  3. When should fallback channels be used?
  4. How would you cache preferences safely?

Exercise

Create a preference matrix for a GitHub-like collaboration app with mentions, pull request reviews, security alerts, and newsletters.

What you will learn

How categories and channels combine into preferences.

Which notifications can be mandatory.

How fallback channels should work.

How to model preferences for fast lookup.

Production checklist

  • Preference categories are defined
  • Mandatory alerts are documented
  • Channel opt-outs are respected
  • Fallback rules are explicit
  • Preference lookup is cached safely
  • Audit trail exists
Notification Preferences - Production Notification System Design | Niraj Kumar