545 lines
24 KiB
Markdown
545 lines
24 KiB
Markdown
# Local iOS Testing with ngrok (notification-wakeup-service)
|
||
|
||
**Last updated:** 2026-05-18
|
||
**Audience:** Developers on **crowd-funder-for-time-pwa**, **daily-notification-plugin**, and **notification-wakeup-service**
|
||
**Goal:** Exercise silent push wake (`WAKEUP_PING`), FCM token registration, and notification refresh against a Mac-hosted backend reachable from a physical iPhone.
|
||
|
||
---
|
||
|
||
## Architecture overview
|
||
|
||
End-to-end flow when testing New Activity / silent wake on a physical iPhone:
|
||
|
||
```text
|
||
┌─────────────────────┐ HTTPS ┌──────────────────────┐
|
||
│ Mac (localhost) │ ◄───────────── │ ngrok edge │
|
||
│ notification- │ tunnel │ (public HTTPS URL) │
|
||
│ wakeup-service │ └──────────┬───────────┘
|
||
└──────────┬──────────┘ │
|
||
│ │ fetch
|
||
│ POST /notifications/refresh │ POST /notifications/register
|
||
│ ▼
|
||
│ ┌──────────────────────┐
|
||
│ │ crowd-funder-for- │
|
||
│ │ time-pwa (Capacitor │
|
||
│ │ iOS on iPhone) │
|
||
│ └──────────┬───────────┘
|
||
│ │
|
||
│ FCM data message (WAKEUP_PING) │ daily-notification-plugin
|
||
▼ ▼ (local schedule replace)
|
||
┌─────────────────────┐ ┌──────────────────────┐
|
||
│ Firebase Cloud │ ──APNs──────► │ iPhone (physical) │
|
||
│ Messaging │ silent push │ app.timesafari │
|
||
└─────────────────────┘ └──────────────────────┘
|
||
```
|
||
|
||
### Repos and responsibilities
|
||
|
||
| Repo | Role |
|
||
|------|------|
|
||
| **notification-wakeup-service** | HTTP API: device registration, refresh payload (`nextNotifications`), health, debug wakeup send |
|
||
| **crowd-funder-for-time-pwa** | Capacitor app: FCM token, `POST /notifications/register` & `/refresh`, handles `WAKEUP_PING` push |
|
||
| **daily-notification-plugin** | Native iOS/Android: clear + reschedule local notifications from refresh timestamps |
|
||
|
||
### Silent wake sequence (production path)
|
||
|
||
1. Backend (or `/debug/send-wakeup`) sends an FCM **data** message with `data.type = "WAKEUP_PING"`.
|
||
2. APNs delivers to the device (best-effort; see iOS caveats below).
|
||
3. Capacitor `pushNotificationReceived` fires → `handleCapacitorPushNotificationReceived()`.
|
||
4. App calls `POST {backend}/notifications/refresh` with `testMode` (from debug config).
|
||
5. Backend returns `nextNotifications: [{ timestamp }, ...]`.
|
||
6. App calls `applyNotificationRefreshPayload()` → plugin clears and schedules new local alarms.
|
||
|
||
Console and debug panel lines are prefixed with **`[Notifications]`** (see `NotificationDebugEvents.ts`).
|
||
|
||
---
|
||
|
||
## Prerequisites
|
||
|
||
- Mac with Xcode, Node.js 18+, and the **notification-wakeup-service** repo cloned and runnable
|
||
- Physical iPhone (USB or wireless debugging) — **simulator is not sufficient** for reliable silent push / APNs behavior
|
||
- ngrok account (free tier is enough for dev)
|
||
- Firebase project with APNs configured for the iOS app bundle ID
|
||
- Non-production app build (Notification Debug Panel is dev-only)
|
||
|
||
---
|
||
|
||
## 1. Install and configure ngrok (macOS)
|
||
|
||
### Install
|
||
|
||
```bash
|
||
# Homebrew
|
||
brew install ngrok/ngrok/ngrok
|
||
```
|
||
|
||
Or download from [https://ngrok.com/download](https://ngrok.com/download).
|
||
|
||
### Account and auth token
|
||
|
||
1. Sign up at [https://dashboard.ngrok.com/signup](https://dashboard.ngrok.com/signup).
|
||
2. Copy your authtoken from **Your Authtoken** in the dashboard.
|
||
3. Configure the CLI:
|
||
|
||
```bash
|
||
ngrok config add-authtoken YOUR_AUTHTOKEN_HERE
|
||
```
|
||
|
||
### Start a tunnel to the wakeup service
|
||
|
||
Assume the service listens on port **3000** (confirm in **notification-wakeup-service** `README` or `.env`).
|
||
|
||
If the service already defaults to port 3000 internally, you may not need to export PORT manually.
|
||
|
||
```bash
|
||
# Terminal A — backend
|
||
cd /path/to/notification-wakeup-service
|
||
|
||
npm install
|
||
|
||
# one-time setup if needed
|
||
cp .env.example .env
|
||
|
||
# configure Firebase/service account/etc as required
|
||
export PORT=3000
|
||
|
||
npm run dev
|
||
```
|
||
|
||
```bash
|
||
# Terminal B — ngrok
|
||
ngrok http 3000
|
||
```
|
||
|
||
The backend only needs to be started once. The dedicated backend section below exists for verification and troubleshooting details, not as a second startup step.
|
||
|
||
ngrok prints a forwarding URL, for example:
|
||
|
||
```text
|
||
Forwarding https://abc123.ngrok-free.app -> http://localhost:3000
|
||
```
|
||
|
||
Use the **HTTPS** URL (not `http://127.0.0.1:3000`). The iPhone cannot reach your Mac’s localhost without the tunnel.
|
||
|
||
> **Note:** Free ngrok URLs change every time you restart ngrok unless you use a reserved domain (paid). Update the app debug override whenever the URL changes.
|
||
|
||
---
|
||
|
||
## 2. Start the backend locally
|
||
|
||
Example (adjust to match **notification-wakeup-service**). On first setup, copy `.env.example` to `.env` and set Firebase service account, `PORT`, and other variables per that repo's docs.
|
||
|
||
If the backend is not already running from section 1:
|
||
|
||
```bash
|
||
# If not already running from the previous step:
|
||
cd /path/to/notification-wakeup-service
|
||
npm run dev
|
||
```
|
||
|
||
Verify locally before ngrok:
|
||
|
||
```bash
|
||
curl -sS http://localhost:3000/health
|
||
```
|
||
|
||
Expected: HTTP 200 and a JSON body indicating the service is up (exact shape depends on that repo).
|
||
|
||
---
|
||
|
||
## 3. Obtain and use the ngrok HTTPS URL
|
||
|
||
1. Run `ngrok http <PORT>`.
|
||
2. Copy the `https://….ngrok-free.app` host from the **Forwarding** line.
|
||
3. Do **not** add a trailing slash when saving in the app (the debug config trims it).
|
||
4. Optional: open `http://127.0.0.1:4040` (ngrok web UI) to inspect requests and responses while testing.
|
||
|
||
Test through the tunnel from your Mac:
|
||
|
||
```bash
|
||
export NGROK_URL="https://abc123.ngrok-free.app"
|
||
curl -sS "$NGROK_URL/health"
|
||
```
|
||
|
||
---
|
||
|
||
## 4. Generate and open the iOS workspace
|
||
|
||
From **crowd-funder-for-time-pwa**, generate the Capacitor iOS project and open it in Xcode. **[Section 5](#5-firebase--apns-setup-first-time-setup) (Firebase + APNs)** needs this workspace—for example to add `GoogleService-Info.plist` and enable Push Notifications in the app target. The app does not need Firebase or push fully configured yet; the goal here is a buildable Xcode project on your Mac.
|
||
|
||
```bash
|
||
npm install
|
||
npm run build:ios:dev # or build:ios:test — non-production for debug panel
|
||
```
|
||
|
||
Open the generated Xcode workspace (for example `ios/App/App.xcworkspace`), select your **physical iPhone**, enable signing, and Run when you are ready to verify the app launches.
|
||
|
||
Ensure `VITE_FIREBASE_*` variables are set for the Capacitor build you use (see `.env` / build docs). Native push registration runs at startup via `initializeNativePushAndFirebaseMessaging()` in `main.capacitor.ts` once Firebase is configured in the next section.
|
||
|
||
---
|
||
|
||
## 5. Firebase + APNs setup (first-time setup)
|
||
|
||
Complete this section once before your first physical-device push test. If Firebase and APNs are already configured for this app, skip to [section 6](#6-configure-the-notification-debug-panel-backend-override).
|
||
|
||
### Create or access a Firebase account
|
||
|
||
1. Sign in with a Google account at [https://console.firebase.google.com/](https://console.firebase.google.com/).
|
||
|
||
2. If this is your first time using Firebase:
|
||
- Accept the Firebase terms.
|
||
- Create a new Firebase account/workspace when prompted.
|
||
|
||
3. No paid Firebase plan is required for local iOS notification testing. The free **Spark** plan is sufficient for:
|
||
- Firebase Cloud Messaging (FCM)
|
||
- APNs silent push testing
|
||
- local ngrok-based development
|
||
|
||
### Create a Firebase project
|
||
|
||
1. In the [Firebase Console](https://console.firebase.google.com/), click **Add project** (or **Create a project**).
|
||
2. Enter a project name (for example, `timesafari-dev`) and continue through the wizard.
|
||
3. **Google Analytics** is optional for this workflow; you can disable it for a simpler dev project.
|
||
4. When the project is created, open it. **Cloud Messaging** is available on all projects — you do not need a separate enable step for FCM.
|
||
|
||
### Register the iOS app in Firebase
|
||
|
||
1. In the project overview, click the **iOS** icon (**Add app** → iOS).
|
||
2. Enter the **Apple bundle ID**. It must **exactly** match the Capacitor / Xcode app ID:
|
||
- **`app.timesafari`** (see `appId` in `capacitor.config.ts` and the Xcode target **Bundle Identifier**).
|
||
3. App nickname and App Store ID are optional for local testing; continue.
|
||
4. Download **`GoogleService-Info.plist`** when prompted and keep it handy for the next step.
|
||
|
||
### Add GoogleService-Info.plist to Xcode
|
||
|
||
1. Open the iOS workspace you generated in [section 4](#4-generate-and-open-the-ios-workspace) (for example `ios/App/App.xcworkspace`).
|
||
2. In the Project Navigator, drag **`GoogleService-Info.plist`** into the **App** folder (the same one that contains AppDelegate.swift and Info.plist).
|
||
3. In the dialog that appears:
|
||
- Check **Copy items if needed** (so the file is copied into the project tree).
|
||
- Under **Add to targets**, ensure the main app target (not only the share extension) is checked.
|
||
4. Confirm the file appears under the app target in Xcode and is listed in **Build Phases** → **Copy Bundle Resources** if your project uses that phase for plists.
|
||
|
||
### Create an APNs Authentication Key
|
||
|
||
Apple uses APNs to deliver pushes to devices; Firebase needs an APNs key to talk to Apple on your behalf.
|
||
|
||
1. Sign in to [Apple Developer](https://developer.apple.com/account/) → **Certificates, Identifiers & Profiles**.
|
||
2. Open **Keys** → **+** (create a new key).
|
||
3. Name the key (for example, `Timesafari APNs Dev`).
|
||
4. Enable **Apple Push Notifications service (APNs)** and continue.
|
||
5. Register the key, then **Download** the `.p8` file. **You can download it only once** — store it securely.
|
||
6. Note:
|
||
- **Key ID** (shown on the key detail page)
|
||
- **Team ID** (top right of the developer portal, or **Membership** details)
|
||
|
||
### Upload APNs key to Firebase
|
||
|
||
1. Firebase Console → your project → **Project settings** (gear icon).
|
||
2. Open the **Cloud Messaging** tab.
|
||
3. Under **Apple app configuration**, select your iOS app (`app.timesafari`) if prompted.
|
||
4. Under **APNs Authentication Key**, click **Upload**.
|
||
5. Select the `.p8` file and enter:
|
||
- **Key ID**
|
||
- **Team ID**
|
||
6. Save. Firebase can now send FCM messages through APNs to your iOS app.
|
||
|
||
### Enable iOS capabilities in Xcode
|
||
|
||
1. Select the **App** target → **Signing & Capabilities**.
|
||
2. Click **+ Capability** and add **Push Notifications**.
|
||
3. Click **+ Capability** again and add **Background Modes**.
|
||
4. Under Background Modes, enable **Remote notifications**.
|
||
|
||
These match what silent / data wake flows expect for background delivery.
|
||
|
||
### Configure Firebase Admin for the backend
|
||
|
||
**notification-wakeup-service** uses the Firebase Admin SDK to send FCM (and thus APNs) messages from your Mac.
|
||
|
||
1. Firebase Console → **Project settings** → **Service accounts**.
|
||
2. Click **Generate new private key** and confirm download of the JSON file.
|
||
3. Store the JSON outside the repo (do not commit it).
|
||
4. Point the backend at it, for example:
|
||
|
||
```bash
|
||
export GOOGLE_APPLICATION_CREDENTIALS="/absolute/path/to/service-account.json"
|
||
```
|
||
|
||
The backend uses this credential to authenticate with Firebase when calling endpoints such as `/debug/send-wakeup`. Set the same variable (or the equivalent env var documented in **notification-wakeup-service**) in the shell where you run `npm run dev`, or add it to that repo’s `.env` per its README.
|
||
|
||
### Verify Firebase configuration
|
||
|
||
Before ngrok end-to-end testing, confirm:
|
||
|
||
- [ ] App builds and launches on a **physical** iPhone without Firebase/plist errors in Xcode.
|
||
- [ ] iOS shows the push **permission** prompt (or Settings → app → Notifications is enabled).
|
||
- [ ] **Notification Debug Panel** shows an FCM token (after permission).
|
||
- [ ] **Register Token Now** succeeds and ngrok (or local backend) shows `POST /notifications/register`.
|
||
- [ ] Backend health and Firebase Admin env are set so `/debug/send-wakeup` can run when you reach that step in the workflow below.
|
||
|
||
---
|
||
|
||
## 6. Configure the Notification Debug Panel backend override
|
||
|
||
|
||
The app normally calls `DEFAULT_NOTIFY_API_SERVER` (from `VITE_DEFAULT_NOTIFY_API_SERVER`, falling back to `AppString.PROD_NOTIFY_API_SERVER`). That is independent of `APP_SERVER`. For local wakeup testing, override the notification API base URL in the Debug Panel without rebuilding.
|
||
|
||
For a full panel reference (configuration, URL resolution order, authentication, and troubleshooting), see [notification-debug-panel.md](./notification-debug-panel.md).
|
||
|
||
### Open the panel
|
||
|
||
1. Use a **non-production** bundle (e.g. dev/test build).
|
||
2. **Account** → enable **Show All General Advanced Functions**.
|
||
3. Open **Notification Debug Panel** (route `/dev/notifications`).
|
||
|
||
### Backend Testing section
|
||
|
||
| Control | Purpose |
|
||
|---------|---------|
|
||
| **Notification Backend URL** | Paste ngrok HTTPS URL → **Save Backend URL** (changes target server only) |
|
||
| **Test Mode** | Sends `testMode: true/false` in register/refresh JSON bodies (default on when unset in storage) |
|
||
| **Skip JWT Authentication (Local Development Only)** | When on, omits `Authorization` headers for local servers that accept unauthenticated requests (default **off**) |
|
||
| **Register Token Now** | `POST /notifications/register` with current FCM token |
|
||
| **Refresh Notifications** | `POST /notifications/refresh` (same as post-wakeup flow) |
|
||
| **Simulate WAKEUP_PING (Local)** | Calls refresh API directly (no FCM) — quick backend test |
|
||
| **Send Real WAKEUP_PING** | `POST /debug/send-wakeup`; server sends real FCM `WAKEUP_PING` (Android doc has full flow) |
|
||
| **Event Log** | Shared `[Notifications]` panel log (100 entries) |
|
||
|
||
Persistence: `localStorage` keys `notificationDebug.backendBaseUrl`, `notificationDebug.testMode`, and `notificationDebug.bypassAuth` (`NotificationDebugConfig.ts`).
|
||
|
||
### Authentication vs backend URL
|
||
|
||
These settings are **independent**:
|
||
|
||
- **Backend URL** — which server receives notification API calls.
|
||
- **Test Mode** — `testMode` field in JSON request bodies only.
|
||
- **Skip JWT Authentication** — whether JWT `Authorization` headers are sent.
|
||
|
||
For a **hosted shared test server**: set the backend URL, keep **Test Mode** on if required, leave **Skip JWT Authentication** **off**, and ensure an active DID exists.
|
||
|
||
For **local ngrok**: set the backend URL; enable **Skip JWT Authentication** only if your local backend accepts unauthenticated requests.
|
||
|
||
### Programmatic override (optional)
|
||
|
||
From Safari Web Inspector or a dev console attached to the WebView:
|
||
|
||
```javascript
|
||
import {
|
||
setBackendBaseUrl,
|
||
setTestMode,
|
||
setBypassAuth,
|
||
getNotificationApiBaseUrl,
|
||
} from "@/services/notifications";
|
||
|
||
setBackendBaseUrl("https://abc123.ngrok-free.app");
|
||
setTestMode(true);
|
||
setBypassAuth(true); // local dev only — omit for hosted servers that require JWT
|
||
getNotificationApiBaseUrl(); // → ngrok URL
|
||
```
|
||
|
||
---
|
||
|
||
## 7. Firebase and Xcode checklist (iOS)
|
||
|
||
This section is a quick verification checklist for the detailed Firebase/APNs setup steps above.
|
||
|
||
| Item | Action |
|
||
|------|--------|
|
||
| **Bundle ID** | Match Capacitor `appId` (`app.timesafari` in `capacitor.config.ts`) to Firebase iOS app and Xcode target |
|
||
| **APNs auth key** | Firebase Console → Project Settings → Cloud Messaging → upload **APNs Authentication Key** (.p8) or certificates |
|
||
| **Push Notifications** | Xcode target → **Signing & Capabilities** → **+ Capability** → **Push Notifications** |
|
||
| **Background Modes** | Enable **Remote notifications** (and any others required by your plugin docs) |
|
||
| **GoogleService-Info.plist** | Present in the iOS target if using Firebase iOS SDK paths in your build |
|
||
| **FCM token** | Confirm **Register Token Now** succeeds in the debug panel and ngrok shows `POST /notifications/register` |
|
||
|
||
Silent/data pushes used for wake typically use a **content-available** style payload; confirm **notification-wakeup-service** and Firebase message format match what `handleCapacitorPushNotificationReceived` expects (`data.type === "WAKEUP_PING"`).
|
||
|
||
---
|
||
|
||
## 8. iOS-specific testing notes
|
||
|
||
### Physical device required
|
||
|
||
- APNs silent delivery and background wake behavior are **not** representative on the iOS Simulator.
|
||
- Always validate on a plugged-in or trusted wireless device with a development provisioning profile.
|
||
|
||
### Silent push is best-effort
|
||
|
||
- iOS may **delay or coalesce** background pushes, especially on battery saver or under load.
|
||
- A successful `/debug/send-wakeup` from the server does not guarantee immediate app wake.
|
||
|
||
### Force-quit limitations
|
||
|
||
- If the user **swipes the app away** from the app switcher, iOS often **will not** deliver background notifications until the user launches the app again.
|
||
- Test with the app **backgrounded** (home button / gesture), not force-quit, when validating wake.
|
||
|
||
### Low Power Mode and Focus
|
||
|
||
- **Low Power Mode** can reduce background execution.
|
||
- **Focus / Do Not Disturb** may affect notification presentation (separate from silent data wake, but confusing during tests).
|
||
|
||
### Two “Simulate WAKEUP_PING” buttons
|
||
|
||
| 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 |
|
||
|
||
Use the backend button to verify ngrok + refresh; use the simulator to verify handler + refresh chaining.
|
||
|
||
---
|
||
|
||
## 9. Recommended debug workflow
|
||
|
||
1. Start **notification-wakeup-service** on the Mac.
|
||
2. Start **ngrok** and copy the HTTPS URL.
|
||
3. Set URL + **Test Mode** in the Notification Debug Panel; confirm **Backend Status**.
|
||
4. Tap **Register Token Now** → confirm ngrok request and `[Notifications] Token registration success`.
|
||
5. Tap **Refresh Notifications** → confirm `Refresh completed in Nms (scheduled X)` in Event Log and ngrok `POST /notifications/refresh`.
|
||
6. From the backend, call **`/debug/send-wakeup`** (see curl below) with the registered `deviceId` / FCM token as required by that service.
|
||
7. Watch **Xcode console** for `[Notifications] pushNotificationReceived type=WAKEUP_PING` and refresh timing lines.
|
||
8. Open **ngrok inspect UI** (`http://127.0.0.1:4040`) to correlate requests.
|
||
9. Use **Pending Notification Inspector** on the panel to see locally scheduled fires after refresh.
|
||
|
||
---
|
||
|
||
## 10. Sample curl commands
|
||
|
||
Set your tunnel base URL:
|
||
|
||
```bash
|
||
export BASE="https://abc123.ngrok-free.app"
|
||
```
|
||
|
||
### Health
|
||
|
||
```bash
|
||
curl -sS -w "\nHTTP %{http_code}\n" "$BASE/health"
|
||
```
|
||
|
||
### Register device (mirror app payload)
|
||
|
||
```bash
|
||
curl -sS -X POST "$BASE/notifications/register" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"deviceId": "00000000-0000-4000-8000-000000000001",
|
||
"fcmToken": "YOUR_FCM_TOKEN_FROM_DEBUG_PANEL",
|
||
"platform": "ios",
|
||
"testMode": true
|
||
}'
|
||
```
|
||
|
||
### Refresh (mirror app payload)
|
||
|
||
```bash
|
||
curl -sS -X POST "$BASE/notifications/refresh" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"platform": "ios",
|
||
"testMode": true
|
||
}'
|
||
```
|
||
|
||
Example success body shape (actual fields may vary by service version):
|
||
|
||
```json
|
||
{
|
||
"shouldNotify": true,
|
||
"nextNotifications": [
|
||
{ "timestamp": 1710000000000 },
|
||
{ "timestamp": 1710003600000 }
|
||
]
|
||
}
|
||
```
|
||
|
||
The app schedules those timestamps via **daily-notification-plugin** (`applyNotificationRefreshPayload` in `NativeNotificationService.ts`).
|
||
|
||
### Send wakeup push (debug)
|
||
|
||
Exact path and body depend on **notification-wakeup-service**; typical pattern:
|
||
|
||
```bash
|
||
curl -sS -X POST "$BASE/debug/send-wakeup" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"deviceId": "00000000-0000-4000-8000-000000000001",
|
||
"testMode": true
|
||
}'
|
||
```
|
||
|
||
Confirm parameters (token vs deviceId, auth headers) in that repo’s README or OpenAPI spec.
|
||
|
||
---
|
||
|
||
## 11. Troubleshooting
|
||
|
||
### Refresh endpoint unreachable
|
||
|
||
| Symptom | Checks |
|
||
|---------|--------|
|
||
| Network error in Event Log | ngrok running? URL saved without typo/trailing slash? |
|
||
| HTTP 404 | Tunnel port matches backend `PORT`; path is `/notifications/refresh` |
|
||
| CORS (web only) | Native Capacitor fetch usually avoids browser CORS; if testing in Safari PWA, configure CORS on the service |
|
||
| ngrok browser warning | Free tier may show an interstitial for browser clients; native `fetch` from the app is usually unaffected |
|
||
|
||
### Token registration failures
|
||
|
||
- Push permission granted on the device?
|
||
- Firebase `VITE_FIREBASE_*` env vars baked into the build?
|
||
- `[Notifications] Token registration failure` in Xcode — read HTTP status in ngrok inspect
|
||
- Duplicate token skip: panel may show “skipped (duplicate)”; use **Register Token Now** to force re-register
|
||
|
||
### Silent push not waking the app
|
||
|
||
- App **backgrounded**, not force-quit
|
||
- Physical device, correct provisioning profile
|
||
- APNs key uploaded to Firebase; bundle ID matches
|
||
- FCM message includes `data.type = "WAKEUP_PING"` (see `NativeNotificationService.ts`)
|
||
- Server actually sent to the **same** FCM token shown in the debug panel
|
||
- Wait 30–120s — delivery is not instant
|
||
- Try **Simulate WAKEUP_PING** (refresh API) to isolate app/plugin from FCM/APNs
|
||
|
||
### Notifications duplicating
|
||
|
||
- Multiple refresh calls (flood test, repeated wakeups) each **replace** schedule via clear + schedule — check Event Log for repeated refreshes
|
||
- Separate issue: Daily Reminder vs New Activity both scheduling — see `doc/notification-new-activity-lay-of-the-land.md`
|
||
|
||
### Stale ngrok URL
|
||
|
||
- After restarting ngrok, update **Notification Backend URL** in the panel and tap **Save**
|
||
- Or clear override (empty field + Save) only if you intend to hit `DEFAULT_NOTIFY_API_SERVER` again
|
||
|
||
### Plugin / JWT errors after refresh
|
||
|
||
- Refresh calls `configureNativeFetcherIfReady()` before scheduling — ensure an **active DID** and endorser API settings exist in the app DB
|
||
- See `doc/notification-from-api-call.md` and `nativeFetcherConfig.ts`
|
||
|
||
---
|
||
|
||
## 12. Key source files (crowd-funder-for-time-pwa)
|
||
|
||
| File | Purpose |
|
||
|------|---------|
|
||
| `src/services/notifications/NotificationDebugConfig.ts` | Backend URL, testMode, and bypassAuth overrides |
|
||
| `src/services/notifications/NotificationDebugEvents.ts` | Panel event log + `logNotification()` |
|
||
| `src/services/notifications/notificationLog.ts` | Structured log helpers |
|
||
| `src/services/notifications/NotificationService.ts` | `POST /notifications/register` |
|
||
| `src/services/notifications/NativeNotificationService.ts` | Refresh, `WAKEUP_PING`, schedule replace |
|
||
| `src/services/notifications/firebaseMessagingClient.ts` | Capacitor push listeners |
|
||
| `src/components/dev/NotificationDebugPanel.vue` | Dev UI |
|
||
| `src/main.capacitor.ts` | Native push init at startup |
|
||
|
||
---
|
||
|
||
## 13. Related docs
|
||
|
||
- [notification-debug-panel.md](./notification-debug-panel.md) — panel controls, authentication, troubleshooting
|
||
- [Notification Debug Panel (README)](../README.md#notification-debug-panel-dev-builds)
|
||
- [notification-system-overview.md](./notification-system-overview.md)
|
||
- [notification-from-api-call.md](./notification-from-api-call.md)
|
||
- [notification-new-activity-lay-of-the-land.md](./notification-new-activity-lay-of-the-land.md)
|
||
- [BUILDING.md](../BUILDING.md) — iOS build commands
|
||
|
||
For plugin-native behavior (exact alarm, iOS pending inspector), see **daily-notification-plugin** documentation. For FCM payload format and `/debug/send-wakeup` contract, see **notification-wakeup-service**.
|