Files
crowd-funder-for-time-pwa/doc/notification-debug-panel.md
Jose Olarte III c84cce54af Document the retired WAKEUP_PING refresh path as inactive and drop unused refresh auth helpers.
Guides and the debug panel still described /notifications/refresh and api_* scheduling as current after Phase 5; keep Phase 4 cleanup and FCM send-wakeup diagnostics.
2026-09-24 22:35:48 +08:00

12 KiB

Notification Debug Panel

Created: 2026-07-07
Updated: 2026-09-24
Audience: Developers testing notification registration, AlertSearch authorization upload, and FCM delivery diagnostics on native (iOS/Android) dev builds.

The Notification Debug Panel is a dev-only UI for FCM token registration, AlertSearch authorization upload, FCM wakeup delivery diagnostics (/debug/send-wakeup), and local schedule inspection. It does not schedule notifications from WAKEUP_PING. The production WAKEUP_PING → /notifications/refresh → api_* path was retired; leftover api_* schedules are cleared once at startup (Phase 4).


Notification API base URL

Notification HTTP calls (/notifications/register, /notifications/alert-authorization, /debug/send-wakeup, etc.) do not use APP_SERVER. They use a dedicated Notification API host, resolved at runtime by getNotificationApiBaseUrl() in NotificationDebugConfig.ts. The app does not call /notifications/refresh.

Configuration constants

Symbol Location Purpose
VITE_DEFAULT_NOTIFY_API_SERVER .env.development / .env.test / .env.production Build-time default Notification API URL for that Vite mode (same pattern as other VITE_DEFAULT_* backends)
DEFAULT_NOTIFY_API_SERVER src/constants/app.ts Runtime constant: import.meta.env.VITE_DEFAULT_NOTIFY_API_SERVER || AppString.PROD_NOTIFY_API_SERVER
AppString.PROD_NOTIFY_API_SERVER src/constants/app.ts Hardcoded production fallback: https://notify-api.timesafari.app
AppString.TEST_NOTIFY_API_SERVER src/constants/app.ts Hardcoded test host: https://test-notify-api.timesafari.app (for explicit UI/debug use; not the automatic fallback)

Production, test, and development builds get different Notification API URLs from their respective .env.* files. Runtime request code always goes through DEFAULT_NOTIFY_API_SERVER (via getNotificationApiBaseUrl()), not by reading the env var directly at each call site.

Typical values today:

Build / env file VITE_DEFAULT_NOTIFY_API_SERVER
.env.production https://notify-api.timesafari.app
.env.test https://test-notify-api.timesafari.app
.env.development https://test-notify-api.timesafari.app

URL resolution order

