Skip to main content

Web Push and Expo Push

The app supports web push (browser) and Expo push (mobile) so users receive chat and call notifications when the tab or app is in the background. Both flows use the same backend pipeline: the API publishes chat/call events to RabbitMQ, and dedicated workers consume and send push to the recipient.

Overview​

ChannelWorkerPurpose
Web Push (browser)WebPushNotificationWorkerSends push to browser (Chrome, Firefox, etc.) via Web Push API; user subscribes in Settings → Notification.
Expo Push (mobile)ExpoPushNotificationWorkerSends push to mobile app via Expo Push Service; app registers Expo token with the API after login.

Both workers consume the same messages from RabbitMQ (ChatMessage, IncomingCallPushMessage, and NotificationMessage for likes/comments/friends/etc.), so when someone sends a chat message, starts a call, or a social notification is created, the appropriate worker sends a push to the recipient’s device(s).

Parity notes (native): Expo chat DMs use the same sorted guid_guid conversation id as web push; system_event chat messages are skipped on both channels; Expo payloads include deepLink (bellamybook://…) for native tap routing. Invalid Expo tokens (DeviceNotRegistered) are deactivated. When the recipient is in Redis presence:online_users (SignalR connected), Expo skips chat/social push (calls still fire); set ExpoPush__SkipWhenUserOnline=false to disable. Social pushes may include Expo richContent.image when imageUrl is set.

What Must Be Running​

For chat/call push to be delivered:

ServicePurpose
RabbitMQMessage broker; API publishes chat/call events here; workers consume from here.
APIWhen a user sends a message (or starts a call), API publishes to RabbitMQ; also stores push subscriptions (web) and Expo tokens (mobile).
MongoDBAPI and workers use it (subscriptions and tokens).
WebPushNotificationWorkerConsumes from RabbitMQ and sends web push to recipient’s browser.
ExpoPushNotificationWorkerConsumes from RabbitMQ and sends push to recipient’s mobile app via Expo.

If a worker shows “Bus started” but no push is received, ensure the API is running when the message or call is sent (the API publishes to RabbitMQ).


Web Push (browser)​

User flow​

  1. User logs in and goes to Settings → Notification.
  2. User clicks Enable notifications and allows the browser permission.
  3. The frontend registers the push subscription with the API (POST /api/push-subscriptions).
  4. When someone sends a chat message or starts a call, the API publishes to RabbitMQ; WebPushNotificationWorker consumes and sends a web push to the recipient’s browser.
  5. The recipient sees an OS/browser notification (e.g. “Someone: message preview” or incoming call).

Test notification (no worker)​

The API can send a test push directly (no RabbitMQ/worker):

  • In the app: Settings → Notification → Send test notification.
  • Or call POST /api/push-subscriptions/test with a valid JWT.

This verifies subscription and permission; real chat/call push still requires the worker and RabbitMQ.

API endpoints (web push)​

MethodEndpointDescription
POST/api/push-subscriptionsRegister a push subscription (endpoint, p256dh, auth).
DELETE/api/push-subscriptionsUnregister by endpoint.
POST/api/push-subscriptions/renewRenew subscription (e.g. after pushsubscriptionchange).
GET/api/push-subscriptionsList current user’s subscriptions.
POST/api/push-subscriptions/testSend a test push (API sends directly).

Run WebPushNotificationWorker​

cd Src/backend/WebPushNotificationWorker
dotnet run

Use the same RabbitMQ and MongoDB (and WebPush VAPID keys) as in the API’s appsettings.Development.json.


Expo Push (mobile)​

After members install Bellamy Book and sign in, the app registers an Expo push token with your API. Keep the Expo push worker running. See Mobile App.

User flow​

  1. User installs the app, enters your API URL (API_PUBLIC_URL — not a frontend-only host), and signs in.
  2. The app requests notification permission and obtains an Expo push token.
  3. The app registers the token (POST /api/push-subscriptions/expo).
  4. Chat / call / social events → RabbitMQ → ExpoPushNotificationWorker → Expo Push Service.
  5. Tap opens the matching screen in the app.

API endpoints (Expo push)​

MethodEndpointDescription
POST/api/push-subscriptions/expoRegister an Expo push token for the current user.
DELETE/api/push-subscriptions/expoUnregister Expo token (e.g. by token or device).

Run ExpoPushNotificationWorker​

cd Src/backend/ExpoPushNotificationWorker
dotnet run

Use the same RabbitMQ and MongoDB as the API.


Message flow (chat / call push)​

  1. User A sends a message to User B (or starts a call to User B).
  2. API saves the message/call and publishes ChatMessage (or IncomingCallPushMessage) to RabbitMQ.
  3. WebPushNotificationWorker consumes the message and, if User B has web push subscriptions, sends a web push to each.
  4. ExpoPushNotificationWorker consumes the same message and, if User B has Expo tokens, sends push via Expo to each device.
  5. User B sees an OS notification (browser and/or mobile) when the tab/app is in the background.

Worker logs to look for:

  • Web: WebPush: Consuming chat message ... and WebPush: Sent chat push for message ...
  • Expo: ExpoPush: Consuming chat message ... and ExpoPush: Sent chat push for message ...

Configuration​

Web Push (VAPID)​

Configure in API and WebPushNotificationWorker (e.g. appsettings.json or appsettings.Development.json):

{
"WebPush": {
"Subject": "mailto:[email protected]",
"PublicKey": "your-vapid-public-key",
"PrivateKey": "your-vapid-private-key"
}
}

The frontend needs the same PublicKey (e.g. VITE_VAPID_PUBLIC_KEY).

RabbitMQ and MongoDB​

Workers must use the same RabbitMQ (host, vhost, credentials) and MongoDB (connection string, database name) as the API so they consume the same messages and read the same subscription/token data.


Troubleshooting​

  • Test notification works but chat/call push does not: Ensure RabbitMQ and the relevant worker (WebPushNotificationWorker and/or ExpoPushNotificationWorker) are running when the message or call is sent.
  • Worker shows “Bus started” but no “Consuming chat message”: The API must be running when the sender submits the message; the API publishes to RabbitMQ.
  • Web: no notification on Mac/Windows: Check OS notification settings for the browser (e.g. System Settings → Notifications → your browser → Allow). Allow notifications for the site in the browser (e.g. site settings for localhost or your domain). Try sending the test with the tab in the background.
  • Expo: no notification on device: Ensure the app registered the Expo token with the API after login and that the device allows notifications for the app.