Push Notification System
This document details the Web Push (FCM) delivery architecture, token privacy policies, notification tray lifecycle management, and deep-link routing in Scripture Habit.
1. FCM Token Storage & Privacy Architecture
To balance user privacy with query performance, notification tokens are partitioned into two tiers:
- Private Token Vault (
users/{uid}/private/tokens)
Device registration tokens (fcmTokensarray) reside strictly within private subcollections accessible only by the authenticated owner. - Public Eligibility Flag (
users/{uid}.hasFcmToken)
A denormalized boolean flag on the user document indicating active token presence, allowing hourly reminder jobs to index candidates without reading private subcollections.
2. Client-Side Service Worker Setup
Push permissions and token registrations are managed via src/utils/notification-helper.ts:
- Browser Compatibility Check: Validates runtime support for Service Workers and PushManager.
- Permission Request: Invokes
Notification.requestPermission(). - Service Worker Registration: Registers
/sw.jswith root scope. - Token Enrollment: Acquires FCM tokens via VAPID key exchange and writes them to the user's private tokens document.
3. Notification Tray Management
To prevent stale notifications from cluttering the OS notification center:
- On App Launch: Dismisses active streak reminder notifications since user engagement has occurred.
- On Entering Group Chat: Selectively dismisses notifications matching the active
groupIdwhile preserving alerts from other groups.
4. Multicast Delivery & Token Purging
- Batched Multicast: Uses Firebase Admin SDK's
sendEachForMulticastto dispatch notifications in 500-token batches. - Self-Healing Token Cleanup: Uninstalled or invalidated tokens (
messaging/registration-token-not-registered) are identified from delivery error codes and purged from Firestore automatically.
5. Notification Click & Deep-Link Flow
When users tap a push notification, the Service Worker and React application coordinate deep-link navigation:
Deep-Link Sequence Breakdown
notificationclickInterception
The Service Worker captures the system tap event and extracts destination payload data (e.g.,/groups/{groupId}).Window Reuse vs. Cold Start
Focuses an existing browser window if available, transmitting the path viapostMessage. Otherwise, it invokesclients.openWindow.Authentication Verification & Route Resolution
React Router resolves the destination path, verifying authentication state before mounting the target chat or note interface.