WIP: new-activity notification #231

Draft
trentlarson wants to merge 71 commits from notify-api into master
Owner

Notifications for New Activity from API

# Notifications for New Activity from API
trentlarson added 2 commits 2026-03-16 01:36:18 +00:00
jose added 1 commit 2026-03-16 10:22:10 +00:00
Add section 6 with Option A (skip single reminder when dialog is for New
Activity), Option B (cancel single reminder on disable, with caveats),
and optional cleanup notes. For team discussion and implementation.
jose added 1 commit 2026-03-16 11:06:07 +00:00
Expand notification-new-activity-lay-of-the-land.md with section 7 on
testing New Activity on real iOS/Android devices (prerequisites, enable/
disable flows, what to verify before and after fix). Update Android
device notes to state this app has exact alarm disabled (no
SCHEDULE_EXACT_ALARM) and that delivery may be inexact or batched.
jose added 1 commit 2026-03-16 13:16:22 +00:00
Document how daily-notification-plugin aligns with app usage (APIs,
dual vs single schedules, native fetcher, exact alarm). Note attention
items: cancelDailyReminder argument shape, INTEGRATION_GUIDE scope, and
iOS use of app-provided id for scheduleDailyNotification.
jose added 3 commits 2026-03-17 13:05:21 +00:00
- PushNotificationPermission: on native, when enabling New Activity
  (DAILY_CHECK_TITLE), skip scheduleDailyNotification so only
  AccountViewView's scheduleNewActivityDualNotification runs (dual
  schedule only). Daily Reminder still uses single reminder path.
- Add reminderIds.ts with REMINDER_ID_DAILY_REMINDER and
  REMINDER_ID_NEW_ACTIVITY; NativeNotificationService uses the former.
- Export reminder IDs from notifications index. Fixes "always fires /
  can't turn off" by avoiding a second, uncancellable single reminder
  for New Activity.
- PushNotificationPermission: show "Turn on New Activity Notifications"
  when enabling New Activity; use NOTIFY_PUSH_SUCCESS_NEW_ACTIVITY for
  success toast so copy says "New Activity notifications are now enabled."
- App.vue: on native, turnOffNotifications invokes the modal's callback
  only (fixes turn-off not updating state); add comment that callback is
  per notification type.
- AccountViewView: handle plugin UNIMPLEMENTED for scheduleDualNotification
  on iOS with friendlier message; add New Activity time block and "Edit
  New Activity Notification…"; rename Daily Reminder button to "Edit Daily
  Reminder…".
- Constants: add NOTIFY_PUSH_SUCCESS_NEW_ACTIVITY. Reminder IDs and
  Option A (skip single reminder for New Activity) from earlier commit.
Add plugin-feedback-ios-scheduleDualNotification.md for the
daily-notification-plugin repo: config shape from the app, expected
behavior, and acceptance criteria so iOS can implement or fix
scheduleDualNotification (currently returns UNIMPLEMENTED).
jose added 1 commit 2026-03-19 13:12:26 +00:00
- Treat updateStarredPlans as optional: catch UNIMPLEMENTED and continue to
  scheduleDualNotification so missing native method no longer blocks scheduling.
- Show specific toast when BGTaskSchedulerErrorDomain error 1 occurs (e.g.
  Simulator): explain that a real device and Background App Refresh are required.
- Add PluginHeaders diagnostic in AccountViewView and main.capacitor.ts to debug
  UNIMPLEMENTED (log DNP methods at call time and at launch).
- Fix main.capacitor.ts build: use CapacitorWindow type and safe cap assignment
  so vite build --mode capacitor succeeds.
- Docs: add UNIMPLEMENTED troubleshooting and updateStarredPlans note in
  plugin-feedback-ios-scheduleDualNotification.md; add section 8.3 in
  notification-new-activity-lay-of-the-land.md.
- Lockfile updates (package-lock.json, Podfile.lock).
jose added 1 commit 2026-03-20 13:19:07 +00:00
- buildDualScheduleConfig: set contentFetch timeout/retryAttempts/retryDelay
  (match capacitor DailyNotification networkConfig), userNotification.vibration,
  return type DualScheduleConfiguration
- @timesafari/daily-notification-plugin 2.1.1 → 2.1.3 (package-lock)
- doc: plugin feedback (contentFetch JSON, parseUserNotificationConfig optional
  fields) and Android DailyNotificationWorker duplicate scheduleId note
