Implement comprehensive logging and observability for recovery operations: - Add HistoryDAO for Core Data history recording - recordRecovery() method with execution time tracking - recordRecoveryFailure() method with detailed error info - Query helpers for history retrieval - Enhance DailyNotificationReactivationManager logging: - Add execution time tracking (startTime/endTime) - Enhanced error logging with NSError details (domain, code, userInfo) - Comprehensive logging at each recovery step - Missed/future notification count logging - Implement Core Data persistence for recovery metrics: - Recovery execution time - Missed notification count - Rescheduled notification count - Verified notification count - Error count - Diagnostic JSON with full recovery context - Update recovery methods to record history: - Cold start recovery - Termination recovery - Boot recovery - All with timing and metrics Completes section 7.1 (Recovery Logging) and 7.2 (Metrics Recording) of iOS implementation checklist.
488 lines
17 KiB
Markdown
488 lines
17 KiB
Markdown
# iOS Implementation Checklist
|
|
|
|
**Author**: Matthew Raymer
|
|
**Date**: 2025-12-08
|
|
**Status**: 🎯 **ACTIVE** - Implementation Tracking
|
|
**Version**: 1.0.0
|
|
|
|
## Purpose
|
|
|
|
Complete checklist of iOS code that needs to be implemented for feature parity with Android. This checklist tracks all implementation tasks with checkboxes.
|
|
|
|
**Reference**:
|
|
- [iOS Implementation Directive](./ios-implementation-directive.md) - Implementation guide
|
|
- [iOS Recovery Scenario Mapping](./ios-recovery-scenario-mapping.md) - Scenario details
|
|
- [iOS Core Data Migration Guide](./ios-core-data-migration.md) - Database entities
|
|
|
|
---
|
|
|
|
## Phase 1: Cold Start Recovery (High Priority)
|
|
|
|
### 1.1 Create ReactivationManager
|
|
|
|
- [x] Create new file: `ios/Plugin/DailyNotificationReactivationManager.swift`
|
|
- [x] Implement class structure with properties:
|
|
- [x] `notificationCenter: UNUserNotificationCenter`
|
|
- [x] `database: DailyNotificationDatabase`
|
|
- [x] `storage: DailyNotificationStorage`
|
|
- [x] `scheduler: DailyNotificationScheduler`
|
|
- [x] `TAG: String = "DNP-REACTIVATION"`
|
|
- [x] Implement `init(database:storage:scheduler:)` initializer
|
|
- [x] Implement `performRecovery()` async method
|
|
- [x] Add timeout protection (2 seconds max)
|
|
- [x] Add error handling (non-fatal, log only)
|
|
|
|
### 1.2 Scenario Detection
|
|
|
|
- [x] Create `RecoveryScenario` enum:
|
|
- [x] `.none` - No recovery needed
|
|
- [x] `.coldStart` - App launched after termination
|
|
- [x] `.termination` - App terminated, notifications missing
|
|
- [x] `.warmStart` - App resumed (optimization)
|
|
- [x] Implement `detectScenario() async throws -> RecoveryScenario`:
|
|
- [x] Check if database has notifications (empty → `.none`)
|
|
- [x] Get pending notifications from `UNUserNotificationCenter`
|
|
- [x] Compare DB state with notification center state
|
|
- [x] Return appropriate scenario
|
|
|
|
### 1.3 Cold Start Recovery Logic
|
|
|
|
- [x] Implement `performColdStartRecovery() async throws -> RecoveryResult`:
|
|
- [x] Detect missed notifications (scheduled_time < now, not delivered)
|
|
- [x] Mark missed notifications in database (Phase 1: basic marking, Phase 2: add delivery_status)
|
|
- [x] Update `last_delivery_attempt` timestamp (Phase 2: add property)
|
|
- [x] Record in history table (Phase 1: logging only, Phase 2: database recording)
|
|
- [x] Verify future notifications are scheduled
|
|
- [x] Reschedule missing future notifications
|
|
- [x] Return `RecoveryResult` with counts
|
|
|
|
### 1.4 Missed Notification Detection
|
|
|
|
- [x] Implement `detectMissedNotifications() async throws -> [NotificationContent]`:
|
|
- [x] Query storage for notifications with `scheduled_time < currentTime`
|
|
- [x] Filter for missed notifications (Phase 1: time-based only, Phase 2: add delivery_status check)
|
|
- [x] Return list of missed notifications
|
|
- [x] Implement `markMissedNotification(_:) async throws`:
|
|
- [x] Mark notification as missed (Phase 1: basic, Phase 2: add delivery_status property)
|
|
- [x] Update notification in storage
|
|
- [x] Record status change (Phase 1: logging, Phase 2: history table)
|
|
|
|
### 1.5 Future Notification Verification
|
|
|
|
- [x] Implement `verifyFutureNotifications() async throws -> VerificationResult`:
|
|
- [x] Get all future notifications from storage
|
|
- [x] Get pending notifications from `UNUserNotificationCenter`
|
|
- [x] Compare notification IDs
|
|
- [x] Identify missing notifications
|
|
- [x] Return verification result
|
|
- [x] Implement `rescheduleMissingNotification(id:) async throws`:
|
|
- [x] For each missing notification, reschedule using `DailyNotificationScheduler`
|
|
- [x] Verify no duplicates created (scheduler handles this)
|
|
- [x] Log rescheduling activity
|
|
|
|
### 1.6 Recovery Result Types
|
|
|
|
- [x] Create `RecoveryResult` struct:
|
|
- [x] `missedCount: Int`
|
|
- [x] `rescheduledCount: Int`
|
|
- [x] `verifiedCount: Int`
|
|
- [x] `errors: Int`
|
|
- [x] Create `VerificationResult` struct:
|
|
- [x] `totalSchedules: Int`
|
|
- [x] `notificationsFound: Int`
|
|
- [x] `notificationsMissing: Int`
|
|
- [x] `missingIds: [String]`
|
|
|
|
### 1.7 Integration with Plugin
|
|
|
|
- [x] Add `reactivationManager` property to `DailyNotificationPlugin`
|
|
- [x] Initialize `ReactivationManager` in `load()` method
|
|
- [x] Call `performRecovery()` in `load()` method (async, non-blocking)
|
|
- [x] Add logging with `DNP-REACTIVATION` tag
|
|
- [x] Ensure recovery doesn't block app startup (Task-based async execution)
|
|
|
|
### 1.8 History Recording
|
|
|
|
- [x] Implement `recordRecoveryHistory(_:scenario:)` method:
|
|
- [x] Record recovery execution (Phase 1: logging with JSON, Phase 2: database table)
|
|
- [x] Include scenario, counts, outcome
|
|
- [x] Add diagnostic JSON with details
|
|
- [x] Implement `recordRecoveryFailure(_:)` method:
|
|
- [x] Record recovery errors (Phase 1: logging, Phase 2: database table)
|
|
- [x] Include error message and error type
|
|
|
|
### 1.9 Testing
|
|
|
|
- [x] Unit tests for scenario detection
|
|
- [x] Unit tests for missed notification detection
|
|
- [x] Unit tests for future notification verification
|
|
- [x] Unit tests for boot detection
|
|
- [x] Unit tests for recovery result types
|
|
- [ ] Integration test for full recovery flow
|
|
- [ ] Manual test with test scripts (`test-phase1.sh`)
|
|
|
|
---
|
|
|
|
## Phase 2: App Termination Detection (High Priority)
|
|
|
|
### 2.1 Termination Detection Logic
|
|
|
|
- [x] Enhance `detectScenario()` to detect termination:
|
|
- [x] Check if DB has notifications but no pending notifications
|
|
- [x] Return `.termination` scenario
|
|
- [x] Implement `handleTerminationRecovery() async throws`:
|
|
- [x] Detect all missed notifications
|
|
- [x] Mark all as missed
|
|
- [x] Reschedule all future notifications
|
|
- [x] Reschedule all fetch schedules (if applicable)
|
|
|
|
### 2.2 Comprehensive Recovery
|
|
|
|
- [x] Implement `performFullRecovery() async throws -> RecoveryResult`:
|
|
- [x] Handle all notifications (missed and future)
|
|
- [x] Reschedule all missing notifications
|
|
- [x] Batch operations for efficiency
|
|
- [x] Return comprehensive result
|
|
|
|
### 2.3 Multiple Schedules Recovery
|
|
|
|
- [x] Implement recovery for multiple schedules:
|
|
- [x] Handle multiple notifications (batch processing)
|
|
- [x] Batch operations for efficiency (single pending request query)
|
|
- [x] Handle partial failures gracefully (continue on error)
|
|
- [x] Separate missed vs future notifications for batch processing
|
|
|
|
### 2.4 Testing
|
|
|
|
- [ ] Test termination detection accuracy
|
|
- [ ] Test full recovery with multiple schedules
|
|
- [ ] Test partial failure scenarios
|
|
- [ ] Manual test with test scripts (`test-phase2.sh`)
|
|
|
|
---
|
|
|
|
## Phase 3: Background Task Registration & Boot Recovery (Medium Priority)
|
|
|
|
### 3.1 BGTaskScheduler Registration
|
|
|
|
- [x] Verify `BGTaskScheduler` registration in `DailyNotificationPlugin.setupBackgroundTasks()`:
|
|
- [x] Check `fetchTaskIdentifier` registration (already implemented)
|
|
- [x] Check `notifyTaskIdentifier` registration (already implemented)
|
|
- [x] Add verification method `verifyBGTaskRegistration()` in ReactivationManager
|
|
- [x] Implement boot detection:
|
|
- [x] Check system uptime on app launch
|
|
- [x] Compare with last launch time (stored in UserDefaults)
|
|
- [x] Detect if boot occurred recently (< 60 seconds threshold)
|
|
|
|
### 3.2 Boot Recovery Logic
|
|
|
|
- [x] Implement `performBootRecovery() async throws`:
|
|
- [x] Detect all missed notifications (past scheduled times)
|
|
- [x] Mark all as missed
|
|
- [x] Reschedule all future notifications
|
|
- [x] Record boot recovery in history
|
|
|
|
### 3.3 Background Task Handlers
|
|
|
|
- [ ] Enhance `handleBackgroundFetch` in `DailyNotificationBackgroundTasks.swift`:
|
|
- [ ] Add recovery logic if needed
|
|
- [ ] Schedule next background task
|
|
- [ ] Handle expiration gracefully
|
|
- [ ] Enhance `handleBackgroundNotify`:
|
|
- [ ] Add recovery logic if needed
|
|
- [ ] Schedule next background task
|
|
|
|
### 3.4 Testing
|
|
|
|
- [ ] Test BGTaskScheduler registration
|
|
- [ ] Test boot detection (simulate or manual)
|
|
- [ ] Test boot recovery logic
|
|
- [ ] Manual test with test scripts (`test-phase3.sh`)
|
|
|
|
---
|
|
|
|
## Core Data Entities (High Priority)
|
|
|
|
### 4.1 NotificationContent Entity
|
|
|
|
- [x] Update `DailyNotificationModel.xcdatamodeld`:
|
|
- [x] Add `NotificationContent` entity
|
|
- [x] Add all 23 attributes (id, pluginVersion, timesafariDid, etc.)
|
|
- [x] Set correct attribute types (String, Date, Int32, Int64, Bool)
|
|
- [x] Add default values where specified
|
|
- [x] Mark required vs optional attributes
|
|
- [x] Add indexes:
|
|
- [x] `timesafariDid` index
|
|
- [x] `notificationType` index
|
|
- [x] `scheduledTime` index
|
|
- [x] Note: Core Data auto-generates class files with `codeGenerationType="class"`
|
|
- [ ] Implement data conversion helpers (if needed):
|
|
- [ ] `Date` ↔ `Long` (epoch milliseconds) conversion helpers
|
|
- [ ] `Int64` ↔ `Long` conversion helpers
|
|
|
|
### 4.2 NotificationDelivery Entity
|
|
|
|
- [x] Update `DailyNotificationModel.xcdatamodeld`:
|
|
- [x] Add `NotificationDelivery` entity
|
|
- [x] Add all 20 attributes
|
|
- [x] Set correct attribute types
|
|
- [x] Add default values
|
|
- [x] Configure relationship:
|
|
- [x] Add `notificationContent` relationship (to-one)
|
|
- [x] Set deletion rule to `Nullify` (Core Data handles cascade via inverse)
|
|
- [x] Add inverse relationship `deliveries` (to-many) on `NotificationContent`
|
|
- [x] Add indexes:
|
|
- [x] `notificationId` index
|
|
- [x] `deliveryTimestamp` index
|
|
- [x] Note: Core Data auto-generates class files
|
|
|
|
### 4.3 NotificationConfig Entity
|
|
|
|
- [x] Update `DailyNotificationModel.xcdatamodeld`:
|
|
- [x] Add `NotificationConfig` entity
|
|
- [x] Add all 13 attributes
|
|
- [x] Set correct attribute types
|
|
- [x] Add default values
|
|
- [x] Add indexes:
|
|
- [x] `configKey` index
|
|
- [x] `configType` index
|
|
- [x] `timesafariDid` index
|
|
- [x] Note: Core Data auto-generates class files
|
|
|
|
### 4.4 Data Access Layer
|
|
|
|
- [x] Create DAO classes or extensions:
|
|
- [x] `NotificationContentDAO` or extension methods
|
|
- [x] `NotificationDeliveryDAO` or extension methods
|
|
- [x] `NotificationConfigDAO` or extension methods
|
|
- [x] Implement CRUD operations:
|
|
- [x] Create/Insert methods
|
|
- [x] Read/Query methods with predicates
|
|
- [x] Update methods
|
|
- [x] Delete methods
|
|
- [x] Implement query helpers:
|
|
- [x] Query by timesafariDid
|
|
- [x] Query by notificationType
|
|
- [x] Query by scheduledTime range
|
|
- [x] Query by deliveryStatus
|
|
|
|
### 4.5 Persistence Controller Updates
|
|
|
|
- [x] Update `PersistenceController` (if exists) or create:
|
|
- [x] Handle new entities in initialization
|
|
- [x] Add migration policies if needed
|
|
- [x] Test database initialization (unit tests verify Core Data stack)
|
|
- [x] Test Core Data stack:
|
|
- [x] Entity creation (tested in DAO unit tests)
|
|
- [x] Relationships (tested in NotificationDeliveryDAOTests)
|
|
- [x] Cascade delete (tested in NotificationDeliveryDAOTests)
|
|
- [x] Data conversion (tested in DailyNotificationDataConversionsTests)
|
|
|
|
---
|
|
|
|
## API Methods (Medium Priority)
|
|
|
|
### 5.1 Notification Permission Methods
|
|
|
|
- [x] Implement `getNotificationPermissionStatus()`:
|
|
- [x] Query `UNUserNotificationCenter.current().getNotificationSettings()`
|
|
- [x] Map to `NotificationPermissionStatus` type
|
|
- [x] Return authorization status
|
|
- [x] Implement `requestNotificationPermission()`:
|
|
- [x] Request authorization via `UNUserNotificationCenter`
|
|
- [x] Handle user response
|
|
- [x] Return `{ granted: boolean }`
|
|
- [x] Implement `openNotificationSettings()`:
|
|
- [x] Open iOS Settings app to notification settings
|
|
- [x] Use `UIApplication.shared.open()` with settings URL
|
|
|
|
### 5.2 Background Task Methods
|
|
|
|
- [x] Implement `getBackgroundTaskStatus()`:
|
|
- [x] Check BGTaskScheduler registration
|
|
- [x] Check Background App Refresh status (cannot check programmatically, return null)
|
|
- [x] Return `BackgroundTaskStatus` object
|
|
- [x] Implement `openBackgroundAppRefreshSettings()`:
|
|
- [x] Open iOS Settings app to Background App Refresh
|
|
- [x] Use `UIApplication.shared.open()` with settings URL
|
|
|
|
### 5.3 Pending Notifications Method
|
|
|
|
- [x] Implement `getPendingNotifications()`:
|
|
- [x] Query `UNUserNotificationCenter.current().getPendingNotificationRequests()`
|
|
- [x] Map to `PendingNotification[]` array
|
|
- [x] Return count and notification details
|
|
- [x] Add to `pluginMethods` array in `DailyNotificationPlugin`
|
|
|
|
### 5.4 Register Methods in Plugin
|
|
|
|
- [x] Add methods to `pluginMethods` array:
|
|
- [x] `getNotificationPermissionStatus`
|
|
- [x] `requestNotificationPermission`
|
|
- [x] `getPendingNotifications`
|
|
- [x] `getBackgroundTaskStatus`
|
|
- [x] `openNotificationSettings`
|
|
- [x] `openBackgroundAppRefreshSettings`
|
|
|
|
---
|
|
|
|
## Data Type Conversions (High Priority)
|
|
|
|
### 6.1 Time Conversions
|
|
|
|
- [x] Create helper functions:
|
|
- [x] `dateFromEpochMillis(_: Int64) -> Date`
|
|
- [x] `epochMillisFromDate(_: Date) -> Int64`
|
|
- [x] Use in all Core Data operations:
|
|
- [x] When reading from database (Long → Date)
|
|
- [x] When writing to database (Date → Long)
|
|
|
|
### 6.2 Numeric Conversions
|
|
|
|
- [x] Ensure correct type mappings:
|
|
- [x] `Int` → `Int32` for small integers
|
|
- [x] `Long` → `Int64` for large integers
|
|
- [x] `Boolean` → `Bool` (direct)
|
|
|
|
### 6.3 String Conversions
|
|
|
|
- [x] Handle optional strings correctly:
|
|
- [x] `String?` in Swift maps to optional in Core Data
|
|
- [x] JSON fields stored as `String?`
|
|
|
|
---
|
|
|
|
## Logging & Observability (Medium Priority)
|
|
|
|
### 7.1 Recovery Logging
|
|
|
|
- [x] Add comprehensive logging:
|
|
- [x] `DNP-REACTIVATION: Starting app launch recovery`
|
|
- [x] `DNP-REACTIVATION: Detected scenario: [scenario]`
|
|
- [x] `DNP-REACTIVATION: Missed notifications detected: [count]`
|
|
- [x] `DNP-REACTIVATION: Future notifications verified: [count]`
|
|
- [x] `DNP-REACTIVATION: Recovery completed: [result]`
|
|
- [x] Add error logging:
|
|
- [x] `DNP-REACTIVATION: Recovery failed (non-fatal): [error]`
|
|
- [x] Include error details and stack trace (NSError domain, code, userInfo)
|
|
|
|
### 7.2 Metrics Recording
|
|
|
|
- [x] Record recovery metrics in history table:
|
|
- [x] Recovery execution time (tracked with startTime/endTime)
|
|
- [x] Missed notification count
|
|
- [x] Rescheduled notification count
|
|
- [x] Error count
|
|
- [x] Add diagnostic JSON to history entries (via HistoryDAO.recordRecovery)
|
|
|
|
---
|
|
|
|
## Error Handling (High Priority)
|
|
|
|
### 8.1 Recovery Error Handling
|
|
|
|
- [ ] Ensure all recovery methods catch errors:
|
|
- [ ] Database errors (non-fatal)
|
|
- [ ] Notification center errors (non-fatal)
|
|
- [ ] Scheduling errors (non-fatal)
|
|
- [ ] Log errors but don't crash app
|
|
- [ ] Return partial results if some operations fail
|
|
|
|
### 8.2 Error Types
|
|
|
|
- [ ] Define iOS-specific error codes:
|
|
- [ ] `NOTIFICATION_PERMISSION_DENIED`
|
|
- [ ] `BACKGROUND_REFRESH_DISABLED`
|
|
- [ ] `PENDING_NOTIFICATION_LIMIT_EXCEEDED`
|
|
- [ ] `BG_TASK_NOT_REGISTERED`
|
|
- [ ] `BG_TASK_EXECUTION_FAILED`
|
|
- [ ] Map to error responses in plugin methods
|
|
|
|
---
|
|
|
|
## Testing (High Priority)
|
|
|
|
### 9.1 Unit Tests
|
|
|
|
- [x] Test `ReactivationManager` initialization (DailyNotificationReactivationManagerTests)
|
|
- [x] Test scenario detection logic:
|
|
- [x] Test `.none` scenario (empty database)
|
|
- [x] Test `.coldStart` scenario
|
|
- [x] Test `.termination` scenario
|
|
- [x] Test `.warmStart` scenario
|
|
- [x] Test missed notification detection
|
|
- [x] Test future notification verification
|
|
- [x] Test recovery result creation
|
|
- [x] Test data conversions (DailyNotificationDataConversionsTests)
|
|
- [x] Test NotificationContentDAO (NotificationContentDAOTests)
|
|
- [x] Test NotificationDeliveryDAO (NotificationDeliveryDAOTests)
|
|
- [x] Test NotificationConfigDAO (NotificationConfigDAOTests)
|
|
|
|
### 9.2 Integration Tests
|
|
|
|
- [ ] Test full recovery flow:
|
|
- [ ] Schedule notification
|
|
- [ ] Terminate app
|
|
- [ ] Launch app
|
|
- [ ] Verify recovery executed
|
|
- [ ] Verify notifications rescheduled
|
|
- [ ] Test error handling:
|
|
- [ ] Test database errors
|
|
- [ ] Test notification center errors
|
|
- [ ] Verify app doesn't crash
|
|
|
|
### 9.3 Manual Testing
|
|
|
|
- [ ] Run `test-phase1.sh` script
|
|
- [ ] Run `test-phase2.sh` script
|
|
- [ ] Run `test-phase3.sh` script
|
|
- [ ] Test on physical device (not just simulator)
|
|
- [ ] Test with Background App Refresh enabled/disabled
|
|
- [ ] Test with notification permission granted/denied
|
|
|
|
---
|
|
|
|
## Documentation Updates (Low Priority)
|
|
|
|
### 10.1 Code Documentation
|
|
|
|
- [ ] Add file-level documentation to `DailyNotificationReactivationManager.swift`
|
|
- [ ] Add method-level documentation to all public methods
|
|
- [ ] Add parameter documentation
|
|
- [ ] Add return value documentation
|
|
- [ ] Add error documentation
|
|
|
|
### 10.2 Implementation Status
|
|
|
|
- [ ] Update `ios/Plugin/README.md` with implementation status
|
|
- [ ] Mark completed features as ✅
|
|
- [ ] Update version numbers
|
|
- [ ] Update "Last Updated" dates
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
**Total Tasks**: ~150+ implementation tasks
|
|
|
|
**Priority Breakdown**:
|
|
- **High Priority**: ~80 tasks (Phase 1, Core Data, API methods, Error handling)
|
|
- **Medium Priority**: ~50 tasks (Phase 2, Phase 3, Logging)
|
|
- **Low Priority**: ~20 tasks (Documentation)
|
|
|
|
**Estimated Implementation Time**:
|
|
- Phase 1: 2-3 days
|
|
- Phase 2: 1-2 days
|
|
- Phase 3: 1 day
|
|
- Core Data: 2-3 days
|
|
- API Methods: 1 day
|
|
- Testing: 2-3 days
|
|
- **Total**: ~10-15 days
|
|
|
|
---
|
|
|
|
**Document Version**: 1.0.0
|
|
**Last Updated**: 2025-12-08
|
|
**Next Review**: After Phase 1 implementation
|
|
|