From 98960d2827b8b54a9360754c9f3ed8a5fbbae12f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Padez?= Date: Wed, 19 Aug 2026 18:59:13 +0000 Subject: [PATCH] app spec: the answers from the app repo, and alpha caught up MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit three questions answered from monorepo-mobile, and two of my assumptions were wrong. bundle ids exist — dev.officer.mobile and dev.officer.mobile.dev. two of them needs nothing special: push_devices is unique on (token, bundleId), so the variants are separate rows on one phone, and the dev variant is exactly the sandbox/production distinction the doc warned about. concrete now rather than derived from build config by guesswork. scheme is officer:// and officer-dev://, both from app.config.ts. expo prebuild, not bare — and a config plugin that creates an ios app extension target ALREADY EXISTS there, withVaultAutofillTarget.js for the autofill extension. the nse follows it. that removes what i had called the longest pole in phase 3. corrected: expo-notifications is not in apps/mobile at all, only apps/chat. the real blocker is narrower than the doc implied and is not code. today's signed build has no aps-environment entitlement, and adding one fails while xcode has no account signed in — same failure as the network extension on 2026-08-05. one manual sign-in, team RGHC4NJC77, then automatic again. alpha: /api/notify was 404 all day because that server predated the work. pulled, db:push, gen:ecosystem, officer-notify started, officer restarted. verified 401 unauthenticated and push_devices with its 10 columns. --- docs/push-notifications-app.md | 53 ++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 9 deletions(-) diff --git a/docs/push-notifications-app.md b/docs/push-notifications-app.md index f5f42714..c7a04f1a 100644 --- a/docs/push-notifications-app.md +++ b/docs/push-notifications-app.md @@ -15,6 +15,11 @@ the build order, and it does not repeat the reasoning. `{"ok":true,"channels":[]}` and every send is a silent no-op that returns success. **A green response does not mean a push was sent** — check `channels` first, or you will debug the app for a day over a server with no key. +- **Alpha is up to date as of 2026-08-19 19:xx.** `/api/notify/*` answered `404` there for most of the day + because the server predated this work; it now answers `401` unauthenticated, `push_devices` has its 10 + columns, and `officer-notify` is running. If you get a `404`, that server needs `git pull` + + `pm2 restart officer`, and `officer-notify` needs starting — it is a new core process, so an existing + install will not have it until `bun gen:ecosystem` runs. ## Which app @@ -31,7 +36,7 @@ work, nothing later will, and everything later is harder to debug. ### 1. iOS project setup -- A bundle id for `apps/mobile` (only `dev.officer.music` was ever confirmed to exist — check). +- A bundle id for `apps/mobile` — **confirmed: `dev.officer.mobile`**, plus `dev.officer.mobile.dev`. - `aps-environment` entitlement. Do **not** copy chat's plugin here; the hub needs the opposite. - Push capability on the App ID in the developer portal, and a provisioning profile that includes it. @@ -143,14 +148,15 @@ longer installed and stop. **One build, ever.** The extension is a generic resolver — it must never `switch` on known codes, or every new notification kind becomes an app store release, which is the entire thing this design exists to avoid. -Note for Expo: a custom NSE needs a config plugin (`expo-notifications` alone does not give you one). Worth -scoping early — it may be the longest pole in Phase 3. +Expo: `ios/` is generated by prebuild, so the NSE target comes from a config plugin. **One already exists +in this repo** — `packages/bw-vault/plugin/withVaultAutofillTarget.js` creates the AutoFill extension +target. Follow it rather than inventing one. ## Phase 4 — deep linking `route` from the mapping is the destination. Tapping a notification opens the hub, which routes onward to -the target app or screen. Confirm the scheme with the owner — the platform uses `officer://` origins -for app surfaces, and I have not verified what `apps/mobile` registers today. +the target app or screen. The scheme is **`officer://`** (`officer-dev://` in the dev variant), from +`app.config.ts`. ## Android — later, but design for it now @@ -177,8 +183,37 @@ Android build and is not yours to absorb. - **`appSlug` means the deep-link destination**, not "which app receives this". The name is a leftover from the first design, where each app had its own token. -## Open questions for the owner +## Answered, from the app repo (2026-08-19) -1. Does `apps/mobile` have a bundle id and a provisioning profile with push enabled? -2. What URL scheme does `apps/mobile` register for deep links? -3. Is the hub in Expo managed or bare? It decides how the NSE gets built. +**Bundle ids exist.** `dev.officer.mobile`, and `dev.officer.mobile.dev` for the side-by-side dev variant. +Two bundle ids is fine and needs nothing special: `push_devices` is unique on `(token, bundleId)`, so the +two variants register as separate rows on the same phone. **Register the dev variant as +`environment: "sandbox"` and production as `"production"`** — that mapping is now concrete, so derive it +from the variant rather than the build config guesswork this document suggested earlier. + +**The URL scheme is `officer://`, and `officer-dev://` in the dev variant.** Both come from +`app.config.ts`, and the share extension embeds the same string natively, so they cannot desync. So the +unknown-code fallback deep link is `officer://resync-notification-mapping` as written. + +**Expo prebuild (CNG), not bare** — `ios/` is generated and gitignored; everything native comes from config +plugins. This is better news than the document assumed: **a config plugin that creates an iOS app-extension +target already exists in this repo**, `packages/bw-vault/plugin/withVaultAutofillTarget.js`, which builds +the AutoFill extension that prebuild cannot. **The NSE follows that pattern rather than being invented**, +which removes what this document called the longest pole in Phase 3. + +**`expo-notifications` is NOT in `apps/mobile`** — only in `apps/chat`, for local turn alerts. Correcting +this document's assumption. Chat's `withoutPushEntitlement.js` still stays exactly as described above; the +hub needs the opposite. + +## The one real blocker: the push entitlement + +Today's signed build (`2026.08.19.02`) has **no `aps-environment` entitlement at all**. Nothing else in +Phase 1 can be tested until it does. + +It has a known shape here. On 2026-08-05 adding a Network Extension failed for the same reason: +`-allowProvisioningUpdates` **cannot add a capability while Xcode has no account signed in**. The fix is a +one-time manual step by the owner — Xcode → Settings → Accounts, team `RGHC4NJC77` — after which it is +automatic again. + +**Owner action, and it is the critical path.** Along with the APNs `.p8`, this is the whole of what stands +between here and a banner on a phone.