jose added 1 commit 2026-03-23 10:56:39 +00:00
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.
jose added 1 commit 2026-03-24 13:20:02 +00:00
Log configure-time starred plan count, fetchContent entry (trigger, scheduledTime,
thread), worker start, POST summary (plan count, truncated afterId), and HTTP
status at INFO so logcat shows clearly when the native fetcher runs versus
plugin-only DNP-FETCH paths.
jose added 1 commit 2026-03-24 14:05:43 +00:00
Document how the daily-notification-plugin dual path uses FetchWorker mock/URL
fetch instead of NativeNotificationContentFetcher, schedules fetch immediately
rather than at contentFetch cron, and why DualScheduleHelper shows useCache=false.
Includes acceptance criteria and file pointers for maintainers fixing the plugin.
jose added 1 commit 2026-03-26 07:50:51 +00:00
`npx cap run android` runs `sync` by default, which regenerated
`capacitor.plugins.json` and removed SafeArea and SharedImage entries
after `restore-local-plugins.js` had already run. Use `--no-sync` in
`build-android.sh` (auto-run) and `auto-run.sh` so the launch step does
not overwrite the restored plugin list.
jose added 2 commits 2026-03-26 10:17:15 +00:00
Call configureNativeFetcherIfReady when the app becomes active so getHeaders can
supply a new JWT before the next background prefetch when users return from
background.

In TimeSafariNativeFetcher, read HttpURLConnection#getErrorStream for non-200
responses and log a capped body snippet (including on retryable errors) to
diagnose JWT_VERIFY_FAILED and other API failures.
Document expired-token causes, client limits, and server-side options (TTL,
scoped tokens, refresh, BFF) plus questions for Endorser maintainers.
jose added 2 commits 2026-03-27 13:34:02 +00:00
Add plan-background-jwt-pool-and-expiry.md (Phase A/B, expiryDays + buffer sizing,
pool size 100). Add plugin-feedback-daily-notification-configureNativeFetcher-jwt-pool.md
for daily-notification-plugin: optional jwtTokens on configureNativeFetcher. Link plan
to plugin doc and endorser-jwt-background-prefetch-options.md.
Add BACKGROUND_JWT_EXPIRY_DAYS/SECONDS and accessTokenForBackgroundNotifications
via createEndorserJwtForDid; configureNativeFetcher uses it instead of getHeaders
so WorkManager prefetch is not stuck with a 60s access token. Interactive API
calls unchanged.
jose added 1 commit 2026-03-30 09:28:16 +00:00
- Mint BACKGROUND_JWT_POOL_SIZE (90 + 10) distinct background JWTs with
  unique jti; pass jwtTokens from nativeFetcherConfig into configureNativeFetcher.
- Android TimeSafariNativeFetcher: overload configure with jwtTokenPool;
  select bearer via epoch day mod pool size; fall back to primary jwtToken.
- Log truncated plansLastUpdatedBetween response at DEBUG for prefetch debugging.
jose added 1 commit 2026-03-31 07:57:37 +00:00
Add syncStarredPlansToNativePlugin() and call it from AccountViewView
(schedule + initializeState) and ProjectViewView.toggleStar when New
Activity is enabled so Android prefetch uses the current starred list.

Update notification-from-api-call.md with the helper and file references.
jose added 1 commit 2026-03-31 11:50:28 +00:00
Aggregate API rows into one notification with Starred Project Update(s) titles,
plan names in typographic quotes, and "+ N more have been updated." for multiples.
Stop emitting the empty-data "No Project Updates" fallback. Sync internal docs.
jose added 1 commit 2026-04-01 12:49:19 +00:00
Add doc/new-activity-notifications-ios-android-parity.md covering dual-schedule
and Endorser API parity, plugin vs app work, Android dual-path notes, prefetch
vs notify ordering on iOS (§3.3), and clarified Phase B JWT pool status on
both platforms. Link the guide from doc/notification-from-api-call.md under the
iOS checklist.
jose added 4 commits 2026-04-02 12:55:33 +00:00
Add §6 with reference file table, Endorser contract summary aligned to
TimeSafariNativeFetcher, likely plugin touchpoints, and suggested implementation
order; renumber acceptance checklist to §7.
Add TimeSafariNativeFetcher (plansLastUpdatedBetween parity with Android) and
call DailyNotificationPlugin.registerNativeFetcher from AppDelegate before JS
configureNativeFetcher; broaden DailyNotificationDelivered scheduled_time types
in willPresent. Wire the new file into the App target; normalize PBX object IDs
to 24-char hex.