getNotificationApiBaseUrl() selects the base URL in this order:

  1. Debug Panel backend override — localStorage key notificationDebug.backendBaseUrl (set via Save Backend URL or setBackendBaseUrl())
  2. VITE_DEFAULT_NOTIFY_API_SERVER — baked into the build as part of DEFAULT_NOTIFY_API_SERVER
  3. AppString.PROD_NOTIFY_API_SERVER — hardcoded fallback when the env var is unset (https://notify-api.timesafari.app)

Clearing the Debug Panel override (empty field + Save) returns the app to step 2 / 3 (DEFAULT_NOTIFY_API_SERVER). The override never changes auth behavior by itself.

APP_SERVER / VITE_APP_SERVER remain for deep links and the main app web host only — not for notification API traffic.


Access

  1. Use a non-production build (for example build:android:dev, build:ios:dev, or vite dev with a non-production mode).
  2. Open Account → enable Show All General Advanced Functions.
  3. Open Notification Debug Panel (route /dev/notifications).

On native platforms, grant notification permission when prompted so FCM token registration and the debug actions work.


Configuration (Backend Testing)

Settings persist in localStorage via NotificationDebugConfig.ts:

Key Default Purpose
notificationDebug.backendBaseUrl (unset — use DEFAULT_NOTIFY_API_SERVER) Override which notification server receives API calls
notificationDebug.testMode true Sent in JSON request bodies (testMode: true/false)
notificationDebug.bypassAuth false When true, omit JWT Authorization headers on notification API calls

All notification API requests (/notifications/register, /notifications/alert-authorization, /debug/send-wakeup, etc.) obtain headers through getNotificationApiHeaders() in notificationApiAuth.ts.

Notification Backend URL

Paste a base URL (no trailing slash) and tap Save Backend URL. This changes only which server the app calls (getNotificationApiBaseUrl()). It does not disable JWT authentication.

Leave empty to use the configured build default (DEFAULT_NOTIFY_API_SERVER, from VITE_DEFAULT_NOTIFY_API_SERVER or AppString.PROD_NOTIFY_API_SERVER). The Debug Panel override still wins whenever a non-empty URL is saved.

Test Mode

When enabled (default if never saved), register and send-wakeup requests include "testMode": true in the JSON body. The backend can use this to route test traffic separately from production.

Test Mode is independent of authentication. It does not control whether Authorization headers are sent.

Skip JWT Authentication (Local Development Only)

When off (default), the app resolves the active DID and sends Authorization: Bearer … on notification API calls.

When on, requests include only Content-Type: application/json — for local servers (localhost or ngrok) that intentionally accept unauthenticated notification requests during development.

Enable this only for local development backends that do not require JWT. Hosted shared test servers that require normal app authentication should leave this off.

The panel Backend Status section shows the active URL, testMode, and bypassAuth values.


Hosted test server

Example: https://test-notify-api.timesafari.app

On development and test builds, this host is already the default via VITE_DEFAULT_NOTIFY_API_SERVER. You can leave Notification Backend URL empty, or paste the same URL explicitly.

Setting Value
Notification Backend URL Empty (use default) or https://test-notify-api.timesafari.app
Test Mode ON (if the server expects testMode: true)
Skip JWT Authentication OFF

Ensure the app has an active identity (DID) with a valid endorser session so JWT headers can be built.

Local localhost / ngrok development

Example: https://abc123.ngrok-free.app or http://127.0.0.1:3000

Setting Value
Notification Backend URL Your local or ngrok URL
Test Mode ON or OFF — match what your local notification-wakeup-service expects
Skip JWT Authentication ON only if the local server accepts unauthenticated requests; OFF if it validates JWT like production

Backend Testing actions

Action What it does
Register Token Now POST {backend}/notifications/register with current FCM token, deviceId, platform, and testMode. Forces re-registration (bypasses duplicate-token skip).
Upload AlertSearch Authorization Mints and uploads delegated AlertSearch JWTs (POST /notifications/alert-authorization). Requires an active did:ethr identity; Test Mode is not used.
Send Real WAKEUP_PING POST {backend}/debug/send-wakeup; server sends a real FCM data message with data.type = "WAKEUP_PING". FCM delivery diagnostic only — the app logs push handler ignored type=… and does not call /notifications/refresh or schedule api_* notifications. Background the app before expecting delivery.

Current FCM Token displays the last token from Capacitor/Firebase registration. Event Log shows the last 100 [Notifications] messages (also visible in logcat / Xcode console on native).


Other panel sections

Section Purpose
Pending Notification Inspector Lists locally scheduled notifications (Daily Reminder, New Activity / dual, and any leftover api_* until Phase 4 cleanup).
Clear Notifications Clears/cancels plugin-scheduled notifications on native. Does not replace the one-time api_* startup cleanup.

Programmatic override (optional)

From a WebView dev console (chrome://inspect on Android, Safari Web Inspector on iOS):

import {
  setBackendBaseUrl,
  setTestMode,
  setBypassAuth,
  getNotificationApiBaseUrl,
} from "@/services/notifications";

setBackendBaseUrl("https://abc123.ngrok-free.app");
setTestMode(true);
setBypassAuth(true); // local dev only
getNotificationApiBaseUrl();

Troubleshooting

401 Unauthorized (registerToken failed: unauthorized)

Likely causes: JWT required but Skip JWT Authentication is off and the session is missing or expired; or JWT sent but the server rejected it.

Checks:

  1. Panel Backend Status → bypassAuth: false for hosted servers.
  2. App has an active DID and endorser login.
  3. Event Log: look for Using authenticated notification request vs Using debug unauthenticated notification request.
  4. For hosted test server: keep Skip JWT Authentication OFF.

Fixes: Sign in / restore identity; refresh endorser session; for local ngrok without JWT support, enable Skip JWT Authentication.

registerToken auth unavailable / Waiting for auth before registration

The app deferred registration because JWT could not be built (no active DID or empty token) and Skip JWT Authentication is off.

Fixes: Complete identity setup in the app, or enable Skip JWT Authentication only for an intentionally unauthenticated local backend.

Failed to fetch / network error

Likely causes: Backend down, wrong URL, stale ngrok tunnel, device offline, or TLS/certificate issues.

Checks: Panel Backend Status URL; curl -sS "$URL/health" from your machine; ngrok inspect UI for incoming requests.

Fixes: Restart backend and ngrok; Save Backend URL with the current HTTPS forwarding URL (no trailing slash).

Backend unreachable / no requests in ngrok

Same as above. Confirm the Active URL in the panel matches your running tunnel or local server port.

Register succeeds but Send Real WAKEUP_PING does not show delivery

Real WAKEUP_PING success only means the backend accepted the wakeup request and attempted FCM delivery. It does not schedule local api_* notifications. Delivery is confirmed when logcat / Event Log shows push handler ignored type=WAKEUP_PING (the retired refresh chain is gone).

Checks: App backgrounded (not force-stopped); FCM token matches registration; Firebase / Play services available.

See platform-specific guides for extended ngrok and FCM workflows:


Key source files

File Purpose
src/constants/app.ts DEFAULT_NOTIFY_API_SERVER, PROD_NOTIFY_API_SERVER, TEST_NOTIFY_API_SERVER
src/components/dev/NotificationDebugPanel.vue Dev UI
src/services/notifications/NotificationDebugConfig.ts Base URL resolution, testMode, bypassAuth persistence
src/services/notifications/notificationApiAuth.ts JWT vs unauthenticated headers
src/services/notifications/notificationApiDebugMode.ts Auth bypass gate
src/services/notifications/NotificationDebugService.ts Panel action handlers
src/services/notifications/NotificationService.ts POST /notifications/register
src/services/notifications/NativeNotificationService.ts Push delivery hook (logs ignored types; no refresh)