Files
maternal-app/PUSH_NOTIFICATIONS_IMPLEMENTATION.md
Andrei 9b31d56c1d
Some checks failed
ParentFlow CI/CD Pipeline / Backend Tests (push) Has been cancelled
ParentFlow CI/CD Pipeline / Frontend Tests (push) Has been cancelled
ParentFlow CI/CD Pipeline / Security Scanning (push) Has been cancelled
ParentFlow CI/CD Pipeline / Build Docker Images (map[context:maternal-app/maternal-app-backend dockerfile:Dockerfile.production name:backend]) (push) Has been cancelled
ParentFlow CI/CD Pipeline / Build Docker Images (map[context:maternal-web dockerfile:Dockerfile.production name:frontend]) (push) Has been cancelled
ParentFlow CI/CD Pipeline / Deploy to Development (push) Has been cancelled
ParentFlow CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / Lint and Test (push) Has been cancelled
CI/CD Pipeline / E2E Tests (push) Has been cancelled
CI/CD Pipeline / Build Application (push) Has been cancelled
Backend CI/CD Pipeline / Lint and Test Backend (push) Has been cancelled
Backend CI/CD Pipeline / E2E Tests Backend (push) Has been cancelled
Backend CI/CD Pipeline / Build Backend Application (push) Has been cancelled
Backend CI/CD Pipeline / Performance Testing (push) Has been cancelled
feat: Add persistent global notification settings for admin panel
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>
2025-10-08 23:09:13 +00:00

15 KiB

Push Notifications Implementation Summary

Status: COMPLETED (Backend + Frontend Integration Ready) Date: October 8, 2025 Implementation Type: Web Push (VAPID) - No Firebase/OneSignal dependency


🎯 Overview

We successfully implemented a streamlined, fully local Web Push notification system for ParentFlow using the Web Push Protocol with VAPID keys. This allows browser-based push notifications without relying on third-party services like Firebase or OneSignal.


📦 Backend Implementation

1. Database Schema

Table: push_subscriptions (Already exists in production)

CREATE TABLE push_subscriptions (
  id uuid PRIMARY KEY DEFAULT uuid_generate_v4(),
  user_id varchar(20) NOT NULL,
  endpoint text NOT NULL UNIQUE,
  p256dh text NOT NULL,
  auth text NOT NULL,
  user_agent text,
  device_type varchar(20),
  browser varchar(50),
  is_active boolean DEFAULT true,
  last_error text,
  failed_attempts integer DEFAULT 0,
  last_success_at timestamp,
  created_at timestamp DEFAULT now(),
  updated_at timestamp DEFAULT now()
);

Indexes:

  • idx_push_subs_user_id on user_id
  • idx_push_subs_active on is_active (WHERE is_active = true)
  • unique_endpoint on endpoint

2. TypeORM Entity

File: src/database/entities/push-subscription.entity.ts

Features:

  • Relationship with User entity (CASCADE delete)
  • Tracks device type, browser, and subscription health
  • Automatic timestamps (created_at, updated_at)

3. Push Service

File: src/modules/push/push.service.ts

Key Features:

  • VAPID configuration from environment variables
  • Subscribe/unsubscribe management
  • Send push notifications to individual users or groups
  • Automatic error handling (404/410 = deactivate, retries for 5xx)
  • User agent parsing for device/browser detection
  • Statistics and cleanup utilities

Main Methods:

- getPublicVapidKey(): string
- subscribe(userId, subscriptionData, userAgent): PushSubscription
- unsubscribe(userId, endpoint): void
- sendToUser(userId, payload): {sent, failed}
- sendToUsers(userIds[], payload): {sent, failed}
- sendTestNotification(userId): void
- cleanupInactiveSubscriptions(daysOld): number
- getStatistics(userId?): Statistics

4. Push Controller

File: src/modules/push/push.controller.ts

REST API Endpoints:

Method Endpoint Description
GET /api/v1/push/vapid-public-key Get VAPID public key for frontend
POST /api/v1/push/subscriptions Subscribe to push notifications
GET /api/v1/push/subscriptions Get user's active subscriptions
DELETE /api/v1/push/subscriptions?endpoint=... Unsubscribe from push
POST /api/v1/push/test Send test notification
GET /api/v1/push/statistics Get push statistics

Authentication: All endpoints require JWT authentication (JwtAuthGuard)

5. Push Module

File: src/modules/push/push.module.ts

Wired into main AppModule and exports PushService for use by other modules.

6. Notifications Integration

Updated: src/modules/notifications/notifications.service.ts

Features:

  • Automatic push notification when creating notifications
  • Intelligent URL routing based on notification type
  • Smart notifications (feeding, sleep, diaper reminders) now trigger push
  • Medication reminders trigger push
  • Anomaly detection triggers push

Integration Flow:

createNotification()
  → Save to DB
  → sendPushNotification()
  → PushService.sendToUser()
  → markAsSent/markAsFailed

7. Environment Configuration

File: maternal-app-backend/.env

# Push Notifications (Web Push - VAPID)
PUSH_NOTIFICATIONS_ENABLED=true
VAPID_PUBLIC_KEY=BErlB-L0pDfv1q3W0SHs3ZXqyFi869OScpt5wJ2aNu2KKbLxLj4a-YO6SyuAamjRG_cqY65yt2agyXdMdy2wEXI
VAPID_PRIVATE_KEY=Rg47clL1z4wSpsBTx4yIOIHHX9qh1W5TyBZwBfPIesk
VAPID_SUBJECT=mailto:hello@parentflow.com
PUSH_DEFAULT_TTL=86400
PUSH_BATCH_SIZE=100

Security: Keep VAPID_PRIVATE_KEY secret. Never expose in logs or client-side code.


🌐 Frontend Implementation

1. Service Worker

File: maternal-web/public/push-sw.js

Features:

  • Listens for push events
  • Shows notifications with custom icons, badges, and data
  • Handles notification clicks (focus existing window or open new)
  • Tracks notification dismissals
  • Test notification support

Event Handlers:

  • push - Receive and display notifications
  • notificationclick - Handle user clicks, navigate to URLs
  • notificationclose - Track dismissals
  • message - Handle messages from the app

2. Push Utilities

File: maternal-web/lib/push-notifications.ts

Utility Functions:

- isPushNotificationSupported(): boolean
- getNotificationPermission(): NotificationPermission
- requestNotificationPermission(): Promise<NotificationPermission>
- getVapidPublicKey(token): Promise<string>
- registerPushServiceWorker(): Promise<ServiceWorkerRegistration>
- subscribeToPush(token): Promise<PushSubscription>
- savePushSubscription(subscription, token): Promise<void>
- getPushSubscription(): Promise<PushSubscription | null>
- unsubscribeFromPush(token): Promise<void>
- isPushSubscribed(): Promise<boolean>
- sendTestPushNotification(token): Promise<void>
- getPushStatistics(token): Promise<any>
- showLocalTestNotification(): Promise<void>

Key Features:

  • Browser compatibility checks
  • VAPID key base64 conversion
  • Service worker registration
  • Subscription management
  • Backend API integration

3. UI Component

File: maternal-web/components/PushNotificationToggle.tsx

Features:

  • Toggle switch to enable/disable push notifications
  • Permission status display
  • Error handling and user feedback
  • Test notification button
  • Loading states
  • Dark mode support
  • Responsive design

Component States:

  • Unsupported browser warning
  • Permission denied message
  • Subscribed confirmation with test button
  • Loading indicator

Usage:

import PushNotificationToggle from '@/components/PushNotificationToggle';

// In settings page
<PushNotificationToggle />

🔧 Testing Guide

Backend Testing

  1. Get VAPID Public Key:
