# 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: 1. Use the given interval (in minutes) when scheduling the **next** occurrence after a notification fires (rollover). 2. **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 })` (no `rolloverIntervalMinutes`). - 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: 1. **When the app calls `scheduleDailyNotification` with `rolloverIntervalMinutes`:** - 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). 2. **When computing the next occurrence (rollover path, after a notification fires):** - Read the stored `rolloverIntervalMinutes` for that schedule. - If present and > 0: next trigger = current trigger + `rolloverIntervalMinutes` minutes. - If absent or 0: next trigger = current trigger + 24 hours (existing behavior). 3. **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. 4. **When the app calls `scheduleDailyNotification` without `rolloverIntervalMinutes` (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 handling `scheduleDailyNotification`. 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 + `rolloverIntervalMinutes` minutes (using `Calendar` or 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, use `Calendar.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 `rolloverIntervalMinutes` when a **dev-only** setting is enabled (e.g. “Use 10-minute rollover for testing” in the Reminder Notifications section). Production users will not set it. - The app will pass it on every `scheduleDailyNotification` call when the user has that setting on (first-time enable and edit). When the user turns the setting off, the app will call `scheduleDailyNotification` without the parameter (so the plugin can persist “no interval” / 24h). --- ## Verification (plugin repo) 1. **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. 2. **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. 3. **Default:** Schedule without `rolloverIntervalMinutes`. Confirm next occurrence is 24 hours later. Reboot; confirm boot recovery still uses 24 hours. 4. **Turn off:** Schedule with 10 minutes, then have the app call `scheduleDailyNotification` again with the same id/time but **no** `rolloverIntervalMinutes`. Confirm stored interval is cleared and next rollover is 24 hours. --- ## Short summary for plugin maintainers - **New optional parameter:** `rolloverIntervalMinutes?: number` on 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:** 1. **API:** In the plugin interface used by the app (e.g. `scheduleDailyNotification`), add an optional parameter `rolloverIntervalMinutes?: number`. Document that when absent, next occurrence is 24 hours (current behavior). 2. **Storage (Android):** In the Schedule entity (or equivalent), add a column/field for the rollover interval (e.g. `rollover_interval_minutes` nullable Int). When handling `scheduleDailyNotification`, persist the value if present; if absent, store null or 0 to mean “24 hours”. 3. **Storage (iOS):** Add the same field to the persistent structure that holds the reminder schedule. Persist it when the app calls the schedule method. 4. **Rollover (both platforms):** In the code that runs when a scheduled notification fires and schedules the next occurrence: - Read the stored `rolloverIntervalMinutes` for 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. 5. **Boot recovery (both platforms):** In the path that runs after device reboot and reschedules from stored data: - Load the stored `rolloverIntervalMinutes` with 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. 6. **Clearing the interval:** When the app calls `scheduleDailyNotification` without `rolloverIntervalMinutes` (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. 7. **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.