Skip to content

spike: can a notarized Developer-ID pkg receive APNs pushes - G9 #59

Description

@Adron

Summary

The push routes are confirmed live and the per-event push switchboard already ships. What is not known is whether a sandboxed, notarized, Developer-ID .pkg app — which is the current distribution model, not Mac App Store — can receive APNs pushes at all, and what provisioning that requires.

Spike first. Do not start the client work until the spike answers the question.

What is already settled

  • POST /api/push/register and DELETE /api/push/unregister exist in the live spec. The old "is unregister POST or DELETE?" question is settled: DELETE.
  • Per-event push switches ship as Settings ▸ Notifications (G18, PR feat: the Settings cluster — app settings, devices, notifications, sessions, tags (G17-G20) #25). Each event's channels.push flag is the switchboard this feature consumes — and the channels genuinely vary per event, so not every event can push.
  • Tray polling + local notifications already work and are not to be replaced. Real pushes augment polling.

The spike question

Can an app distributed as a notarized Developer-ID .pkg (App Sandbox + Hardened Runtime, bundle com.interlinedlist.macos, team BJA9558E4B) register for and receive APNs remote notifications? If yes, exactly what is required — an APNs key or certificate, an entitlement (aps-environment), a provisioning profile embedded in the app, a specific signing flow?

Deliverable: a written answer in docs/spikes/ with the concrete provisioning steps, or a clear "not possible outside the App Store" with the evidence. Either outcome is a good outcome — the second one saves the whole implementation.

Relevant context if the answer is nuanced: the App Store path already exists as a separate future branch, so "push works on the App Store build only" is an acceptable finding that would simply move this feature there.

Deep-link routing depends on a backend field

Routing a push to the right screen wants the notification routePath field, which does not exist yet (tracked with the other backend asks). Without it the client can still route using its existing typed NotificationTarget projection — confirm that projection covers every push-capable event before relying on it.

Division of labor — only after the spike says yes

Spike (do this alone, first)

  • Answer the provisioning question; write it up in docs/spikes/.
  • If provisioning is required, list exactly which secrets/certs the owner must create (this repo's convention is that the owner holds all signing material).

Kit

  • Push.register(token:) / Push.unregister(...) + DTOs + contract tests.

Domain

  • A push-registration service: register on launch and on sign-in, unregister on sign-out. Registration must be idempotent — a token that has not changed should not re-register on every launch.
  • Respect the per-event channels.push preferences from Settings ▸ Notifications.

App

  • Request notification authorization at a sensible moment (not at first launch, before the user knows what the app is).
  • Route an opened push to the right screen, reusing the existing NotificationTarget projection.
  • Pushes must not double-notify alongside tray polling — dedupe on notification id.

Tests

  • happy — token registers on sign-in, unregisters on sign-out
  • invalid — user denies notification permission → no registration attempted, no error surfaced
  • upstream-failure — register returns non-2xx → retried on next launch, never blocks sign-in
  • boundary — token rotation mid-session; the same notification arriving by both push and poll appears once

Acceptance criteria

  • The spike's answer is written down, whichever way it goes.
  • If built: signing out stops pushes to that device.
  • Full E2E gate green.

Notes

work-consolidation.md tracks this as G9 / spike S2. Size M after the spike.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    parityWeb-parity gap with the InterlinedList web appspikeInvestigate first; scope unknown until then

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions