Skip to content

feat(mobile): push notifications MVP - #6269

Draft
brow wants to merge 1 commit into
mainfrom
codex/ios-push-internal
Draft

feat(mobile): push notifications MVP#6269
brow wants to merge 1 commit into
mainfrom
codex/ios-push-internal

Conversation

@brow

@brow brow commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

This PR adds an MVP, iOS-only version of mobile push notifications.

When a message that would normally badge the in-app Notifications tab arrives in a push-enabled community, Buzz for iOS can show a normal iOS notification with the real message content. Tapping it navigates to the message in Buzz.

The feature is off in normal builds and can be enabled only for internal dogfood builds and explicitly configured relays.

Notifications are delivered best-effort, limited to messages, and not yet enabled for external App Store users.

Summary

Add the dormant-by-default iOS push notification MVP for internal dogfood builds. This refreshes the end-to-end work from #2744 onto current main, retains only the best-effort delivery behavior needed from #3347, and includes exact-message notification routing from #6159. Lossless catch-up remains deferred. The earlier drafts remain unchanged for comparison.

This PR keeps the external App Store build and relay rollout off. Internal rollout requires both an explicit dogfood build configuration and relay deployment configuration.

What changed

  • Add a closed, server-owned application profile registry for the canonical push.buzz.xyz gateway. A verified App Attest application ID selects the APNs topic, certificate identity, connection pool, and environment. The client cannot select an APNs topic.
  • Keep certificate-based APNs transport and a constant, opaque wake-up payload. The gateway receives no community, channel, conversation, message, title, or body metadata.
  • Add BUZZ_PUSH_ENABLED, defaulting to false, as the relay deployment gate. NIP-11 advertisement, lease acceptance, matching, workers, and gateway delivery all require the gate.
  • Limit the MVP to message kinds 9, 40002, 45001, and 45003, using the Notifications-tab message eligibility rules.
  • Add a default-off iOS build capability. When off, the Notification Service Extension is not built or embedded, push-native Swift files are excluded, and Dart does not register with APNs or run gateway/relay push behavior.
  • Add the dogfood build configuration for xyz.block.buzz.dogfood.mobile. It embeds the Notification Service Extension, uses App Attest, registers with APNs after permission is granted, enrolls/delegates with the gateway, and publishes relay-scoped leases.
  • Resolve notifications in the extension by fetching from the relay with NIP-98 authorization, then validating the Nostr event ID and signature before rendering plaintext event content.
  • Route notification taps to the exact resolved and signature-verified message. Channel routing remains an observable last-resort fallback during manual validation.
  • On community removal, tombstone the scoped relay lease and remove that community's extension snapshot and key state. Do not revoke a gateway delegation that another community on the same relay identity may still use.
  • Add gateway, relay, database, Flutter, Swift, Xcode-project, Helm, and rollout/latency coverage.

Rollout and rollback

Rollout remains internal-only:

  1. Build the dogfood app with mobile/ios/Flutter/PushEnabled.xcconfig.
  2. Configure the canonical gateway with the closed dogfood profile and its certificate identity.
  3. Set BUZZ_PUSH_ENABLED=true only on selected internal relay deployments.

The private dogfood release builder must include PushEnabled.xcconfig, sign the application and Notification Service Extension with their separate provisioning profiles, and map both bundle identifiers during export. The App Store builder does not include the push overlay, so external push remains absent/off.

To roll back, set BUZZ_PUSH_ENABLED=false on relays. They stop advertising push, accepting leases, matching events, running workers, and sending deliveries. External App Store builds keep the capability absent unless a later change turns it on.

Server metrics cover enrollment, delegation, lease acceptance, match and delivery outcomes, APNs status, queue age, and delivery latency. NSE resolution outcomes and exact-message versus channel-fallback taps are manually counted during dogfood validation until privacy-preserving client telemetry is designed.

Validation

  • lefthook run pre-push
    • branch-skew and file-size gates
    • Rust unit suite
    • 1,552 Flutter tests
    • desktop-native clippy and 2,570 tests
  • cargo clippy -p buzz-push-gateway -p buzz-relay -p buzz-db --all-targets --all-features -- -D warnings
  • swift test --package-path mobile/ios/BuzzPushKit — 51 XCTest cases and 3 Swift Testing cases
  • swift build -c release --package-path mobile/ios/BuzzPushKit
  • just mobile-check
  • python3 scripts/test-ios-pbxproj-semantics.py
  • deploy/charts/buzz-push-gateway/tests/render.sh
  • deploy/charts/buzz-push-gateway/tests/release-contract.sh
  • Default-off iOS Simulator build: app builds without the extension or push-native Swift sources
  • Dogfood push iOS Simulator build: app builds as xyz.block.buzz.dogfood.mobile with xyz.block.buzz.dogfood.mobile.NotificationService embedded

The repository-wide just ci gate passes, including Rust, desktop, web, and mobile checks, tests, and builds.

The prior development-stack hardware demo proved real sandbox APNs delivery and visibly fetched, signature-verified notification content on an iPhone 12 mini using the normal mobile development identity. Exact-message routing is covered by the refreshed implementation and tests. Signed dogfood-artifact validation, including a manual notification tap into the intended message, is the next release-validation step after the change reaches main and an immutable internal candidate reaches Mobile Releases/Comp Portal.

Provisioning note

This change adds the aps-environment, App Attest, application-group, and keychain-access-group entitlements. Before the first push-enabled dogfood candidate, the private release configuration must provide the app and Notification Service Extension identifiers, capabilities, and separate provisioning profiles; local dogfood signing is intentionally not a merge blocker for this source PR.

Signed-off-by: Tom Brow <tomb@squareup.com>
@brow
brow force-pushed the codex/ios-push-internal branch from c7a089a to d69b89c Compare August 18, 2026 23:25
@brow brow changed the title Add internal iOS push notification MVP feat(mobile): push notifications MVP Aug 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants