Files
daily-notification-plugin/docs/alarms/03-plugin-requirements.md
Matthew Raymer 35babb3126 docs(alarms): unify and enhance alarm directive documentation stack
Create unified alarm documentation system with strict role separation:
- Doc A: Platform capability reference (canonical OS facts)
- Doc B: Plugin behavior exploration (executable test harness)
- Doc C: Plugin requirements (guarantees, JS/TS contract, traceability)

Changes:
- Add canonical rule to Doc A preventing platform fact duplication
- Convert Doc B to pure executable test spec with scenario tables
- Complete Doc C with guarantees matrix, JS/TS API contract, recovery
  contract, unsupported behaviors, and traceability matrix
- Remove implementation details from unified directive
- Add compliance milestone tracking and iOS parity gates
- Add deprecation banners to legacy platform docs

All documents now enforce strict role separation with cross-references
to prevent duplication and ensure single source of truth.
2025-11-25 10:09:46 +00:00

48 KiB

Plugin Requirements & Implementation Rules

Author: Matthew Raymer
Date: November 2025
Status: Active Requirements - Implementation Guide
Version: 1.1.0
Last Synced With Plugin Version: v1.1.0

Purpose

This document defines the rules the plugin MUST follow to behave predictably across Android and iOS platforms. It specifies:

Language Standards: This document uses RFC-2119 keywords:

  • MUST — Required for correctness. Violation breaks plugin guarantees.
  • SHOULD — Strong recommendation. Exceptions MUST be documented.
  • MUST NOT — Prohibited behavior. Plugin must not attempt this.
  • MAY — Optional. Plugin may or may not implement.

Cross-Reference Format: All references use format [Doc X §Y.Z] where:

  • Plugin behavior guarantees and limitations
  • Persistence requirements
  • Recovery strategies
  • Missed alarm handling contract
  • JS/TS API contract and caveats
  • Platform-specific requirements
  • Testing requirements

Reference: See Platform Capability Reference for OS-level facts.


1. Plugin Behavior Guarantees & Limitations

1.1 Cross-Platform Guarantees Matrix

Behavior Android iOS Guarantee Level Platform Source
Survives swipe-kill Yes Yes MUST (OS-guaranteed) Doc A §2.1.1, Doc A §3.1.1
Survives reboot ⚠️ Only if rescheduled Yes Android: SHOULD (best-effort), iOS: MUST (OS-guaranteed) Doc A §2.1.2, Doc A §3.1.2
Runs code on trigger Yes (PendingIntent) No (never) Android: MUST, iOS: MUST NOT Doc A §2.1.1, Doc A §3.2.1
Missed alarm detection Required Required MUST (Plugin-required) Doc A §2.1.4
Force stop recovery Required N/A MUST (Plugin-required) Doc A §2.2.1
Exact timing ⚠️ With permission ⚠️ ±180s tolerance Android: SHOULD (with permission), iOS: SHOULD (OS limitation) Doc A §5.2, Doc A §6.1
Background execution ⚠️ WorkManager ⚠️ BGTaskScheduler SHOULD (best-effort, system-controlled) Doc A §3.1.3

Guarantee Level Definitions:

  • MUST = Plugin guarantees this behavior
  • SHOULD = Plugin attempts this but cannot guarantee (best-effort)
  • MUST NOT = Plugin cannot and will not attempt this

1.2 Limitations by Platform

See §8 - Explicit Unsupported Behaviors for complete list.

Summary:

  • Android Force Stop: Cannot auto-recover - See Doc A §2.2.1
  • iOS Code Execution: Cannot run code on notification fire - See Doc A §3.2.1
  • iOS Timing: ±180s tolerance - See Doc A §6.1
  • Background Execution: System-controlled, not guaranteed - See Doc A §3.1.3

2. Persistence Requirements

2.1 Required Persistence Items

The plugin MUST persist the following for each scheduled alarm/notification:

Field Type Required Purpose Storage Location
alarm_id String Yes Unique identifier Schedule.id, NotificationContentEntity.id
trigger_time Long/TimeInterval Yes When to fire Schedule.nextRunAt, NotificationContentEntity.scheduledTime
repeat_rule String/Enum Yes NONE, DAILY, WEEKLY, CUSTOM Schedule.cron, Schedule.clockTime
channel_id String Yes Notification channel (Android) NotificationContentEntity (implicit)
priority String/Int Yes Notification priority NotificationContentEntity.priority
title String Yes Notification title NotificationContentEntity.title
body String Yes Notification body NotificationContentEntity.body
sound_enabled Boolean Yes Sound preference NotificationContentEntity.soundEnabled
vibration_enabled Boolean Yes Vibration preference NotificationContentEntity.vibrationEnabled
payload String/JSON ⚠️ Optional Additional content ContentCache.payload
created_at Long/TimeInterval Yes Creation timestamp NotificationContentEntity.createdAt
updated_at Long/TimeInterval Yes Last update timestamp NotificationContentEntity.updatedAt
enabled Boolean Yes Whether alarm is active Schedule.enabled

2.2 Storage Implementation

Android:

  • Primary: Room database (DailyNotificationDatabase)
  • Location: android/src/main/java/com/timesafari/dailynotification/
  • Entities: Schedule, NotificationContentEntity, ContentCache

iOS:

  • Primary: UNUserNotificationCenter (OS-managed)
  • Secondary: Plugin storage (UserDefaults, CoreData, or files)
  • Location: ios/Plugin/
  • Component: DailyNotificationStorage?

2.3 Persistence Validation

The plugin MUST:

  • Validate persistence on every alarm schedule
  • Log persistence failures
  • Handle persistence errors gracefully
  • Provide recovery mechanism if persistence fails

Acceptance Criteria:

  • Test: Schedule alarm, kill app immediately, verify alarm persists in database
  • Test: Schedule alarm, fill storage, verify graceful error handling
  • Test: Schedule alarm, corrupt database, verify recovery mechanism
  • Pass: All persistence operations succeed or fail gracefully with logging

2.4 Data Integrity Rules

Required Validation:

  • MUST validate all required fields before persistence
  • MUST validate schedule format (cron or HH:mm)
  • MUST validate trigger time is in the future (or handle past times appropriately)
  • MUST ensure foreign key relationships are valid (Schedule → NotificationContentEntity)

Data Integrity Constraints:

  • alarm_id MUST be unique across all schedules
  • scheduleId MUST reference an existing Schedule.id
  • scheduledTime MUST be a valid timestamp
  • deliveryStatus MUST be one of: "pending", "delivered", "missed"

2.5 Failure Modes

Persistence Failure Handling:

  • Database errors: Log error, continue with alarm scheduling (best effort), retry persistence
  • Storage full: Log warning, attempt cleanup, retry, notify user if critical
  • Invalid data: Skip invalid entries, log warning, continue processing
  • Migration failures: Rollback to backup, notify user, preserve existing data

3. Recovery Contract

3.1 Recovery Triggers & Required Actions

The plugin MUST implement recovery at the following points with the specified actions. This is the complete recovery contract that defines what the plugin guarantees for each recovery scenario.

3.1.1 Boot Event (Android Only)

Trigger: BOOT_COMPLETED broadcast

Required Actions:

  1. Load all enabled alarms from persistent storage
  2. Reschedule each alarm using AlarmManager
  3. Detect missed alarms (trigger_time < now)
  4. Generate missed alarm events/notifications
  5. Log recovery actions

Code Reference: BootReceiver.kt line 24

Implementation Status: See Phase 3 Implementation

Platform Reference: Android §2.1.2

Acceptance Criteria:

  • Test: Schedule alarm for 10 minutes, reboot device, do NOT open app, wait 15 minutes
  • Expected: Alarm does NOT fire (OS limitation - see Doc A §2.1.2)
  • Test: Open app after reboot
  • Expected: Plugin detects missed alarm, reschedules future alarms
  • Pass: Missed alarm detected exactly once, future alarms rescheduled

Missed Alarm Detection Acceptance Criteria:

  • Test: Create alarm scheduled for 2 minutes, kill app, wait 5 minutes, launch app
  • Expected: Plugin detects missed alarm, marks in database (delivery_status = 'missed')
  • Test: Create repeating alarm, miss 3 occurrences, launch app
  • Expected: Plugin detects all 3 missed alarms, reschedules next occurrence
  • Pass: All missed alarms detected and marked, no duplicates, future alarms rescheduled

3.1.2 App Cold Start

Trigger: App launched from terminated state

Required Actions:

  1. Load all enabled alarms from persistent storage
  2. Verify active alarms match stored alarms
  3. Detect missed alarms (trigger_time < now)
  4. Reschedule future alarms
  5. Generate missed alarm events/notifications
  6. Log recovery actions

Implementation Status: See Phase 1 Implementation

Code Location: Plugin initialization (DailyNotificationPlugin.load() or equivalent)

Platform Reference: Android §2.1.4

Acceptance Criteria:

  • Test: Schedule alarm for 5 minutes, kill app process (not force stop), wait 10 minutes
  • Expected: Alarm fires (OS handles)
  • Test: Launch app after alarm time passed
  • Expected: Plugin detects missed alarm if alarm did not fire, reschedules future alarms
  • Pass: Missed alarm detected if applicable, future alarms verified/rescheduled

3.1.3 App Warm Start

Trigger: App returning from background

Required Actions:

  1. Verify active alarms are still scheduled
  2. Detect missed alarms (trigger_time < now)
  3. Reschedule if needed
  4. Log recovery actions

Implementation Status: Deferred to future phase

Platform Reference: Android §2.1.4


3.1.4 Force Stop Recovery (Android Only)

Trigger: App launched after Force Stop

Required Actions:

  1. Detect force stop scenario (DB has alarms, AlarmManager has zero)
  2. Mark all past alarms as missed
  3. Reschedule all future alarms
  4. Generate missed alarm events/notifications
  5. Log recovery actions

Implementation Status: See Phase 2 Implementation

Platform Reference: Android §2.2.1, Android §2.2.2

Acceptance Criteria:

  • Test: Schedule multiple alarms (past and future), force stop app, wait past scheduled times
  • Expected: No alarms fire (OS limitation)
  • Test: Open app after force stop
  • Expected: Plugin detects force stop scenario, marks all past alarms as missed, reschedules all future alarms
  • Pass: All past alarms marked as missed, all future alarms rescheduled

3.1.5 User Taps Notification

Trigger: User interaction with notification

Required Actions:

  1. Launch app (OS handles)
  2. Detect if notification was missed
  3. Handle notification action
  4. Update alarm state if needed

Implementation Status: Basic support exists

Platform Reference: Android §2.1.1, iOS §3.1.1


3.2 Recovery Matrix

Recovery Point Android iOS Implementation Phase
Boot event Required Not needed (OS handles) Phase 3
Cold start Required Required Phase 1
Warm start ⚠️ Optional ⚠️ Optional Future
Force stop Required N/A Phase 2
User tap Required Required Basic

4. Missed Alarm Handling Contract

4.1 Definition

An alarm is "missed" if:

  • trigger_time < now
  • Alarm was not fired (or firing status unknown)
  • Alarm is still enabled
  • Alarm has not been manually cancelled

4.2 Detection Triggers

Missed alarms MUST be detected at:

  1. App cold start - When app launches from terminated state
  2. App warm start - When app returns from background (optional, future phase)
  3. Boot event (Android) - When device reboots
  4. Force stop recovery (Android) - When app launches after force stop

4.3 Required Actions

When a missed alarm is detected, the plugin MUST:

  1. Detect missed alarms during recovery
  2. Mark missed alarms in database (delivery_status = 'missed')
  3. Generate missed alarm event/notification (optional, future phase)
  4. Reschedule future occurrences (if repeating)
  5. Log missed alarm for debugging
  6. Update alarm state (mark as missed or reschedule)

4.4 Missed Alarm Resolution Rules

Resolution Strategy:

Scenario Detection Time Resolution Action Next Occurrence
Single alarm missed Cold start Mark as missed, do not reschedule N/A (one-time alarm)
Repeating alarm missed Cold start Mark as missed, reschedule next occurrence Calculate from current time
Multiple alarms missed Force stop recovery Mark all as missed, reschedule all future Calculate from current time
Boot recovery Boot event Mark past as missed, reschedule all future Calculate from current time

State Transition Table:

NONE (first launch, empty DB)
  ↓
COLD_START (DB populated, alarms may exist)
  ↓
FORCE_STOP? (detect: DB populated & no scheduled alarms)
  ↓
BOOT (detect: SharedPreferences flag set)
  ↓
Recovery Actions:
  - Detect missed alarms
  - Mark missed in database
  - Reschedule future alarms
  - Update state

Transition Detection:

  • NONE → COLD_START: DB empty on first launch
  • COLD_START → FORCE_STOP: DB has schedules but AlarmManager has zero alarms
  • COLD_START → BOOT: SharedPreferences last_boot_at flag set
  • Any → Recovery: Execute recovery actions based on scenario

4.5 Implementation Requirements

  • MUST run on app launch (cold/warm start)
  • MUST run on boot (Android)
  • MUST NOT duplicate missed alarm notifications
  • MUST handle timezone changes
  • MUST handle clock adjustments

Implementation Status:


5. JS/TS API Contract

5.1 JS/TS API Contract

The plugin MUST document and guarantee the following behaviors to JavaScript/TypeScript developers:

5.1.1 scheduleDailyNotification(options)

Method Signature:

scheduleDailyNotification(options: {
  schedule: string;        // Cron or HH:mm format
  title: string;
  body: string;
  sound?: boolean;
  vibration?: boolean;
  priority?: 'high' | 'normal' | 'low';
  payload?: object;
}): Promise<{
  success: boolean;
  alarmId?: string;
  error?: {
    code: string;
    message: string;
    action?: 'opened_settings' | 'permission_denied';
  };
}>

Returned Fields:

  • success (boolean) - Whether scheduling succeeded
  • alarmId (string, optional) - Unique identifier for scheduled alarm
  • error (object, optional) - Error details if scheduling failed
    • code (string) - Error code for programmatic handling
    • message (string) - Human-readable error message
    • action (string, optional) - Action taken (e.g., "opened_settings")

Guarantees:

  • Notification will fire if app is swiped from recents - MUST (OS-guaranteed)
  • Notification will fire if app is terminated by OS - MUST (OS-guaranteed)
  • ⚠️ Notification will fire after reboot only if:
    • Android: Boot receiver is registered and working - SHOULD (best-effort)
    • iOS: Automatic (OS handles) - MUST (OS-guaranteed)
  • Notification will NOT fire after Android Force Stop until app is opened - MUST NOT (OS limitation)
  • ⚠️ iOS notifications have ±180s timing tolerance - SHOULD (OS limitation)

Platform Caveats:

  • Android requires SCHEDULE_EXACT_ALARM permission on Android 12+ - See Doc A §5.2
  • Android requires RECEIVE_BOOT_COMPLETED permission for reboot recovery - See Doc A §2.1.2
  • iOS requires notification authorization - See Doc A §3.1.1

Error States:

  • EXACT_ALARM_PERMISSION_REQUIRED - Android 12+ exact alarm permission needed
    • Response: Plugin opens system settings, returns action: "opened_settings"
  • NOTIFICATIONS_DENIED - Notification permission denied
    • Response: Plugin shows error message, returns action: "permission_denied"
  • SCHEDULE_FAILED - Scheduling failed (check logs)
    • Response: Plugin logs error, returns error with message
  • STORAGE_FULL - Cannot persist alarm (storage full)
    • Response: Plugin attempts cleanup, retries, or returns error
  • INVALID_SCHEDULE - Schedule format invalid
    • Response: Plugin returns error with validation message

Platform References:

Developer Responsibilities:

  • MUST handle permission requests (Android 12+ exact alarm, iOS notification authorization)
  • MUST handle error responses and provide user feedback
  • SHOULD check getNotificationStatus() to verify alarm scheduling
  • MUST NOT assume alarms will fire after Force Stop (Android) until app is opened
  • MUST NOT assume exact timing on iOS (±180s tolerance)
  • SHOULD implement retry logic for scheduling failures

Platform Differences:

  • Android: Requires boot receiver for reboot recovery - See Doc A §2.1.2
  • iOS: Notifications persist automatically across reboot - See Doc A §3.1.2
  • Android: App code runs when alarm fires - See Doc A §2.1.1
  • iOS: App code does NOT run when notification fires - See Doc A §3.2.1

5.1.2 scheduleDailyReminder(options)

Method Signature: Same as scheduleDailyNotification() but without payload option.

Guarantees:

  • Same as scheduleDailyNotification() above
  • Static reminder (no content dependency)
  • Fires even if content fetch fails

5.1.3 getNotificationStatus()

Method Signature:

getNotificationStatus(): Promise<{
  pendingCount: number;
  lastNotificationTime?: number;
  missedAlarms?: Array<{
    alarmId: string;
    scheduledTime: number;
    detectedAt: number;
  }>;
  permissions: {
    exactAlarm?: boolean;        // Android 12+
    notifications?: boolean;      // iOS
    bootReceiver?: boolean;       // Android
  };
}>

Returned Fields:

  • pendingCount (number) - Number of scheduled alarms
  • lastNotificationTime (number, optional) - Timestamp of last notification
  • missedAlarms (array, optional) - Array of missed alarms
    • alarmId (string) - Unique identifier
    • scheduledTime (number) - When alarm was scheduled to fire
    • detectedAt (number) - When missed alarm was detected
  • permissions (object) - Current permission status
    • exactAlarm (boolean, optional) - Android 12+ exact alarm permission
    • notifications (boolean, optional) - iOS notification authorization
    • bootReceiver (boolean, optional) - Android boot receiver capability

Guarantees:

  • Returns current notification status - MUST
  • Includes pending notifications - MUST
  • Includes last notification time - SHOULD
  • May include missed alarm information - SHOULD (if detected)

5.2 API Warnings

The plugin MUST document the following warnings in JS/TS API documentation:

Android Warnings:

  • "Notifications will not fire after device reboot unless the app is opened at least once" - See Doc A §2.1.2
  • "Force Stop will prevent all notifications until the app is manually opened" - See Doc A §2.2.1
  • "Exact alarm permission is required on Android 12+ for precise timing" - See Doc A §5.2

iOS Warnings:

  • "Notifications have ±180 seconds timing tolerance" - See Doc A §6.1
  • "App code does not run when notifications fire (unless user interacts)" - See Doc A §3.2.1
  • "Background execution is system-controlled and not guaranteed" - See Doc A §3.1.3

Cross-Platform Warnings:

  • "Missed alarms are detected on app launch, not at trigger time" - See Doc C §4.2
  • "Repeating alarms must be rescheduled for each occurrence (Android)" - See Doc A §2.1.2
  • "Location-based triggers do not persist across reboot (iOS)" - See Doc A §3.1.2

5.3 API Error Handling

The plugin MUST:

  • Return clear error messages
  • Include error codes for programmatic handling
  • Open system settings when permission is needed
  • Provide actionable guidance in error messages

Example Error Response:

{
  code: "EXACT_ALARM_PERMISSION_REQUIRED",
  message: "Exact alarm permission required. Please grant 'Alarms & reminders' permission in Settings, then try again.",
  action: "opened_settings" // or "permission_denied"
}

6. Plugin WILL NOT Guarantee

6.1 Hard Boundaries (Cannot Ever Guarantee)

The plugin MUST NOT promise or attempt to guarantee:

Behavior Platform Reason Platform Reference
Auto-recovery after Force Stop Android OS hard kill - cannot bypass Doc A §2.2.1
App code execution on iOS notification fire iOS OS limitation - code does not run Doc A §3.2.1
Exact timing on iOS iOS ±180s tolerance is OS limitation Doc A §6.1
Background execution timing iOS System-controlled, not guaranteed Doc A §3.1.3
Alarm persistence without storage Both Must persist in durable storage Doc A §2.2.3

Enforcement: These behaviors MUST be documented as unsupported in JS/TS API documentation.


6.2 Guarantee vs Best-Effort Matrix

Behavior Android iOS Guarantee Level Notes
Notification fires after swipe Guaranteed Guaranteed MUST - OS-guaranteed Doc A §2.1.1, Doc A §3.1.1
Notification fires after reboot ⚠️ Best-effort Guaranteed Android: SHOULD (requires boot receiver), iOS: MUST Doc A §2.1.2, Doc A §3.1.2
Missed alarm detection Guaranteed Guaranteed MUST - Plugin-required Doc C §4.2
Force stop recovery Guaranteed N/A MUST - Plugin-required Doc C §3.1.4
Exact timing ⚠️ Best-effort ⚠️ Best-effort Android: SHOULD (with permission), iOS: SHOULD (±180s) Doc A §5.2, Doc A §6.1
Background execution ⚠️ Best-effort ⚠️ Best-effort SHOULD - System-controlled Doc A §3.1.3

Legend:

  • MUST = Plugin guarantees this behavior
  • SHOULD = Plugin attempts this but cannot guarantee (best-effort)
  • MUST NOT = Plugin cannot and will not attempt this

6.3 Failure Modes & Required Responses

Failure Mode Platform Required Plugin Response User Impact
Persistence failure Both Log error, continue with alarm scheduling (best effort), retry persistence Alarm may be lost if app killed
Storage full Both Log warning, attempt cleanup, retry, notify user if critical User must free space
Invalid data Both Skip invalid entries, log warning, continue processing Invalid alarms ignored
Permission denied Android Open settings, show error message, return error code User must grant permission
Boot receiver not registered Android Log error, alarms not rescheduled on boot Alarms lost on reboot
Force stop Android Detect on app restart, recover all alarms, mark missed Alarms lost until app opened
Background execution denied iOS Log warning, schedule next attempt, notify user Prefetch may fail
Notification authorization denied iOS Show error, return error code, cannot schedule Notifications disabled

Required Actions:

  • MUST log all failures with sufficient context
  • MUST provide user-visible error messages for critical failures
  • SHOULD provide recovery mechanisms where possible
  • MUST NOT crash or silently fail

7. Explicit Storage Schema

7.1 Required Database Schema

Android (Room Database):

Table Field Type Required Purpose
Schedule id String Yes Unique identifier
kind String Yes "notify" or "fetch"
enabled Boolean Yes Whether alarm is active
cron String? ⚠️ Optional Cron expression
clockTime String? ⚠️ Optional HH:mm format
nextRunAt Long? ⚠️ Optional Next scheduled time
createdAt Long Yes Creation timestamp
updatedAt Long Yes Last update timestamp
NotificationContentEntity id String Yes Unique identifier
scheduleId String Yes Foreign key to Schedule
title String Yes Notification title
body String Yes Notification body
scheduledTime Long Yes When to fire
deliveryStatus String Yes "pending", "delivered", "missed"
priority String Yes Notification priority
soundEnabled Boolean Yes Sound preference
vibrationEnabled Boolean Yes Vibration preference
createdAt Long Yes Creation timestamp
updatedAt Long Yes Last update timestamp
ContentCache id String Yes Unique identifier
scheduleId String Yes Foreign key to Schedule
payload String? ⚠️ Optional Additional content (JSON)
createdAt Long Yes Creation timestamp

iOS (Plugin Storage):

Storage Type Field Type Required Purpose
UserDefaults/CoreData alarm_id String Yes Unique identifier
trigger_time TimeInterval Yes When to fire
repeat_rule String Yes NONE, DAILY, WEEKLY, CUSTOM
title String Yes Notification title
body String Yes Notification body
enabled Boolean Yes Whether alarm is active
created_at TimeInterval Yes Creation timestamp
updated_at TimeInterval Yes Last update timestamp

Note: iOS also uses UNUserNotificationCenter (OS-managed) for notification scheduling, but plugin MUST maintain parallel storage for missed detection.


8. Explicit Unsupported Behaviors

8.1 Hard Boundaries (Plugin WILL NOT Guarantee)

The plugin MUST NOT support or guarantee the following behaviors:

Behavior Platform Reason Platform Reference
Auto-recovery after Android Force Stop Android OS hard kill - cannot bypass Doc A §2.2.1
App code execution on iOS notification fire iOS OS limitation - code does not run Doc A §3.2.1
Exact timing on iOS iOS ±180s tolerance is OS limitation Doc A §6.1
Background execution timing guarantees Both System-controlled, not guaranteed Doc A §3.1.3
Alarm persistence without durable storage Both Must use database/files Doc A §2.2.3
Repeating alarms without rescheduling Android Must reschedule each occurrence Doc A §2.1.2
Location-based triggers iOS Does not persist across reboot Doc A §3.1.2
Silent rescheduling without user launch Android Force stop blocks all execution Doc A §2.2.1

Documentation Requirement: All unsupported behaviors MUST be documented in JS/TS API with clear warnings. See §5.2 - API Warnings.


8.2 Platform-Specific Limitations

Android:

  • Force Stop is a hard kill that cannot be bypassed - See Doc A §2.2.1
  • Reboot wipes all alarms; must reschedule from storage - See Doc A §2.1.2
  • Exact alarm permission required on Android 12+ - See Doc A §5.2
  • Doze mode may defer inexact alarms - See Doc A §2.1.1

iOS:


9. Traceability Matrix

Complete mapping from platform facts → requirements → tests → implementation:

Requirement Platform Source (Doc A) Expected Plugin Behavior (Doc C) Test Scenario (Doc B) Implemented in Phase
Missed alarm detection Android §2.1.4 §4.2 - Detection Triggers Test 4 Step 6 Phase 1
Boot reschedule Android §2.1.2 §3.1.1 - Boot Event Test 4 Step 7 Phase 3
Force stop recovery Android §2.2.1 §3.1.4 - Force Stop Recovery Test 5 Phase 2
Cold start recovery Android §2.1.4 §3.1.2 - App Cold Start Test 4 Step 5 Phase 1
Swipe from recents Android §2.1.1, iOS §3.1.1 §1.1 - Guarantees Matrix Test 2 OS-guaranteed
iOS notification persistence iOS §3.1.2 §1.1 - Guarantees Matrix Test 3 OS-guaranteed
Persistence Android §2.2.3 §2 - Persistence Requirements Persistence Investigation Phase 1
Exact alarm permission Android §5.2 §10.1.1 - Permissions Test 6 Phase 1

10. Platform-Specific Requirements

10.1 Android Requirements

10.1.1 Permissions

Required Permissions:

  • RECEIVE_BOOT_COMPLETED - Boot receiver
  • SCHEDULE_EXACT_ALARM - Android 12+ (API 31+) for exact alarms
  • POST_NOTIFICATIONS - Android 13+ (API 33+) for notifications

Permission Handling:

  • Check permission before scheduling
  • Request permission if not granted
  • Open system settings if permission denied
  • Provide clear error messages

Code Reference: DailyNotificationPlugin.kt line 1309

Platform Reference: Android §2.2.4


10.1.2 Manifest Entries

Required Manifest Entries:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<receiver
    android:name="com.timesafari.dailynotification.BootReceiver"
    android:enabled="true"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
    </intent-filter>
</receiver>

<receiver
    android:name="com.timesafari.dailynotification.DailyNotificationReceiver"
    android:enabled="true"
    android:exported="false">
    <intent-filter>
        <action android:name="com.timesafari.daily.NOTIFICATION" />
    </intent-filter>
</receiver>

Location: Test app manifest: test-apps/android-test-app/app/src/main/AndroidManifest.xml


10.1.3 Notification Channels

Required Channels:

  • timesafari.daily - Primary notification channel
  • daily_reminders - Reminder notifications (if used)

Channel Configuration:

  • Importance: HIGH (for alarms), DEFAULT (for reminders)
  • Sound: Enabled by default
  • Vibration: Enabled by default
  • Show badge: Enabled

Code Reference: ChannelManager.java or NotifyReceiver.kt line 454


10.1.4 Alarm Scheduling

Required API Usage:

  • setAlarmClock() for Android 5.0+ (preferred)
  • setExactAndAllowWhileIdle() for Android 6.0+ (fallback)
  • setExact() for older versions (fallback)

Code Reference: NotifyReceiver.kt line 219, 223, 231

Platform Reference: Android §2.1.1


10.2 iOS Requirements

10.2.1 Permissions

Required Permissions:

  • Notification authorization (requested at runtime)

Permission Handling:

  • Request permission before scheduling
  • Handle authorization status
  • Provide clear error messages

10.2.2 Background Tasks

Required Background Task Identifiers:

  • com.timesafari.dailynotification.fetch - Background fetch
  • com.timesafari.dailynotification.notify - Notification task (if used)

Background Task Registration:

  • Register in Info.plist:
    <key>BGTaskSchedulerPermittedIdentifiers</key>
    <array>
        <string>com.timesafari.dailynotification.fetch</string>
    </array>
    

Code Reference: DailyNotificationPlugin.swift line 31-32

Platform Reference: iOS §3.1.3


10.2.3 Notification Scheduling

Required API Usage:

  • UNUserNotificationCenter.add() - Schedule notifications
  • UNCalendarNotificationTrigger - Calendar-based triggers (preferred)
  • UNTimeIntervalNotificationTrigger - Time interval triggers

Code Reference: DailyNotificationScheduler.swift line 185

Platform Reference: iOS §3.1.1


10.2.4 Notification Categories

Required Categories:

  • DAILY_NOTIFICATION - Primary notification category

Category Configuration:

  • Actions: Configure as needed
  • Options: Custom sound, custom actions

Code Reference: DailyNotificationScheduler.swift line 62+


11. Testing Requirements

11.1 Required Test Scenarios

The plugin must be tested for:

Android:

  • Base case (alarm fires on time)
  • Swipe from recents
  • OS kill (memory pressure)
  • Device reboot (with and without app launch)
  • Force stop (with app restart)
  • Exact alarm permission (Android 12+)
  • Boot receiver functionality
  • Missed alarm detection

iOS:

  • Base case (notification fires on time)
  • Swipe app away
  • Device reboot (without app launch)
  • Hard termination and relaunch
  • Background execution limits
  • Missed notification detection

Cross-Platform:

  • Timezone changes
  • Clock adjustments
  • Multiple simultaneous alarms
  • Repeating alarms
  • Alarm cancellation

Test Documentation: See Plugin Behavior Exploration for test matrices.


12. Migration Rules

12.1 Storage Format Changes

If plugin storage format changes, migration MUST define:

  1. Version detection: How to identify old vs new format
  2. Safe upgrade path: Step-by-step migration process
  3. Failure fallback: What happens if migration fails
  4. No data loss: All existing alarms must be preserved or explicitly marked as lost

Migration Requirements:

  • MUST run automatically on app launch
  • MUST log migration steps for debugging
  • MUST handle partial migrations gracefully
  • MUST NOT lose user data without explicit user confirmation

Example Migration:

// Pseudo-code
if (databaseVersion < currentVersion) {
    migrateDatabase(oldVersion, currentVersion)
    verifyMigrationIntegrity()
    if (migrationFailed) {
        rollbackToBackup()
        notifyUser()
    }
}

12.2 API Contract Changes

If JS/TS API changes:

  • MUST maintain backward compatibility for at least one major version
  • MUST provide deprecation warnings before removal
  • MUST document migration path in changelog
  • MUST update Doc C before releasing breaking changes

13. API Stability Guarantees

13.1 Breaking Change Policy

No breaking change may occur without:

  1. Doc C update - Requirements document updated first
  2. MINOR or MAJOR version bump - Semantic versioning enforced
  3. Migration notes - Clear upgrade path documented
  4. Deprecation period - Old API deprecated for at least one release cycle

13.2 Stability Guarantees

Plugin guarantees:

  • MUST maintain API contract within same major version
  • SHOULD maintain API contract across minor versions (exceptions documented)
  • MUST NOT break API contract without major version bump

Example:

  • v1.0.0v1.1.0: New features added, no breaking changes
  • v1.1.0v2.0.0: Breaking API change, migration guide required
  • v1.1.0v1.2.0: Breaking API change (must be v2.0.0)

14. "What Happens If We Do Nothing?" Analysis

14.1 No Recovery Implementation

If plugin does NOT implement recovery:

Scenario What Happens Impact
Device Reboot (Android) All alarms wiped, never fire Critical: User loses all scheduled alarms
Force Stop (Android) All alarms cleared, never fire until app opened Critical: User loses alarms until manual app launch
Cold Start Missed alarms never detected Major: User unaware of missed notifications
Warm Start Alarms may be missing, never verified Minor: Edge case, alarms usually still work

Conclusion: Recovery MUST be implemented for Android reboot and force stop scenarios. Cold start recovery SHOULD be implemented for user experience.

14.2 No Persistence

If plugin does NOT persist alarms:

Scenario What Happens Impact
App Kill All alarms lost Critical: User loses all scheduled alarms
Reboot Cannot reschedule Critical: Recovery impossible
Force Stop Cannot detect missed alarms Major: Recovery incomplete

Conclusion: Persistence MUST be implemented. It is foundational for all recovery scenarios.

14.3 No Missed Alarm Detection

If plugin does NOT detect missed alarms:

Scenario What Happens Impact
Missed Alarm User never notified Major: User unaware of missed notifications
Repeating Alarm Next occurrence may be wrong Major: Schedule drift over time

Conclusion: Missed alarm detection SHOULD be implemented for user experience and schedule accuracy.


15. Versioning Requirements

15.1 Breaking Changes

Any change to alarm behavior is breaking and requires:

  • MAJOR version bump (semantic versioning)
  • Migration guide for existing users
  • Deprecation warnings (if applicable)
  • Clear changelog entry

10.2 Non-Breaking Changes

Non-breaking changes include:

  • Bug fixes
  • Performance improvements
  • Additional features (backward compatible)
  • Documentation updates

16. Cross-Reference Anchors

All cross-references use standardized anchors:

Reference Format Example Resolves To
[Doc A §X.Y] [Doc A §2.1.1] Platform Reference §2.1.1
[Doc B §X.Y] [Doc B §1.2] Exploration §1.2
[Doc C §X.Y] [Doc C §3.1.2] Requirements §3.1.2
[Phase N §X.Y] [Phase 1 §2.3] Phase 1 Implementation

Anchor Rules:

  • All section headers MUST have unique anchors
  • Cross-references MUST use exact anchor format
  • Broken links MUST be fixed immediately


Version History

  • v1.1.0 (November 2025): Enhanced with non-guarantees, failure modes, storage schema

    • Added "Plugin WILL NOT Guarantee" section
    • Added Guarantee vs Best-Effort matrix
    • Added Failure Modes & Required Responses table
    • Added Explicit Storage Schema
    • Enhanced JS/TS API contract with returned fields and error states
    • Added Missed Alarm Resolution Rules
    • Added State Transition Table
    • Added Explicit Unsupported Features List
  • v1.0.0 (November 2025): Initial requirements document

    • Plugin behavior guarantees and limitations
    • Persistence requirements
    • Recovery requirements
    • Missed alarm handling contract
    • JS/TS API contract
    • Platform-specific requirements
    • Testing requirements
    • Traceability matrix