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:
343
docs/platform/ios/ROLLOVER_QA.md
Normal file
343
docs/platform/ios/ROLLOVER_QA.md
Normal file
@@ -0,0 +1,343 @@
|
||||
# iOS Rollover Implementation — Open Questions & Answers
|
||||
|
||||
**Date**: 2025-01-27
|
||||
**Status**: Pre-Implementation Decisions
|
||||
|
||||
---
|
||||
|
||||
## Question 1: Fetcher Integration
|
||||
|
||||
**Question**: How should we integrate DailyNotificationFetcher for prefetch scheduling? (Phase 2)
|
||||
|
||||
### Current State Analysis
|
||||
|
||||
- **Android**: Uses `DailyNotificationFetcher.scheduleFetch(fetchTime)` and `scheduleImmediateFetch()`
|
||||
- **iOS**: Has `DailyNotificationBackgroundTaskManager` with `scheduleBackgroundTask()` method
|
||||
- **iOS Pattern**: Uses `BGTaskScheduler` with `BGAppRefreshTaskRequest`
|
||||
|
||||
### Recommendation: **Defer to Phase 2, Use Placeholder Pattern**
|
||||
|
||||
**Rationale**:
|
||||
1. **Phase 1 Focus**: Core rollover functionality (scheduling next notification)
|
||||
2. **Prefetch is Separate**: Prefetch scheduling is independent of rollover
|
||||
3. **Existing Infrastructure**: iOS already has background task infrastructure
|
||||
4. **Android Pattern**: Android also separates rollover from prefetch (optional parameter)
|
||||
|
||||
### Implementation Approach
|
||||
|
||||
**Phase 1 (Current)**:
|
||||
- Make `fetcher` parameter optional in `scheduleNextNotification()`
|
||||
- Add TODO comments for Phase 2 integration
|
||||
- Log prefetch scheduling intent (even if not executed)
|
||||
|
||||
**Phase 2 (Future)**:
|
||||
- Create `DailyNotificationFetcher` class (iOS equivalent)
|
||||
- Integrate with `DailyNotificationBackgroundTaskManager`
|
||||
- Use `BGTaskScheduler` for prefetch scheduling
|
||||
- Calculate fetch time: `nextScheduledTime - (5 * 60 * 1000)` (5 minutes before)
|
||||
|
||||
### Code Pattern
|
||||
|
||||
```swift
|
||||
// Phase 1: Optional fetcher, log intent
|
||||
if let fetcher = fetcher {
|
||||
let fetchTime = nextScheduledTime - (5 * 60 * 1000)
|
||||
// TODO: Phase 2 - Implement fetcher.scheduleFetch(fetchTime)
|
||||
print("\(Self.TAG): RESCHEDULE_PREFETCH_SCHEDULED id=\(content.id) next_fetch=\(fetchTime)")
|
||||
} else {
|
||||
print("\(Self.TAG): RESCHEDULE_PREFETCH_SKIP id=\(content.id) fetcher_not_available")
|
||||
}
|
||||
```
|
||||
|
||||
**Decision**: ✅ **Defer to Phase 2, use optional parameter pattern**
|
||||
|
||||
---
|
||||
|
||||
## Question 2: AppDelegate Access
|
||||
|
||||
**Question**: Is there a better way to access the plugin from AppDelegate without using Capacitor bridge?
|
||||
|
||||
### Current State Analysis
|
||||
|
||||
- **Capacitor Pattern**: Uses `CAPBridgeViewController` to access plugins
|
||||
- **Test App**: Already uses this pattern for other operations
|
||||
- **Production Apps**: May have different AppDelegate structures
|
||||
|
||||
### Recommendation: **Use Notification Center Pattern**
|
||||
|
||||
**Rationale**:
|
||||
1. **Decoupling**: AppDelegate doesn't need direct plugin reference
|
||||
2. **Flexibility**: Works across different app architectures
|
||||
3. **Reliability**: Notification center is always available
|
||||
4. **Testability**: Easier to test without Capacitor dependency
|
||||
|
||||
### Implementation Approach
|
||||
|
||||
**Option A: Notification Center (Recommended)**
|
||||
- Plugin registers for notification delivery events
|
||||
- AppDelegate posts notification when delivery detected
|
||||
- Plugin handles rollover in response to notification
|
||||
|
||||
**Option B: Capacitor Bridge (Fallback)**
|
||||
- Use existing bridge pattern
|
||||
- Works but creates tight coupling
|
||||
- Use as fallback if notification center doesn't work
|
||||
|
||||
### Code Pattern
|
||||
|
||||
```swift
|
||||
// In DailyNotificationPlugin.load():
|
||||
NotificationCenter.default.addObserver(
|
||||
self,
|
||||
selector: #selector(handleNotificationDelivery(_:)),
|
||||
name: NSNotification.Name("DailyNotificationDelivered"),
|
||||
object: nil
|
||||
)
|
||||
|
||||
// In AppDelegate.willPresent:
|
||||
NotificationCenter.default.post(
|
||||
name: NSNotification.Name("DailyNotificationDelivered"),
|
||||
object: nil,
|
||||
userInfo: [
|
||||
"notification_id": notificationId,
|
||||
"scheduled_time": scheduledTime
|
||||
]
|
||||
)
|
||||
```
|
||||
|
||||
**Decision**: ✅ **Use Notification Center pattern, with Capacitor bridge as fallback**
|
||||
|
||||
---
|
||||
|
||||
## Question 3: Background Task
|
||||
|
||||
**Question**: Should we add a dedicated background task for rollover detection, or rely on existing recovery mechanisms?
|
||||
|
||||
### Current State Analysis
|
||||
|
||||
- **Existing Recovery**: `DailyNotificationReactivationManager` already runs on app launch
|
||||
- **Background Tasks**: iOS has strict limits on background execution
|
||||
- **Reliability**: Multiple detection mechanisms increase reliability
|
||||
|
||||
### Recommendation: **Rely on Existing Recovery + AppDelegate**
|
||||
|
||||
**Rationale**:
|
||||
1. **iOS Limitations**: Background tasks are unreliable (system-controlled)
|
||||
2. **Existing Infrastructure**: Recovery manager already handles app launch scenarios
|
||||
3. **Coverage**: AppDelegate (foreground) + Recovery (background) covers all cases
|
||||
4. **Simplicity**: Fewer moving parts = fewer failure points
|
||||
|
||||
### Implementation Approach
|
||||
|
||||
**Two Detection Mechanisms**:
|
||||
1. **Foreground**: AppDelegate `willPresent` → immediate rollover
|
||||
2. **Background**: Recovery Manager → rollover on app launch
|
||||
|
||||
**No Dedicated Background Task**:
|
||||
- Background tasks are unreliable (system decides when to run)
|
||||
- Recovery manager already covers app launch scenarios
|
||||
- Adding another mechanism adds complexity without significant benefit
|
||||
|
||||
### Code Pattern
|
||||
|
||||
```swift
|
||||
// Detection Mechanism 1: Foreground (AppDelegate)
|
||||
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, ...) {
|
||||
// Trigger rollover immediately
|
||||
await handleNotificationRollover(...)
|
||||
}
|
||||
|
||||
// Detection Mechanism 2: Background (Recovery Manager)
|
||||
func performColdStartRecovery() async {
|
||||
// Check for delivered notifications
|
||||
await checkAndProcessDeliveredNotifications()
|
||||
}
|
||||
```
|
||||
|
||||
**Decision**: ✅ **Rely on existing recovery + AppDelegate, no dedicated background task**
|
||||
|
||||
---
|
||||
|
||||
## Question 4: Error Handling
|
||||
|
||||
**Question**: How should we handle rollover failures? Retry? Log? User notification?
|
||||
|
||||
### Current State Analysis
|
||||
|
||||
- **Android Pattern**: Logs errors, continues execution (non-fatal)
|
||||
- **iOS Recovery Manager**: Catches all errors, logs, continues (non-fatal)
|
||||
- **User Experience**: Failures should be silent (background operation)
|
||||
|
||||
### Recommendation: **Log + Continue (Non-Fatal)**
|
||||
|
||||
**Rationale**:
|
||||
1. **Background Operation**: Rollover is background, shouldn't interrupt user
|
||||
2. **Recovery Available**: Recovery manager will catch missed rollovers on next app launch
|
||||
3. **Consistency**: Matches Android and existing iOS recovery patterns
|
||||
4. **User Experience**: Silent failures, recovery on next launch
|
||||
|
||||
### Implementation Approach
|
||||
|
||||
**Error Handling Strategy**:
|
||||
1. **Log Errors**: Comprehensive logging for debugging
|
||||
2. **Continue Execution**: Don't crash or interrupt app
|
||||
3. **No Retry**: Let recovery manager handle on next launch
|
||||
4. **No User Notification**: Background operation, silent failure
|
||||
5. **History Recording**: Record failures in history (if history implemented)
|
||||
|
||||
### Code Pattern
|
||||
|
||||
```swift
|
||||
func scheduleNextNotification(...) async -> Bool {
|
||||
do {
|
||||
// Rollover logic
|
||||
return true
|
||||
} catch {
|
||||
print("\(Self.TAG): RESCHEDULE_ERR id=\(content.id) err=\(error.localizedDescription)")
|
||||
// Log error but don't throw - let recovery handle on next launch
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// In recovery manager:
|
||||
if !scheduled {
|
||||
print("\(Self.TAG): Failed to roll over delivered notification id=\(notificationId)")
|
||||
// Recovery will retry on next app launch
|
||||
}
|
||||
```
|
||||
|
||||
**Decision**: ✅ **Log + Continue (non-fatal), no retry, no user notification**
|
||||
|
||||
---
|
||||
|
||||
## Question 5: Performance
|
||||
|
||||
**Question**: Should we batch rollover operations or process individually?
|
||||
|
||||
### Current State Analysis
|
||||
|
||||
- **Android Pattern**: Processes individually (one notification at a time)
|
||||
- **iOS Recovery**: Processes notifications individually
|
||||
- **Volume**: Typically 1-2 notifications per day (low volume)
|
||||
|
||||
### Recommendation: **Process Individually**
|
||||
|
||||
**Rationale**:
|
||||
1. **Low Volume**: Typically 1 notification per day, batching unnecessary
|
||||
2. **Simplicity**: Individual processing is simpler and easier to debug
|
||||
3. **Error Isolation**: Individual processing isolates failures
|
||||
4. **Consistency**: Matches Android and existing iOS patterns
|
||||
|
||||
### Implementation Approach
|
||||
|
||||
**Individual Processing**:
|
||||
- Process each notification rollover separately
|
||||
- Each rollover is independent operation
|
||||
- Failures in one don't affect others
|
||||
- Easier to log and debug
|
||||
|
||||
**Future Optimization** (if needed):
|
||||
- If volume increases, consider batching
|
||||
- Current volume doesn't justify batching complexity
|
||||
|
||||
### Code Pattern
|
||||
|
||||
```swift
|
||||
// Process individually (current approach)
|
||||
for notification in deliveredNotifications {
|
||||
await scheduler.scheduleNextNotification(notification, ...)
|
||||
}
|
||||
|
||||
// Batching would look like:
|
||||
// await scheduler.scheduleNextNotificationsBatch(notifications, ...)
|
||||
// But not needed for current volume
|
||||
```
|
||||
|
||||
**Decision**: ✅ **Process individually (current volume doesn't justify batching)**
|
||||
|
||||
---
|
||||
|
||||
## Question 6: Testing
|
||||
|
||||
**Question**: Do we need automated tests for rollover, or is manual testing sufficient for Phase 1?
|
||||
|
||||
### Current State Analysis
|
||||
|
||||
- **Existing Tests**: iOS has unit tests for recovery manager
|
||||
- **Test Coverage**: Some components have tests, others don't
|
||||
- **Phase 1 Scope**: Core rollover functionality
|
||||
|
||||
### Recommendation: **Manual Testing for Phase 1, Automated Tests for Phase 2**
|
||||
|
||||
**Rationale**:
|
||||
1. **Phase 1 Focus**: Core functionality, manual testing sufficient
|
||||
2. **Complexity**: Rollover involves system notifications (hard to test automatically)
|
||||
3. **Time Investment**: Automated tests take time, manual testing faster for Phase 1
|
||||
4. **Phase 2**: Add automated tests when edge cases are implemented
|
||||
|
||||
### Implementation Approach
|
||||
|
||||
**Phase 1 Testing**:
|
||||
- Manual testing checklist
|
||||
- Test scenarios: foreground delivery, background delivery, duplicates
|
||||
- Real device testing (simulator may not handle notifications correctly)
|
||||
|
||||
**Phase 2 Testing**:
|
||||
- Unit tests for time calculations (DST, timezone)
|
||||
- Integration tests for rollover flow
|
||||
- Edge case tests (time changes, timezone changes)
|
||||
|
||||
### Test Checklist (Phase 1)
|
||||
|
||||
1. ✅ **Foreground Delivery**: App running, notification fires → rollover triggers
|
||||
2. ✅ **Background Delivery**: App not running, notification fires → rollover on launch
|
||||
3. ✅ **Duplicate Prevention**: Multiple rollover attempts → only one scheduled
|
||||
4. ✅ **DST Transition**: Schedule on DST day → correct time calculation
|
||||
5. ✅ **Error Handling**: Simulate failure → graceful degradation
|
||||
|
||||
**Decision**: ✅ **Manual testing for Phase 1, automated tests for Phase 2**
|
||||
|
||||
---
|
||||
|
||||
## Summary of Decisions
|
||||
|
||||
| Question | Decision | Rationale |
|
||||
|----------|----------|-----------|
|
||||
| **Fetcher Integration** | Defer to Phase 2, optional parameter | Prefetch is separate concern, Phase 1 focuses on core rollover |
|
||||
| **AppDelegate Access** | Notification Center pattern | Decoupling, flexibility, reliability |
|
||||
| **Background Task** | Rely on existing recovery | iOS limitations, existing infrastructure sufficient |
|
||||
| **Error Handling** | Log + Continue (non-fatal) | Background operation, recovery handles failures |
|
||||
| **Performance** | Process individually | Low volume, simplicity, consistency |
|
||||
| **Testing** | Manual for Phase 1, automated for Phase 2 | Phase 1 scope, complexity, time investment |
|
||||
|
||||
---
|
||||
|
||||
## Implementation Impact
|
||||
|
||||
### Changes to Review Document
|
||||
|
||||
Based on these decisions, the review document should be updated:
|
||||
|
||||
1. **Fetcher Parameter**: Make optional, add Phase 2 TODOs
|
||||
2. **AppDelegate Pattern**: Use Notification Center instead of Capacitor bridge
|
||||
3. **Background Task**: Remove dedicated background task, rely on recovery
|
||||
4. **Error Handling**: Add comprehensive logging, non-fatal errors
|
||||
5. **Performance**: Individual processing (no batching)
|
||||
6. **Testing**: Manual testing checklist for Phase 1
|
||||
|
||||
### Next Steps
|
||||
|
||||
1. ✅ **Decisions Made** (This document)
|
||||
2. **Update Review Document** with decisions
|
||||
3. **Update Implementation Plan** with specific patterns
|
||||
4. **Begin Phase 1 Implementation**
|
||||
|
||||
---
|
||||
|
||||
## References
|
||||
|
||||
- Review Document: `docs/ios-rollover-implementation-review.md`
|
||||
- Edge Case Plan: `docs/ios-rollover-edge-case-plan.md`
|
||||
- Android Implementation: `android/src/main/java/com/timesafari/dailynotification/DailyNotificationWorker.java`
|
||||
- iOS Recovery Manager: `ios/Plugin/DailyNotificationReactivationManager.swift`
|
||||
- iOS Background Tasks: `ios/Plugin/DailyNotificationBackgroundTaskManager.swift`
|
||||
Reference in New Issue
Block a user