# Notification Channel Preferences

- **Pattern:** `ab-000774` (`community-social-engagement.notifications.channel-preferences`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000774
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000774)

## Why it matters

Sending every notification type to every user with no opt-out mechanism violates GDPR Art. 21 (right to object to processing) and GDPR Art. 7 (conditions for consent). CCPA §1798.120 grants similar opt-out rights. Beyond compliance, a platform that ignores preferences trains users to mute or uninstall the app rather than adjusting settings — a direct retention problem. Notification preference checks must happen before dispatch, not as a post-hoc filter; dispatching a notification and suppressing delivery still constitutes processing the personal data used to trigger it.

## Severity rationale

Low because the immediate harm is user experience degradation and notification fatigue, but the GDPR Art. 21 right-to-object exposure elevates the compliance risk above cosmetic severity.

## Remediation

Add a `NotificationPreference` model to your Prisma schema and check it before dispatching any notification in your notification service.

```ts
// lib/notifications.ts
export async function sendNotification(
  recipientId: string,
  type: 'post_liked' | 'user_followed' | 'post_commented',
  data: Record<string, unknown>
) {
  const prefs = await db.notificationPreference.findUnique({
    where: { userId: recipientId }
  })

  const gateMap = {
    post_liked: prefs?.notifyOnLike ?? true,
    user_followed: prefs?.notifyOnFollow ?? true,
    post_commented: prefs?.notifyOnComment ?? true
  }

  if (!gateMap[type]) return // Preference says no: abort before any dispatch

  await db.notification.create({ data: { userId: recipientId, type, payload: data } })

  if (prefs?.emailEnabled ?? true) {
    await sendNotificationEmail(recipientId, type, data)
  }
}
```

Expose preference toggles in `app/settings/notifications/page.tsx` so users can adjust each type independently without contacting support.

## Detection

- **ID:** `channel-preferences`
- **Severity:** `low`
- **What to look for:** Enumerate all relevant files and Check the user settings or preferences schema for notification preferences. Look for fields like `notify_on_like`, `notify_on_follow`, `email_notifications_enabled`, `push_notifications_enabled`. Check API routes or settings UI that allow users to customize notification behavior.
- **Pass criteria:** User notification preferences exist in the schema. Settings UI allows users to opt out of specific notification types. Notification creation logic checks these preferences before dispatching.
- **Fail criteria:** All users receive all notifications, or no preference mechanism exists.
- **Skip (N/A) when:** Platform doesn't support notifications or has very few notification types.
- **Detail on fail:** `"No notification_preferences table — users cannot opt out of notification types"` or `"Settings UI has no notification preferences"` or `"Notification creation doesn't check user preferences before dispatching"`
- **Remediation:** Add notification preferences:

  ```ts
  // Prisma schema
  model NotificationPreference {
    id String @id
    userId String @unique
    notifyOnLike Boolean @default(true)
    notifyOnFollow Boolean @default(true)
    notifyOnComment Boolean @default(true)
    emailEnabled Boolean @default(true)
    pushEnabled Boolean @default(true)
    user User @relation(fields: [userId], references: [id], onDelete: Cascade)
  }

  // Check preferences before creating notifications
  async function createNotification(type: string, recipientId: string, data: any) {
    const prefs = await db.notificationPreference.findUnique({ where: { userId: recipientId } })

    const typeMap = {
      'post_liked': 'notifyOnLike',
      'user_followed': 'notifyOnFollow',
      'post_commented': 'notifyOnComment'
    }

    const shouldNotify = prefs?.[typeMap[type]] ?? true
    if (!shouldNotify) return

    const notification = await db.notification.create({
      data: { userId: recipientId, type, content: JSON.stringify(data) }
    })

    if (prefs?.emailEnabled) {
      await sendNotificationEmail(recipientId, notification)
    }
  }

  // Settings page
  async function updateNotificationPreferences(userId: string, updates: any) {
    return db.notificationPreference.upsert({
      where: { userId },
      update: updates,
      create: { userId, ...updates }
    })
  }
  ```

---

## External references

- gdpr Art. 21
- gdpr Art. 7
- ccpa §1798.120

Taxons: privacy-consent, user-experience

HTML version: https://auditbuffet.com/patterns/ab-000774
