docs(android): document Send Real WAKEUP_PING debug panel flow

Add §6 coverage for the full backend→FCM→refresh pipeline, expected
Logcat lines, and troubleshooting that distinguishes backend success
from end-to-end delivery; cross-link checklist, workflow, and §14.
This commit is contained in:
Jose Olarte III
2026-06-12 18:23:19 +08:00
parent 693bfacc1e
commit 6a7f341990

View File

@@ -291,7 +291,8 @@ The app normally calls `APP_SERVER` (from `VITE_APP_SERVER`). For local wakeup t
| **Test Mode** | Sends `testMode: true` on register/refresh (default on when unset in storage) |
| **Register Token Now** | `POST /notifications/register` with current FCM token and `platform: "android"` |
| **Refresh Notifications** | `POST /notifications/refresh` (same as post-wakeup flow) |
| **Simulate WAKEUP_PING** | Calls refresh API directly (no FCM) — quick backend + ngrok test |
| **Simulate WAKEUP_PING (Local)** | Calls refresh API directly (no FCM) — quick backend + ngrok test |
| **Send Real WAKEUP_PING** | `POST /debug/send-wakeup` on the backend override URL; server sends a real FCM `WAKEUP_PING` to the panels current FCM token (see below) |
| **Event Log** | Shared `[Notifications]` panel log (100 entries) |
Persistence: `localStorage` keys `notificationDebug.backendBaseUrl` and `notificationDebug.testMode` (`NotificationDebugConfig.ts`).
@@ -300,14 +301,59 @@ Persistence: `localStorage` keys `notificationDebug.backendBaseUrl` and `notific
When **Test Mode** is on (default if never saved), register and refresh requests include `"testMode": true`. The backend can route dev traffic separately from production. Turn it off in the panel only if you intentionally want production-mode API behavior against your tunnel.
### Two “Simulate WAKEUP_PING” buttons
### WAKEUP_PING debug controls
Three panel actions exercise different segments of the wakeup pipeline. Use them to bisect failures (see [Troubleshooting §14](#fcm-message-not-received)).
| Button | Behavior |
|--------|----------|
| **Backend Testing → Simulate WAKEUP_PING** | Skips FCM; calls refresh API only (ngrok path test) |
| **Wakeup Ping Simulator** (lower on panel) | Runs production handler with synthetic `WAKEUP_PING` payload |
| **Backend Testing → Simulate WAKEUP_PING (Local)** | Skips FCM; calls refresh API only (ngrok path test) |
| **Backend Testing → Send Real WAKEUP_PING** | Full pipeline: backend `/debug/send-wakeup` → FCM → Capacitor listener → refresh (see below) |
| **Wakeup Ping Simulator** (lower on panel) | Runs production handler with synthetic `WAKEUP_PING` payload (no FCM, no backend wakeup call) |
Use the backend button to verify ngrok + refresh; use the simulator to verify handler + refresh chaining without FCM.
Use **Simulate WAKEUP_PING (Local)** to verify ngrok + refresh; use **Wakeup Ping Simulator** to verify handler + refresh chaining without FCM; use **Send Real WAKEUP_PING** for end-to-end FCM delivery on device.
### Send Real WAKEUP_PING
**Send Real WAKEUP_PING** is the in-app equivalent of calling **`POST /debug/send-wakeup`** from the Mac (see [Verification Checklist step 7](#7-manual-wakeup-endpoint-sends-fcm-successfully)). It is intended for **local testing and diagnostics** on non-production builds only.
**What it does:**
1. Reads the **Current FCM Token** shown in the panel (same token used by **Register Token Now**). If no token is available, the action fails with a panel status message.
2. `POST`s to `{backend override}/debug/send-wakeup` with `deviceId`, `fcmToken`, `platform: "android"`, and `testMode` from the panel config (`NotificationDebugService.sendRealWakeupPing()`).
3. On HTTP success, the **notification-wakeup-service** enqueues a real FCM **data** message with `data.type = "WAKEUP_PING"` to that device.
4. When FCM delivers the message to the app, Capacitor fires `pushNotificationReceived` → `handleCapacitorPushNotificationReceived()` → `refreshNotificationsWithDiagnostics({ source: "WAKEUP_PING" })` → `POST /notifications/refresh` → `applyNotificationRefreshPayload()` (clear + reschedule via **daily-notification-plugin**).
That exercises the full **backend → FCM → Capacitor push listener → refresh request → notification rescheduling** path on Android without manual `curl` on the Mac.
**Prerequisites:** ngrok backend override saved, **Test Mode** as needed, notification permission granted, **Register Token Now** succeeded, app **backgrounded** (Home — not force-stop) before expecting FCM delivery ([§8](#8-android-platform-notes)).
#### Expected Logcat output
Filter logcat (prefix is always `[Notifications]`):
```bash
adb logcat | grep -E '\[Notifications\].*(Real WAKEUP_PING|pushNotificationReceived|WAKEUP_PING|Refresh started|Refresh completed)'
```
On a **successful end-to-end** run (HTTP success from the panel, then FCM delivery within ~30120s), expect these key lines in order:
```
[Notifications] Real WAKEUP_PING requested
[Notifications] Real WAKEUP_PING success
[Notifications] pushNotificationReceived type=WAKEUP_PING
[Notifications] WAKEUP_PING handler — invoking refresh
[Notifications] Refresh started (WAKEUP_PING)
[Notifications] Refresh completed (WAKEUP_PING) in …ms (scheduled N)
```
Intermediate lines (e.g. `WAKEUP_PING received — will trigger refresh`, `Schedule replacement: …`, auth bypass messages) are normal. ngrok should also show a new `POST /notifications/refresh` after the push is handled.
#### Send Real WAKEUP_PING vs end-to-end success
The panel status **“Real WAKEUP_PING sent via backend.”** and the Event Log line **`Real WAKEUP_PING success`** only confirm that the backend **accepted the request and attempted FCM delivery**. They do **not** prove the device received the push or ran refresh.
**Successful end-to-end delivery** is confirmed only when the subsequent **`pushNotificationReceived`**, **`WAKEUP_PING handler`**, and **`Refresh started (WAKEUP_PING)`** / **`Refresh completed (WAKEUP_PING)`** lines appear in logcat (or Event Log) within the delivery window. If you see `Real WAKEUP_PING success` but not those lines, treat it as an FCM delivery problem ([FCM message not received](#fcm-message-not-received)), not a backend enqueue failure.
### Programmatic override (optional)
@@ -408,7 +454,7 @@ Doze, App Standby, and OEM battery menus are weak or absent on many emulators. U
adb logcat | grep -E '\[Notifications\]|\[FirebaseMessaging\]|\[NativeNotificationService\]'
```
Expect `pushNotificationReceived type=WAKEUP_PING` and `WAKEUP_PING handler — invoking refresh` after a successful wake.
Expect `pushNotificationReceived type=WAKEUP_PING` and `WAKEUP_PING handler — invoking refresh` after a successful wake. For a panel-driven test, use **Send Real WAKEUP_PING** ([§6](#send-real-wakeup_ping)) instead of manual `curl`.
---
@@ -453,7 +499,7 @@ If wakeup works on a **Pixel** but fails on an OEM phone, assume battery policy
1. Server accepts `/debug/send-wakeup` → FCM enqueue succeeds.
2. Device may **hold** the message until Doze maintenance or OEM policy allows delivery.
3. `pushNotificationReceived` runs → `refreshNotificationsWithDiagnostics()` → ngrok `POST /notifications/refresh`.
4. Any step can lag under battery savers; use **Simulate WAKEUP_PING** in the debug panel to separate FCM delay from refresh/API issues.
4. Any step can lag under battery savers; use **Simulate WAKEUP_PING (Local)** in the debug panel to separate FCM delay from refresh/API issues; use **Send Real WAKEUP_PING** for the full FCM path ([§6](#send-real-wakeup_ping)).
---
@@ -466,9 +512,9 @@ If wakeup works on a **Pixel** but fails on an OEM phone, assume battery policy
5. Open **Notification Debug Panel** → paste ngrok URL → **Save Backend URL**; confirm **Test Mode** is on.
6. Tap **Register Token Now** → confirm ngrok `POST /notifications/register` and `[Notifications] Token registration success` in Event Log / logcat.
7. Tap **Refresh Notifications** → confirm `POST /notifications/refresh` and `Refresh completed in Nms (scheduled X)` in Event Log.
8. Optional: tap **Simulate WAKEUP_PING** (backend button) to verify ngrok + refresh without FCM.
9. From the Mac, call **`/debug/send-wakeup`** (see [curl examples](#13-sample-curl-commands)) with the registered `deviceId` / token as required by **notification-wakeup-service**.
10. Watch logcat for `WAKEUP_PING` and refresh timing lines.
8. Optional: tap **Simulate WAKEUP_PING (Local)** to verify ngrok + refresh without FCM.
9. Background the app (Home), then tap **Send Real WAKEUP_PING** (or from the Mac, call **`/debug/send-wakeup`** see [curl examples](#13-sample-curl-commands)) with the registered `deviceId` / token as required by **notification-wakeup-service**.
10. Watch logcat for `WAKEUP_PING` and `Refresh completed (WAKEUP_PING)` lines ([expected output](#expected-logcat-output)).
11. Open **ngrok inspect UI** (`http://127.0.0.1:4040`) to correlate HTTP traffic.
12. Use **Pending Notification Inspector** on the panel to confirm locally scheduled fires after refresh.
@@ -581,7 +627,9 @@ curl -sS -X POST "$BASE/notifications/refresh" \
**Actions:**
1. Use `deviceId` from step 4.
2. From the Mac:
2. Either:
- **On device:** background the app (Home), open **Notification Debug Panel**, tap **Send Real WAKEUP_PING**; or
- **From the Mac:**
```bash
curl -sS -X POST "$BASE/debug/send-wakeup" \
@@ -591,7 +639,7 @@ curl -sS -X POST "$BASE/debug/send-wakeup" \
3. Check **notification-wakeup-service** logs for FCM send success (no Admin SDK / token errors).
**Expected outcome:** HTTP **200** (or documented success code) from `/debug/send-wakeup`; server logs indicate FCM message enqueued/sent with `data.type = "WAKEUP_PING"`. This step alone does not prove device delivery (see step 8).
**Expected outcome:** HTTP **200** (or documented success code) from `/debug/send-wakeup`; Event Log / logcat: `Real WAKEUP_PING success` when using the panel button; server logs indicate FCM message enqueued/sent with `data.type = "WAKEUP_PING"`. This step alone does not prove device delivery (see step 8 and [Send Real WAKEUP_PING vs end-to-end success](#send-real-wakeup_ping-vs-end-to-end-success)).
---
@@ -600,7 +648,7 @@ curl -sS -X POST "$BASE/debug/send-wakeup" \
**Actions:**
1. **Background** the app (Home — not force-stop).
2. Run step 7 again (or wait for a server-driven wakeup).
2. Run step 7 again (panel **Send Real WAKEUP_PING** or Mac `curl`), or wait for a server-driven wakeup.
3. Filter logcat:
```bash
@@ -609,12 +657,13 @@ adb logcat | grep -E 'WAKEUP_PING|pushNotificationReceived|Refresh completed'
**Expected outcome (within ~30120s, longer under Doze/OEM):**
1. `pushNotificationReceived` / `WAKEUP_PING received`
1. `pushNotificationReceived type=WAKEUP_PING` / `WAKEUP_PING received`
2. `WAKEUP_PING handler — invoking refresh`
3. ngrok: new `POST /notifications/refresh`
4. `Refresh completed in …ms (scheduled N)`
3. `Refresh started (WAKEUP_PING)`
4. ngrok: new `POST /notifications/refresh`
5. `Refresh completed (WAKEUP_PING) in …ms (scheduled N)`
**Isolation:** **Wakeup Ping Simulator** on the panel should produce lines 24 without FCM. **Backend Testing → Simulate WAKEUP_PING** proves refresh only (no handler).
**Isolation:** **Wakeup Ping Simulator** on the panel should produce lines 25 without FCM. **Simulate WAKEUP_PING (Local)** proves refresh only (no handler, source `WAKEUP_PING simulation`). Full expected logcat for **Send Real WAKEUP_PING**: [§6](#expected-logcat-output).
---
@@ -687,9 +736,9 @@ npm run dev
13. Background app (Home).
14. Mac: `curl -X POST "$BASE/debug/send-wakeup" -H "Content-Type: application/json" -d '{"deviceId":"…","testMode":true}'` → server FCM success.
14. Tap **Send Real WAKEUP_PING** in the panel (or Mac: `curl -X POST "$BASE/debug/send-wakeup" -H "Content-Type: application/json" -d '{"deviceId":"…","testMode":true}'`) panel `Real WAKEUP_PING success` and server FCM enqueue success.
15. Within 30120s (longer if unplugged/Doze): logcat shows `WAKEUP_PING` → refresh; ngrok shows second `POST /notifications/refresh`.
15. Within 30120s (longer if unplugged/Doze): logcat shows `pushNotificationReceived` → `Refresh completed (WAKEUP_PING)`; ngrok shows second `POST /notifications/refresh`.
16. Pending Inspector **Refresh** → timestamps updated (replacement, not duplicate stack).
@@ -697,7 +746,7 @@ npm run dev
17. If `testMode` returned a trigger within a few minutes, wait for wall-clock fire with app backgrounded; confirm notification appears (permission + channel + exact alarm rules).
18. If FCM step 15 failed but step 11 passed: run **Simulate WAKEUP_PING** (backend) then **Wakeup Ping Simulator** to bisect FCM vs handler; see [Troubleshooting](#14-troubleshooting).
18. If FCM step 15 failed but step 11 passed: run **Simulate WAKEUP_PING (Local)** then **Wakeup Ping Simulator** to bisect FCM vs handler; see [Troubleshooting](#14-troubleshooting) and [Send Real WAKEUP_PING vs end-to-end success](#send-real-wakeup_ping-vs-end-to-end-success).
### End-to-end pass criteria
@@ -839,7 +888,7 @@ Compare with panel **Backend Status** and Event Log error text.
**Verification:**
1. **Simulate WAKEUP_PING** (backend button) — if this fails, problem is ngrok/refresh API, not FCM.
1. **Simulate WAKEUP_PING (Local)** — if this fails, problem is ngrok/refresh API, not FCM.
2. ngrok inspect for refresh status code and response body.
3. Logcat: `refreshNotifications failed` or JWT errors from `configureNativeFetcherIfReady()`.
@@ -849,15 +898,17 @@ Compare with panel **Backend Status** and Event Log error text.
### FCM message not received
**Symptoms:** `/debug/send-wakeup` returns success on Mac; no `pushNotificationReceived` / `WAKEUP_PING` in logcat within 2 minutes; refresh never triggered.
**Symptoms:** `/debug/send-wakeup` or panel **Send Real WAKEUP_PING** shows success (`Real WAKEUP_PING success` in Event Log); no `pushNotificationReceived` / `WAKEUP_PING` in logcat within 2 minutes; refresh never triggered.
**Likely causes:** Force-stopped app; wrong FCM token on server; Doze/OEM delay; no Google Play services; payload missing `data.type = "WAKEUP_PING"`; device offline.
**Note:** `Real WAKEUP_PING success` only means the backend accepted and sent the FCM request. Missing downstream refresh logs indicates a **delivery** failure, not a failed wakeup API call ([§6](#send-real-wakeup_ping-vs-end-to-end-success)).
**Verification:**
1. App **backgrounded** (Home), not force-stopped.
2. Panel FCM token matches token used by server/register.
3. **Simulate WAKEUP_PING** (backend button) works → isolates FCM path.
3. **Simulate WAKEUP_PING (Local)** works → isolates FCM path from refresh/API.
4. Wait 30120s (longer on Doze/OEM).
5. Battery **Unrestricted** and OEM autostart enabled for test device.