Skip to content

Service Worker Push Notification Router with Topic-Based Subscription Registry #55

Description

@elizabetheonoja-art

Problem Statement / Feature Objective

The dashboard must deliver push notifications to field operators when critical events occur: meter breach, contract execution failure, or resource depletion alerts. A Service Worker push notification router must maintain a topic-based subscription registry, allowing different UI modules (spatial alerts, financial transactions, system health) to register for specific event topics. The router de-duplicates notifications within a 60-second coalescence window and renders them using the Notification API with actionable buttons (e.g., "Acknowledge", "View on Map"). When the app is in the foreground, notifications are routed to an in-app toast queue instead.

Technical Invariants & Bounds

  • Topic taxonomy: three-level hierarchy (domain.subdomain.action), e.g., "meter.water.breach", "contract.execution.reverted", "system.health.cpu".
  • Maximum registered subscriptions: 200 topics with up to 5 handler callbacks each.
  • Coalescence window: 60 seconds; identical events within the window increment a count on the existing notification rather than creating duplicates.
  • Push payload size limit: 4 KB (browser push limit). Unused payload bytes are reserved for optional data fields.
  • Action buttons: max 2 per notification (Chrome limit on desktop); each action maps to a URL or internal app route.
  • Foreground detection: check document.visibilityState and navigator.onLine; if visible, skip Notification API and post message to client via postMessage.

Codebase Navigation Guide

  • public/sw.js - Service Worker entry point. Currently handles caching; must be extended with push event listener.
  • src/services/pushSubscriptionManager.ts - Registers/unregisters push subscriptions with the backend via REST.
  • src/utils/topicRouter.ts - Topic trie structure for matching incoming push events to registered handlers.
  • src/hooks/usePushNotifications.ts - Hook that requests permission, registers subscription, and wires in-app toast fallback.
  • src/store/slices/notificationSlice.ts - Redux slice managing notification queue state, dismissal, and coalescence counters.
  • src/components/panels/ToastContainer.tsx - In-app toast renderer reading from notification slice.

Implementation Blueprint

  1. In public/sw.js, add a push event listener: parse event.data.json(), extract { topic, title, body, data, action }. Compute a coalescence key as (topic + body.substring(0, 80)). Check clients.matchAll for any foreground client; if found, postMessage the notification instead of showing a system notification.
  2. Build the topic trie in src/utils/topicRouter.ts: insert(topic, handler), match(topic) returns all handlers for that topic and its wildcard ancestors (e.g., "meter.water.*" matches "meter.water.breach").
  3. Create src/services/pushSubscriptionManager.ts: subscribe() calls registration.pushManager.subscribe with userVisibleOnly true and applicationServerKey from env; sends the subscription endpoint to POST /api/push/subscribe; unsubscribe() calls DELETE.
  4. The usePushNotifications hook orchestrates: check Notification.permission, prompt if needed, call subscribe, store subscription in Redux, and register a message event listener on navigator.serviceWorker for foreground delivery.
  5. Implement coalescence logic: notificationSlice maintains a Map<coalescenceKey, { count, timeoutId }>. When a new notification arrives, if key exists, increment count and extend coalescence window; otherwise create entry with 60s auto-dismiss timeout.
  6. ToastContainer renders the coalesced notifications, grouping by key and showing "(N more)" suffix for counts > 1.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions