docs: Consolidate documentation structure (139 files, zero information loss)
Consolidate all markdown documentation into organized structure per CONSOLIDATION_DIRECTIVE. All files preserved (canonical, merged, or archived). - docs/integration/ - Integration documentation (7 files) - docs/platform/ios/ - iOS platform docs (12 files) - docs/platform/android/ - Android platform docs (9 files) - docs/testing/ - Testing documentation (15 files) - docs/design/ - Design & research (5 files) - docs/ai/ - AI/ChatGPT artifacts (7 files) - docs/archive/2025-legacy-doc/ - Historical docs (17 files) - Integration: Root INTEGRATION_GUIDE.md → docs/integration/ - Platform: Separated iOS and Android into platform/ subdirectories - Testing: Consolidated all testing docs to docs/testing/ - Legacy: Archived entire doc/ directory to archive/ - AI: Moved all ChatGPT artifacts to docs/ai/ - Added docs/00-INDEX.md - Central navigation hub - Added docs/CONSOLIDATION_SOURCE_MAP.md - Complete audit trail - Added docs/CONSOLIDATION_COMPLETE.md - Consolidation summary - Updated README.md with links to documentation index - All 139 files have destinations (see CONSOLIDATION_SOURCE_MAP.md) - Zero information loss (all files preserved) - Archive preserves original structure - Index provides clear navigation - 87 files moved/created/updated - Root-level docs consolidated - Legacy doc/ directory archived - Test app docs remain with test apps (indexed) Ref: CONSOLIDATION_DIRECTIVE Author: Matthew Raymer
This commit is contained in:
423
docs/platform/ios/RECOVERY_SCENARIO_MAPPING.md
Normal file
423
docs/platform/ios/RECOVERY_SCENARIO_MAPPING.md
Normal file
@@ -0,0 +1,423 @@
|
||||
# iOS Recovery Scenario Mapping: Android → iOS Equivalents
|
||||
|
||||
**Author**: Matthew Raymer
|
||||
**Date**: 2025-12-08
|
||||
**Status**: 🎯 **ACTIVE** - Recovery Scenario Mapping Reference
|
||||
**Version**: 1.0.0
|
||||
**Last Synced With Plugin Version**: v1.1.0
|
||||
|
||||
## Purpose
|
||||
|
||||
This document maps Android recovery scenarios to their iOS equivalents, providing a clear translation guide for implementing iOS recovery logic based on Android patterns.
|
||||
|
||||
**Reference**:
|
||||
- [Android Implementation Directive](./android-implementation-directive.md) - Android scenarios
|
||||
- [iOS Implementation Directive](./ios-implementation-directive.md) - iOS scenarios
|
||||
- [Platform Capability Reference](./alarms/01-platform-capability-reference.md) - OS-level facts
|
||||
|
||||
---
|
||||
|
||||
## 1. Scenario Mapping Overview
|
||||
|
||||
### 1.1 Direct Mappings
|
||||
|
||||
| Android Scenario | iOS Equivalent | Detection Method | Recovery Action |
|
||||
| ---------------- | -------------- | ---------------- | --------------- |
|
||||
| `COLD_START` | App Launch After Termination | Compare UNUserNotificationCenter vs DB | Detect missed, verify future |
|
||||
| `FORCE_STOP` | App Terminated by System | DB has schedules, no notifications | Full recovery of all schedules |
|
||||
| `BOOT` | Device Reboot | BGTaskScheduler registration | Reschedule all notifications |
|
||||
| `WARM_START` | App Resume (Foreground) | Notifications match DB state | No recovery needed (optimization) |
|
||||
| `NONE` | First Launch / No Recovery | Empty database | No action needed |
|
||||
|
||||
### 1.2 Key Differences
|
||||
|
||||
**iOS Advantages**:
|
||||
- ✅ Notifications persist across termination (OS-guaranteed)
|
||||
- ✅ Notifications persist across reboot (OS-guaranteed)
|
||||
- ❌ No user-facing "force stop" equivalent
|
||||
|
||||
**iOS Challenges**:
|
||||
- ❌ App code does NOT run when notification fires
|
||||
- ❌ Must detect missed notifications on app launch
|
||||
- ❌ Background execution severely limited
|
||||
|
||||
---
|
||||
|
||||
## 2. Detailed Scenario Mappings
|
||||
|
||||
### 2.1 COLD_START → App Launch After Termination
|
||||
|
||||
**Android Definition**:
|
||||
- Process killed, alarms may or may not exist
|
||||
- Database still populated
|
||||
- Alarms may have been cleared by OS
|
||||
|
||||
**iOS Equivalent**:
|
||||
- App terminated by system or user
|
||||
- Notifications may still exist (OS-guaranteed persistence)
|
||||
- Database still populated
|
||||
- Need to verify notification state matches database
|
||||
|
||||
**Detection Logic**:
|
||||
|
||||
**Android**:
|
||||
```kotlin
|
||||
// Check if alarms exist in AlarmManager
|
||||
val alarmsExist = alarmManager.hasAlarm(pendingIntent)
|
||||
if (alarmsExist && dbHasSchedules) {
|
||||
return COLD_START
|
||||
}
|
||||
```
|
||||
|
||||
**iOS**:
|
||||
```swift
|
||||
// Check if notifications exist in UNUserNotificationCenter
|
||||
let pendingNotifications = try await notificationCenter.pendingNotificationRequests()
|
||||
let dbSchedules = try database.getEnabledSchedules()
|
||||
|
||||
if !pendingNotifications.isEmpty && !dbSchedules.isEmpty {
|
||||
// Compare notification IDs with DB state
|
||||
let dbIds = Set(dbSchedules.flatMap { $0.getScheduledNotificationIds() })
|
||||
let pendingIds = Set(pendingNotifications.map { $0.identifier })
|
||||
|
||||
if dbIds != pendingIds {
|
||||
return .coldStart // Mismatch indicates recovery needed
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Recovery Actions**:
|
||||
1. Detect missed notifications (scheduled_time < now, not delivered)
|
||||
2. Mark missed notifications in database
|
||||
3. Verify future notifications are scheduled
|
||||
4. Reschedule missing future notifications
|
||||
|
||||
**Platform Reference**: [iOS §3.1.1](./alarms/01-platform-capability-reference.md#311-notifications-survive-app-termination)
|
||||
|
||||
---
|
||||
|
||||
### 2.2 FORCE_STOP → App Terminated by System
|
||||
|
||||
**Android Definition**:
|
||||
- User force-stopped app via Settings
|
||||
- All alarms cleared
|
||||
- Database still populated
|
||||
- Boot receiver blocked until user launches app
|
||||
|
||||
**iOS Equivalent**:
|
||||
- App terminated by system (low memory, etc.)
|
||||
- Notifications may be missing (system cleared them)
|
||||
- Database still populated
|
||||
- No user-facing force stop equivalent
|
||||
|
||||
**Key Difference**: iOS doesn't have a user-facing "force stop" option. System termination is the closest equivalent.
|
||||
|
||||
**Detection Logic**:
|
||||
|
||||
**Android**:
|
||||
```kotlin
|
||||
// Check if alarms exist
|
||||
val alarmsExist = alarmManager.hasAlarm(pendingIntent)
|
||||
if (!alarmsExist && dbHasSchedules && !isBootRecent) {
|
||||
return FORCE_STOP
|
||||
}
|
||||
```
|
||||
|
||||
**iOS**:
|
||||
```swift
|
||||
// Check if notifications exist
|
||||
let pendingNotifications = try await notificationCenter.pendingNotificationRequests()
|
||||
let dbSchedules = try database.getEnabledSchedules()
|
||||
|
||||
if pendingNotifications.isEmpty && !dbSchedules.isEmpty {
|
||||
// DB has schedules but no notifications scheduled
|
||||
return .termination
|
||||
}
|
||||
```
|
||||
|
||||
**Recovery Actions**:
|
||||
1. Detect all missed notifications
|
||||
2. Mark all missed notifications in database
|
||||
3. Reschedule all future notifications
|
||||
4. Reschedule all fetch schedules (if applicable)
|
||||
|
||||
**Platform Reference**: [iOS §3.2.1](./alarms/01-platform-capability-reference.md#321-app-code-does-not-run-when-notification-fires)
|
||||
|
||||
---
|
||||
|
||||
### 2.3 BOOT → Device Reboot
|
||||
|
||||
**Android Definition**:
|
||||
- Device rebooted
|
||||
- All alarms wiped (OS behavior)
|
||||
- Database still populated
|
||||
- Boot receiver executes after boot completes
|
||||
|
||||
**iOS Equivalent**:
|
||||
- Device rebooted
|
||||
- Notifications persist automatically (OS-guaranteed)
|
||||
- Database still populated
|
||||
- BGTaskScheduler may execute (system-controlled)
|
||||
|
||||
**Key Difference**: iOS automatically persists notifications across reboot. Android requires manual rescheduling.
|
||||
|
||||
**Detection Logic**:
|
||||
|
||||
**Android**:
|
||||
```kotlin
|
||||
// Check boot flag (set by BootReceiver)
|
||||
val bootFlag = sharedPreferences.getLong("last_boot_time", 0)
|
||||
val currentTime = System.currentTimeMillis()
|
||||
if (bootFlag > 0 && (currentTime - bootFlag) < 60000) {
|
||||
return BOOT
|
||||
}
|
||||
```
|
||||
|
||||
**iOS**:
|
||||
```swift
|
||||
// BGTaskScheduler registration handles boot
|
||||
// Check if this is a boot-triggered background task
|
||||
if isBootBackgroundTask {
|
||||
return .boot
|
||||
}
|
||||
|
||||
// Or detect on app launch after reboot
|
||||
let lastLaunchTime = UserDefaults.standard.double(forKey: "last_launch_time")
|
||||
let bootTime = ProcessInfo.processInfo.systemUptime
|
||||
if lastLaunchTime > 0 && bootTime < 60 {
|
||||
return .boot
|
||||
}
|
||||
```
|
||||
|
||||
**Recovery Actions**:
|
||||
1. Verify notifications still exist (iOS usually handles this)
|
||||
2. Detect any missed notifications during reboot window
|
||||
3. Reschedule any missing notifications
|
||||
4. Update next run times for repeating schedules
|
||||
|
||||
**Platform Reference**: [iOS §3.1.2](./alarms/01-platform-capability-reference.md#312-notifications-persist-across-device-reboot)
|
||||
|
||||
---
|
||||
|
||||
### 2.4 WARM_START → App Resume (Foreground)
|
||||
|
||||
**Android Definition**:
|
||||
- App resumed from background
|
||||
- Alarms still exist
|
||||
- Database matches alarm state
|
||||
- No recovery needed (optimization)
|
||||
|
||||
**iOS Equivalent**:
|
||||
- App resumed from background
|
||||
- Notifications still exist
|
||||
- Database matches notification state
|
||||
- No recovery needed (optimization)
|
||||
|
||||
**Detection Logic**:
|
||||
|
||||
**Android**:
|
||||
```kotlin
|
||||
// Check if alarms exist and match DB
|
||||
val alarmsExist = alarmManager.hasAlarm(pendingIntent)
|
||||
if (alarmsExist && dbMatchesAlarms) {
|
||||
return WARM_START
|
||||
}
|
||||
```
|
||||
|
||||
**iOS**:
|
||||
```swift
|
||||
// Check if notifications exist and match DB
|
||||
let pendingNotifications = try await notificationCenter.pendingNotificationRequests()
|
||||
let dbSchedules = try database.getEnabledSchedules()
|
||||
|
||||
let dbIds = Set(dbSchedules.flatMap { $0.getScheduledNotificationIds() })
|
||||
let pendingIds = Set(pendingNotifications.map { $0.identifier })
|
||||
|
||||
if dbIds == pendingIds {
|
||||
return .warmStart // Match indicates warm resume
|
||||
}
|
||||
```
|
||||
|
||||
**Recovery Actions**:
|
||||
- None (optimization only)
|
||||
- May perform lightweight verification
|
||||
- May update metrics
|
||||
|
||||
---
|
||||
|
||||
### 2.5 NONE → First Launch / No Recovery
|
||||
|
||||
**Android Definition**:
|
||||
- First app launch
|
||||
- Empty database
|
||||
- No schedules configured
|
||||
- No recovery needed
|
||||
|
||||
**iOS Equivalent**:
|
||||
- First app launch
|
||||
- Empty database
|
||||
- No schedules configured
|
||||
- No recovery needed
|
||||
|
||||
**Detection Logic**:
|
||||
|
||||
**Android**:
|
||||
```kotlin
|
||||
// Check if database is empty
|
||||
val schedules = database.scheduleDao().getEnabled()
|
||||
if (schedules.isEmpty()) {
|
||||
return NONE
|
||||
}
|
||||
```
|
||||
|
||||
**iOS**:
|
||||
```swift
|
||||
// Check if database is empty
|
||||
let schedules = try database.getEnabledSchedules()
|
||||
if schedules.isEmpty {
|
||||
return .none
|
||||
}
|
||||
```
|
||||
|
||||
**Recovery Actions**:
|
||||
- None
|
||||
|
||||
---
|
||||
|
||||
## 3. Recovery Action Mapping
|
||||
|
||||
### 3.1 Missed Notification Detection
|
||||
|
||||
**Android**:
|
||||
- Query AlarmManager for past alarms
|
||||
- Check database for undelivered notifications
|
||||
- Mark as missed in database
|
||||
|
||||
**iOS**:
|
||||
- Query database for past scheduled notifications
|
||||
- Check delivery status
|
||||
- Mark as missed in database
|
||||
|
||||
**Key Difference**: iOS cannot query past notifications from UNUserNotificationCenter. Must rely on database state.
|
||||
|
||||
### 3.2 Future Notification Verification
|
||||
|
||||
**Android**:
|
||||
- Query AlarmManager for future alarms
|
||||
- Compare with database schedules
|
||||
- Reschedule missing alarms
|
||||
|
||||
**iOS**:
|
||||
- Query UNUserNotificationCenter for pending notifications
|
||||
- Compare with database schedules
|
||||
- Reschedule missing notifications
|
||||
|
||||
**Key Difference**: iOS uses UNUserNotificationCenter instead of AlarmManager.
|
||||
|
||||
### 3.3 Full Recovery
|
||||
|
||||
**Android**:
|
||||
- Reschedule all notify schedules
|
||||
- Reschedule all fetch schedules (WorkManager)
|
||||
- Mark past notifications as missed
|
||||
|
||||
**iOS**:
|
||||
- Reschedule all notify schedules
|
||||
- Reschedule all fetch schedules (BGTaskScheduler)
|
||||
- Mark past notifications as missed
|
||||
|
||||
**Key Difference**: iOS uses BGTaskScheduler instead of WorkManager.
|
||||
|
||||
---
|
||||
|
||||
## 4. Implementation Checklist
|
||||
|
||||
### 4.1 Phase 1: Cold Start Recovery
|
||||
|
||||
- [ ] Implement scenario detection (cold start)
|
||||
- [ ] Implement missed notification detection
|
||||
- [ ] Implement future notification verification
|
||||
- [ ] Test cold start recovery
|
||||
|
||||
### 4.2 Phase 2: Termination Detection
|
||||
|
||||
- [ ] Implement termination detection
|
||||
- [ ] Implement full recovery logic
|
||||
- [ ] Test termination recovery
|
||||
|
||||
### 4.3 Phase 3: Boot Recovery
|
||||
|
||||
- [ ] Implement BGTaskScheduler registration
|
||||
- [ ] Implement boot detection
|
||||
- [ ] Test boot recovery
|
||||
|
||||
---
|
||||
|
||||
## 5. Platform-Specific Notes
|
||||
|
||||
### 5.1 iOS Advantages
|
||||
|
||||
1. **Notification Persistence**: iOS automatically persists notifications across termination and reboot
|
||||
2. **No Force Stop**: iOS doesn't have user-facing force stop, reducing complexity
|
||||
3. **Simplified Recovery**: Less recovery needed due to OS persistence
|
||||
|
||||
### 5.2 iOS Challenges
|
||||
|
||||
1. **No Code Execution on Fire**: App code doesn't run when notification fires
|
||||
2. **Background Limits**: Severely limited background execution
|
||||
3. **Timing Tolerance**: ±180 second tolerance for calendar triggers
|
||||
|
||||
### 5.3 Android Advantages
|
||||
|
||||
1. **Code Execution on Fire**: PendingIntent can execute code when alarm fires
|
||||
2. **WorkManager**: More reliable background execution
|
||||
3. **Exact Timing**: Can achieve exact timing with permission
|
||||
|
||||
### 5.4 Android Challenges
|
||||
|
||||
1. **No Persistence**: Alarms don't persist across reboot
|
||||
2. **Force Stop**: Hard kill that cannot be bypassed
|
||||
3. **Boot Recovery**: Must implement boot receiver
|
||||
|
||||
---
|
||||
|
||||
## 6. Testing Strategy
|
||||
|
||||
### 6.1 Scenario Testing
|
||||
|
||||
**Cold Start**:
|
||||
1. Terminate app (swipe away)
|
||||
2. Wait for notification time to pass
|
||||
3. Launch app
|
||||
4. Verify missed notification detection
|
||||
5. Verify future notifications rescheduled
|
||||
|
||||
**Termination**:
|
||||
1. Schedule notifications
|
||||
2. Terminate app
|
||||
3. Clear notifications (simulate system clearing)
|
||||
4. Launch app
|
||||
5. Verify full recovery
|
||||
|
||||
**Boot**:
|
||||
1. Schedule notifications
|
||||
2. Reboot device (or simulate)
|
||||
3. Launch app
|
||||
4. Verify notifications still exist
|
||||
5. Verify any missed notifications detected
|
||||
|
||||
---
|
||||
|
||||
## 7. References
|
||||
|
||||
- [Android Implementation Directive](./android-implementation-directive.md) - Android scenarios
|
||||
- [iOS Implementation Directive](./ios-implementation-directive.md) - iOS scenarios
|
||||
- [Platform Capability Reference](./alarms/01-platform-capability-reference.md) - OS-level facts
|
||||
- [Plugin Requirements](./alarms/03-plugin-requirements.md) - Requirements
|
||||
|
||||
---
|
||||
|
||||
**Document Version**: 1.0.0
|
||||
**Last Updated**: 2025-12-08
|
||||
**Next Review**: After Phase 1 implementation
|
||||
|
||||
Reference in New Issue
Block a user