Self-contained Android push via NotificationService.Subscribe #58
Labels
No labels
adr
android
area/calendar
area/design-system
area/i18n
area/jobs
area/offline
area/server
area/testing
bug
ci
duplicate
enhancement
help wanted
invalid
notifications
question
reliability
security
severity/low
severity/medium
tracking
web
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
eagraiclainne/app#58
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Make Android push notifications self-contained. Remove the dependency on an external UnifiedPush push server (ntfy) and on a separate distributor app. The main server already exposes a live notification stream. Android will hold that stream open and render notifications directly.
Motivation
Today Android push depends on two external things:
deploy/k8s/ntfy/ntfy.yaml).connector:3.3.3).Both break system rule 3 (keep it self-contained). We do not want to run a second service for notifications, and we do not want to force members to install another app.
The backend for a self-contained path already exists.
proto/api/core/v1/notification.proto:63defines:The web client already consumes this stream (
web/src/notifications.ts:98). Android does not — it only runs a 15-minuteInboxPollWorker. The plan closes that gap.Why not embed ntfy
The ntfy server (
heckel.io/ntfy/v2) does import as a Go package, and it is modular. We still reject it:Subscribestream over our own TLS and JWT channel. No Web Push encryption is needed, because that protects untrusted relays.go.modeven when gated off. That reads badly against the OSS, pinned-dependency, and FCM-free invariants.Transport decision
Use the existing Connect server-streaming RPC (
Subscribe). Do not add a Server-Sent Events endpoint.Subscribeis already generated ingen/android. Android iterates a typedNotificationflow. No hand-rolled parser, no schema drift.EventSource. So SSE offers no real gain.Scope of this issue
Server:
NotificationService.Subscribefits a long-lived mobile consumer.Android:
Subscribestream while the app is alive. Render eachNotificationthrough the existingNotifier.InboxPollWorker(15-minute) as the background fallback for now.Removal:
org.unifiedpush.android:connectordependency.PushRegistrar.ktandAppPushService.kt.SessionStore.Out of scope (keep as-is):
internal/push, VAPID keys, thepush_subscriptiontable, and thePushServiceRPCs. These still serve web Web Push, which uses the browser vendor push service and does not change.ADR
Add
docs/adr/0028-self-contained-android-push.md. Record:Subscribestream.Known interim regression
Until the follow-up foreground service lands, closed-app Android push falls back to the 15-minute poll. A member who had installed an external distributor loses instant closed-app push. For a family install with the connector being dropped anyway, this is acceptable.
Surface parity note
Web is unchanged. MCP and CLI do not carry push. The change updates the Android surface and its removed dependency, per system rule 1.
Definition of done
Subscribewhile the app is open.make checkpasses. Behavior verified on device against the live deploy.nalum referenced this issue2026-08-14 11:14:20 +00:00