docs: expand New Activity testing (starred plans, Endorser URL)

Add an Android-focused procedure for verifying API-driven copy when a
starred plan has updates via plansLastUpdatedBetween, including expected
notification text, prefetch timing, repeatability, and logcat. Clarify
that iOS parity is documented separately and that the native fetcher uses
Account API Server URL (test Endorser is valid), not the Partner API URL.
This commit is contained in:
Jose Olarte III
2026-03-23 18:56:10 +08:00
parent e121db5fcf
commit 178dcec5b8

View File

@@ -154,6 +154,7 @@ Use this section to verify the New Activity flow end-to-end on a physical device
- **Build:** Native app built and installed (e.g. `npx cap sync` then build/run from Xcode or Android Studio), or a dev build on device.
- **Identity:** User is signed in (active DID set) so `configureNativeFetcherIfReady` and the native fetcher can use a valid JWT.
- **Endorser API URL:** New Activity prefetch uses **Account → API Server URL** (the Endorser base URL passed to `configureNativeFetcher`), not the Partner API URL. You can run these tests against **production, test, or local Endorser** (e.g. the test preset `https://test-api.endorser.ch`); use an identity, JWT, and starred plans that exist on **that** server. Changing only **Partner API** URL does not change where `plansLastUpdatedBetween` is called.
- **Optional:** One or more starred plans so the API can return activity; with zero starred plans the notification should still show with a sensible fallback (e.g. “No updates in your starred projects”).
### Enable flow
@@ -186,6 +187,35 @@ Use this section to verify the New Activity flow end-to-end on a physical device
- **JWT / API errors:** After leaving the app in background for a long time, the JWT may expire. Re-opening Account (or app) may re-run `configureNativeFetcherIfReady`; document or test whether a new notification still gets valid content or shows fallback.
- **Daily Reminder and New Activity both on:** With the fix, turning off only New Activity should not affect the Daily Reminder notification (they use different plugin APIs; Option B must not cancel the single reminder if the user still has Daily Reminder on).
### Testing: starred project with new activity (Android native fetcher)
Use this to verify that when a **starred** plan has **new** activity reported by `plansLastUpdatedBetween`, the notification shows API-derived copy (not only the dual-schedule default from `dualScheduleConfig.ts`).
The steps and expected notification copy below are **Android-specific**: this repo registers `TimeSafariNativeFetcher` only on Android today. Do not assume the same strings or behavior on iOS until native fetcher parity exists; see **`doc/notification-from-api-call.md`** (iOS checklist and remaining tasks).
**How it works (short):** On Android, `TimeSafariNativeFetcher` POSTs to `/api/v2/report/plansLastUpdatedBetween` with `planIds` from the plugin (`updateStarredPlans`) and `afterId` from stored `last_acked_jwt_id` (or `"0"` initially). When the response `data` array is **non-empty**, each row becomes notification content with titles like `Update: <last 8 chars of handleId>` and bodies like `Plan <last 12 chars of handleId> has been updated.` When `data` is **empty**, the fetcher still supplies a single item: title **No Project Updates**, body **No updates in your starred projects.** (See `android/app/src/main/java/app/timesafari/TimeSafariNativeFetcher.java`.)
**Procedure (repeatable on device)**
1. Sign in on the Endorser environment you mean to test (e.g. test API URL in Account—see **Prerequisites**, Endorser API URL) so `configureNativeFetcherIfReady` can set JWT and `activeDid`.
2. Star at least one project you can change (e.g. your own test plan on staging).
3. Turn **New Activity Notification** on and pick a time **25 minutes ahead** (same quick-test pattern as above).
4. Open **Account** once (or finish the enable flow) so `updateStarredPlans({ planIds })` runs with current `starredPlanHandleIds`.
5. **Background the app** (home out; do not force-quit). Prefetch runs on the cron **~5 minutes before** the chosen time; the user notification fires at the chosen time.
6. **Produce new activity the API will return:** before that prefetch window (i.e. early enough that the scheduled content fetch still sees it), make a real change to the starred plan so `plansLastUpdatedBetween` returns **new** rows after the current `afterId` (e.g. an edit or other update your backend exposes through that report). If you change the plan **after** prefetch already ran with no new rows, you may only see **No Project Updates** until the next prefetch cycle (typically the next day at the same T5 schedule, unless you reschedule).
**What to verify**
- **One notification** at the chosen time (no extra static “Daily Check-In” after the fix—see “What to verify (after fix)” above).
- **Success path (API returns updates):** Title/body match the **Update: …** / **Plan … has been updated.** pattern (truncated handle segments), not the generic `buildDualScheduleConfig` defaults (**New Activity** / **Check your starred projects and offers for updates.**), which apply when the plugin falls back—e.g. fetch failure—not when the Android fetcher successfully returns Endorser-parsed content.
- **Contrast (cursor caught up, no new rows):** After a successful fetch that returned data, `last_acked_jwt_id` advances. Without further plan changes, a later run may show **No Project Updates** / **No updates in your starred projects.**—useful to compare against the “has activity” case.
**Repeatability:** Each successful fetch that returns data moves the `afterId` cursor forward. To see **Update: …** again on subsequent tests, make **another** qualifying plan change (or accept heavier setup such as clearing app/plugin storage to reset cursor—usually unnecessary).
**Debugging:** On Android, filter **logcat** for `TimeSafariNativeFetcher` (e.g. HTTP 200, `Fetched N notification(s)`) to confirm prefetch ran and how many `NotificationContent` items were built.
**Note:** The in-app **New Activity** screen loads starred changes via the JS stack; the **push** path uses the native fetcher and plugin cache. Validate the notification using **background + prefetch timing**, not only by opening that screen.
---
## 8. Plugin Repo Alignment and Attention Items