architecture/frontend
Making a Notification Tap Land on the Right Screen
A notification that says “your request was approved” and then dumps you on a dashboard has wasted everyone’s time. The tap has to carry you to the thing it’s about. On the web side of the suite, that meant teaching the service worker how to route.
The gap between delivery and destination
Delivering the notification is only half the job. When the user taps it, the browser fires a `notificationclick` in the service worker — and by default that does nothing useful. If you want the tap to open a specific route, the routing target has to travel with the notification and the worker has to act on it.
So the backend started attaching a redirect target to each notification’s data payload, and the service worker learned to read it.
Routing from the service worker
The pattern: on `notificationclick`, close the notification, look for an already-open client on the target route (focus it if found), and otherwise open a new window at the destination. The subtlety is matching an existing tab so you focus it instead of piling up duplicates.
self.addEventListener('notificationclick', (event) => {
event.notification.close();
const target = event.notification.data?.redirectUrl || '/';
event.waitUntil((async () => {
const clientsList = await self.clients.matchAll({
type: 'window',
includeUncontrolled: true,
});
const existing = clientsList.find((c) => c.url.includes(target));
if (existing) return existing.focus();
return self.clients.openWindow(target);
})());
});Why it took more than one attempt
This is the kind of code that behaves differently across browsers, PWA install states, and whether the app is already open. Getting a fallback redirect URL right (so a malformed target still lands somewhere sane), and making sure the same logic shipped consistently across every app in the suite, took a few iterations of ship-observe-adjust rather than one clean landing.
The payoff is that “tap the notification, arrive at the record” finally became true across the whole suite — not just on the one app where it was first prototyped.