Document plugin ≥3 handoff (consuming-app-handoff-ios-native-fetcher-chained-dual),
refresh iOS/Android parity and notification-from-api-call file tables.
Use generic/platform=iOS Simulator instead of a fixed device name so CLI builds
do not fail when that simulator is not installed (e.g. newer Xcode runtimes).

Pass -quiet to xcodebuild and enable SWIFT_SUPPRESS_WARNINGS plus
GCC_WARN_INHIBIT_ALL_WARNINGS for scripted builds and IPA archive/export so
terminal output stays smaller; full diagnostics remain available in Xcode.
Restructure the quick start with Web, Android, and iOS subheadings; put
each npm command in its own code block; fold the test-page step into the
Web section. Document Android (build:android:test:run + ADB, link to
BUILDING.md) and iOS (build:ios:studio + Xcode prerequisites).
jose added 1 commit 2026-04-09 13:47:01 +00:00
- Podfile: use static frameworks; post_install/post_integrate hooks to
  avoid mixing Apple libsqlite3/SQLite headers with SQLCipher (including
  stripping aggregate Pods-App xcconfig flags for Swift explicit modules).
- Xcode: enable CLANG_ENABLE_MODULES; replace CocoaPods “Embed Pods
  Frameworks” phase with “Copy Pods Resources”; minor project file hygiene.
- Pods: SQLCipher 4.10.0, ZIPFoundation patch bump; Podfile.lock updated.
- package.json: allow patch updates for @capacitor-community/sqlite (^6.0.2);
  regenerate package-lock.json.
- Info.plist: reorder keys only (same URL scheme, background modes, BG tasks,
  notification alert style).
jose added 1 commit 2026-04-20 09:44:16 +00:00
jose added 3 commits 2026-04-23 08:08:28 +00:00
Document PLUGIN_NOTIFICATION_FIX_ANDROID diagnosis and recommended changes in
the daily-notification-plugin repo, verified against plugin 3.0.0.
Avoid showing default New Activity copy when dual content is missing or
outside contentTimeout, per PLUGIN_NOTIFICATION_FIX_ANDROID.md.
jose added 1 commit 2026-05-06 07:31:49 +00:00
Add firebaseMessagingClient to ensure the Firebase app is created from VITE_FIREBASE_*,
wire PushNotifications (listeners, requestPermissions, register) before token work,
and call getMessaging/getToken/onMessage when firebase/messaging is supported. Hook
startup from main.capacitor and set PushNotifications presentationOptions in
capacitor.config. Depend on firebase and @capacitor/push-notifications.
jose added 5 commits 2026-05-06 09:15:23 +00:00
Add registerToken POST to /notifications/register (platform, testMode).
Call it from Capacitor registration and Firebase getToken with deduped
registerRetrievedToken; expose registerToken via barrel and useNotifications
as registerFcmToken.
Add refreshNotifications (configureNativeFetcherIfReady) and
handleCapacitorPushNotificationReceived for data.type WAKEUP_PING; invoke from
Capacitor pushNotificationReceived without UI.
Update refreshNotifications to POST /notifications/refresh and map returned
nextNotifications timestamps to clockTime schedules, upserting them via the
DailyNotification schedule APIs (with deterministic IDs) after refreshing native
fetcher credentials.
Cancel all native notifications before applying the backend-provided schedule so
refreshNotifications always performs a full replacement and never leaves stale
entries behind.
Trigger refreshNotifications on composable mount and document resume, using a
debounced/in-flight guarded wrapper to avoid rapid duplicate refresh calls.
Expose the debounced refresh function from useNotifications.
jose added 1 commit 2026-05-06 09:57:21 +00:00
Stop converting backend timestamps to HH:mm/recurring schedules and remove
createSchedule/updateSchedule reconciliation. After a successful refresh payload,
clear existing notifications and schedule exact timestamps via the plugin
scheduleNotifications API (with back-compat clear fallback) to prevent drift.
jose added 2 commits 2026-05-07 12:40:55 +00:00
Add a dev-only Notification Debug Panel at /dev/notifications for testing
predictive refresh and WAKEUP_PING without a backend.

