Files
daily-notification-plugin/COMMIT_MESSAGE.txt
Matthew Raymer 9b73e873d9 refactor(android): Complete plugin refactoring and safety fixes (Batches 0-7)
Comprehensive refactoring to make DailyNotificationPlugin a thin adapter,
eliminate duplicated logic, remove unsafe operations, and harden security.

Batch 0 - Constants Centralization:
- Created DailyNotificationConstants.kt to eliminate magic numbers and duplicates
- Centralized: PERMISSION_REQUEST_CODE, channel constants, intent actions/extras,
  SharedPreferences keys, WorkManager tags, notification IDs
- Replaced duplicates across Plugin, PermissionManager, ChannelManager, Scheduler

Batch 1 - Permission Flow Unification:
- Created PermissionStatus.kt data class for unified permission reporting
- Added PermissionManager.getPermissionStatus() as single source of truth
- Implemented PendingPermissionRequest tracking for reliable resume resolution
- Replaced method-name-based resume logic with token-based tracking
- Plugin now delegates all permission checks to PermissionManager

Batch 2 - Notification Status Checker Hardening:
- Modified NotificationStatusChecker to always check OS-level notification
  enablement via NotificationManagerCompat.areNotificationsEnabled()
- Added getReadinessReport() method providing comprehensive status with issues
  and actionable guidance
- Plugin checkStatus() now uses readiness report

Batch 3 - Cancel Semantics Safety:
- Removed unsafe brute-force cancellation loop (was trying request codes 0-100)
- Cancellation now only targets alarms proven to exist in database
- Prevents accidental cancellation of other alarms and false confidence

Batch 4 - Legacy Scheduler Removal:
- Removed unused legacy scheduleExactAlarm() method (48 lines)
- All scheduling now goes through modern paths:
  1. exactAlarmManager.scheduleAlarm() (if available)
  2. pendingIntentManager.scheduleExactAlarm() (modern path)
  3. pendingIntentManager.scheduleWindowedAlarm() (fallback)

Batch 5 - Input Contract Tightening:
- Enforced single input shape for updateStarredPlans: { planIds: string[] }
- Added validation: rejects non-array, non-string elements, empty strings
- Legacy support: single string normalized to array (with warning)
- Clear error messages for contract violations

Batch 6 - Token Storage Security:
- Added explicit opt-in for JWT token persistence (persistToken: true)
- Default behavior: tokens NOT persisted (secure default)
- Security warnings logged when persistence is enabled
- Documents unencrypted storage risk

Batch 7 - Plugin Thinning:
- Moved getExactAlarmStatus() to PermissionManager.getExactAlarmStatus()
- Moved canRequestExactAlarmPermission() to PermissionManager
- Removed direct AlarmManager access in cancelAllNotifications()
- Delegated scheduleUserNotification/scheduleDualNotification permission
  handling to PermissionManager.requestExactAlarmPermission()
- Removed unused imports: AlarmManager, PendingIntent, PowerManager,
  NotificationManagerCompat

Result:
- Plugin is now a thin adapter delegating to services
- No duplicated permission logic
- No unsafe cancellation operations
- No legacy scheduler paths
- Secure token storage defaults
- Clear input contracts
- Comprehensive status reporting

Files modified:
- DailyNotificationConstants.kt (new)
- PermissionStatus.kt (new)
- DailyNotificationPlugin.kt (thinned, ~500 lines refactored)
- PermissionManager.java (enhanced with status methods)
- NotificationStatusChecker.java (hardened)
- DailyNotificationScheduler.java (legacy removed)

Refs: Cursor directive Batches 0-7
2025-12-23 12:51:48 +00:00

77 lines
3.4 KiB
Plaintext

refactor(android): Complete plugin refactoring and safety fixes (Batches 0-7)
Comprehensive refactoring to make DailyNotificationPlugin a thin adapter,
eliminate duplicated logic, remove unsafe operations, and harden security.
Batch 0 - Constants Centralization:
- Created DailyNotificationConstants.kt to eliminate magic numbers and duplicates
- Centralized: PERMISSION_REQUEST_CODE, channel constants, intent actions/extras,
SharedPreferences keys, WorkManager tags, notification IDs
- Replaced duplicates across Plugin, PermissionManager, ChannelManager, Scheduler
Batch 1 - Permission Flow Unification:
- Created PermissionStatus.kt data class for unified permission reporting
- Added PermissionManager.getPermissionStatus() as single source of truth
- Implemented PendingPermissionRequest tracking for reliable resume resolution
- Replaced method-name-based resume logic with token-based tracking
- Plugin now delegates all permission checks to PermissionManager
Batch 2 - Notification Status Checker Hardening:
- Modified NotificationStatusChecker to always check OS-level notification
enablement via NotificationManagerCompat.areNotificationsEnabled()
- Added getReadinessReport() method providing comprehensive status with issues
and actionable guidance
- Plugin checkStatus() now uses readiness report
Batch 3 - Cancel Semantics Safety:
- Removed unsafe brute-force cancellation loop (was trying request codes 0-100)
- Cancellation now only targets alarms proven to exist in database
- Prevents accidental cancellation of other alarms and false confidence
Batch 4 - Legacy Scheduler Removal:
- Removed unused legacy scheduleExactAlarm() method (48 lines)
- All scheduling now goes through modern paths:
1. exactAlarmManager.scheduleAlarm() (if available)
2. pendingIntentManager.scheduleExactAlarm() (modern path)
3. pendingIntentManager.scheduleWindowedAlarm() (fallback)
Batch 5 - Input Contract Tightening:
- Enforced single input shape for updateStarredPlans: { planIds: string[] }
- Added validation: rejects non-array, non-string elements, empty strings
- Legacy support: single string normalized to array (with warning)
- Clear error messages for contract violations
Batch 6 - Token Storage Security:
- Added explicit opt-in for JWT token persistence (persistToken: true)
- Default behavior: tokens NOT persisted (secure default)
- Security warnings logged when persistence is enabled
- Documents unencrypted storage risk
Batch 7 - Plugin Thinning:
- Moved getExactAlarmStatus() to PermissionManager.getExactAlarmStatus()
- Moved canRequestExactAlarmPermission() to PermissionManager
- Removed direct AlarmManager access in cancelAllNotifications()
- Delegated scheduleUserNotification/scheduleDualNotification permission
handling to PermissionManager.requestExactAlarmPermission()
- Removed unused imports: AlarmManager, PendingIntent, PowerManager,
NotificationManagerCompat
Result:
- Plugin is now a thin adapter delegating to services
- No duplicated permission logic
- No unsafe cancellation operations
- No legacy scheduler paths
- Secure token storage defaults
- Clear input contracts
- Comprehensive status reporting
Files modified:
- DailyNotificationConstants.kt (new)
- PermissionStatus.kt (new)
- DailyNotificationPlugin.kt (thinned, ~500 lines refactored)
- PermissionManager.java (enhanced with status methods)
- NotificationStatusChecker.java (hardened)
- DailyNotificationScheduler.java (legacy removed)
Refs: Cursor directive Batches 0-7