Notify the user when a podcast is ready via a server-sent APNs push, and let
generation complete without the app staying alive. Because generation already
runs server-side, this replaces the client-side poll/BGTask approach entirely:
the backend knows when a job finishes and simply tells the device.
This supersedes the original BGTask design — polling podcastStatus and running
a background task on the client goes away.
Why server-driven
The compute already happens on the magicive.api backend. Today the app only does
the bookkeeping around it — poll status, download the mp3, write PodcastIndex,
and (in the old plan) a BGTask to keep that alive. Move the "when is it done"
signal to APNs and almost all of that disappears.
Backend fires a user-facing APNs alert when a job completes:
"Your podcast on
## Summary
Notify the user when a podcast is ready via a **server-sent APNs push**, and let
generation complete without the app staying alive. Because generation already
runs server-side, this replaces the client-side poll/BGTask approach entirely:
the backend knows when a job finishes and simply *tells* the device.
This supersedes the original BGTask design — polling `podcastStatus` and running
a background task on the client goes away.
## Why server-driven
The compute already happens on the magicive.api backend. Today the app only does
the bookkeeping around it — poll status, download the mp3, write `PodcastIndex`,
and (in the old plan) a BGTask to keep that alive. Move the "when is it done"
signal to APNs and almost all of that disappears.
## Recommended approach — Variant A: download-on-play
- Backend fires a **user-facing APNs alert** when a job completes:
"Your podcast on <title> is ready", deep-linking via the existing
`marks://podcast?url=…` handler (`handleDeepLink` in `MarksApp`).
- The episode "exists" server-side; the client **downloads the audio only when
the user opens/plays it**. No BGTask, no background download, fully
server-driven.
- The library lists server-known episodes that may not be downloaded yet
(download on play, then cache locally as today).
## Optional follow-up — Variant B: pre-download for offline
- Add a **silent push** (`content-available: 1`) + a background `URLSession`
download so the mp3 is on-device before the app is opened.
- Note: iOS throttles silent pushes, so delivery is best-effort, not instant.
- Slim client handler; still no polling loop. Defer unless offline-before-open
is required.
## Backend tasks
- [ ] APNs credentials: auth key (`.p8`), topic = app bundle id.
- [ ] `device_token ↔ user` registry (the generate endpoint already runs under a
Bearer identity via `MarksAuth`, so the user mapping exists).
- [ ] On job completion, send an APNs alert with title + `marks://podcast?url=…`
payload. (Variant B: also send a silent `content-available` push.)
- [ ] Per-user episode catalog endpoint (see tradeoff below) so the client can
list server-known episodes.
## Client tasks
- [ ] Register for remote notifications; request permission at first generation.
- [ ] Send the APNs **device token** to the backend, tied to the auth identity.
- [ ] Handle notification tap → open the player via the existing deep link.
- [ ] List server-known (not-yet-downloaded) episodes; download audio on play.
- [ ] (Variant B only) Background-push handler + background `URLSession` download.
## Tradeoff to accept
Server-driven means the **backend takes on per-user episode state** (catalog +
device registry), whereas today the client owns everything locally in
`PodcastIndex` keyed by URL hash. That's a real backend scope increase — but it
also enables **multi-device sync** for free.
## Irreducible client pieces (Apple requirements)
- The APNs **device-token handshake** cannot move to the server.
- Notifications require user permission; fall back to the in-app "Generating…"
banner when denied.
## Relationship to shipped work
- Builds on background generation (#2) and share-extension auto-generate (#3):
the share extension enqueues server-side, the backend generates and pushes.
- Badge/clear coordinates with the unread-count item in #6.
admin
changed title from Episode-ready notification + true background generation (BGTask) to Episode-ready push notification (server-driven, no client polling/BGTask)2026-07-01 17:43:55 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Notify the user when a podcast is ready via a server-sent APNs push, and let
generation complete without the app staying alive. Because generation already
runs server-side, this replaces the client-side poll/BGTask approach entirely:
the backend knows when a job finishes and simply tells the device.
This supersedes the original BGTask design — polling
podcastStatusand runninga background task on the client goes away.
Why server-driven
The compute already happens on the magicive.api backend. Today the app only does
the bookkeeping around it — poll status, download the mp3, write
PodcastIndex,and (in the old plan) a BGTask to keep that alive. Move the "when is it done"
signal to APNs and almost all of that disappears.
Recommended approach — Variant A: download-on-play
"Your podcast on
Episode-ready notification + true background generation (BGTask)to Episode-ready push notification (server-driven, no client polling/BGTask)