curl http://localhost:3020/api/v1/push/vapid-public-key
  1. Subscribe (requires auth token):
curl -X POST http://localhost:3020/api/v1/push/subscriptions \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "endpoint": "https://fcm.googleapis.com/fcm/send/...",
    "keys": {
      "p256dh": "...",
      "auth": "..."
    }
  }'
  1. Send Test Notification:
curl -X POST http://localhost:3020/api/v1/push/test \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"
  1. Get Statistics:
curl http://localhost:3020/api/v1/push/statistics \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Frontend Testing

  1. Open Web App: Navigate to http://maternal.noru1.ro

  2. Go to Settings: Find the Push Notification Toggle component

  3. Enable Notifications:

    • Click the toggle switch
    • Grant permission when prompted
    • Wait for confirmation
  4. Test Notification:

    • Click "Send Test Notification" button
    • Check browser notifications
  5. Test Full Flow:

    • Create a feeding/sleep/diaper activity
    • Wait for reminder notification (based on patterns)
    • Check notification appears

Browser Compatibility Testing

Test on:

  • Chrome (Desktop & Mobile)
  • Firefox (Desktop & Mobile)
  • Edge (Desktop)
  • Safari (iOS 16.4+ PWA only - must be installed to home screen)

📊 Notification Flow

1. User Action (e.g., feeding activity)
   ↓
2. NotificationsService detects pattern
   ↓
3. createNotification() called
   ↓
4. Notification saved to DB
   ↓
5. sendPushNotification() triggered
   ↓
6. PushService.sendToUser() sends to all user's devices
   ↓
7. Web Push sends to browser
   ↓
8. Service Worker receives push event
   ↓
9. Service Worker shows notification
   ↓
10. User clicks notification
   ↓
11. Service Worker navigates to URL

🔒 Security Considerations

VAPID Keys

  • Private key stored in .env (never committed to git)
  • Public key safe to expose to frontend
  • Subject configured as mailto: contact email

Authentication

  • All push endpoints require JWT authentication
  • Users can only manage their own subscriptions
  • Endpoint validation prevents injection attacks

Data Privacy

  • Subscription endpoints hashed in logs
  • User agent data stored for analytics only
  • Inactive subscriptions auto-cleaned after 90 days
  • Cascade delete when user is deleted

Rate Limiting

  • ⚠️ TODO: Add rate limiting to push endpoints
  • Recommended: 10 requests/minute per user for subscribe/unsubscribe
  • Recommended: 100 notifications/day per user

📈 Monitoring & Maintenance

Database Cleanup

Run periodic cleanup (recommended: daily cron job):

-- Delete inactive subscriptions older than 90 days
DELETE FROM push_subscriptions
WHERE is_active = false
AND updated_at < NOW() - INTERVAL '90 days';

Or use the service method:

await pushService.cleanupInactiveSubscriptions(90);

Statistics Monitoring

const stats = await pushService.getStatistics();
// Returns:
// {
//   totalSubscriptions: 150,
//   activeSubscriptions: 142,
//   inactiveSubscriptions: 8,
//   byBrowser: { chrome: 100, firefox: 30, safari: 12 },
//   byDeviceType: { mobile: 90, desktop: 50, tablet: 10 }
// }

Error Monitoring

Check push subscription errors:

SELECT user_id, endpoint, last_error, failed_attempts
FROM push_subscriptions
WHERE is_active = false
AND last_error IS NOT NULL
ORDER BY updated_at DESC
LIMIT 20;

🚀 Deployment Checklist

Production Deployment

  • Generate production VAPID keys (npx web-push generate-vapid-keys)
  • Add VAPID keys to production .env
  • Set VAPID_SUBJECT to production email (mailto:support@parentflow.com)
  • Enable HTTPS (required for Web Push)
  • Test on all major browsers
  • Set up monitoring for failed push deliveries
  • Configure rate limiting
  • Set up cleanup cron job
  • Test notification appearance on mobile devices
  • Verify service worker registration on production domain