- Gate route and Advanced Settings entry on import.meta.env.DEV
- NotificationDebugService drives mock refresh, flood test, clear, and
  wake simulation via existing handleCapacitorPushNotificationReceived and
  applyNotificationRefreshPayload (shared with refreshNotifications)
- Add NotificationInspector Capacitor plugin: iOS lists pending
  UNNotificationRequest identifiers and next trigger; Android stub returns
  empty pending for safe registration
- Report UNIMPLEMENTED from Android NotificationInspector instead of empty pending
- Surface iOS-only inspector message in NotificationDebugPanel without noisy errors
- Gate Account debug link with import.meta.env.DEV and document intent
- Add architecture comments on NotificationDebugService, inspector plugin, and native exports
jose added 4 commits 2026-05-08 13:27:16 +00:00
Vue’s template compiler treats bindings as non-module JS, so
`import.meta.env.DEV` in `v-if` broke the Capacitor/Vite build.
Expose a readonly `isDev` from the script instead.
Register the dev-notifications route whenever the bundle is non-production
(DEV or Vite MODE !== production), matching the account screen so RouterLink
to Notification Debug does not throw after vite build.

Align AccountViewView isDev with that rule and document the coupling.

Add NotificationInspectorPlugin.swift to the App target compile sources so
AppDelegate can register the plugin.
Add includeDevToolkitRoutes (vite dev or MODE !== production) and use it
from the router, AccountViewView, and NotificationDebugView so the debug
screen matches dev-notifications registration after vite build.

Update the gated banner copy to refer to production Vite builds.
jose added 2 commits 2026-05-11 05:51:19 +00:00
Expose wall-clock fire targets from the iOS NotificationInspector
(scheduled_time userInfo and predictive_<epochMs> ids) so the debug
panel is not misleading when nextTriggerDate resamples for interval
triggers. Extend TS types and show the scheduled target in the UI,
with a note when iOS nextTriggerDate diverges.

