Super People Docs
Operations

Browser push — production smoke test

A ten-minute, two-account real-browser check to run after any deploy that changes browser push or its Firebase variables.

Run this once against https://people.superlabs.co after the first deploy that carries browser push, and again after any deploy that changes the Firebase variables. It takes about ten minutes and needs two accounts.

Everything below is a real browser check. The automated suite (npm run test:e2e -w api) proves the server's half — whose tokens are looked up, what the payload carries, what happens to a dead one — by stubbing Google at the fetch boundary. It cannot prove that Google accepts the message, that the browser draws it, or that a permission grant produces a working token. That is what this document is for.

Before you start

Confirm the build actually carries the config. Without this every step below fails for the same uninteresting reason:

curl -s https://people.superlabs.co/firebase-messaging-sw.js | head -8

The firebase.initializeApp({...}) line must show a non-empty apiKey, projectId, messagingSenderId and appId. If they are empty strings, the web image was built without the NEXT_PUBLIC_FIREBASE_* build args — push is off, and no amount of clicking in the UI will turn it on. Fix the Gitea variables and rebuild; restarting the container will not help, because the values are compiled into the bundle.

Then confirm the icons resolve, or notifications draw with a blank square:

curl -sI https://people.superlabs.co/icon.png  | head -1   # expect 200
curl -sI https://people.superlabs.co/badge.png | head -1   # expect 200

The checklist

#StepExpected
1Sign in to people.superlabs.co as User A, Chrome desktop.Feed loads.
2Look at the top of the feed.A "Stay updated" card, with Enable notifications and Not now. No browser permission dialog has appeared on its own.
3Click Not now, then reload.The card is gone and stays gone.
4Go to Settings → Notifications."In-app notifications — Always on"; "Browser push notifications" toggle off.
5Click the push toggle.Now the browser's permission dialog appears — only after this click.
6Allow it.Toggle turns on.
7DevTools → Application → Service Workers.firebase-messaging-sw.js is activated and running, scope /.
8Confirm the token reached the server (see the SQL below).One row for User A, isActive = true.
9As User B in another browser, mention User A in a post (@ their name).—
10Switch away from the Super People tab, or minimise the window.A native OS notification appears: title "… mentioned you!", the SuperLabs mark as its icon.
11Click the notification.The existing tab is focused (not a second one) and lands on /feed#post-…, scrolled to that post.
12Close the Super People tab entirely. Have User B comment on one of A's posts.The notification still arrives, with the tab closed.
13Click it.A new tab opens on the right post.
14Bring the tab to the foreground. Have User B react to A's post.The bell count moves and an in-app alert appears. No duplicate OS notification is drawn on top of it.
15Settings → turn the push toggle off. Have User B mention A again.No OS notification. The bell still increments — in-app is unaffected.
16Turn it back on.No second permission dialog: the grant is still in place.
17Sign out.The token row for that browser is gone (SQL below).
18Sign back in and re-enable.A row exists again.
19Repeat 5–11 in Edge, or on a phone, signed in as the same User A.Both rows are present and both devices receive the next notification.
20In Chrome's site settings, set Notifications to Block. Reload the feed.No "Stay updated" card reappears — a blocked user is not nagged. Settings explains how to unblock.

The SQL for steps 8, 17, 18 and 19

SELECT token, platform, "isActive", "lastUsedAt", left("userAgent", 40)
  FROM push_token
 WHERE "userId" = (SELECT id FROM "user" WHERE email = 'user-a@superlabs.co')
 ORDER BY "createdAt";

lastUsedAt moves on every successful delivery, so after step 10 it should be within seconds of now. A token FCM has rejected shows isActive = false rather than disappearing — that is deliberate, and registering the same browser again flips it back to true.

Notification types worth spot-checking

The automated suite covers the payload for all seven. These are the two worth seeing land in a real browser, because they are the ones whose click target is not a post:

  • Announcement — a super admin posts with the announcement switch on. Everybody gets "New announcement"; clicking opens the post.
  • Grievance — a handler moves a grievance to In review. The submitter gets "Grievance update"; clicking opens /grievance. Read the notification text carefully: it must not contain the handler's name, the grievance subject, the reason, or any of the description. It should read only "Your grievance has moved to In review." If it says anything more than that, stop and treat it as a privacy incident.

If nothing arrives

In order of likelihood:

  1. Empty config in the service worker — see Before you start. This is by far the most common cause and it is a rebuild, not a restart.
  2. FCM_* not set on the API. The API logs "Push notifications are off" once at boot when the service account is missing, and a specific complaint when the private key is present but mangled. Check the container log.
  3. The OS is suppressing it. macOS Focus modes and Windows Focus Assist swallow notifications silently; Chrome shows them again once off.
  4. Permission is granted but the token never registered. The browser is subscribed with FCM but the API has no row — check the network tab for a failed POST /api/v1/push/tokens.

On this page