docs(mobile): document the full push-notification setup and its gotchas
Push notifications went from "wired but not deliverable" to fully working end-to-end this session. Records the three separate one-time setup pieces (EAS project id, FCM credentials baked at prebuild time, and the FCM V1 vs. Legacy service-account-key slot mixup that produced a confusing "Unable to retrieve the FCM server key" error) so a future session doesn't have to rediscover them. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fcb5ae3eef
commit
a890904b6c
1 file changed
+54
-16
+54
-16
@@ -17,10 +17,10 @@ comments, repost, pet profile detail (view/follow/edit/followers-following),
|
||||
stories (tray/creation/viewer), video playback, search, health tracking
|
||||
(consent gate + weight/vet/vaccine logs), milestones, and message
|
||||
sending/receiving are done and verified end-to-end against the live backend.
|
||||
Push notifications are wired end-to-end but not yet deliverable — see "Push
|
||||
notifications" below. Android is the priority platform; iOS builds need a
|
||||
Mac + Apple Developer account and come later (same codebase, no separate
|
||||
source tree — see "Android-first, then iOS" below).
|
||||
Push notifications are fully working — see "Push notifications" below.
|
||||
Android is the priority platform; iOS builds need a Mac + Apple Developer
|
||||
account and come later (same codebase, no separate source tree — see
|
||||
"Android-first, then iOS" below).
|
||||
|
||||
## Architecture
|
||||
|
||||
@@ -206,9 +206,10 @@ separately. "Starting with Android" means:
|
||||
budgeted in `../mobil.md`) before an internal test track can be created.
|
||||
- iOS needs a Mac (for `expo run:ios` / EAS builds with credentials) and an
|
||||
Apple Developer account (99 €/year) — deferred until Android is validated.
|
||||
- EAS Build (`eas.json`, not yet added) is the recommended path for
|
||||
producing signed Android/iOS binaries without a local Android
|
||||
Studio/Xcode toolchain; add it when a first real build is needed.
|
||||
- EAS Build (`eas.json` — added, currently just default profiles) is the
|
||||
recommended path for producing signed Android/iOS binaries without a
|
||||
local Android Studio/Xcode toolchain; no EAS Build has been run yet, the
|
||||
file only exists so far because `eas credentials` requires it.
|
||||
|
||||
## What's not built yet
|
||||
|
||||
@@ -229,17 +230,54 @@ emulator. Still missing, roughly in the order they'd unblock the most:
|
||||
|
||||
- No i18n — the whole app is hardcoded German text, matching the sign-in screen
|
||||
|
||||
### Push notifications — wired but not yet deliverable
|
||||
### Push notifications
|
||||
|
||||
`usePushNotifications` (in `app/_layout.tsx`) requests notification
|
||||
permission and registers the resulting Expo push token with the backend
|
||||
(`owner.registerPushToken`); `src/lib/notify.ts` on the web side sends a
|
||||
best-effort push through Expo's push API alongside every in-app
|
||||
Notification it creates (follow, reaction, comment, message, ...). Minting
|
||||
a real token needs an **EAS project id** (`app.json`'s
|
||||
`extra.eas.projectId`, set once via `eas init` — free, no EAS Build
|
||||
required, but does need an Expo account login). Until that's done, the
|
||||
permission prompt shows and is granted, but `getExpoPushTokenAsync` has
|
||||
nothing to attach to and the hook no-ops with a console warning
|
||||
(`[push] No EAS project id configured...`) — confirmed via `adb logcat` on
|
||||
2026-09-06. No Owner row has an `expoPushToken` set until this is run.
|
||||
Notification it creates (follow, reaction, comment, message, ...).
|
||||
Verified end-to-end on 2026-09-06: permission → real Expo push token →
|
||||
registered in the DB → delivered to the Android emulator's notification
|
||||
tray.
|
||||
|
||||
Getting here needed three separate one-time setup pieces, each easy to
|
||||
half-do and end up with a silent non-working state:
|
||||
|
||||
1. **EAS project id** (`app.json`'s `extra.eas.projectId`) — via
|
||||
`eas login` + `eas init --account pawfeed`. Without this,
|
||||
`getExpoPushTokenAsync` has nothing to attach to and the hook no-ops
|
||||
with `[push] No EAS project id configured...`.
|
||||
2. **FCM credentials for Android** (`app.json`'s `googleServicesFile` →
|
||||
`google-services.json`, gitignored — redownload from the Firebase
|
||||
Console's `org.pawfeed.app` Android app on a fresh clone). This is
|
||||
baked into the native project at `expo prebuild` time, so adding it
|
||||
needs a real rebuild (`expo prebuild --platform android` + `expo run:android`),
|
||||
unlike the EAS project id which the dev client picks up from a plain
|
||||
JS reload.
|
||||
3. **The FCM *service account key* uploaded to EAS** via
|
||||
`eas credentials -p android` (needs `eas.json` to exist first, hence
|
||||
that file). The credentials manager has two separate Android push
|
||||
slots — **"FCM Legacy"** (a plain API key string, and Google shut the
|
||||
underlying Legacy API down in 2024) and **"FCM V1"** (a Google Service
|
||||
Account JSON key, what Firebase Console's "generate new private key"
|
||||
actually gives you). Uploading the service-account JSON to the wrong
|
||||
slot leaves EAS's send API returning
|
||||
`Unable to retrieve the FCM server key for the recipient's app` even
|
||||
though a real push token exists and permission is granted — that
|
||||
symptom means step 3 landed in the wrong slot, not that steps 1–2 are
|
||||
broken.
|
||||
|
||||
Also note: `getExpoPushTokenAsync` can hang indefinitely rather than
|
||||
reject if the device can't reach Google's registration backend — the hook
|
||||
wraps it in a 15s timeout so a real failure surfaces instead of permanent
|
||||
silence.
|
||||
|
||||
**Deploy note:** `owner.registerPushToken` is a *web* backend change.
|
||||
Since the mobile app's default `EXPO_PUBLIC_API_URL` is the live
|
||||
`pawfeed.org` deployment, this endpoint doesn't exist there until the web
|
||||
app is redeployed too (`ssh` to the NAS, `git pull`, `./docker/rolling-deploy.sh`
|
||||
— see root `CLAUDE.md`'s deployment section). This is the one case where
|
||||
a "mobile" feature session still needs a web deploy — [[project_mobile_deployment_target]]'s
|
||||
"mobile changes need no NAS deploy" is about `mobile/` code itself, not
|
||||
backend endpoints mobile happens to call.
|
||||
Reference in new issue
Block a user