- Rename "Reminder Notification(s)" to "Daily Reminder" in Account and Help views
- Update NOTIFY_PUSH_SUCCESS title/message ("Notifications On", "Daily Reminder notifications are now enabled.")
- Align plugin spec doc with "Notifications" section naming
11 KiB
Plugin spec: Configurable rollover interval (e.g. 10 minutes for testing)
Date: 2026-03-03
Target repo: daily-notification-plugin
Consuming app: crowd-funder-for-time-pwa (TimeSafari)
Platforms: iOS and Android
Summary
The consuming app needs to support rapid testing of daily notification rollover on device. Today, after a notification fires, the plugin always schedules the next occurrence 24 hours later. We need an optional parameter so the app can request a different interval (e.g. 10 minutes) for dev/testing. When that parameter is present, the plugin must:
- Use the given interval (in minutes) when scheduling the next occurrence after a notification fires (rollover).
- Persist that interval with the schedule so that it survives device reboot and is used again when:
- Boot recovery reschedules alarms from stored data, and
- Any subsequent rollover runs (after the next notification fires).
If the interval is not persisted, then after a device restart the plugin would no longer know to use 10 minutes and would fall back to 24 hours; rapid testing after reboot would break. So persistence is a required part of this feature.
API contract (app → plugin)
Method: scheduleDailyNotification (or equivalent used for the app’s daily reminder)
Add an optional parameter:
- Name:
rolloverIntervalMinutes(or equivalent, e.g.repeatIntervalMinutes). - Type:
number(integer), optional. - Meaning: When the scheduled notification fires, schedule the next occurrence this many minutes after the current trigger time (instead of 24 hours). When absent or not provided, behavior is unchanged: next occurrence is 24 hours later (current behavior).
Example (pseudocode):
- App calls:
scheduleDailyNotification({ id, time, title, body, ..., rolloverIntervalMinutes: 10 }). - Plugin stores the schedule including
rolloverIntervalMinutes: 10. - When the notification fires, plugin computes next trigger = current trigger + 10 minutes (instead of + 24 hours), and schedules that.
- When the device reboots, boot recovery loads the schedule, sees
rolloverIntervalMinutes: 10, and uses it when (a) computing the next run time for reschedule and (b) any future rollover after the next fire.
Example (normal production, no param):
- App calls:
scheduleDailyNotification({ id, time, title, body })(norolloverIntervalMinutes). - Plugin stores the schedule with no interval (or default 24h).
- Rollover and boot recovery behave as today: next occurrence 24 hours later.
Persistence requirement (critical for device restart)
The rollover interval must be stored with the schedule in the plugin’s persistent storage (e.g. Room on Android, UserDefaults/DB on iOS), not only kept in memory. Concretely:
-
When the app calls
scheduleDailyNotificationwithrolloverIntervalMinutes:- Persist that value in the same place you persist the rest of the schedule (e.g. Schedule entity, or equivalent table/row that is read on boot and on rollover).
-
When computing the next occurrence (rollover path, after a notification fires):
- Read the stored
rolloverIntervalMinutesfor that schedule. - If present and > 0: next trigger = current trigger +
rolloverIntervalMinutesminutes. - If absent or 0: next trigger = current trigger + 24 hours (existing behavior).
- Read the stored
-
When boot recovery runs (after device restart):
- Load schedules from persistent storage (including the stored
rolloverIntervalMinutes). - When rescheduling each alarm, use the stored interval to compute the next run time (same logic as rollover: if interval is set, use it; otherwise 24 hours).
- When the next notification fires after reboot, the rollover path will again read the same stored value, so the 10-minute (or whatever) interval continues to apply.
- Load schedules from persistent storage (including the stored
-
When the app calls
scheduleDailyNotificationwithoutrolloverIntervalMinutes(or to turn off fast rollover):- Overwrite the stored schedule so that the interval is cleared or set to default (24h). Subsequent rollovers and boot recovery then use 24 hours again.
Why this matters: Without persisting the interval, a device restart would lose the “10 minutes” setting; rollover and boot recovery would have no way to know to use 10 minutes and would default to 24 hours. Rapid testing after reboot would not work.
Platform-specific notes
Android
- Storage: Add
rollover_interval_minutes(or equivalent) to the Schedule entity (or wherever the app’s reminder schedule is stored) and persist it when handlingscheduleDailyNotification. Use it in:- Rollover path (e.g. when scheduling next alarm after notification fires).
- Boot recovery path (when rebuilding alarms from DB after
BOOT_COMPLETED).
- Next trigger: Current trigger time +
rolloverIntervalMinutesminutes (usingCalendaror equivalent so DST/timezone is handled correctly; same care as for 24h rollover).
iOS
- Storage: Add the same field to whatever persistent structure holds the schedule (e.g. the same place that stores time, title, body, id). Persist it when the app calls the schedule method.
- Rollover: In
scheduleNextNotification()(or equivalent), read the stored interval; if set, useCalendar.date(byAdding: .minute, value: rolloverIntervalMinutes, to: currentDate)(or equivalent) instead of adding 24 hours. - App launch / recovery: If the plugin has any path that restores or reschedules after app launch or system events, use the stored interval there as well so behavior is consistent.
Edge cases and defaults
- Parameter absent: Do not change current behavior. Next occurrence = 24 hours later.
- Parameter = 0 or negative: Treat as “use default”; same as absent (24 hours).
- Parameter > 0 (e.g. 10): Next occurrence = current trigger + that many minutes.
- Existing schedules (created before this feature): No stored interval → treat as 24 hours. No migration required beyond “missing field = default”.
App-side behavior (for context)
- The app will only pass
rolloverIntervalMinuteswhen a dev-only setting is enabled (e.g. “Use 10-minute rollover for testing” in the Notifications section). Production users will not set it. - The app will pass it on every
scheduleDailyNotificationcall when the user has that setting on (first-time enable and edit). When the user turns the setting off, the app will callscheduleDailyNotificationwithout the parameter (so the plugin can persist “no interval” / 24h).
Verification (plugin repo)
- Rollover with interval: Schedule with
rolloverIntervalMinutes: 10. Trigger the notification (or wait). Confirm the next scheduled time is ~10 minutes after the current trigger (not 24 hours). Let it fire again; confirm the following occurrence is again ~10 minutes later. - Persistence: Schedule with
rolloverIntervalMinutes: 10, then restart the device (do not open the app). After boot, confirm (via logs or next fire) that the rescheduled alarm uses the 10-minute interval (e.g. next fire is 10 minutes after the last stored trigger, not 24 hours). After that notification fires, confirm the next rollover is still 10 minutes later. - Default: Schedule without
rolloverIntervalMinutes. Confirm next occurrence is 24 hours later. Reboot; confirm boot recovery still uses 24 hours. - Turn off: Schedule with 10 minutes, then have the app call
scheduleDailyNotificationagain with the same id/time but norolloverIntervalMinutes. Confirm stored interval is cleared and next rollover is 24 hours.
Short summary for plugin maintainers
- New optional parameter:
rolloverIntervalMinutes?: numberon the schedule method used for the app’s daily reminder. - When set (e.g. 10): After a notification fires, schedule the next occurrence in that many minutes instead of 24 hours.
- Must persist: Store the value with the schedule in the plugin’s DB/storage. Use it in rollover and in boot recovery so that after a device restart the same interval is used. Without persistence, the feature would not work after reboot.
- When absent: Behavior unchanged (24-hour rollover). No migration needed for existing schedules.
For Cursor (plugin repo) — actionable handoff
Use this section when implementing this feature in the daily-notification-plugin repo (e.g. with Cursor). You can paste or @-mention this doc as context.
Goal: Support an optional rolloverIntervalMinutes (or equivalent) on the daily reminder schedule API. When provided (e.g. 10), schedule the next occurrence that many minutes after the current trigger instead of 24 hours. Persist this value with the schedule so that rollover and boot recovery both use it; after a device restart, the same interval must still apply.
Concrete tasks:
-
API: In the plugin interface used by the app (e.g.
scheduleDailyNotification), add an optional parameterrolloverIntervalMinutes?: number. Document that when absent, next occurrence is 24 hours (current behavior). -
Storage (Android): In the Schedule entity (or equivalent), add a column/field for the rollover interval (e.g.
rollover_interval_minutesnullable Int). When handlingscheduleDailyNotification, persist the value if present; if absent, store null or 0 to mean “24 hours”. -
Storage (iOS): Add the same field to the persistent structure that holds the reminder schedule. Persist it when the app calls the schedule method.
-
Rollover (both platforms): In the code that runs when a scheduled notification fires and schedules the next occurrence:
- Read the stored
rolloverIntervalMinutesfor that schedule. - If present and > 0: next trigger = current trigger + that many minutes (using Calendar/date APIs that respect timezone/DST).
- Else: next trigger = current trigger + 24 hours (existing behavior).
- Persist the same interval on the new schedule record so the next rollover still uses it.
- Read the stored
-
Boot recovery (both platforms): In the path that runs after device reboot and reschedules from stored data:
- Load the stored
rolloverIntervalMinuteswith each schedule. - When computing “next run time” for reschedule, use the same logic: if interval set, current trigger + that many minutes; else + 24 hours.
- Do not rely on in-memory state; always read from persisted storage so behavior is correct after restart.
- Load the stored
-
Clearing the interval: When the app calls
scheduleDailyNotificationwithoutrolloverIntervalMinutes(e.g. user turned off “fast rollover” in the app), overwrite the stored schedule so the interval field is null/0. Subsequent rollovers and boot recovery then use 24 hours. -
Tests: Add or extend tests for: (a) rollover with 10 minutes, (b) boot recovery with stored 10-minute interval, (c) default 24h when parameter absent or cleared.