Implement database-backed notification settings that persist across restarts: Backend changes: - Updated DashboardService to read/write notification settings from database - Added 6 notification settings keys to dbSettingsMap: * enable_email_notifications (boolean) * enable_push_notifications (boolean) * admin_notifications (boolean) * error_alerts (boolean) * new_user_alerts (boolean) * system_health_alerts (boolean) - Settings are now retrieved from database with fallback defaults Database: - Seeded 6 default notification settings in settings table - All notification toggles default to 'true' - Settings persist across server restarts Frontend: - Admin settings page at /settings already configured - Notifications tab contains all 6 toggle switches - Settings are loaded from GET /api/v1/admin/dashboard/settings - Settings are saved via POST /api/v1/admin/dashboard/settings API Endpoints (already existed, now enhanced): - GET /api/v1/admin/dashboard/settings - Returns all settings including notifications - POST /api/v1/admin/dashboard/settings - Persists notification settings to database Files modified: - maternal-app-backend/src/modules/admin/dashboard/dashboard.service.ts Benefits: ✅ Global notification settings are now persistent ✅ Admin can control email/push notifications globally ✅ Admin can configure alert preferences ✅ Settings survive server restarts and deployments 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
15 KiB
Push Notifications Persistence Implementation
Status: ✅ COMPLETED Date: October 8, 2025
Overview
This document summarizes the implementation of persistent notification preferences for the ParentFlow push notifications system. Users' notification settings are now stored in the database and respected across sessions and devices.
What Was Implemented
1. Enhanced User Entity ✅
File: src/database/entities/user.entity.ts
Updated the preferences JSONB column to include detailed notification settings:
preferences?: {
notifications?: {
pushEnabled?: boolean; // Master toggle for push notifications
emailEnabled?: boolean; // Email notifications toggle
feedingReminders?: boolean; // Feeding reminder notifications
sleepReminders?: boolean; // Sleep reminder notifications
diaperReminders?: boolean; // Diaper change notifications
medicationReminders?: boolean; // Medication reminders
milestoneAlerts?: boolean; // Milestone achievement alerts
patternAnomalies?: boolean; // Pattern anomaly warnings
};
emailUpdates?: boolean;
darkMode?: boolean;
measurementUnit?: 'metric' | 'imperial';
timeFormat?: '12h' | '24h';
}
Database: Uses existing users.preferences JSONB column - no migration needed!
2. User Preferences Service ✅
File: src/modules/users/user-preferences.service.ts
Complete service for managing user preferences with the following methods:
Core Methods
getUserPreferences(userId)- Get all preferences with defaultsupdateUserPreferences(userId, preferences)- Update any preferenceupdateNotificationPreferences(userId, notificationPreferences)- Update notification settings only
Push Notification Helpers
enablePushNotifications(userId)- Enable push notificationsdisablePushNotifications(userId)- Disable push notificationsisPushNotificationsEnabled(userId)- Check if push is enabledisNotificationTypeEnabled(userId, type)- Check specific notification type
Utility Methods
getNotificationPreferencesSummary(userId)- Get summary of enabled/disabled typesresetToDefaults(userId)- Reset all preferences to defaults
Default Values: All notification types are enabled by default to ensure users receive important reminders.
3. Preferences Controller ✅
File: src/modules/users/user-preferences.controller.ts
REST API endpoints for managing preferences:
| Method | Endpoint | Description |
|---|---|---|
| GET | /api/v1/preferences |
Get all user preferences |
| PUT | /api/v1/preferences |
Update all preferences |
| PUT | /api/v1/preferences/notifications |
Update notification preferences only |
| POST | /api/v1/preferences/notifications/push/enable |
Enable push notifications |
| POST | /api/v1/preferences/notifications/push/disable |
Disable push notifications |
| GET | /api/v1/preferences/notifications/summary |
Get notification settings summary |
| POST | /api/v1/preferences/reset |
Reset all preferences to defaults |
Authentication: All endpoints require JWT authentication
4. Users Module ✅
File: src/modules/users/users.module.ts
New NestJS module that:
- Imports User entity from TypeORM
- Provides UserPreferencesService and UserPreferencesController
- Exports UserPreferencesService for use by other modules
- Integrated into main AppModule
5. Updated Push Service ✅
File: src/modules/push/push.service.ts
Enhanced sendToUser() method to:
- Check if user has push notifications enabled via
UserPreferencesService - Skip sending if push is disabled at user level
- Log when notifications are skipped due to preferences
async sendToUser(userId: string, payload: PushNotificationPayload) {
// Check if user has push notifications enabled
const isPushEnabled = await this.userPreferencesService.isPushNotificationsEnabled(userId);
if (!isPushEnabled) {
this.logger.debug(`Push notifications disabled for user ${userId}, skipping`);
return { sent: 0, failed: 0 };
}
// Continue with sending...
}
6. Updated DTOs ✅
File: src/modules/auth/dto/update-profile.dto.ts
Created new DTOs to match the enhanced preference structure:
NotificationPreferencesDto:
- Validates all notification preference fields
- All fields optional with
@IsBoolean()validation
UserPreferencesDto:
- Updated to use
NotificationPreferencesDtoinstead of simple boolean - Maintains backward compatibility
UpdateProfileDto:
- Uses updated
UserPreferencesDto - Allows updating preferences via profile endpoint
7. Frontend Integration ✅
File: maternal-web/components/PushNotificationToggle.tsx
Enhanced component to:
- Save preference to backend when toggling push notifications
- Call new
PUT /api/v1/preferences/notificationsendpoint - Handle errors gracefully (subscription works even if preference save fails)
const savePreference = async (authToken: string, enabled: boolean) => {
const response = await fetch(`${apiUrl}/api/v1/preferences/notifications`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${authToken}`,
},
body: JSON.stringify({
pushEnabled: enabled,
}),
});
};
How It Works
Flow Diagram
┌─────────────────────────────────────────────────────────────┐
│ 1. User toggles push notifications in UI │
└────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 2. Frontend subscribes/unsubscribes from push │
└────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 3. Frontend saves preference to database │
│ PUT /api/v1/preferences/notifications │
│ { pushEnabled: true/false } │
└────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 4. UserPreferencesService updates users.preferences │
│ (JSONB column) │
└────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 5. Later: NotificationsService creates notification │
└────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 6. PushService checks user preferences before sending │
│ if (!isPushEnabled) return; // Skip sending │
└────────────────────┬────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ 7. Push sent only if user has push enabled │
└─────────────────────────────────────────────────────────────┘
API Examples
Get User Preferences
GET /api/v1/preferences
Authorization: Bearer <token>
Response:
{
"notifications": {
"pushEnabled": true,
"emailEnabled": true,
"feedingReminders": true,
"sleepReminders": true,
"diaperReminders": true,
"medicationReminders": true,
"milestoneAlerts": true,
"patternAnomalies": true
},
"emailUpdates": true,
"darkMode": false,
"measurementUnit": "metric",
"timeFormat": "12h"
}
Update Notification Preferences
PUT /api/v1/preferences/notifications
Authorization: Bearer <token>
Content-Type: application/json
{
"pushEnabled": false,
"feedingReminders": false
}
Response:
{
"notifications": {
"pushEnabled": false,
"emailEnabled": true,
"feedingReminders": false, // Updated
"sleepReminders": true,
"diaperReminders": true,
"medicationReminders": true,
"milestoneAlerts": true,
"patternAnomalies": true
},
// ... other preferences
}
Enable Push Notifications
POST /api/v1/preferences/notifications/push/enable
Authorization: Bearer <token>
Response:
{
"success": true
}
Get Notification Summary
GET /api/v1/preferences/notifications/summary
Authorization: Bearer <token>
Response:
{
"enabled": true,
"enabledTypes": [
"feedingReminders",
"sleepReminders",
"diaperReminders",
"medicationReminders",
"milestoneAlerts",
"patternAnomalies"
],
"disabledTypes": []
}
Database Storage
Schema
The preferences are stored in the existing users.preferences JSONB column:
-- Example data
UPDATE users
SET preferences = '{
"notifications": {
"pushEnabled": true,
"emailEnabled": true,
"feedingReminders": true,
"sleepReminders": true,
"diaperReminders": true,
"medicationReminders": true,
"milestoneAlerts": true,
"patternAnomalies": true
},
"emailUpdates": true,
"darkMode": false,
"measurementUnit": "metric",
"timeFormat": "12h"
}'
WHERE id = 'usr_123';
Query Examples
-- Get users with push notifications enabled
SELECT id, email, preferences->'notifications'->>'pushEnabled' as push_enabled
FROM users
WHERE preferences->'notifications'->>'pushEnabled' = 'true';
-- Get users with feeding reminders disabled
SELECT id, email
FROM users
WHERE preferences->'notifications'->>'feedingReminders' = 'false';
-- Update a specific preference
UPDATE users
SET preferences = jsonb_set(
preferences,
'{notifications,pushEnabled}',
'false'
)
WHERE id = 'usr_123';
Default Behavior
New Users
- All notification preferences default to enabled
- Push notifications are enabled by default
- Users can customize after onboarding
Existing Users (Migration)
- Existing users without preferences get defaults on first access
- No database migration needed - handled by service layer
- Backward compatible with old preference format
Key Features
✅ Persistent Across Sessions - Settings saved to database, not local storage ✅ Multi-Device Sync - Same preferences across all user's devices ✅ Granular Control - Enable/disable specific notification types ✅ API-Driven - RESTful endpoints for all preference operations ✅ Type-Safe - Full TypeScript validation with DTOs ✅ Default Values - Sensible defaults ensure notifications work out-of-box ✅ Audit Trail - All changes logged via user updates ✅ Privacy-Focused - User controls all notification types
Testing
Backend Testing
# Get preferences
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:3020/api/v1/preferences
# Disable push notifications
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
http://localhost:3020/api/v1/preferences/notifications/push/disable
# Update specific preferences
curl -X PUT \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"feedingReminders": false, "sleepReminders": false}' \
http://localhost:3020/api/v1/preferences/notifications
Frontend Testing
- Open web app at
http://maternal.noru1.ro - Navigate to Settings page
- Toggle push notifications ON
- Verify preference saved in database
- Toggle push notifications OFF
- Verify preference updated
- Refresh page - verify setting persists
Future Enhancements
Planned Features
- Per-Child Preferences - Different notification settings per child
- Time-Based Quiet Hours - Disable notifications during sleep hours
- Notification Frequency Control - Limit number of notifications per day
- Smart Suggestions - ML-based preference recommendations
- Bulk Operations - Enable/disable all notification types at once
- Advanced UI - Rich settings page with toggles for each type
API Extensions
GET /api/v1/preferences/notifications/children/:childId- Per-child preferencesPUT /api/v1/preferences/notifications/quiet-hours- Set quiet hoursPOST /api/v1/preferences/notifications/bulk-update- Bulk enable/disable
Troubleshooting
Common Issues
Issue: Preferences not persisting Solution: Check JWT token is valid and user has permissions
Issue: Push still sending when disabled Solution: Clear browser service worker cache, re-subscribe
Issue: Preferences showing as null
Solution: Service returns defaults for null values - working as intended
Issue: Cannot update preferences
Solution: Ensure request body matches NotificationPreferencesDto validation
Summary
✅ All notification preferences are now persistent in the database ✅ Users can customize notification types and push settings ✅ Backend respects user preferences before sending push notifications ✅ Frontend automatically saves preferences when toggling ✅ Backend compiled successfully with 0 errors ✅ RESTful API for all preference operations
Implementation Complete! The push notification system now fully respects user preferences stored in the database. 🎉
Documentation Updates
The main implementation documentation has been updated:
- PUSH_NOTIFICATIONS_IMPLEMENTATION.md - Complete system overview
- pwa_web_push_implementation_plan.md - Updated with completion status
Last Updated: October 8, 2025 Status: Production Ready ✅