v0.12.27 schedule list view update
This commit is contained in:
99
CLAUDE.md
99
CLAUDE.md
@@ -300,10 +300,105 @@ Single-user add/remove via `groups.js` (GroupInfoModal) always uses the named me
|
||||
|
||||
---
|
||||
|
||||
## FCM Push Notifications
|
||||
|
||||
**Status:** Working on Android (v0.12.26+). iOS in progress.
|
||||
|
||||
### Overview
|
||||
|
||||
Push notifications use Firebase Cloud Messaging (FCM) — not the older web-push/VAPID approach. VAPID env vars are still present (auto-generated on first start) but are no longer used for push delivery.
|
||||
|
||||
### Firebase Project Setup
|
||||
|
||||
1. Create a Firebase project at console.firebase.google.com
|
||||
2. Add a **Web app** to the project → copy the web app config values into `.env`
|
||||
3. In Project Settings → Cloud Messaging → **Web Push certificates** → generate a key pair → copy the public key as `FIREBASE_VAPID_KEY`
|
||||
4. In Project Settings → Service accounts → Generate new private key → download JSON → stringify it (remove all newlines) → set as `FIREBASE_SERVICE_ACCOUNT` in `.env`
|
||||
|
||||
Required `.env` vars:
|
||||
```
|
||||
FIREBASE_API_KEY=
|
||||
FIREBASE_PROJECT_ID=
|
||||
FIREBASE_APP_ID=
|
||||
FIREBASE_MESSAGING_SENDER_ID=
|
||||
FIREBASE_VAPID_KEY= # Web Push certificate public key (from Cloud Messaging tab)
|
||||
FIREBASE_SERVICE_ACCOUNT= # Full service account JSON, stringified (backend only)
|
||||
```
|
||||
|
||||
### Architecture
|
||||
|
||||
```
|
||||
Frontend (browser/PWA)
|
||||
└─ usePushNotifications hook (Chat.jsx or dedicated hook)
|
||||
├─ GET /api/push/firebase-config → fetches SDK config from backend
|
||||
├─ Initialises Firebase JS SDK + getMessaging()
|
||||
├─ getToken(messaging, { vapidKey }) → obtains FCM token
|
||||
└─ POST /api/push/subscribe → registers token in push_subscriptions table
|
||||
|
||||
Backend (push.js)
|
||||
├─ sendPushToUser(schema, userId, payload) — shared helper, called from:
|
||||
│ ├─ messages.js (REST POST route — PRIMARY message path)
|
||||
│ └─ index.js (socket message:send handler — secondary/fallback)
|
||||
└─ Firebase Admin SDK sends the FCM message to Google's servers → device
|
||||
```
|
||||
|
||||
### Database
|
||||
|
||||
Table `push_subscriptions` (migration 007):
|
||||
```sql
|
||||
id, user_id, device ('mobile'|'desktop'), fcm_token, created_at
|
||||
```
|
||||
PK is `(user_id, device)` — one token per device type per user. `/api/push/subscribe` deletes the old row then inserts, so tokens stay fresh.
|
||||
|
||||
### Message Payload Structure
|
||||
|
||||
All real messages use `notification + data`:
|
||||
```js
|
||||
{
|
||||
token: sub.fcm_token,
|
||||
notification: { title, body }, // FCM shows this even if SW fails
|
||||
data: { url: '/', groupId: '42' }, // SW uses for click routing
|
||||
android: { priority: 'high', notification: { sound: 'default' } },
|
||||
webpush: { headers: { Urgency: 'high' }, fcm_options: { link: url } },
|
||||
}
|
||||
```
|
||||
|
||||
### Service Worker (sw.js)
|
||||
|
||||
`onBackgroundMessage` fires when the PWA is backgrounded/closed. Shows the notification and stores `groupId` for click routing. When the user taps the notification, the SW's `notificationclick` handler navigates to the app.
|
||||
|
||||
### Push Trigger Logic (messages.js)
|
||||
|
||||
**Critical:** The frontend sends messages via `POST /api/messages/group/:groupId` (REST), not via the socket `message:send` event. Push notifications **must** be fired from `messages.js`, not just from the socket handler in `index.js`.
|
||||
|
||||
- **Private group:** query `group_members`, skip sender, call `sendPushToUser` for each member
|
||||
- **Public group:** query `DISTINCT user_id FROM push_subscriptions WHERE user_id != sender`, call `sendPushToUser` for each
|
||||
- Image messages use body `'📷 Image'`
|
||||
- The socket handler in `index.js` has identical logic for any future socket-path senders
|
||||
|
||||
### Debug & Test Endpoints
|
||||
|
||||
```
|
||||
GET /api/push/debug # admin only — lists all FCM tokens for this schema + firebase status
|
||||
POST /api/push/test # sends test push to own device
|
||||
POST /api/push/test?mode=browser # webpush-only test (Chrome handles directly, no SW involved)
|
||||
```
|
||||
|
||||
Use `/debug` to confirm tokens are registered. Use `/test` to verify end-to-end delivery independently of real message flow.
|
||||
|
||||
### Stale Token Cleanup
|
||||
|
||||
`sendPushToUser` catches FCM errors and deletes the `push_subscriptions` row for codes:
|
||||
- `messaging/registration-token-not-registered`
|
||||
- `messaging/invalid-registration-token`
|
||||
- `messaging/invalid-argument`
|
||||
|
||||
---
|
||||
|
||||
## Outstanding / Deferred Work
|
||||
|
||||
### Android Background Push (KNOWN_LIMITATIONS.md)
|
||||
**Status:** Implemented (v0.11.26+). Replaced web-push/VAPID with Firebase Cloud Messaging (FCM). Requires Firebase project setup — see .env.example for required env vars and sw.js for the SW config block.
|
||||
### iOS Push Notifications
|
||||
**Status:** In progress. Android working (v0.12.26+). iOS PWA push requires additional handling — investigation ongoing.
|
||||
|
||||
### WebSocket Reconnect on Focus
|
||||
**Status:** Deferred. Socket drops when Android PWA is backgrounded.
|
||||
|
||||
Reference in New Issue
Block a user