Make refreshPending a plain fetch so mock refresh, wakeup ping, flood
test, and clear notifications can refresh the pending list while an
outer withBusy guard is already active.
jose added 1 commit 2026-05-13 10:43:11 +00:00
Add getOrCreateDeviceId() backed by Capacitor Preferences so one UUID
survives app restarts and token refreshes. Include deviceId in POST
/notifications/register alongside fcmToken, platform, and testMode.
Add @capacitor/preferences and lightweight DeviceId logs (no token/ID values).
jose added 1 commit 2026-05-13 12:57:24 +00:00
If randomUUID is unavailable (older WebViews), generate a one-time ID
with Date.now + random segment, log a single DeviceId warning, and
persist it as before so registration still works.
jose added 1 commit 2026-05-18 07:07:11 +00:00
Introduce NotificationDebugConfig so register/refresh use getNotificationApiBaseUrl()
(APP_SERVER by default, optional LAN/ngrok override) and configurable testMode without rebuilds.
jose added 1 commit 2026-05-18 08:28:43 +00:00
Add backend URL, test mode, token re-register, refresh diagnostics, FCM token display,
and a capped event log; expose refreshNotificationsWithDiagnostics and reregisterFcmTokenNow.
jose added 1 commit 2026-05-18 10:46:40 +00:00
Introduce NotificationDebugEvents and [Notifications] console/panel logging for push
handlers, token registration, refresh timing, schedule replacement, and WAKEUP_PING.
jose added 1 commit 2026-05-18 13:23:06 +00:00
Document Mac backend + ngrok + physical iPhone setup, debug panel overrides,
Firebase/APNs checklist, curl examples, and troubleshooting for WAKEUP_PING flows.
jose added 1 commit 2026-05-20 07:45:58 +00:00
Use getHeaders(activeDid) for POST /notifications/register and
/notifications/refresh so requests include Authorization: Bearer tokens
like the rest of the app. Add notificationApiAuth helper for shared header
resolution, auth logging, and graceful handling when identity or token
is missing or the server returns 401/403.
jose added 1 commit 2026-05-20 07:55:00 +00:00
Queue token registration when Bearer auth is unavailable at startup,
with bounded exponential backoff retries. Flush the pending token when
identity is set, the app resumes, or the native fetcher configures.
Skip refresh API calls when auth is missing and log lifecycle events
for registration wait and refresh skip.
jose added 1 commit 2026-05-20 11:34:59 +00:00
Add shouldBypassNotificationAuth() when test mode or a backend URL override
is set so register/refresh can proceed without DID/Bearer headers. Production
paths still require auth when bypass is off; log bypass vs authenticated
request modes for easier WAKEUP_PING and panel smoke testing.
jose added 1 commit 2026-05-24 02:26:43 +00:00
Consolidate first-run backend setup in section 1 and reframe section 2
as verification only, so local iPhone testing does not look like two
separate startup steps.
jose added 1 commit 2026-05-24 09:33:31 +00:00
Document first-time FCM/APNs configuration (project, plist, .p8 key,
Admin credentials, Xcode capabilities) before the iOS build step, and
renumber later sections so the checklist references the new flow.
jose added 1 commit 2026-05-25 08:59:28 +00:00
Reorder first-time setup so Capacitor/Xcode workspace generation (section 4)
precedes Firebase and APNs steps that require Xcode. Update cross-links and
skip targets; no change to Firebase/APNs technical instructions.
jose added 1 commit 2026-05-25 09:06:18 +00:00
Wire @capacitor/preferences into the iOS Capacitor Podfile so stable
deviceId persistence works on native builds. Refresh package-lock.json.
jose added 1 commit 2026-05-27 09:02:08 +00:00
Also clarify the ngrok iOS guide steps for dragging the plist into the correct App folder/target.
jose added 1 commit 2026-05-27 09:26:46 +00:00
Add AppDebug.entitlements with development aps-environment for Debug builds, point Debug signing at it, and add remote-notification to UIBackgroundModes.
jose added 1 commit 2026-06-02 13:33:38 +00:00
Add local-android-testing-ngrok.md for FCM wakeup, debug panel, Firebase
setup, platform/battery notes, troubleshooting, verification checklist, and
end-to-end QA flow. Add local-android-testing-analysis.md as planning
notes mapping reuse from the iOS ngrok guide.
jose added 2 commits 2026-06-03 10:02:41 +00:00
Register @capacitor/preferences in the Android Capacitor project so
notification deviceId storage matches iOS. Replace the placeholder
google-services.json with the production Firebase client config for FCM.
Refresh package-lock after native sync / install.
activeBackendUrl was a computed with no reactive deps, so it stayed stale
until the panel remounted. Use a ref and update it in syncBackendState().
jose added 1 commit 2026-06-05 11:14:19 +00:00
The /notifications/refresh endpoint now requires deviceId or fcmToken.
Reuse the stable device ID from registration so refresh no longer returns 400.
jose added 1 commit 2026-06-08 11:43:20 +00:00
Avoid cancelAllNotifications during schedule replacement so Daily
Reminder schedules are not cleared.
jose added 1 commit 2026-06-09 09:49:26 +00:00
Update app logs, comments, and debug inspector labels to use API
notification wording while keeping clearPredictiveNotifications plugin
calls unchanged. Align the iOS pending-notification inspector with the
plugin's api_ identifier prefix.
jose added 1 commit 2026-06-09 11:40:18 +00:00
Update the refresh replacement flow for the renamed plugin APIs and remove
the obsolete clearPredictiveNotifications type augmentation.
jose added 1 commit 2026-06-11 09:01:39 +00:00
Add Send Real WAKEUP_PING via /debug/send-wakeup and rename the local
refresh shortcut to Simulate WAKEUP_PING (Local).
jose added 1 commit 2026-06-12 09:12:34 +00:00
Thread options.source through logRefreshSuccess and logRefreshFailure so
WAKEUP_PING and debug-panel refreshes are grep-friendly end-to-end in
Logcat and the Event Log without changing refresh behavior.
jose added 1 commit 2026-06-12 10:23:34 +00:00
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 pull request has changes conflicting with the target branch.
  • BUILDING.md
  • android/app/build.gradle
  • android/app/src/main/java/app/timesafari/TimeSafariNativeFetcher.java
  • ios/App/Podfile
  • ios/App/Podfile.lock
  • package-lock.json
  • package.json
  • scripts/build-ios.sh
  • src/views/AccountViewView.vue
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin notify-api:notify-api
git checkout notify-api
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: trent_larson/crowd-funder-for-time-pwa#231