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_profilevia 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:
- Mailer receives event (e.g., “user logged in”, “package expiring”)
- Mailer queries notification settings for target user(s)
- 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:
- Call
GetMyNotificationSettingson page load - Pre-populate checkboxes with returned values
- Handle both existing settings and default values transparently
Save Changes:
- Gather all three checkbox states (even unchanged ones)
- Call
SetNotificationSettingswith all three values - Show confirmation message on success
- 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:
- Notification Module Introduction - Module overview and architecture
- Announcement - System-wide messaging feature
- Mailer Module - Email sending and template management