Components and state#

The feature is split into five main parts. Each part has one clear job.

flowchart LR UI["Settings UI"] --> API["Push API"] Events["Chat events"] --> Service["Push service"] API --> Service Service --> Store["Subscription store"] Service --> WebPush["Web Push client"] WebPush --> Browser["Browser service worker"]

Responsibilities#

PartResponsibility
Settings UIShows support, permission, subscription, test, and error states
Push APIAuthenticates the user and accepts subscriptions and presence updates
Push serviceChooses recipients and sends notifications to their devices
Subscription storePersists the VAPID key and per-user browser subscriptions
Web Push clientEncrypts payloads and safely connects to push providers
Service workerDisplays notifications and routes clicks into the application

State locations#

StateLocationLifetime
VAPID key pairDATA_DIR/webpush-vapid.jsonUntil deliberately rotated
Browser subscriptionsDATA_DIR/push-subscriptions/Until disabled, retired, logout, or user removal
Presence claimsBackend memoryClaims live for 55 seconds; revisions are bounded per user
Parked-question stateBackend memoryUntil a user, completion, or error event
Browser permission and subscriptionBrowser profileControlled by the browser and user

At startup, Remote loads or creates the VAPID key, verifies the key pair, and constructs the Web Push client. If that fails, notifications are disabled but the rest of Remote still starts normally.

Main source locations#

  • backend/internal/service/push_notifier.go
  • backend/internal/service/push/
  • backend/internal/integration/webpush/
  • backend/internal/stores/filepush/
  • frontend/src/api/pushSubscriptionApi.ts
  • frontend/src/state/push/pushPresenceState.ts
  • frontend/public/sw.js
remote.futrx documentation