|
1 | 1 | # Notification Strategy |
2 | 2 |
|
3 | | -## Overview |
4 | | -TeachLink implements a robust notification handling system to prevent notification spam, deduplicate identical alerts, and batch similar notifications. This ensures a high-quality user experience without overwhelming the user or draining their device's battery. |
5 | | - |
6 | | -## Core Features |
7 | | - |
8 | | -### 1. Deduplication |
9 | | -Duplicate notifications sent within a **10-minute window** are automatically ignored. |
10 | | -- A unique fingerprint is generated for each incoming notification based on its `type`, `targetKey`, `title`, and `body`. |
11 | | -- We maintain a history of the last 200 notifications. If an incoming notification matches a fingerprint in the history within the deduplication window, it is suppressed. |
12 | | - |
13 | | -### 2. Batching (Grouping) |
14 | | -Similar notifications are grouped together into a single summary notification if they have the same `type` and target data (e.g., multiple messages in the same conversation). |
15 | | -- Titles and bodies are aggregated (e.g., "2 new messages"). |
16 | | -- The group count is tracked and updated as new notifications for the same group arrive. |
17 | | - |
18 | | -### 3. Adaptive Throttling (Spam Prevention) |
19 | | -To prevent notification spam, we apply adaptive throttling based on user engagement. The time gap required between notifications of the same type depends on when the user last interacted with a notification: |
20 | | -- **Active users** (engaged within 24 hours): Throttled to max 1 per 5 minutes. |
21 | | -- **Recently inactive** (24-72 hours): Throttled to max 1 per 30 minutes. |
22 | | -- **Inactive** (72+ hours): Throttled to max 1 per 3 hours (180 minutes). |
23 | | - |
24 | | -### 4. Storage & History Limit |
25 | | -- Unread counts and grouped notifications are stored persistently using `Zustand` and `AsyncStorage`. |
26 | | -- The primary notification queue is capped at **100 stored notifications**. |
27 | | -- The deduplication history is capped at **200 entries** to ensure fast read/write operations and minimal memory usage. |
| 3 | +This document outlines the strategy for handling push notifications in the mobile application. |
| 4 | + |
| 5 | +## Token Registration |
| 6 | + |
| 7 | +When a user enables push notifications, the app generates a unique Expo Push Token. This token is sent to the backend and associated with the user's account. |
| 8 | + |
| 9 | +**Endpoint:** `POST /api/notifications/register` |
| 10 | + |
| 11 | +**Request Body:** |
| 12 | + |
| 13 | +```json |
| 14 | +{ |
| 15 | + "token": "ExponentPushToken[...]", |
| 16 | + "platform": "ios" | "android" |
| 17 | +} |
| 18 | +``` |
| 19 | + |
| 20 | +**Response:** |
| 21 | + |
| 22 | +- `200 OK`: If the token is successfully registered. |
| 23 | +- `400 Bad Request`: If the request is malformed. |
| 24 | +- `500 Internal Server Error`: If an error occurs on the backend. |
| 25 | + |
| 26 | +## Token De-registration |
| 27 | + |
| 28 | +When a user logs out or disables push notifications, the app sends a request to the backend to de-register the token. |
| 29 | + |
| 30 | +**Endpoint:** `DELETE /api/notifications/tokens/:token` |
| 31 | + |
| 32 | +**Response:** |
| 33 | + |
| 34 | +- `204 No Content`: If the token is successfully de-registered. |
| 35 | +- `404 Not Found`: If the token does not exist. |
| 36 | +- `500 Internal Server Error`: If an error occurs on the backend. |
| 37 | + |
| 38 | +## Token Refresh |
| 39 | + |
| 40 | +The Expo push token can be rotated by the OS. The app listens for token refresh events and re-registers the new token with the backend automatically. |
| 41 | + |
| 42 | +## Notification Preferences |
| 43 | + |
| 44 | +Users can customize their notification preferences in the app settings. These preferences are stored on the backend and used to determine which notifications to send. |
| 45 | + |
| 46 | +**Endpoint:** `PUT /api/notifications/preferences` |
| 47 | + |
| 48 | +**Request Body:** |
| 49 | + |
| 50 | +```json |
| 51 | +{ |
| 52 | + "courseUpdates": true, |
| 53 | + "messages": false, |
| 54 | + "learningReminders": true, |
| 55 | + "achievementUnlocks": true, |
| 56 | + "communityActivity": false |
| 57 | +} |
| 58 | +``` |
| 59 | + |
| 60 | +**Response:** |
| 61 | + |
| 62 | +- `200 OK`: If the preferences are successfully updated. |
| 63 | +- `400 Bad Request`: If the request is malformed. |
| 64 | +- `500 Internal Server Error`: If an error occurs on the backend. |
0 commit comments