Environment Variables (Production)

PUSH_NOTIFICATIONS_ENABLED=true
VAPID_PUBLIC_KEY=<production-public-key>
VAPID_PRIVATE_KEY=<production-private-key>
VAPID_SUBJECT=mailto:support@parentflow.com
PUSH_DEFAULT_TTL=86400
PUSH_BATCH_SIZE=100

🎨 Customization Guide

Notification Appearance

Edit in maternal-web/public/push-sw.js:

const options = {
  body: data.body,
  icon: '/icons/icon-192x192.png',  // Change app icon
  badge: '/icons/icon-72x72.png',    // Change badge icon
  vibrate: [200, 100, 200],          // Customize vibration pattern
  tag: data.tag || 'default',
  data: data.data || {},
  requireInteraction: false,         // Set true for persistent notifications
};

Notification URLs

Edit URL routing in notifications.service.ts:

private getNotificationUrl(notification: Notification): string {
  switch (notification.type) {
    case NotificationType.FEEDING_REMINDER:
      return `/children/${notification.childId}/activities`;
    // Add custom routes here
  }
}

Notification Triggers

Add custom notification triggers in notifications.service.ts:

async createCustomNotification(userId: string, childId: string) {
  await this.createNotification(
    userId,
    NotificationType.CUSTOM,
    'Custom Title',
    'Custom Message',
    {
      childId,
      priority: NotificationPriority.HIGH,
      metadata: { customData: 'value' }
    }
  );
}

🐛 Troubleshooting

Common Issues

Issue: "Push notifications not supported" Solution: Ensure HTTPS is enabled. Service Workers require secure context.

Issue: "Permission denied" Solution: User must manually reset permissions in browser settings.

Issue: "Subscription failed" Solution: Check VAPID public key is correctly fetched from backend.

Issue: "Notifications not appearing" Solution: Check browser notification settings, ensure service worker is registered.

Issue: "Push fails with 404/410" Solution: Subscription is invalid/expired. System auto-deactivates these.

Issue: "iOS not receiving notifications" Solution: On iOS, app must be installed as PWA (Add to Home Screen).

Debug Logs

Browser Console:

// Check service worker registration
navigator.serviceWorker.getRegistrations().then(console.log);

// Check current subscription
navigator.serviceWorker.ready.then(reg =>
  reg.pushManager.getSubscription().then(console.log)
);

// Check notification permission
console.log(Notification.permission);

Backend Logs:

# Check push service logs
tail -f /tmp/backend-dev.log | grep "\[Push\]"

📚 References


Completion Status

Backend

  • Database schema (already existed)
  • PushSubscription entity
  • PushService implementation
  • PushController with REST endpoints
  • PushModule integration
  • NotificationsService integration
  • Environment configuration
  • VAPID keys generated

Frontend

  • Service Worker (push-sw.js)
  • Push utilities library
  • PushNotificationToggle component
  • Browser compatibility checks
  • Error handling

Testing 🔄

  • Backend compilation successful
  • Backend running on port 3020
  • End-to-end push notification test
  • Multi-device testing
  • Browser compatibility testing

🎉 Next Steps

  1. Test End-to-End Flow:

    • Log in to web app
    • Enable push notifications in settings
    • Send test notification
    • Create activities and verify smart notifications
  2. Production Deployment:

    • Generate production VAPID keys
    • Update environment variables
    • Deploy to production
    • Test on production domain
  3. Monitoring Setup:

    • Set up error tracking for failed push sends
    • Configure cleanup cron job
    • Set up analytics for notification engagement
  4. Documentation:

    • Add push notification docs to user guide
    • Create admin documentation for monitoring
    • Update API documentation

Implementation Complete! 🚀 The push notification system is ready for testing and deployment.