Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Notification Settings

Notification Settings provide per-user preferences that control which types of email notifications and alerts a user receives. This enables users to opt-in or opt-out of different notification categories according to their preferences.

Core Concept

Each user has a personalized notification settings record that controls three types of notifications:

  • Login Notifications (send_login_email): Email alerts when the user logs in
  • Marketing Communications (receive_marketing_email): Promotional and marketing emails
  • Service Alerts (notify_package_expired): Notifications about package/subscription expiration

These settings are stored per-user and are designed to be consumed by other modules (primarily the Mailer module) when deciding whether to send notifications.

Data Model

pub struct NotificationSettings {
    pub id: Uuid,                           // User ID (foreign key to auth.user_profile)
    pub send_login_email: bool,
    pub receive_marketing_email: bool,
    pub notify_package_expired: bool,
    pub created_at: PrimitiveDateTime,
    pub updated_at: PrimitiveDateTime,
}

Default Behavior

Notification settings use a lazy creation approach:

  • Settings are not automatically created when a user signs up
  • When fetching settings for a user without a record, the API returns default values
  • Settings are only created in the database when the user first modifies them

Default Values:

  • send_login_email: false (login notifications disabled by default)
  • receive_marketing_email: false (marketing emails disabled by default)
  • notify_package_expired: true (service alerts enabled by default)

This design reduces database writes for users who never change their preferences while still providing predictable defaults.

Notification Types

Login Email Notifications

Purpose: Alert users when someone logs into their account

Use Case: Security monitoring—users can detect unauthorized access attempts

Default: Disabled (false)

Consumer: Mailer module checks this setting when the Auth module publishes login events

Frontend Consideration: Present as “Email me when I log in” checkbox in user settings

Marketing Email Notifications

Purpose: Promotional emails, feature announcements, and marketing campaigns

Use Case: Allow users to opt-out of non-essential marketing communications while still receiving critical service updates

Default: Disabled (false)

Consumer: Mailer module or external marketing systems check this before sending promotional content

Compliance: Important for GDPR and email marketing regulations—users must explicitly opt-in

Package Expiration Notifications

Purpose: Alert users when their service package/subscription is about to expire or has expired

Use Case: Ensure users are aware of expiring services and can take action (renew, upgrade, etc.)

Default: Enabled (true)

Consumer: Telecom module or background jobs check this before sending expiration alerts

Why Enabled by Default: Service continuity—users generally want to know when their service is expiring

User Operations

All operations are exposed through the NotificationService gRPC service and automatically use the authenticated user’s ID from the request middleware.

Get Notification Settings

Operation: GetMyNotificationSettings

Retrieves the current user’s notification preferences.

Authentication: User ID extracted from request middleware

Behavior:

  • If settings exist: Returns stored preferences
  • If settings don’t exist: Returns default values (without creating a database record)

Use Case: Display current preferences in user settings page

Set Notification Settings

Operation: SetNotificationSettings

Updates the user’s notification preferences.

Authentication: User ID extracted from request middleware

Parameters: All three boolean flags (must provide all values, not partial updates)

Behavior: Uses UPSERT operation—creates record if none exists, updates if it does

Effect: Changes are immediate—other modules will see updated preferences on their next check

Design Note: Requires all three flags to prevent partial updates. Frontend should fetch current settings first, then send all values with modifications.

Database Schema

Table: notification.settings

id                      UUID PRIMARY KEY
                        REFERENCES auth.user_profile(id) ON DELETE CASCADE
send_login_email        BOOLEAN NOT NULL DEFAULT FALSE
receive_marketing_email BOOLEAN NOT NULL DEFAULT FALSE
notify_package_expired  BOOLEAN NOT NULL DEFAULT TRUE
created_at              TIMESTAMP NOT NULL DEFAULT NOW()
updated_at              TIMESTAMP NOT NULL DEFAULT NOW()

Key Characteristics:

  • Primary key is user ID (foreign key to auth.user_profile)
  • Cascade delete: Settings are removed when user account is deleted
  • No additional indexes needed (lookups by primary key are already fast)
  • Automatic timestamps via database triggers

Integration Points

With Auth Module

  • Settings table references auth.user_profile via foreign key
  • User ID is the primary key—one settings record per user
  • Cascade delete ensures data consistency when users are removed

With Mailer Module

While not directly coupled (no foreign keys or direct queries), the notification settings are designed to be consumed by the mailer module:

Integration Pattern:

  1. Mailer receives event (e.g., “user logged in”, “package expiring”)
  2. Mailer queries notification settings for target user(s)
  3. Mailer respects user preferences before sending email

Batch Operations: The FindNotificationSettingsByIds processor supports fetching settings for multiple users efficiently, useful for bulk email campaigns.

With Telecom Module

Service expiration notifications are checked against notify_package_expired before sending alerts about package/subscription expirations.

Frontend Integration Points

User Settings Page

Display Current Settings:

  1. Call GetMyNotificationSettings on page load
  2. Pre-populate checkboxes with returned values
  3. Handle both existing settings and default values transparently

Save Changes:

  1. Gather all three checkbox states (even unchanged ones)
  2. Call SetNotificationSettings with all three values
  3. Show confirmation message on success
  4. No need to re-fetch—changes are immediate

UI Recommendations:

  • Group notifications by category (Security, Marketing, Service)
  • Provide clear descriptions of what each setting controls
  • Consider warning users before disabling critical notifications (package expiration)
  • Show last updated timestamp if available

Example Layout:

Notification Preferences
━━━━━━━━━━━━━━━━━━━━━━━

Security Notifications
☐ Email me when I log in

Marketing & Promotions
☐ Receive promotional emails and feature announcements

Service Alerts
☑ Notify me when my package is about to expire

Account Registration Flow

No Action Needed: Settings don’t need to be created during registration. Users will see default values until they modify preferences.

Design Decisions

Why Lazy Creation?

Settings are only created when users first modify them:

Pros:

  • Reduces database writes for users who never change settings
  • Simpler registration flow (one less insert operation)
  • No storage cost for default preferences

Cons:

  • API must handle missing records gracefully
  • Queries can’t use JOIN without LEFT JOIN

Decision: The storage savings and reduced write load outweigh the minor complexity of handling missing records.

Why Return Defaults Instead of 404?

When settings don’t exist, the API returns default values rather than an error:

Reasoning:

  • Better UX—frontend doesn’t need special handling for new users
  • Predictable behavior—defaults are consistent
  • Simpler frontend code—no need to distinguish “not set” from “default”

Why Require All Three Flags on Update?

The SetNotificationSettings API requires all three boolean values (no partial updates):

Reasoning:

  • Prevents accidental resets—frontend must be intentional about all values
  • Simpler implementation—no need to handle partial updates
  • Clear semantics—“set these preferences” not “update some preferences”
  • Atomic updates—all settings change together

Frontend Impact: Must fetch current settings first, then send all values. This is the standard pattern for settings pages anyway.

Why No Granular Notification Types?

Currently only three notification types exist:

Trade-off:

  • Fewer types = simpler UX, less overwhelming for users
  • Limited flexibility—can’t opt-in to some marketing emails but not others

Extensibility: If more granular control is needed in the future, additional boolean fields can be added to the schema without breaking existing APIs (protobuf supports field addition).

Why No Notification Channels?

Settings don’t distinguish between email, SMS, push notifications:

Current Design: All settings assume email notifications

Future Expansion: If other channels (SMS, push, in-app) are added:

  • Could add separate fields (e.g., send_login_email_sms, send_login_email_push)
  • Or restructure to nested channel preferences
  • Current design doesn’t block future expansion

See Also: