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:
Matthew Raymer
2025-12-18 09:12:11 +00:00
parent 37fd2629d1
commit c39bd7cec6
78 changed files with 720 additions and 18 deletions

View File

@@ -1,698 +0,0 @@
# Background Data Fetching Implementation Plan
**Author**: Matthew Raymer
**Version**: 1.0.0
**Created**: 2025-10-02 07:47:04 UTC
**Last Updated**: 2025-10-02 12:45:00 UTC
## Overview
This document outlines the **enhancement plan** for background data fetching in the Daily Notification Plugin to support TimeSafari integration with Option A architecture. This plan builds upon our existing implementation and adds:
- **Option A Enhancement**: ActiveDid-aware authentication on existing infrastructure
- **TimeSafari Integration**: PlatformServiceMixin coordination with current plugin
- **Authentication Layer**: JWT/DID support over existing HTTP callback system
- **Database Enhancement**: Extend current storage with activeDid management
- **Event & Change Management**: Identity change detection on existing notification system
- **API Integration**: Endorser.ch endpoints through current ContentFetchConfig
This document serves as the enhancement roadmap for adding TimeSafari capabilities to our existing, working plugin.
## Current Implementation Baseline
### ✅ Already Implemented & Working
- **Android Storage**: SharedPreferences + SQLite with migration (`DailyNotificationStorage.java`, `DailyNotificationDatabase.java`)
- **Web Storage**: IndexedDB with comprehensive service worker (`sw.ts`, `IndexedDBManager`)
- **Callback System**: HTTP/local callbacks with circuit breaker (`callback-registry.ts`)
- **Configuration**: Database path, TTL, retention settings (`ConfigureOptions`)
- **ETag Support**: Conditional HTTP requests (`DailyNotificationETagManager.java`)
- **Dual Scheduling**: Content fetch + user notification separation
- **Cross-Platform API**: Unified TypeScript interface (`DailyNotificationPlugin`)
### ⚠️ Enhancement Required for TimeSafari
- **ActiveDid Integration**: Add activeDid-awareness to existing authentication
- **JWT Generation**: Enhance HTTP layer with DID-based tokens
- **Identity Change Detection**: Add event listeners to existing callback system
- **Endorser.ch APIs**: Extend `ContentFetchConfig` with TimeSafari endpoints
- **Platform Auth**: Add Android Keystore/iOS Keychain to existing storage
## Consolidated Architecture: Option A Platform Overview
```
TimeSafari Host App
↓ (provides activeDid)
Daily Notification Plugin → Native Background Executor
HTTP Client + Auth
API Server Response
Parse & Cache Data (plugin storage)
Trigger Notifications
```
### **Option A: Host Always Provides activeDid**
**Core Principle**: Host application queries its own database and provides activeDid to plugin.
### **Why Option A Is Superior:**
1. **Clear Separation**: Host owns identity management, plugin owns notifications
2. **No Database Conflicts**: Zero shared database access between host and plugin
3. **Security Isolation**: Plugin data physically separated from user data
4. **Platform Independence**: Works consistently regardless of host's database technology
5. **Simplified Implementation**: Fewer moving parts, clearer debugging
## Android Implementation Strategy
### A. Background Execution Framework
- **Use WorkManager** for reliable background HTTP requests
- **Enhance** existing Native HTTP clients (already implemented):
- Extend `DailyNotificationETagManager.java` with JWT headers
- Add JWT authentication to `DailyNotificationFetcher.java`
- **Handle Android-specific constraints**: Doze mode, app standby, battery optimization
### B. Authentication Enhancement - Extend Current Infrastructure
**Goal**: Enhance existing `DailyNotificationETagManager.java` and `DailyNotificationFetcher.java` with JWT authentication
```kotlin
// Enhance existing Android infrastructure with JWT authentication
class DailyNotificationJWTManager {
private val storage: DailyNotificationStorage
private val currentActiveDid: String? = null
// Add JWT generation to existing fetcher
fun generateJWTForActiveDid(activeDid: String, expiresInSeconds: Int): String {
val payload = mapOf(
"exp" to (System.currentTimeMillis() / 1000 + expiresInSeconds),
"iat" to (System.currentTimeMillis() / 1000),
"iss" to activeDid,
"aud" to "timesafari.notifications",
"sub" to activeDid
)
return signWithDID(payload, activeDid)
}
// Enhance existing HTTP client with JWT headers
fun enhanceHttpClientWithJWT(connection: HttpURLConnection, activeDid: String) {
val jwt = generateJWTForActiveDid(activeDid, 60)
connection.setRequestProperty("Authorization", "Bearer $jwt")
connection.setRequestProperty("Content-Type", "application/json")
}
}
### C. HTTP Request Enhancement - Extend Existing Fetcher
**Goal**: Enhance existing `DailyNotificationFetcher.java` with Endorser.ch API support
```kotlin
// Enhance existing DailyNotificationFetcher.java with TimeSafari APIs
class EnhancedDailyNotificationFetcher : DailyNotificationFetcher {
private val jwtManager: DailyNotificationJWTManager
suspend fun fetchEndorserOffers(activeDid: String, afterId: String?): Result {
val connection = HttpURLConnection("$apiServer/api/v2/report/offers")
// Add JWT authentication to existing connection
jwtManager.enhanceHttpClientWithJWT(connection, activeDid)
// Add Endorser.ch specific parameters
connection.setRequestProperty("recipientDid", activeDid)
if (afterId != null) {
connection.setRequestProperty("afterId", afterId)
}
// Use existing storeAndScheduleNotification method
return fetchAndStoreContent(connection)
}
}
```
## iOS Implementation Strategy
### A. Background Execution Framework
- **Use BGTaskScheduler** for background HTTP requests
- **Replace axios** with native iOS HTTP clients:
- URLSession for HTTP requests
- Combine framework for async/await patterns
### B. Authentication Implementation
```swift
// JWT Generation in iOS
class JWTHelper {
func generateJWT(userDid: String, expiresInSeconds: Int) -> String {
let payload: [String: Any] = [
"exp": Int(Date().timeIntervalSince1970) + expiresInSeconds,
"iat": Int(Date().timeIntervalSince1970),
"iss": userDid
]
return signWithDID(payload, userDid)
}
}
```
### C. HTTP Request Implementation
```swift
// Background HTTP Task
class DataFetchTask {
func fetchData() async {
let jwt = generateJWT(userDid: activeDid, expiresInSeconds: 60)
var request = URLRequest(url: apiURL)
request.setValue("Bearer \(jwt)", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
do {
let (data, _) = try await URLSession.shared.data(for: request)
let offersResponse = try JSONDecoder().decode(OffersResponse.self, from: data)
await scheduleNotification(with: offersResponse.data)
} catch {
// Handle errors
}
}
}
```
## Data Models & Type Safety
### Shared TypeScript Interfaces
```typescript
// Definitions for native bridge
interface OffersResponse {
data: OfferSummaryRecord[];
hitLimit: boolean;
}
interface OfferSummaryRecord {
jwtId: string;
handleId: string;
issuedAt: string;
offeredByDid: string;
recipientDid: string;
unit: string;
amount: number;
// ... other fields
}
```
### Native Implementations
- **Kotlin sealed classes** for type-safe responses
- **Swift Codable structs** for JSON parsing
- **Shared error handling** patterns
## Configuration Management
### Plugin Configuration
```typescript
interface PluginConfig {
apiServer: string;
jwtExpirationSeconds: number;
requestTimeoutMs: number;
retryAttempts: number;
activeDid: string; // Simplified to single active DID
lastKnownOfferId?: string;
lastKnownPlanId?: string;
}
```
### Platform-Specific Settings
- **Android**: Manage API keys in `AndroidManifest.xml`, use SharedPreferences for runtime config
- **iOS**: Use `Info.plist` for static config, UserDefaults for runtime settings
## Error Handling & Resilience
### Network Error Handling
- **Connectivity checks** before making requests
- **Exponential backoff** for retry scenarios
- **Circuit breaker pattern** for API failures
- **Graceful degradation** when offline
### Authentication Error Handling
- **Token refresh** mechanisms
- **Fallback to anonymous** requests when authentication fails
- **Secure credential storage** using platform keychains
## Cache & State Management
### Data Persistence
#### **Platform-Specific Storage Architecture**
**Android/Electron Platforms:**
- **@capacitor-community/sqlite** plugin integration for native SQLite access
- **Shared plugin database** - Plugin manages its own SQLite database instance
- **Direct SQL execution** via plugin's `dbExec()` methods for complex queries
- **Background worker integration** for database operations during content fetch
**Web Platform:**
- **absurd-sql** for SQLite support in browser (managed by host application)
- **Plugin delegation pattern** - Plugin provides SQL queries, host executes them
- **IndexedDB fallback** for basic caching when SQLite unavailable
**iOS Platform:**
- **Core Data integration** via native Swift implementation
- **Background task compatibility** with iOS background refresh constraints
### State Synchronization
- **JavaScript → Native** configuration updates
- **Native → JavaScript** status reporting
- **Cross-platform state consistency**
- **Background ↔ Foreground** state synchronization
- **Database logging** for audit trails and debugging
### Enhanced Caching Strategy
Based on TimeSafari's optimization patterns:
- **Batch-oriented processing** for API requests to reduce overhead
- **Intelligent batching** with configurable timing (max 100ms wait, max 10 items)
- **Memory-optimized caching** with automatic cleanup (keep last 1000 log entries)
- **Request deduplication** to prevent redundant API calls
- **Performance monitoring** with operation timing and metrics collection
## Performance Optimizations
### Request Optimization
- **Deduplication** of identical requests
- **Batch requests** when possible
- **Intelligent polling** based on user activity
### Memory Management
- **Background memory limits** enforcement
- **Cache cleanup** on memory pressure
- **Resource lifecycle** management
## Critical Requirement: Plugin Must Know When activeDid Changes
### **Security Implications of Missing ActiveDid Change Detection**
**Without immediate activeDid change detection, the plugin faces severe risks:**
- **Cross-User Data Exposure**: Plugin fetches notifications for wrong user after identity switch
- **Unauthorized API Access**: JWT tokens valid for incorrect user context
- **Background Task Errors**: Content fetching operates with wrong identity
### **Event-Based Solution**
**Host Application Responsibility**: Dispatch `activeDidChanged` event
```typescript
// TimeSafari PlatformServiceMixin modification
async $updateActiveDid(newDid: string | null): Promise<void> {
// Update TimeSafari's active_identity table (existing logic)
await this.$dbExec(
"UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1",
[newDid || ""]
);
// CRITICAL: Notify plugin of change IMMEDIATELY
document.dispatchEvent(new CustomEvent('activeDidChanged', {
detail: { activeDid: newDid }
}));
}
```
**Plugin Responsibility**: Listen and respond to changes
```typescript
// Plugin service layer implementation
plugin.onActiveDidChange(async (newActiveDid) => {
// 1. Clear all cached content for previous identity
await plugin.clearCacheForNewIdentity();
// 2. Refresh authentication tokens with new activeDid
await plugin.refreshAuthenticationForNewIdentity(newActiveDid);
// 3. Restart background tasks with correct identity
await plugin.updateBackgroundTaskIdentity(newActiveDid);
logger.info(`[DailyNotificationService] ActiveDid updated to: ${newActiveDid}`);
});
```
## TimeSafari Integration Patterns
### **ActiveDid Management Analysis**
**TimeSafari's Database Architecture:**
- **Table**: `active_identity` (single row with `id = 1`)
- **Content**: `activeDid TEXT`, `lastUpdated DATETIME`
- **Purpose**: Single source of truth for active user identity
**Access via PlatformServiceMixin:**
```typescript
// Retrieving activeDid in TimeSafari components
const activeIdentity = await this.$getActiveIdentity();
const activeDid = activeIdentity.activeDid;
// Updating activeDid via PlatformServiceMixin
async $updateActiveDid(newDid: string | null): Promise<void> {
await this.$dbExec(
"UPDATE active_identity SET activeDid = ?, lastUpdated = datetime('now') WHERE id = 1",
[newDid || ""]
);
}
```
### **Plugin Hosting Strategy**
**Existing Plugin Usage**: TimeSafari already uses Capacitor plugins extensively via `CapacitorPlatformService.ts`
**Recommended Integration Architecture:**
- Plugin integrates as standard Capacitor plugin
- Host provides activeDid via event-driven pattern
- Plugin manages own isolated storage
- Clear separation of responsibilities maintained
## Integration Points
### Enhanced Plugin Interface for Host Application Integration
#### **Database Integration Patterns**
**Android/Electron: Host-Provided activeDid Approach (Option A)**
```typescript
// Host queries its own database and provides activeDid
const activeIdentity = await this.$getActiveIdentity(); // Uses host's CapacitorSQLite
await plugin.setActiveDidFromHost(activeIdentity.activeDid);
// Plugin configures its own isolated database
await plugin.configureDatabase({
platform: 'android',
storageType: 'plugin-managed' // Plugin owns its storage
});
// Set up activeDid change listener for future changes
plugin.onActiveDidChange(async (newActiveDid) => {
await plugin.clearCacheForNewIdentity();
await plugin.refreshAuthenticationForNewIdentity(newActiveDid);
logger.info(`[TimeSafari] ActiveDid changed to: ${newActiveDid}`);
});
```
**Web: Host-Provided activeDid Approach (Option A)**
```typescript
// Host queries its absurd-sql database and provides activeDid
const activeIdentity = await this.$getActiveIdentity(); // Uses host's absurd-sql
await plugin.setActiveDidFromHost(activeIdentity.activeDid);
// Plugin uses host-delegated storage for its own data
await plugin.configureDatabase({
platform: 'web',
storageType: 'host-managed' // Plugin delegates to host for storage
});
// Plugin operates independently with provided activeDid
const results = await plugin.executeContentFetch(contentConfig);
```
**iOS: Host-Provided activeDid Approach (Option A)**
```typescript
// Host queries its CapacitorSQLite database and provides activeDid
const activeIdentity = await this.$getActiveIdentity(); // Uses host's CapacitorSQLite
await plugin.setActiveDidFromHost(activeIdentity.activeDid);
// Plugin configures its own Core Data storage
await plugin.configureDatabase({
platform: 'ios',
storageType: 'plugin-managed' // Plugin owns Core Data storage
});
// Plugin operates with provided activeDid, no database sharing needed
const results = await plugin.executeBackgroundContentFetch();
```
#### **Enhancement Required: Extend Current Plugin Interface**
**Current Interface** (already implemented):
```typescript
interface DailyNotificationPlugin {
configure(options: ConfigureOptions): Promise<void>;
scheduleContentFetch(config: ContentFetchConfig): Promise<void>;
scheduleUserNotification(config: UserNotificationConfig): Promise<void>;
// ... existing methods (see definitions.ts)
}
```
**Enhancement Required** (add to existing interface):
```typescript
interface EnhancedDailyNotificationPlugin extends DailyNotificationPlugin {
// Enhanced configuration with activeDid support
configure(options: ConfigureOptions & {
activeDidIntegration?: {
platform: 'android' | 'ios' | 'web' | 'electron';
storageType: 'plugin-managed' | 'host-managed';
};
}): Promise<void>;
// Host-provided activeDid Management (Option A Implementation)
setActiveDidFromHost(activeDid: string): Promise<void>;
// Critical: ActiveDid Change Handling
onActiveDidChange(callback: (newActiveDid: string) => Promise<void>): void;
refreshAuthenticationForNewIdentity(activeDid: string): Promise<void>;
}
```
### Background Scheduling with Hybrid activeDid Management
- **Integrate** with existing WorkManager/BGTaskScheduler
- **Coordinate** API fetch timing with notification schedules
- **Handle** app lifecycle events (background/foreground)
- **Implement** host-provided activeDid access (Option A):
- **Always**: Host provides activeDid via `setActiveDidFromHost()`
- **No Database Sharing**: Plugin never accesses TimeSafari's active_identity table
- **Critical**: Plugin **MUST** know when activeDid changes for:
- **Event-Based Notification**: Host dispatches `activeDidChanged` events
- **Cache Invalidation**: Clear cached content when user switches identity
- **Token Refresh**: Generate new JWT tokens with updated active Did
- **Background Task Coordination**: Restart tasks with new identity context
- **Maintain** clear separation: Host owns identity management, plugin owns notifications
## Migration & Testing Strategy
### Gradual Migration
1. **Phase 1**: Implement basic HTTP + JWT authentication
2. **Phase 2**: Add caching and state management
3. **Phase 3**: Integrate with notification scheduling
4. **Phase 4**: Add passkey authentication support
### Testing Approach with Host-Provided activeDid Management
- **Unit tests** for JWT generation and HTTP clients with activeDid
- **Integration tests** for API endpoint interactions using TimeSafari active_identity patterns
- **Host-provided activeDid testing**:
- Test `setActiveDidFromHost()` with TimeSafari PlatformServiceMixin
- Test host event dispatch and plugin event listening
- **Critical**: Test `onActiveDidChange()` listener with identity switches
- Test cache invalidation and token refresh during activeDid changes
- Verify database isolation between host and plugin
- **Background testing** on real devices (doze mode, app backgrounding)
- **Authentication testing** with actual DID credentials from TimeSafari active_identity table
- **Cross-platform testing** for Android/Electron (SQLite access) vs Web (host delegation) patterns
## API Endpoints to Support
### Offers to User Endpoint
```
GET {apiServer}/api/v2/report/offers?recipientDid={userDid}&afterId={jwtId}&beforeId={jwtId}
```
**Response Structure:**
```json
{
"data": Array<OfferSummaryRecord>,
"hitLimit": boolean
}
```
### Offers to User Projects Endpoint
```
GET {apiServer}/api/v2/report/offersToPlansOwnedByMe?afterId={jwtId}&beforeId={jwtId}
```
**Response Structure:**
```json
{
"data": Array<OfferToPlanSummaryRecord>,
"hitLimit": boolean
}
```
## Authentication Implementation Strategy
### Option 1: Simple DID Authentication (Basic)
- Generate traditional JWT using DID signing
- Short-lived tokens (60 seconds)
- Suitable for basic notification data fetching
- Use `did-jwt` library for token generation and verification
- Based on TimeSafari's existing JWT implementation patterns
### Option 2: Enhanced Passkey Authentication (Advanced)
- Leverage device biometrics/security keys
- Longer-lived tokens with automatic refresh
- Support for cached authentication state
- Better user experience for frequent polling
- Integrate with SimpleWebAuthn for cross-platform biometric support
- Support JWANT tokens (JWT + WebAuthn) for enhanced security
## Platform-Specific Considerations
### Android Considerations
- Use OkHttp or native Android HTTP clients
- Handle certificate pinning if required
- Support Android Keystore for secure key storage
- Handle biometric prompt integration for passkeys
### iOS Considerations
- Use URLSession for HTTP requests
- Support iOS Keychain for authentication tokens
- Handle Face ID/Touch ID integration for passkeys
- Support certificate pinning if required
- Use BGTaskScheduler for reliable background execution
- Handle iOS-specific background refresh restrictions
- Support Core Data for notification metadata persistence
## Data Flow Integration Points
### Token Generation
- Accept activeDid as input
- Generate JWT authentication token using DID signing
- Include activeDid as both issuer (`iss`) and subject (`sub`)
- Return token for immediate use or caching
### Request Execution
- Construct full API URLs with query parameters
- Apply authentication headers
- Execute HTTP requests with proper error handling
- Return structured response data
### Caching Strategy
- Support token caching with expiration management
- Implement request deduplication for same endpoints
- Support cache invalidation for authentication failures
## Implementation Phases
### Phase 1: Extend Core Infrastructure (Building on Existing)
- **Extend existing** Android `DailyNotificationFetcher.java` with JWT authentication
- **Enhance existing** iOS implementation (when added) with authentication layer
- **Add JWT generation** to existing `DailyNotificationETagManager.java`
- **Enhance current** `ConfigureOptions` with activeDid integration
- **Build on existing** error handling (circuit breaker already implemented)
### Phase 2: ActiveDid Integration & TimeSafari API Enhancement
- **Add** host-provided activeDid management to existing plugin interface
- **Extend** existing `configure()` method with activeDid options
- **Enhance** existing `ContentFetchConfig` with Endorser.ch API endpoints
- **Add** `setActiveDidFromHost()` and `onActiveDidChange()` to existing interface
- **Integrate** existing `callback-registry.ts` with activeDid-aware callbacks
- **Enhance** existing platform storage:
- **Android**: Extend existing SQLite with activeDid-aware JWT storage
- **Web**: Enhance existing IndexedDB with activeDid support (no host delegation needed initially)
### Phase 3: Background Enhancement & TimeSafari Coordination
- **Enhance** existing WorkManager integration with activeDid-aware workers
- **Coordinate** existing notification scheduling with TimeSafari PlatformServiceMixin
- **Extend** existing app lifecycle handling with activeDid change detection
- **Enhance** existing state synchronization with identity management
- **Critical: Enhance retry policies** for activeDid changes:
- **Android**: Modify `DailyNotificationFetchWorker.java` retry logic to detect activeDid changes during retry sequence
- **Web**: Enhance `callback-registry.ts` to refresh authentication before retry attempts
- **Unify**: Standardize retry delays across platforms (Android 1min→1hour vs Web 1sec→1min)
- **Integrate activeDid change detection** into existing circuit breaker and error handling systems
### Phase 4: TimeSafari Integration & Advanced Features
- **Integrate** with TimeSafari's existing PlatformServiceMixin patterns
- **Add** Endorser.ch API endpoint support to existing `ContentFetchConfig`
- **Implement** DID-based authentication alongside existing callback system
- **Enhance** existing testing with TimeSafari-specific scenarios
## Current Scheduled Event Update Policies
### ✅ **Existing Consistent Policies**
- **Retry Logic**: Exponential backoff with platform-specific limits (Android: 5 retries, Web: 5 retries)
- **Circuit Breaker**: Opens after 5 consecutive failures
- **Fallback Content**: Uses cached/emergency content when all retries fail
- **ETag Updates**: Conditional requests with 304 Not Modified handling
- **Error Classification**: Network/Storage errors retryable, Permission/Config errors not retryable
### ⚠️ **Enhancement Required for TimeSafari Integration**
- **ActiveDid Change Detection**: Handle identity switches during scheduled events
- **Authentication Refresh**: Update JWT tokens for ongoing retry attempts
- **Cache Invalidation**: Clear cached content when activeDid changes
- **Platform Policy Unification**: Standardize retry delays and fallback mechanisms
### **TimeSafari-Aware Update Policy**
```typescript
interface TimeSafariUpdatePolicy extends ContentFetchConfig {
activeDidAwareRetry?: {
maxRetriesDuringActiveDidChange: number; // More retries during identity change
authenticationRefreshDelay: number; // Time to refresh auth before retry
cacheInvalidationOnChange: boolean; // Clear cache when activeDid changes
};
}
```
## Success Criteria
- [ ] **Functional Requirements**: API data fetching works reliably in background with activeDid awareness
- [ ] **Performance Requirements**: Requests complete within 30 seconds, including authentication refresh
- [ ] **Security Requirements**: ActiveDid-based authentication with token refresh during retries
- [ ] **Reliability Requirements**: Enhanced retry policies that handle activeDid changes gracefully
- [ ] **Integration Requirements**: Seamless integration with existing plugin APIs + TimeSafari patterns
- [ ] **Testing Requirements**: Comprehensive test coverage including activeDid change scenarios
- [ ] **Authentication Requirements**: DID-based JWT with automatic refresh during scheduled events
- [ ] **Optimization Requirements**: Intelligent retry policies based on error type and activeDid state
- [ ] **Logging Requirements**: Structured logging with activeDid context and retry state tracking
- [ ] **Cross-Platform Requirements**: Unified activeDid-aware retry and fallback mechanisms
## Risks & Mitigation
### Technical Risks
- **Background execution limits**: Mitigated by using platform-specific background task systems
- **Authentication complexity**: Mitigated by implementing gradual migration path
- **Cross-platform consistency**: Mitigated by shared interfaces and careful API design
### Timeline Risks
- **Platform-specific complexity**: Mitigated by prioritizing Android first, then iOS
- **Testing complexity**: Mitigated by automated testing and CI/CD integration
- **Integration challenges**: Mitigated by maintaining backward compatibility
---
**Status**: Enhancement plan for existing implementation (Option A) - Ready for implementation
**Next Steps**: Begin Phase 1 - enhance existing Android HTTP infrastructure with JWT authentication
**Dependencies**: Existing plugin infrastructure, Android Studio, Capacitor CLI, TimeSafari PlatformServiceMixin
**Enhancement Approach**:
- **Build on Existing**: Leverage current SQLite, IndexedDB, callback system, and dual scheduling
- **Option A Integration**: Add activeDid management to existing configuration and HTTP layers
- **TimeSafari Enhancement**: Extend current ContentFetchConfig with Endorser.ch API endpoints
- **Authentication Layer**: Add JWT/DID authentication over existing HTTP infrastructure
- **Event Integration**: Enhance existing callback system with activeDid change detection

View File

@@ -1,155 +0,0 @@
# iOS Build Fixes Summary
**Date:** 2025-11-13
**Status:****BUILD SUCCEEDED**
---
## Objective
Fix all Swift compilation errors to enable iOS test app building and testing.
---
## Results
**BUILD SUCCEEDED**
**All compilation errors resolved**
**Test app ready for iOS Simulator testing**
---
## Error Categories Fixed
### 1. Type System Mismatches
- **Issue:** `Int64` timestamps incompatible with Swift `Date(timeIntervalSince1970:)` which expects `Double`
- **Fix:** Explicit conversion: `Date(timeIntervalSince1970: Double(value) / 1000.0)`
- **Files:** `DailyNotificationTTLEnforcer.swift`, `DailyNotificationRollingWindow.swift`
### 2. Logger API Inconsistency
- **Issue:** Code called `logger.debug()`, `logger.error()` but API only provides `log(level:message:)`
- **Fix:** Updated to `logger.log(.debug, "\(TAG): message")` format
- **Files:** `DailyNotificationErrorHandler.swift`, `DailyNotificationPerformanceOptimizer.swift`, `DailyNotificationETagManager.swift`
### 3. Immutable Property Assignment
- **Issue:** Attempted to mutate `let` properties on `NotificationContent`
- **Fix:** Create new instances instead of mutating existing ones
- **Files:** `DailyNotificationBackgroundTaskManager.swift`
### 4. Missing Imports
- **Issue:** `CAPPluginCall` used without importing `Capacitor`
- **Fix:** Added `import Capacitor`
- **Files:** `DailyNotificationCallbacks.swift`
### 5. Access Control
- **Issue:** `private` properties inaccessible to extension methods
- **Fix:** Changed to `internal` (default) access level
- **Files:** `DailyNotificationPlugin.swift`
### 6. Phase 2 Features in Phase 1
- **Issue:** Code referenced CoreData `persistenceController` which doesn't exist in Phase 1
- **Fix:** Stubbed Phase 2 methods with TODO comments
- **Files:** `DailyNotificationBackgroundTasks.swift`, `DailyNotificationCallbacks.swift`
### 7. iOS API Availability
- **Issue:** `interruptionLevel` requires iOS 15.0+ but deployment target is iOS 13.0
- **Fix:** Added `#available(iOS 15.0, *)` checks
- **Files:** `DailyNotificationPlugin.swift`
### 8. Switch Exhaustiveness
- **Issue:** Missing `.scheduling` case in `ErrorCategory` switch
- **Fix:** Added missing case
- **Files:** `DailyNotificationErrorHandler.swift`
### 9. Variable Initialization
- **Issue:** Variables captured by closures before initialization
- **Fix:** Extract values from closures into local variables
- **Files:** `DailyNotificationErrorHandler.swift`
### 10. Capacitor API Signature
- **Issue:** `call.reject()` doesn't accept dictionary as error parameter
- **Fix:** Use `call.reject(message, code)` format
- **Files:** `DailyNotificationPlugin.swift`
### 11. Method Naming
- **Issue:** Called `execSQL()` but method is `executeSQL()`
- **Fix:** Updated to correct method name
- **Files:** `DailyNotificationPerformanceOptimizer.swift`
### 12. Async/Await
- **Issue:** Async function called in synchronous context
- **Fix:** Made functions `async throws` where needed
- **Files:** `DailyNotificationETagManager.swift`
### 13. Codable Conformance
- **Issue:** `NotificationContent` needed `Codable` for JSON encoding
- **Fix:** Added `Codable` protocol conformance
- **Files:** `NotificationContent.swift`
---
## Build Script Improvements
### Simulator Auto-Detection
- **Before:** Hardcoded "iPhone 15" (not available on all systems)
- **After:** Auto-detects available iPhone simulators using device ID (UUID)
- **Implementation:** Extracts device ID from `xcrun simctl list devices available`
- **Fallback:** Device name → Generic destination
### Workspace Path
- **Fix:** Corrected path to `test-apps/ios-test-app/ios/App/App.xcworkspace`
### CocoaPods Detection
- **Fix:** Handles both system and rbenv CocoaPods installations
---
## Statistics
- **Total Error Categories:** 13
- **Individual Errors Fixed:** ~50+
- **Files Modified:** 12 Swift files + 2 configuration files
- **Build Time:** Successful on first clean build after fixes
---
## Verification
**Build Command:**
```bash
./scripts/build-ios-test-app.sh --simulator
```
**Result:** ✅ BUILD SUCCEEDED
**Simulator Detection:** ✅ Working
- Detects: iPhone 17 Pro (ID: 68D19D08-4701-422C-AF61-2E21ACA1DD4C)
- Builds successfully for simulator
---
## Next Steps
1. ✅ Build successful
2. ⏳ Run test app on iOS Simulator
3. ⏳ Test Phase 1 plugin methods
4. ⏳ Verify notification scheduling
5. ⏳ Test background task execution
---
## Lessons Learned
See `doc/directives/0003-iOS-Android-Parity-Directive.md` Decision Log section for detailed lessons learned from each error category.
**Key Takeaways:**
- Always verify type compatibility when bridging platforms
- Check API contracts before using helper classes
- Swift's type system catches many errors at compile time
- Phase separation (Phase 1 vs Phase 2) requires careful code organization
- Auto-detection improves portability across environments
---
**Last Updated:** 2025-11-13

View File

@@ -1,133 +0,0 @@
# Build Script Improvements
**Date:** 2025-11-13
**Status:****FIXED**
---
## Issues Fixed
### 1. Missing Build Folder ✅
**Problem:**
- Script was looking for `build` directory: `find build -name "*.app"`
- Xcode actually builds to `DerivedData`: `~/Library/Developer/Xcode/DerivedData/App-*/Build/Products/`
**Solution:**
- Updated script to search in `DerivedData`:
```bash
DERIVED_DATA_PATH="$HOME/Library/Developer/Xcode/DerivedData"
APP_PATH=$(find "$DERIVED_DATA_PATH" -name "App.app" -path "*/Build/Products/Debug-iphonesimulator/*" -type d 2>/dev/null | head -1)
```
**Result:** ✅ App path now correctly detected
---
### 2. Simulator Not Launching ✅
**Problem:**
- Script only built the app, didn't boot or launch simulator
- No automatic deployment after build
**Solution:**
- Added automatic simulator boot detection and booting
- Added Simulator.app opening if not already running
- Added boot status polling (waits up to 60 seconds)
- Added automatic app installation
- Added automatic app launch (with fallback methods)
**Implementation:**
```bash
# Boot simulator if not already booted
if [ "$SIMULATOR_STATE" != "Booted" ]; then
xcrun simctl boot "$SIMULATOR_ID"
open -a Simulator # Open Simulator app
# Wait for boot with polling
fi
# Install app
xcrun simctl install "$SIMULATOR_ID" "$APP_PATH"
# Launch app
xcrun simctl launch "$SIMULATOR_ID" com.timesafari.dailynotification.test
```
**Result:** ✅ Simulator now boots and app launches automatically
---
## Improvements Made
### Boot Detection
- ✅ Polls simulator state every second
- ✅ Waits up to 60 seconds for full boot
- ✅ Provides progress feedback every 5 seconds
- ✅ Adds 3-second grace period after boot detection
### App Launch
- ✅ Tries direct launch first
- ✅ Falls back to console launch if needed
- ✅ Provides manual instructions if automatic launch fails
- ✅ Handles errors gracefully
### Error Handling
- ✅ All commands have error handling
- ✅ Warnings instead of failures for non-critical steps
- ✅ Clear instructions for manual fallback
---
## Current Behavior
1. ✅ **Builds** the iOS test app successfully
2. ✅ **Finds** the built app in DerivedData
3. ✅ **Detects** available iPhone simulator
4. ✅ **Boots** simulator if not already booted
5. ✅ **Opens** Simulator.app if needed
6. ✅ **Waits** for simulator to fully boot
7. ✅ **Installs** app on simulator
8. ✅ **Launches** app automatically
---
## Known Limitations
### Launch May Fail
- Sometimes `xcrun simctl launch` fails even though app is installed
- **Workaround:** App can be manually launched from Simulator home screen
- **Alternative:** Use Xcode to run the app directly (Cmd+R)
### Boot Time
- Simulator boot can take 30-60 seconds on first boot
- Subsequent boots are faster
- Script waits up to 60 seconds, but may need more on slower systems
---
## Testing
**Command:**
```bash
./scripts/build-ios-test-app.sh --simulator
```
**Expected Output:**
```
[INFO] Build successful!
[INFO] App built at: /Users/.../DerivedData/.../App.app
[STEP] Checking simulator status...
[STEP] Booting simulator (iPhone 17 Pro)...
[STEP] Waiting for simulator to boot...
[INFO] Simulator booted successfully (took Xs)
[STEP] Installing app on simulator...
[INFO] App installed successfully
[STEP] Launching app...
[INFO] ✅ App launched successfully!
[INFO] ✅ Build and deployment complete!
```
---
**Last Updated:** 2025-11-13

View File

@@ -1,652 +0,0 @@
# TimeSafari Daily Notification Plugin Integration Checklist
**Author**: Matthew Raymer
**Version**: 2.0.0
**Created**: 2025-01-27 12:00:00 UTC
**Last Updated**: 2025-10-08 06:08:15 UTC
**Audit Status**: ✅ **PASSED** - 2025-10-08 06:08:15 UTC. All phases complete with comprehensive observability, accessibility, and compliance implementation.
## Overview
This checklist tracks the integration of the TimeSafari Daily Notification Plugin into the main TimeSafari PWA project. The plugin provides enterprise-grade daily notification functionality with dual scheduling, callback support, TTL-at-fire logic, and comprehensive observability across Mobile (Capacitor) and Desktop (Electron) platforms.
**Critical Integration Requirements:**
- Privacy-preserving claims architecture via endorser.ch
- Decentralized Identifiers (DIDs) integration
- Cryptographic verification patterns
- TimeSafari community features (starred projects, trust networks)
- SQLite/Absurd SQL database integration
- Vite build system compatibility
- Accessibility & Localization of notification content (A11y text, language/region)
- Observability hooks (structured logs, metrics, traces) and privacy-preserving redaction
## Integration Requirements Analysis
### Current Plugin Structure
- **Package Name**: `@timesafari/daily-notification-plugin`
- **Repository**: Standalone plugin repository
- **Build System**: Rollup + TypeScript
- **Platforms**: Android, iOS, Web (target **Capacitor v6** runtime compatibility)
- **Dependencies**: Capacitor **6.2.1**, TypeScript **5.2.2**, Jest **29.7.0** (aligned with host)
### TimeSafari PWA Requirements
- **Architecture**: Vue 3 + TypeScript + Platform Services + Privacy-Preserving Claims
- **Build System**: Vite with platform-specific configs (Web/Capacitor/Electron)
- **Testing**: Playwright E2E, Jest unit tests with platform coverage
- **Platform Services**: Abstracted behind interfaces with factory pattern
- **Database**: SQLite via Absurd SQL (browser) and native SQLite (mobile/desktop)
- **Privacy Architecture**: DIDs, cryptographic verification, endorser.ch integration
- **Community Features**: Starred projects, trust networks, Endorser.ch API
- **State Management**: Pinia stores with platform-specific persistence
- **Security**: User-controlled visibility, secure storage, permission handling
## Integration Phases
### Phase 1: Package Preparation & Publishing
#### 1.1 Package Configuration
- [ ] Update `package.json` with correct TimeSafari repository URL
- [ ] Align package name with TimeSafari naming conventions (`@timesafari/daily-notification-plugin`)
- [ ] Update version to match TimeSafari release cycle
- [ ] Add proper keywords and description for TimeSafari context
- [ ] Update author and license information
- [ ] Add TimeSafari-specific peer dependencies
- [ ] Configure package for Vite compatibility (ESM/CJS dual build)
- [ ] Add an `exports` map in `package.json` to ensure ESM-first resolution in Vite 5 and Node 18+
- [ ] Confirm dual builds: `module` (ESM) and `main` (CJS) remain valid for bundlers; keep `types` pointed at ESM d.ts
- [ ] Replace placeholder repo fields with TimeSafari org URLs (`repository.url`, `bugs.url`)
- [ ] Add `"sideEffects": false` if tree-shaking is safe
- [ ] **Release scripts (no CI/CD):** add `standard-version` (or `changesets`) and npm scripts:
* `release:prepare` → runs tests, typecheck, bundle-size check, generates changelog, bumps version, creates a local tag
* `release:publish` → pushes tag and publishes to npm (or your registry)
* `release:notes` → opens/updates draft Release Notes with links to evidence artifacts
- [ ] Declare **engines** (Node ≥ 18) to match Vite 5 toolchain expectations
- [ ] Publish **types** checksum via **local script** (`npm run types:checksum`) to catch accidental API changes (commit checksum file)
- [ ] **Public API guard (local)**: `npm run api:check` (API Extractor or dts diff) **must pass** before any release; if the API changed, use `feat` or include **BREAKING CHANGE** in notes
- [ ] **Local quality-gates scripts present**: `npm run size:check`, `npm run api:check`, `npm run types:checksum` are implemented in `scripts/` and referenced from Release Notes
#### 1.2 Repository Integration
- [ ] Create integration branch in TimeSafari PWA repository
- [ ] Setup plugin as submodule or local package
- [ ] Configure git submodule or local installation path
- [ ] Test basic repository access and cloning
- [ ] Verify TimeSafari PWA repository structure matches documented architecture
- [ ] Confirm access to TimeSafari's privacy-preserving claims architecture
#### 1.3 Publishing Strategy
- [ ] **Option A**: Local package installation (recommended for development)
- [ ] Configure `npm install file:./daily-notification-plugin`
- [ ] Test local installation in TimeSafari PWA
- [ ] Validate package resolution and imports
- [ ] Test Vite build integration with local package
- [ ] **Option B**: Git-based installation
- [ ] Configure git-based installation with correct TimeSafari repository URL
- [ ] Test git-based installation
- [ ] Validate branch/tag resolution
- [ ] Test build integration with git-based package
- [ ] **Option C**: Private npm registry
- [ ] Setup private npm registry access
- [ ] Publish plugin to private registry
- [ ] Configure TimeSafari PWA to use private registry
- [ ] Test registry-based installation and build
#### 1.4 Workspace / Monorepo Linking
- [ ] Prefer **workspace linking** (npm/pnpm/yarn) during integration; ensure the plugin package name remains `@timesafari/daily-notification-plugin`
*Rationale: aligns with TimeSafari's multi-platform build scripts and keeps local iteration fast.*
### Phase 2: Dependency Alignment
#### 2.1 Capacitor Version Compatibility (v6 target)
- [ ] Upgrade plugin deps to **@capacitor/core 6.x** and platform packages to **6.x**
- [ ] Re-test plugin registration/initialization against Capacitor 6 bridge
- [ ] Android: verify Notification Channel creation, Foreground services policy, WorkManager compatibility on API 34+
- [ ] iOS: validate BGTaskScheduler identifiers and notification permission flow on iOS 17+
- [ ] Maintain a **compat matrix** (plugin@version ↔ Capacitor major) in the README
- [ ] README **compatibility matrix** links to the example app "Quick Smoke Test" and the **Manual Smoke Test** doc (no CI)
- [ ] Re-test **permission prompts** & "provisional" iOS notification flows; document UX paths and fallbacks
- [ ] Validate **deferred/deadline** behaviors vs. **TTL-at-fire logic** across OS versions (Android 1214, iOS 1518)
- [ ] **Version-skew cleanup**: after this phase is completed and the README matrix is updated, remove the "Version skew noted" bullet from *Current Plugin Structure*
#### 2.2 TypeScript Configuration
- [ ] Align TypeScript versions between plugin and TimeSafari PWA
- [ ] Check TypeScript configuration compatibility
- [ ] Validate type definitions and exports
- [ ] Test TypeScript compilation in integrated environment
- [ ] Align TS to **~5.2.x** to match host app toolchain; re-run `tsc --noEmit` in the integrated repo
#### 2.3 Build Tools Alignment
- [ ] Verify Rollup configuration compatibility with Vite
- [ ] Check build output formats and targets (ESM/CJS dual build)
- [ ] Validate module resolution and bundling
- [ ] Test build process integration
- [ ] Configure plugin for Vite's external dependencies handling
- [ ] Test plugin with TimeSafari's platform-specific Vite configs
- [ ] Validate plugin build outputs work with TimeSafari's asset validation
- [ ] Validate Rollup 3 output consumption by **Vite 5** (optimizeDeps, `build.commonjsOptions`)
- [ ] Ensure no transitive dependency locks the plugin to older `vite`/`rollup` plugin APIs
- [ ] Verify **`exports`** map resolution (ESM-first) in Vite 5 cold-start and SSR (if used)
- [ ] Add bundle-size guard (rollup-plugin-visualizer or vite's `--mode analyze`) with a **performance budget**
#### 2.4 Dependency Conflict Resolution
- [ ] Identify potential dependency conflicts
- [ ] Resolve version conflicts using npm/yarn resolutions
- [ ] Test dependency resolution in integrated environment
- [ ] Validate all dependencies are properly resolved
- [ ] Check TimeSafari-specific dependency patterns (Pinia, vue-facing-decorator)
- [ ] Validate plugin doesn't conflict with TimeSafari's privacy-preserving dependencies
- [ ] Test plugin with TimeSafari's structured logging dependencies
- [ ] Confirm no duplicate Reactivity libs in host (e.g., vue reactivity duplication) and no `any` leakage in d.ts (DX guard)
#### 2.5 Test Runner Alignment
- [ ] Align **Jest 30.x** in the plugin with the app's Jest 30.x to avoid mixed runners; remove `jest-environment-jsdom@30` duplication if unnecessary
### Phase 3: TimeSafari Architecture Integration
#### 3.1 Privacy-Preserving Claims Architecture
- [x] Integrate plugin with TimeSafari's endorser.ch architecture
- [x] Implement DIDs (Decentralized Identifiers) support in plugin
- [x] Add cryptographic verification patterns to plugin
- [x] Configure plugin for user-controlled visibility
- [x] Test plugin with TimeSafari's privacy-preserving patterns
- [x] Verify DID/VC flows integrate with **Veramo** stack already present in the app (`@veramo/*`, `did-jwt`, `did-resolver`, `web-did-resolver`). Include example notification payloads signed or referenced via DID where applicable
- [x] Provide **sample DID-signed payloads** and verification steps in docs; include **revocation / expiration** examples
- [x] Add **data retention** and **field-level redaction** policy for logs/analytics events emitted by the plugin
#### 3.2 Database Integration with TimeSafari Storage
- [x] Integrate plugin storage with TimeSafari's SQLite/Absurd SQL approach
- [x] Configure plugin to use TimeSafari's database patterns
- [x] Implement IndexedDB compatibility for legacy browsers
- [x] Test plugin storage with TimeSafari's database architecture
- [x] Validate data persistence across TimeSafari's storage layers
- [x] Define a **storage adapter contract** (interface) with versioning and migration notes; forbid the plugin from owning its own DB lifecycle
#### 3.3 Community Features Integration
- [x] Implement starred projects polling integration
- [x] Add Endorser.ch API integration patterns
- [x] Configure trust network integration callbacks
- [x] Test plugin with TimeSafari's community features
- [x] Validate notification delivery for community events
- [x] Ensure notification templates can reference **starred projects/trust networks** without creating tight coupling; expose a narrow plugin API the app can call
- [x] Add **rate limits** and **backoff policy** for community polling to protect mobile battery/network budgets
#### 3.4 Security Integration
- [x] Integrate plugin with TimeSafari's security audit requirements
- [x] Add TimeSafari's permission handling patterns
- [x] Configure secure storage integration
- [x] Test plugin with TimeSafari's security patterns
- [x] Validate plugin meets TimeSafari's security standards
### Phase 4: Build System Integration
#### 4.1 Vite Configuration Integration
- [ ] Integrate plugin build with TimeSafari's Vite configuration
- [ ] Configure plugin as external dependency or bundled module
- [ ] Update `vite.config.ts` with plugin-specific settings
- [ ] Test build process with integrated plugin
- [ ] Configure plugin for TimeSafari's platform-specific Vite configs
- [ ] Test plugin with TimeSafari's asset validation and resource generation
- [ ] Confirm **ESM-first** consumption: Vite should resolve `module`/`exports` correctly; add a guard doc note for consumers on Node ESM
- [ ] Add **SSR-safety note** (if host uses SSR for preview) to avoid `window`/Capacitor bridge at import time
- [ ] Verify **tree-shaking** works: example app proves unused exports are dropped
#### 4.2 Build Script Updates
- [ ] Update `package.json` scripts to include plugin compilation
- [ ] Add plugin build steps to existing build commands
- [ ] Configure platform-specific build integration
- [ ] Test all build commands (`build:web`, `build:capacitor`, `build:electron`)
- [ ] Integrate plugin build with TimeSafari's build scripts
- [ ] Test plugin with TimeSafari's build validation scripts
#### 4.3 Platform-Specific Builds
- [ ] Ensure Android build integration works correctly
- [ ] Validate iOS build integration
- [ ] Test Web build integration
- [ ] Verify Electron build integration
- [ ] Test plugin with TimeSafari's platform-specific build configurations
- [ ] Validate plugin works with TimeSafari's platform detection patterns
- [ ] **Electron**: validate basic desktop notification fallback when running via `@capacitor-community/electron`
- [ ] Web-only fallback when native bridges are unavailable (e.g., desktop browser PWA): no runtime errors, graceful degrade
#### 4.4 Build Output Validation
- [ ] Validate plugin build outputs are correctly included
- [ ] Check plugin files are properly bundled or referenced
- [ ] Test build outputs in all target platforms
- [ ] Verify build artifacts are correctly deployed
- [ ] Test plugin with TimeSafari's build output validation
- [ ] Validate plugin assets work with TimeSafari's asset management
### Phase 5: Platform Configuration
#### 5.1 Capacitor Configuration Updates
- [ ] Update `capacitor.config.ts` with plugin configuration
- [ ] Configure plugin-specific settings for TimeSafari context
- [ ] Add generic polling configuration for starred projects
- [ ] Setup notification templates and grouping rules
#### 5.2 Android Platform Configuration
- [x] Update `android/settings.gradle` to include plugin
- [x] Modify `android/app/build.gradle` with plugin dependency
- [x] Add required permissions to `AndroidManifest.xml`
- [x] Configure WorkManager and background execution
- [x] Test Android build and runtime integration
- [x] Confirm `compileSdk`/`targetSdk` alignment with the app's Android **build scripts** and WorkManager scheduler settings (no CI)
- [x] Document **notification channel** taxonomy (IDs, importance, sound/vibrate); enforce **single source of truth** constants
- [x] Verify **Doze/App Standby** delivery expectations and document worst-case latencies
#### 5.3 iOS Platform Configuration
- [x] Update `ios/App/Podfile` to include plugin
- [x] Add required permissions to `Info.plist`
- [x] Configure background modes and BGTaskScheduler
- [x] Enable iOS capabilities in Xcode
- [x] Test iOS build and runtime integration
- [x] Verify required **Push/Background Modes** match the app's build matrix scripts; document BGTask identifiers and scheduling constraints used by the plugin
- [x] Document **UNUserNotificationCenter** delegation points and **BGTaskScheduler** identifiers; include sample plist entries
- [x] Add **quiet-hours** and **focus mode** notes for user expectation setting
- [x] Request **provisional authorization** when appropriate (`UNAuthorizationOptionProvisional`) and document the UX path and downgrade/upgrade flows
#### 5.4 Web Platform Configuration
- [x] ~~Configure Service Worker integration~~ **REMOVED: Web support dropped for native-first architecture**
- [x] ~~Setup IndexedDB for web storage~~ **REMOVED: Web support dropped for native-first architecture**
- [x] ~~Configure push notification setup~~ **REMOVED: Web support dropped for native-first architecture**
- [x] ~~Test web platform functionality~~ **REMOVED: Web support dropped for native-first architecture**
### Phase 6: Service Integration Layer
#### 6.1 DailyNotificationService Creation
- [ ] Create `src/services/DailyNotificationService.ts`
- [ ] Implement singleton pattern following TimeSafari conventions
- [ ] Add initialization method with TimeSafari context
- [ ] Implement error handling and logging
- [ ] Emit structured logs (info/warn/error) with **opaque event IDs** only—no PII; expose hooks to host logger
- [ ] Provide **circuit-breaker/backoff** knobs (config) for schedule failures
#### 6.2 PlatformServiceMixin Integration
- [ ] Update `src/utils/PlatformServiceMixin.ts` with notification methods
- [ ] Add TypeScript declarations for Vue components
- [ ] Implement notification service methods in mixin
- [ ] Test mixin integration with Vue components
- [ ] Provide d.ts augmentation for Vue components using **vue-facing-decorator** patterns to preserve DX (no `any`)
- [ ] Supply **type-safe decorators**/mixins examples for Vue 3 (vue-facing-decorator) to avoid `any` in app code
#### 6.3 TimeSafari Community Features Integration
- [ ] Implement starred projects polling setup
- [ ] Add Endorser.ch API integration patterns
- [ ] Configure community notification templates
- [ ] Setup trust network integration callbacks
#### 6.4 Database Integration
- [ ] Integrate with TimeSafari's SQLite database
- [ ] Configure plugin storage to use TimeSafari's database
- [ ] Implement watermark management with TimeSafari's storage
- [ ] Test database integration and data persistence
- [ ] On Web, prefer app's **Absurd-SQL / sql.js** path; on Mobile/Electron prefer `@capacitor-community/sqlite`. The plugin should **not** introduce its own DB; it should accept a storage adapter from the host
### Phase 7: Testing & Validation
#### 7.1 Unit Testing Integration
- [ ] Integrate plugin unit tests with TimeSafari's Jest configuration
- [ ] Create TimeSafari-specific unit tests for notification service
- [ ] Test plugin functionality in TimeSafari context
- [ ] Validate all unit tests pass in integrated environment
#### 7.2 Integration Testing
- [ ] Create integration tests for notification service
- [ ] Test plugin initialization with TimeSafari's platform services
- [ ] Validate notification delivery and callback functionality
- [ ] Test cross-platform notification behavior
#### 7.3 E2E Testing Integration
- [ ] Add notification tests to TimeSafari's Playwright E2E suite
- [ ] Test notification scheduling and delivery in E2E scenarios
- [ ] Validate notification interactions with TimeSafari UI
- [ ] Test notification callbacks and community features
- [ ] Add Playwright scenarios for permission prompts + first-run notification scheduling in **Web/Android/iOS** using the app's existing Playwright harness
- [ ] Add tests for **permission-denied**, **provisional allowed**, **focus mode**, **quiet-hours** scenarios
- [ ] Battery/network impact smoke tests: schedule density and cancellation bursts
#### 7.4 Cross-Platform Testing
- [ ] Test Android notification functionality
- [ ] Validate iOS notification behavior
- [ ] Test Web notification delivery
- [ ] Verify Electron notification integration
- [ ] Include an **Electron** smoke test (desktop notification or fallback UI)
- [ ] Electron: verify **fallback notification UI** works without native bridges and respects i18n/A11y
### Phase 8: Documentation & Examples
#### 8.1 Integration Guide Updates
- [ ] Update `INTEGRATION_GUIDE.md` for TimeSafari-specific context
- [ ] Add TimeSafari community feature examples
- [ ] Document Endorser.ch API integration patterns
- [ ] Provide TimeSafari-specific troubleshooting guide
- [ ] Include a **Capacitor 5→6 migration note** (breaking changes, permission APIs, Android 14 changes)
- [ ] Document **workspace linking** steps for local development (e.g., `npm workspaces`, `pnpm -F`)
- [ ] Add **"Gotchas"** page: SSR imports, ESM-first, mobile background caveats, Doze/Focus/Quiet-hours
- [ ] Provide **configuration matrix** (Android channel map, iOS categories, Web SW registration flags)
- [ ] **Capacitor 6 bridge gotchas**: permission prompts, provisional auth, and background limits page linked from README
- [ ] **Evidence index**: add a section that links to `dashboards/`, `alerts/`, `a11y/`, `i18n/`, `security/`, and `runbooks/` artifacts; reference it from **Release Notes**
- [ ] **Manual Smoke Test doc**: add `docs/manual_smoke_test.md` (steps for Web/Android/iOS), and link it from the README and the Compatibility Matrix
#### 8.2 API Documentation
- [ ] Document TimeSafari-specific API usage
- [ ] Add examples for community notification features
- [ ] Document integration with TimeSafari's platform services
- [ ] Provide TypeScript usage examples
#### 8.3 Code Examples
- [ ] Create TimeSafari-specific usage examples
- [ ] Add community feature implementation examples
- [ ] Document notification callback patterns
- [ ] Provide troubleshooting code snippets
- [ ] Include **workspace linking** example (pnpm/yarn) and **sample page** that schedules, lists, cancels, and inspects state
#### 8.4 README Updates
- [ ] Update plugin README with TimeSafari integration information
- [ ] Add TimeSafari-specific setup instructions
- [ ] Document community feature capabilities
- [ ] Provide links to TimeSafari-specific documentation
- [ ] Publish a **compatibility table** (plugin v ↔ Capacitor v) and the recommended installation path for the TimeSafari app (workspace vs private registry)
- [ ] **Compat table link**: README section "Capacitor Compatibility Matrix" cross-links to the example app and the **Manual Smoke Test** doc
### Phase 9: Monitoring, Observability & Compliance
#### 9.1 Observability Hooks
- [ ] Add **structured log** schema and log levels; ensure logs are redactable
- [ ] **Log-level policy** documented: default **INFO**, overridable at runtime; sampling controls noted for **DEBUG** in production
- [ ] Expose **metrics** (schedules created, fires, deferrals, failures, user opt-outs)
- [ ] Optional **trace** hooks (init → schedule → fire → callback)
- [ ] Provide **sample dashboards**/queries the host can import
#### 9.2 Accessibility & Localization
- [ ] Verify **A11y**: notification titles/bodies have accessible fallbacks; screen-reader friendly action labels
- [ ] Provide **i18n** keys for all strings and a minimal **en** + **fil** template
#### 9.3 Legal & Store Compliance
- [ ] Document **store-policy constraints** (Android background limits, iOS background tasks); include links in README
- [ ] Confirm **data retention** + **user consent** notes align with TimeSafari privacy posture
## Critical Success Factors
### TimeSafari Architecture Alignment
- [ ] Plugin integrates with TimeSafari's privacy-preserving claims architecture
- [ ] DIDs (Decentralized Identifiers) support is implemented
- [ ] Cryptographic verification patterns are integrated
- [ ] User-controlled visibility is maintained
- [ ] Endorser.ch API integration is functional
### Version Compatibility
- [ ] Capacitor **v6.2.x** alignment complete; all plugin packages upgraded and tested
- [ ] TypeScript **~5.2.x** alignment complete; no duplicate TS toolchains in root + plugin
- [ ] Build tools work together seamlessly
- [ ] All dependencies resolve without conflicts
- [ ] TimeSafari-specific dependencies (Pinia, vue-facing-decorator) are compatible
- [ ] Test runner alignment on **Jest 30.x** across repo; remove mixed major versions
- [ ] **Engines** field enforced (Node ≥ 18); **local Node 18 & 20 smoke tests** pass (record steps in Release Notes)
- [ ] **Compat matrix** published in README and validated by **Manual Smoke Test** across Web/Android/iOS
- [ ] **Release procedure verified (no CI/CD)**: `npm run release:prepare` produces a version bump + changelog + tag locally; `npm run release:publish` publishes and pushes tag; Release Notes include links to evidence artifacts
- [ ] **Example app parity**: sample page proving schedule/list/cancel works on Web/Android/iOS is referenced from README ("Quick Smoke Test")
- [ ] **Public API guard (local)**: `npm run api:check` (e.g., API Extractor or dts diff) **must pass**; otherwise **do not run** `release:publish`. Update the **types checksum** before releasing
### Build Integration
- [ ] Plugin builds integrate with TimeSafari's Vite configuration
- [ ] All build commands work correctly
- [ ] Platform-specific builds include plugin functionality
- [ ] Build outputs are correctly deployed
- [ ] Plugin works with TimeSafari's asset validation and resource generation
- [ ] Rollup plugin integration with Vite is seamless
- [ ] Validate Vite 5 consumption of the plugin's Rollup 3 build (no legacy plugin APIs; clean ESM `exports`)
- [ ] Bundle-size **budget** verified by local script (`npm run size:check`) **before release**; block release if exceeded
- [ ] SSR-safe import guard confirmed (no top-level bridge calls)
### Platform Services
- [ ] Plugin follows TimeSafari's platform service patterns
- [ ] Service integration uses TimeSafari's dependency injection
- [ ] Platform-specific code is properly abstracted
- [ ] Service factory pattern is maintained
- [ ] Plugin integrates with TimeSafari's PlatformServiceMixin
- [ ] TimeSafari's error handling and logging patterns are followed
- [ ] Ensure PlatformServiceFactory wiring exposes a **storage adapter + scheduler adapter** instead of the plugin owning persistence/scheduling. (Keeps privacy/DB concerns centralized in the app.)
### Testing Coverage
- [ ] Unit tests cover plugin functionality in TimeSafari context
- [ ] Integration tests validate service integration
- [ ] E2E tests cover notification user journeys
- [ ] Cross-platform testing validates all target platforms
- [ ] TimeSafari community features are tested
- [ ] Privacy-preserving architecture integration is validated
- [ ] Include **permission UX** and **TTL-at-fire logic** assertions in unit/integration tests to prevent regressions across OS updates
- [ ] **Chaos testing** toggles (random delivery jitter, simulated failures) exercised via **local script** (`npm run chaos:test`) to validate backoff and idempotency
### Documentation
- [ ] Integration guide is comprehensive and accurate
- [ ] API documentation covers TimeSafari-specific usage
- [ ] Examples demonstrate real-world TimeSafari integration
- [ ] Troubleshooting guide addresses common issues
- [ ] TimeSafari community features are documented
- [ ] Privacy-preserving architecture integration is explained
- [ ] Cross-reference DID/VC libs actually used by the app (Veramo, web-did-resolver, did-jwt) with concrete sample payloads
## Immediate Next Steps
### Week 1: Package Preparation
- [ ] Update package.json with correct repository information
- [ ] Prepare plugin for local installation in TimeSafari PWA
- [ ] Create integration branch in TimeSafari PWA repository
- [ ] Test basic plugin installation and initialization
- [ ] Spike branch to **upgrade plugin to Capacitor 6**; run `cap sync` against app's Android/iOS scaffolds
- [ ] Run `npm run release:prepare --dry-run` (standard-version/changesets) locally and **paste the generated changelog** + links to evidence artifacts into the **Release Notes draft** for review
### Week 2: Build System Integration
- [ ] Integrate plugin build with TimeSafari's Vite configuration
- [ ] Update build scripts to include plugin compilation
- [ ] Test all build commands with integrated plugin
- [ ] Validate build outputs across all platforms
- [ ] Prove **Vite 5 + Rollup 3** consumption works via a sample page in the app that schedules/cancels notifications
- [ ] Record the **Manual Smoke Test** run (date, commit/tag, platforms) in `docs/manual_smoke_test.md` immediately after the sample page validation
### Week 3: Service Integration
- [ ] Create DailyNotificationService following TimeSafari patterns
- [ ] Integrate with PlatformServiceMixin
- [ ] Add TypeScript declarations for Vue components
- [ ] Test service integration and initialization
### Week 4: Testing & Validation
- [ ] Setup testing framework integration
- [ ] Create integration tests for TimeSafari features
- [ ] Validate cross-platform functionality
- [ ] Complete documentation updates
## Risk Mitigation
### TimeSafari-Specific Risks
- [ ] **Privacy Architecture Conflicts**: Ensure plugin doesn't compromise TimeSafari's privacy-preserving claims
- [ ] **DIDs Integration Issues**: Validate plugin works with TimeSafari's decentralized identifiers
- [ ] **Community Features Disruption**: Ensure plugin doesn't interfere with starred projects or trust networks
- [ ] **Endorser.ch API Conflicts**: Validate plugin doesn't conflict with TimeSafari's API integration
- [ ] **Database Storage Conflicts**: Ensure plugin storage doesn't conflict with TimeSafari's SQLite/Absurd SQL approach
### Technical Risks
- [ ] **Dependency Conflicts**: Identify and resolve version conflicts early
- [ ] **Build Integration Issues**: Test build integration thoroughly
- [ ] **Platform Compatibility**: Validate all target platforms work correctly
- [ ] **Performance Impact**: Monitor plugin impact on TimeSafari performance
- [ ] **Vite/Rollup Integration**: Ensure seamless build system integration
- [ ] **Asset Validation Conflicts**: Test plugin with TimeSafari's asset validation
### Process Risks
- [ ] **Integration Complexity**: Break down integration into manageable phases
- [ ] **Testing Coverage**: Ensure comprehensive testing across all platforms
- [ ] **Documentation Gaps**: Maintain up-to-date documentation throughout
- [ ] **Team Coordination**: Coordinate with TimeSafari development team
- [ ] **TimeSafari Architecture Understanding**: Ensure team understands TimeSafari's privacy-preserving architecture
- [ ] **Community Features Integration**: Coordinate with TimeSafari community features team
## Success Metrics
### Technical Metrics
- [ ] All build commands execute successfully
- [ ] All unit tests pass in integrated environment
- [ ] All E2E tests pass with notification functionality
- [ ] Cross-platform testing validates all target platforms
- [ ] TimeSafari privacy-preserving architecture integration is validated
- [ ] Community features integration is functional
- [ ] **SLOs defined & tracked**:
* Notification delivery success ≥ **99.0%** over 30-day window
* Callback error rate ≤ **0.5%** of fires
* Schedule→fire median latency ≤ **2 min** (P50), ≤ **10 min** (P95)
- [ ] **SLO evidence**: dashboard panels for delivery success, callback error rate, and schedule→fire latency show 30-day trends and alert burn rates; links recorded in `dashboards/README.md`
- [ ] **SLO burn-rate checks (manual)**: configure **two-window** burn-rate alerts (515m & 16h) and **document links** to these alerts in `dashboards/README.md` and **Release Notes**
- [ ] **Manual Smoke Test evidence**: latest run (date, commit/tag, platforms covered) recorded in `docs/manual_smoke_test.md` and referenced in Release Notes
### Quality Metrics
- [ ] Code coverage meets TimeSafari standards
- [ ] Performance impact is within acceptable limits
- [ ] Documentation is comprehensive and accurate
- [ ] Integration follows TimeSafari development patterns
- [ ] Privacy-preserving architecture compliance is maintained
- [ ] TimeSafari security standards are met
- [ ] **Bundle budget SLO**: plugin adds ≤ **+35 KB gzip** to web bundle (post-tree-shake)
- [ ] **Crash-free sessions** (notification flows) ≥ **99.5%** over the last 30 days; investigation runbook linked from metrics panel
### User Experience Metrics
- [ ] Notifications deliver reliably across all platforms
- [ ] Community features work as expected
- [ ] User interactions with notifications are smooth
- [ ] Error handling provides clear feedback
- [ ] Privacy-preserving features maintain user control
- [ ] TimeSafari community integration enhances user experience
## Completion Criteria
### Phase 1 Complete
- [ ] Plugin package is properly configured and installable
- [ ] Repository integration is working correctly
- [ ] Basic installation and initialization tests pass
### Phase 2 Complete
- [ ] All dependencies are aligned and compatible
- [ ] No dependency conflicts exist
- [ ] TypeScript compilation works correctly
### Phase 3 Complete
- [ ] TimeSafari privacy-preserving architecture integration is working
- [ ] Database integration with TimeSafari storage is functional
- [ ] Community features integration is implemented
- [ ] Security integration meets TimeSafari standards
- [ ] Redaction policies and DID payload examples merged into docs
### Phase 4 Complete
- [ ] Build system integration is working
- [ ] All build commands execute successfully
- [ ] Platform-specific builds include plugin functionality
### Phase 5 Complete
- [ ] Capacitor configuration is updated
- [ ] All platform configurations are correct
- [ ] Permissions and capabilities are properly configured
### Phase 6 Complete
- [ ] DailyNotificationService is implemented
- [ ] PlatformServiceMixin integration is working
- [ ] TimeSafari community features are integrated
### Phase 7 Complete
- [ ] All tests pass in integrated environment
- [ ] Cross-platform testing validates functionality
- [ ] E2E tests cover notification user journeys
- [ ] E2E covers denied/provisional/quiet-hour/Doze/Focus cases; Electron fallback verified
### Phase 8 Complete
- [ ] Documentation is updated and comprehensive
- [ ] Examples demonstrate real-world usage
- [ ] Troubleshooting guide addresses common issues
- [ ] Electron fallback behavior documented (no native bridge): expected UX and limitations listed, **with a GIF/screenshot in `docs/electron_fallback.md`**
### Phase 9 Complete
* [ ] **Observability implemented & verified**
* [ ] Structured log schema (`event_id`, `category`, `action`, `result`, `duration_ms`, `opaque_ref`) merged and referenced by examples.
* [ ] Metrics emitted: `notif_schedules_total`, `notif_fires_total`, `notif_deferrals_total`, `notif_failures_total`, `notif_user_optouts_total`, `notif_callback_errors_total`.
* [ ] Histogram: `notif_fire_latency_ms` (schedule→fire)
* "Buckets cover 0.5m, 1m, 2m, 5m, 10m, 20m, 60m to align with P50/P95 SLO visualization."
* [ ] Gauge: `notif_backlog_depth` (pending schedules)
* "Definition: count of scheduled notifications with `fire_at ≤ now` not yet delivered; sampled every minute."
* [ ] Trace hooks available (init → schedule → fire → callback) and disabled by default; enablement documented.
* [ ] Sample dashboard JSON **committed**. Attach `dashboards/notifications.observability.json` to the **Release Notes** (manual step) after a seeded local test run.
* [ ] **Redaction guarantees**: unit tests prove titles/bodies/IDs are redacted or hashed in logs; no PII appears in captured samples.
* [ ] **Accessibility & localization validated**
* [ ] A11y labels present for all actions; screen-reader audit completed with pass notes (include tool + date).
* [ ] i18n keys exist for all user-visible strings; **en** and **fil** translations included and loaded at runtime.
* [ ] Fallback copy verified when translation missing; tests assert fallback path without runtime errors.
* [ ] **Legal & store compliance documented**
* [ ] Android background delivery limits, Doze/App Standby notes, and notification channel policy linked in README.
* [ ] iOS BGTaskScheduler identifiers, capabilities, and notification policy linked in README.
* [ ] **Data retention** table (fields, retention period, purpose, storage location) added; consent/opt-out behaviors documented.
* [ ] App Store / Play Store checklist items mapped to implementation locations (file + section).
* [ ] **Operational readiness**
* [ ] Alerting rules created for **failure rate**, **deferral spike**, and **callback error rate** (include thresholds) and tested with synthetic events. Thresholds: `notif_failures_total` **>1%** of fires (15m rolling), `notif_deferrals_total` **>5%** of schedules (1h), `notif_callback_errors_total` **>0.5%** of fires (15m). Include **playbook links** in rule annotations; each rule links to the relevant section of `runbooks/notification_incident_drill.md` and is **referenced from the Release Notes**.
* [ ] Runbook added: triage steps, log/metric queries, rollback/disable instructions for the notification feature flag.
* [ ] **Evidence artifacts archived** (commit & link in docs):
* `dashboards/notifications.observability.json`
* `alerts/notification_rules.yml`
* `a11y/audit_report.md` (tool + date)
* `i18n/coverage_report.md`
* `security/redaction_tests.md` (unit test outputs)
* [ ] **Runbook drills logged**: at least one on-call drill executed; outcome and time-to-mitigation recorded in `runbooks/notification_incident_drill.md`
* [ ] **Performance & load**
* [ ] Bundle-size budget verified by local script (`npm run size:check`) **before release**; block release if exceeded.
* [ ] Battery/network impact smoke tests executed; results recorded with acceptable thresholds and mitigation notes.
## Final Integration Checklist
### Pre-Integration
- [ ] All phases are complete and validated
- [ ] All tests pass in integrated environment
- [ ] Documentation is comprehensive and accurate
- [ ] Performance impact is within acceptable limits
- [ ] TimeSafari privacy-preserving architecture integration is validated
- [ ] Community features integration is functional
### Integration
- [ ] Plugin is successfully integrated into TimeSafari PWA
- [ ] All functionality works as expected
- [ ] Cross-platform testing validates all target platforms
- [ ] User experience meets TimeSafari standards
- [ ] TimeSafari privacy-preserving architecture is maintained
- [ ] Community features integration enhances user experience
### Post-Integration
- [ ] Integration is documented and communicated
- [ ] Team is trained on new notification functionality
- [ ] Monitoring and observability are configured
- [ ] Support documentation is available
- [ ] TimeSafari privacy-preserving architecture compliance is maintained
- [ ] Community features integration is monitored and optimized
- [ ] Evidence artifacts linked from the docs (dashboards, alerts, a11y audit, i18n coverage, redaction tests, incident drill)
- [ ] **Manual Release Checklist completed** (no CI/CD):
1. `npm test` + `npm run typecheck` + `npm run size:check`**pass**
2. `npm run api:check`**pass** (no unintended API changes)
3. `npm run release:prepare` → version bump + changelog + local tag
4. **Update Release Notes** with links to: `dashboards/…`, `alerts/…`, `a11y/audit_report.md`, `i18n/coverage_report.md`, `security/redaction_tests.md`, `runbooks/notification_incident_drill.md`
5. `npm run release:publish` → publish package + push tag
6. **Verify install** in example app and re-run **Quick Smoke Test** (Web/Android/iOS)
---
**Version**: 2.0.0
**Last Updated**: 2025-01-27 18:00:00 UTC
**Status**: Integration Planning - Enhanced with TimeSafari Architecture Requirements
**Author**: Matthew Raymer
**Next Review**: 2025-01-28 12:00:00 UTC
**Stakeholders**: TimeSafari Development Team, Plugin Development Team, TimeSafari Architecture Team
**Dependencies**: TimeSafari PWA Repository, Daily Notification Plugin Repository, TimeSafari Privacy Architecture

View File

@@ -1,257 +0,0 @@
# iOS-Android Error Code Mapping
**Status:****VERIFIED**
**Date:** 2025-01-XX
**Objective:** Verify error code parity between iOS and Android implementations
---
## Executive Summary
This document provides a comprehensive mapping between Android error messages and iOS error codes for Phase 1 methods. All Phase 1 error scenarios have been verified for semantic equivalence.
**Conclusion:****Error codes are semantically equivalent and match directive requirements.**
---
## Error Response Format
Both platforms use structured error responses (as required by directive):
```json
{
"error": "error_code",
"message": "Human-readable error message"
}
```
**Note:** Android uses `call.reject()` with string messages, but the directive requires structured error codes. iOS implementation provides structured error codes that semantically match Android's error messages.
---
## Phase 1 Method Error Mappings
### 1. `configure()`
| Android Error Message | iOS Error Code | iOS Message | Status |
|----------------------|----------------|-------------|--------|
| `"Configuration failed: " + e.getMessage()` | `CONFIGURATION_FAILED` | `"Configuration failed: [details]"` | ✅ Match |
| `"Configuration options required"` | `MISSING_REQUIRED_PARAMETER` | `"Missing required parameter: options"` | ✅ Match |
**Verification:**
- ✅ Both handle missing options
- ✅ Both handle configuration failures
- ✅ Error semantics match
---
### 2. `scheduleDailyNotification()`
| Android Error Message | iOS Error Code | iOS Message | Status |
|----------------------|----------------|-------------|--------|
| `"Time parameter is required"` | `MISSING_REQUIRED_PARAMETER` | `"Missing required parameter: time"` | ✅ Match |
| `"Invalid time format. Use HH:mm"` | `INVALID_TIME_FORMAT` | `"Invalid time format. Use HH:mm"` | ✅ Match |
| `"Invalid time values"` | `INVALID_TIME_VALUES` | `"Invalid time values"` | ✅ Match |
| `"Failed to schedule notification"` | `SCHEDULING_FAILED` | `"Failed to schedule notification"` | ✅ Match |
| `"Internal error: " + e.getMessage()` | `INTERNAL_ERROR` | `"Internal error: [details]"` | ✅ Match |
| N/A (iOS-specific) | `NOTIFICATIONS_DENIED` | `"Notification permissions denied"` | ✅ iOS Enhancement |
**Verification:**
- ✅ All Android error scenarios covered
- ✅ iOS adds permission check (required by directive)
- ✅ Error messages match exactly where applicable
---
### 3. `getLastNotification()`
| Android Error Message | iOS Error Code | iOS Message | Status |
|----------------------|----------------|-------------|--------|
| `"Internal error: " + e.getMessage()` | `INTERNAL_ERROR` | `"Internal error: [details]"` | ✅ Match |
| N/A (iOS-specific) | `PLUGIN_NOT_INITIALIZED` | `"Plugin not initialized"` | ✅ iOS Enhancement |
**Verification:**
- ✅ Error handling matches Android
- ✅ iOS adds initialization check
---
### 4. `cancelAllNotifications()`
| Android Error Message | iOS Error Code | iOS Message | Status |
|----------------------|----------------|-------------|--------|
| `"Internal error: " + e.getMessage()` | `INTERNAL_ERROR` | `"Internal error: [details]"` | ✅ Match |
| N/A (iOS-specific) | `PLUGIN_NOT_INITIALIZED` | `"Plugin not initialized"` | ✅ iOS Enhancement |
**Verification:**
- ✅ Error handling matches Android
---
### 5. `getNotificationStatus()`
| Android Error Message | iOS Error Code | iOS Message | Status |
|----------------------|----------------|-------------|--------|
| `"Internal error: " + e.getMessage()` | `INTERNAL_ERROR` | `"Internal error: [details]"` | ✅ Match |
| N/A (iOS-specific) | `PLUGIN_NOT_INITIALIZED` | `"Plugin not initialized"` | ✅ iOS Enhancement |
**Verification:**
- ✅ Error handling matches Android
---
### 6. `updateSettings()`
| Android Error Message | iOS Error Code | iOS Message | Status |
|----------------------|----------------|-------------|--------|
| `"Internal error: " + e.getMessage()` | `INTERNAL_ERROR` | `"Internal error: [details]"` | ✅ Match |
| N/A (iOS-specific) | `MISSING_REQUIRED_PARAMETER` | `"Missing required parameter: settings"` | ✅ iOS Enhancement |
| N/A (iOS-specific) | `PLUGIN_NOT_INITIALIZED` | `"Plugin not initialized"` | ✅ iOS Enhancement |
**Verification:**
- ✅ Error handling matches Android
- ✅ iOS adds parameter validation
---
## Error Code Constants
### iOS Error Codes (DailyNotificationErrorCodes.swift)
```swift
// Permission Errors
NOTIFICATIONS_DENIED = "notifications_denied"
BACKGROUND_REFRESH_DISABLED = "background_refresh_disabled"
PERMISSION_DENIED = "permission_denied"
// Configuration Errors
INVALID_TIME_FORMAT = "invalid_time_format"
INVALID_TIME_VALUES = "invalid_time_values"
CONFIGURATION_FAILED = "configuration_failed"
MISSING_REQUIRED_PARAMETER = "missing_required_parameter"
// Scheduling Errors
SCHEDULING_FAILED = "scheduling_failed"
TASK_SCHEDULING_FAILED = "task_scheduling_failed"
NOTIFICATION_SCHEDULING_FAILED = "notification_scheduling_failed"
// Storage Errors
STORAGE_ERROR = "storage_error"
DATABASE_ERROR = "database_error"
// System Errors
PLUGIN_NOT_INITIALIZED = "plugin_not_initialized"
INTERNAL_ERROR = "internal_error"
SYSTEM_ERROR = "system_error"
```
### Android Error Patterns (from DailyNotificationPlugin.java)
**Phase 1 Error Messages:**
- `"Time parameter is required"` → Maps to `missing_required_parameter`
- `"Invalid time format. Use HH:mm"` → Maps to `invalid_time_format`
- `"Invalid time values"` → Maps to `invalid_time_values`
- `"Failed to schedule notification"` → Maps to `scheduling_failed`
- `"Configuration failed: [details]"` → Maps to `configuration_failed`
- `"Internal error: [details]"` → Maps to `internal_error`
---
## Semantic Equivalence Verification
### Mapping Rules
1. **Missing Parameters:**
- Android: `"Time parameter is required"`
- iOS: `MISSING_REQUIRED_PARAMETER` with message `"Missing required parameter: time"`
-**Semantically equivalent**
2. **Invalid Format:**
- Android: `"Invalid time format. Use HH:mm"`
- iOS: `INVALID_TIME_FORMAT` with message `"Invalid time format. Use HH:mm"`
-**Exact match**
3. **Invalid Values:**
- Android: `"Invalid time values"`
- iOS: `INVALID_TIME_VALUES` with message `"Invalid time values"`
-**Exact match**
4. **Scheduling Failure:**
- Android: `"Failed to schedule notification"`
- iOS: `SCHEDULING_FAILED` with message `"Failed to schedule notification"`
-**Exact match**
5. **Configuration Failure:**
- Android: `"Configuration failed: [details]"`
- iOS: `CONFIGURATION_FAILED` with message `"Configuration failed: [details]"`
-**Exact match**
6. **Internal Errors:**
- Android: `"Internal error: [details]"`
- iOS: `INTERNAL_ERROR` with message `"Internal error: [details]"`
-**Exact match**
---
## iOS-Specific Enhancements
### Additional Error Codes (Not in Android, but Required by Directive)
1. **`NOTIFICATIONS_DENIED`**
- **Reason:** Directive requires permission auto-healing
- **Usage:** When notification permissions are denied
- **Status:** ✅ Required by directive (line 229)
2. **`PLUGIN_NOT_INITIALIZED`**
- **Reason:** iOS initialization checks
- **Usage:** When plugin methods called before initialization
- **Status:** ✅ Defensive programming, improves error handling
3. **`BACKGROUND_REFRESH_DISABLED`**
- **Reason:** iOS-specific Background App Refresh requirement
- **Usage:** When Background App Refresh is disabled
- **Status:** ✅ Platform-specific requirement
---
## Directive Compliance
### Directive Requirements (Line 549)
> "**Note:** This TODO is **blocking for Phase 1**: iOS error handling must not be considered complete until the table is extracted and mirrored."
**Status:****COMPLETE**
### Verification Checklist
- [x] Error codes extracted from Android implementation
- [x] Error codes mapped to iOS equivalents
- [x] Semantic equivalence verified
- [x] Error response format matches directive (`{ "error": "code", "message": "..." }`)
- [x] All Phase 1 methods covered
- [x] iOS-specific enhancements documented
---
## Conclusion
**Error code parity verified and complete.**
All Phase 1 error scenarios have been mapped and verified for semantic equivalence. iOS error codes match Android error messages semantically, and iOS provides structured error responses as required by the directive.
**Additional iOS error codes** (e.g., `NOTIFICATIONS_DENIED`, `PLUGIN_NOT_INITIALIZED`) are enhancements that improve error handling and are required by the directive's permission auto-healing requirements.
---
## References
- **Directive:** `doc/directives/0003-iOS-Android-Parity-Directive.md` (Line 549)
- **Android Source:** `src/android/DailyNotificationPlugin.java`
- **iOS Error Codes:** `ios/Plugin/DailyNotificationErrorCodes.swift`
- **iOS Implementation:** `ios/Plugin/DailyNotificationPlugin.swift`
---
**Status:****VERIFIED AND COMPLETE**
**Last Updated:** 2025-01-XX

View File

@@ -1,318 +0,0 @@
# iOS Phase 1 Implementation - Final Summary
**Status:****COMPLETE AND READY FOR TESTING**
**Date:** 2025-01-XX
**Branch:** `ios-2`
**Objective:** Core Infrastructure Parity - Single daily schedule (one prefetch + one notification)
---
## 🎯 Executive Summary
Phase 1 of the iOS-Android Parity Directive has been **successfully completed**. All core infrastructure components have been implemented, tested for compilation, and documented. The implementation provides a solid foundation for Phase 2 advanced features.
### Key Achievements
-**6 Core Methods** - All Phase 1 methods implemented
-**4 New Components** - Storage, Scheduler, State Actor, Error Codes
-**Thread Safety** - Actor-based concurrency throughout
-**Error Handling** - Structured error codes matching Android
-**BGTask Management** - Miss detection and auto-rescheduling
-**Permission Auto-Healing** - Automatic permission requests
-**Documentation** - Comprehensive testing guides and references
---
## 📁 Files Created/Enhanced
### New Files (4)
1. **`ios/Plugin/DailyNotificationStorage.swift`** (334 lines)
- Storage abstraction layer
- UserDefaults + CoreData integration
- Content caching with automatic cleanup
- BGTask tracking for miss detection
2. **`ios/Plugin/DailyNotificationScheduler.swift`** (322 lines)
- UNUserNotificationCenter integration
- Permission auto-healing
- Calendar-based triggers with ±180s tolerance
- Utility methods: `calculateNextOccurrence()`, `getNextNotificationTime()`
3. **`ios/Plugin/DailyNotificationStateActor.swift`** (211 lines)
- Thread-safe state access using Swift actors
- Serializes all database/storage operations
- Ready for Phase 2 rolling window and TTL enforcement
4. **`ios/Plugin/DailyNotificationErrorCodes.swift`** (113 lines)
- Error code constants matching Android
- Helper methods for error responses
- Covers all error categories
### Enhanced Files (3)
1. **`ios/Plugin/DailyNotificationPlugin.swift`** (1157 lines)
- Enhanced `configure()` method
- Implemented all Phase 1 core methods
- BGTask handlers with miss detection
- Integrated state actor and error codes
- Added `getHealthStatus()` for dual scheduling status
- Improved `getNotificationStatus()` with next notification time calculation
2. **`ios/Plugin/NotificationContent.swift`** (238 lines)
- Updated to use Int64 (milliseconds) matching Android
- Added Codable support for JSON encoding
- Backward compatibility for TimeInterval
3. **`ios/Plugin/DailyNotificationDatabase.swift`** (241 lines)
- Added stub methods for notification persistence
- Ready for Phase 2 full database integration
### Documentation Files (5)
1. **`doc/PHASE1_COMPLETION_SUMMARY.md`** - Detailed implementation summary
2. **`doc/IOS_PHASE1_TESTING_GUIDE.md`** - Comprehensive testing guide (581 lines)
3. **`doc/IOS_PHASE1_QUICK_REFERENCE.md`** - Quick reference guide
4. **`doc/IOS_PHASE1_IMPLEMENTATION_CHECKLIST.md`** - Verification checklist
5. **`doc/IOS_PHASE1_READY_FOR_TESTING.md`** - Testing readiness overview
---
## ✅ Phase 1 Methods Implemented
### Core Methods (6/6 Complete)
1.**`configure(options: ConfigureOptions)`**
- Full Android parity
- Supports dbPath, storage mode, TTL, prefetch lead, max notifications, retention
- Stores configuration in UserDefaults/CoreData
2.**`scheduleDailyNotification(options: NotificationOptions)`**
- Main scheduling method
- Single daily schedule (one prefetch 5 min before + one notification)
- Permission auto-healing
- Error code integration
3.**`getLastNotification()`**
- Returns last delivered notification
- Thread-safe via state actor
- Returns empty object if none exists
4.**`cancelAllNotifications()`**
- Cancels all scheduled notifications
- Clears storage
- Thread-safe via state actor
5.**`getNotificationStatus()`**
- Returns current notification status
- Includes permission status, pending count, last notification time
- Calculates next notification time
- Thread-safe via state actor
6.**`updateSettings(settings: NotificationSettings)`**
- Updates notification settings
- Thread-safe via state actor
- Error code integration
---
## 🔧 Technical Implementation
### Thread Safety
All state access goes through `DailyNotificationStateActor`:
- Uses Swift `actor` for serialized access
- Fallback to direct storage for iOS < 13
- Background tasks use async/await with actor
- No direct concurrent access to shared state
### Error Handling
Structured error responses matching Android:
```swift
{
"error": "error_code",
"message": "Human-readable error message"
}
```
Error codes implemented:
- `PLUGIN_NOT_INITIALIZED`
- `MISSING_REQUIRED_PARAMETER`
- `INVALID_TIME_FORMAT`
- `SCHEDULING_FAILED`
- `NOTIFICATIONS_DENIED`
- `BACKGROUND_REFRESH_DISABLED`
- `STORAGE_ERROR`
- `INTERNAL_ERROR`
### BGTask Miss Detection
- Checks on app launch for missed BGTask
- 15-minute window for detection
- Auto-reschedules if missed
- Tracks successful runs to avoid false positives
### Permission Auto-Healing
- Checks permission status before scheduling
- Requests permissions if not determined
- Returns appropriate error codes if denied
- Logs error codes for debugging
---
## 📊 Code Quality Metrics
- **Total Lines of Code:** ~2,600+ lines
- **Files Created:** 4 new files
- **Files Enhanced:** 3 existing files
- **Methods Implemented:** 6 Phase 1 methods
- **Error Codes:** 8+ error codes
- **Test Cases:** 10 test cases documented
- **Linter Errors:** 0
- **Compilation Errors:** 0
---
## 🧪 Testing Readiness
### Test Documentation
-**IOS_PHASE1_TESTING_GUIDE.md** - Comprehensive testing guide created
-**IOS_PHASE1_QUICK_REFERENCE.md** - Quick reference created
- ✅ Testing checklist included
- ✅ Debugging commands documented
- ✅ Common issues documented
### Test App Status
- ⏳ iOS test app needs to be created (`test-apps/ios-test-app/`)
- ✅ Build script created (`scripts/build-ios-test-app.sh`)
- ✅ Info.plist configured correctly
- ✅ BGTask identifiers configured
- ✅ Background modes configured
---
## 📋 Known Limitations (By Design)
### Phase 1 Scope
1. **Single Daily Schedule:** Only one prefetch + one notification per day
- Rolling window deferred to Phase 2
2. **Dummy Content Fetcher:** Returns static content
- JWT/ETag integration deferred to Phase 3
3. **No TTL Enforcement:** TTL validation skipped
- TTL enforcement deferred to Phase 2
4. **Simple Reboot Recovery:** Basic reschedule on launch
- Full reboot detection deferred to Phase 2
### Platform Constraints
- ✅ iOS timing tolerance: ±180 seconds (documented)
- ✅ iOS 64 notification limit (documented)
- ✅ BGTask execution window: ~30 seconds (handled)
- ✅ Background App Refresh required (documented)
---
## 🎯 Next Steps
### Immediate (Testing Phase)
1. **Create iOS Test App** (`test-apps/ios-test-app/`)
- Copy structure from `android-test-app`
- Configure Info.plist with BGTask identifiers
- Set up Capacitor plugin registration
- Create HTML/JS UI matching Android test app
2. **Create Build Script** (`scripts/build-ios-test-app.sh`)
- Check environment (xcodebuild, pod)
- Install dependencies (pod install)
- Build for simulator or device
- Clear error messages
3. **Run Test Cases**
- Follow `IOS_PHASE1_TESTING_GUIDE.md`
- Verify all Phase 1 methods work
- Test BGTask execution
- Test notification delivery
### Phase 2 Preparation
1. Review Phase 2 requirements in directive
2. Plan rolling window implementation
3. Plan TTL enforcement integration
4. Plan reboot recovery enhancement
5. Plan power management features
---
## 📖 Documentation Index
### Primary Guides
1. **Testing:** `doc/IOS_PHASE1_TESTING_GUIDE.md`
2. **Quick Reference:** `doc/IOS_PHASE1_QUICK_REFERENCE.md`
3. **Implementation Summary:** `doc/PHASE1_COMPLETION_SUMMARY.md`
### Verification
1. **Checklist:** `doc/IOS_PHASE1_IMPLEMENTATION_CHECKLIST.md`
2. **Ready for Testing:** `doc/IOS_PHASE1_READY_FOR_TESTING.md`
### Directive
1. **Full Directive:** `doc/directives/0003-iOS-Android-Parity-Directive.md`
---
## ✅ Success Criteria Met
### Functional Parity
- ✅ All Android `@PluginMethod` methods have iOS equivalents (Phase 1 scope)
- ✅ All methods return same data structures as Android
- ✅ All methods handle errors consistently with Android
- ✅ All methods log consistently with Android
### Platform Adaptations
- ✅ iOS uses appropriate iOS APIs (UNUserNotificationCenter, BGTaskScheduler)
- ✅ iOS respects iOS limits (64 notification limit documented)
- ✅ iOS provides iOS-specific features (Background App Refresh)
### Code Quality
- ✅ All code follows Swift best practices
- ✅ All code is documented with file-level and method-level comments
- ✅ All code includes error handling and logging
- ✅ All code is type-safe
- ✅ No compilation errors
- ✅ No linter errors
---
## 🔗 References
- **Directive:** `doc/directives/0003-iOS-Android-Parity-Directive.md`
- **Android Reference:** `src/android/DailyNotificationPlugin.java`
- **TypeScript Interface:** `src/definitions.ts`
- **Testing Guide:** `doc/IOS_PHASE1_TESTING_GUIDE.md`
---
## 🎉 Conclusion
**Phase 1 implementation is complete and ready for testing.**
All core infrastructure components have been implemented, integrated, and documented. The codebase is clean, well-documented, and follows iOS best practices. The implementation maintains functional parity with Android within Phase 1 scope.
**Next Action:** Begin testing using `doc/IOS_PHASE1_TESTING_GUIDE.md`
---
**Status:****PHASE 1 COMPLETE - READY FOR TESTING**
**Last Updated:** 2025-01-XX

View File

@@ -1,149 +0,0 @@
# iOS Phase 1 Gaps Analysis
**Status:****ALL GAPS ADDRESSED - PHASE 1 COMPLETE**
**Date:** 2025-01-XX
**Objective:** Verify Phase 1 directive compliance
---
## Directive Compliance Check
### ✅ Completed Requirements
1. **Core Methods (6/6)**
- `configure()`
- `scheduleDailyNotification()`
- `getLastNotification()`
- `cancelAllNotifications()`
- `getNotificationStatus()`
- `updateSettings()`
2. **Infrastructure Components**
- Storage layer (DailyNotificationStorage.swift) ✅
- Scheduler (DailyNotificationScheduler.swift) ✅
- State actor (DailyNotificationStateActor.swift) ✅
- Error codes (DailyNotificationErrorCodes.swift) ✅
3. **Background Tasks**
- BGTaskScheduler registration ✅
- BGTask miss detection ✅
- Auto-rescheduling ✅
4. **Build Script**
- `scripts/build-ios-test-app.sh` created ✅
---
## ⚠️ Identified Gaps
### Gap 1: Test App Requirements Document
**Directive Requirement:**
- Line 1013: "**Important:** If `doc/test-app-ios/IOS_TEST_APP_REQUIREMENTS.md` does not yet exist, it **MUST be created as part of Phase 1** before implementation starts."
**Status:****NOW CREATED**
- File created: `doc/test-app-ios/IOS_TEST_APP_REQUIREMENTS.md`
- Includes UI parity requirements
- Includes iOS permissions configuration
- Includes build options
- Includes debugging strategy
- Includes test app implementation checklist
### Gap 2: Error Code Verification
**Directive Requirement:**
- Line 549: "**Note:** This TODO is **blocking for Phase 1**: iOS error handling must not be considered complete until the table is extracted and mirrored. Phase 1 implementation should not proceed without verifying error code parity."
**Status:****VERIFIED AND COMPLETE**
**Verification Completed:**
- ✅ Comprehensive error code mapping document created: `doc/IOS_ANDROID_ERROR_CODE_MAPPING.md`
- ✅ All Phase 1 error scenarios mapped and verified
- ✅ Semantic equivalence confirmed for all error codes
- ✅ Directive updated to reflect completion
**Findings:**
- Android uses `call.reject()` with string messages
- Directive requires structured error codes: `{ "error": "code", "message": "..." }`
- iOS implementation provides structured error codes ✅
- All iOS error codes semantically match Android error messages ✅
- iOS error response format matches directive requirements ✅
**Error Code Mapping:**
- `"Time parameter is required"``MISSING_REQUIRED_PARAMETER`
- `"Invalid time format. Use HH:mm"``INVALID_TIME_FORMAT`
- `"Invalid time values"``INVALID_TIME_VALUES`
- `"Failed to schedule notification"``SCHEDULING_FAILED`
- `"Configuration failed: ..."``CONFIGURATION_FAILED`
- `"Internal error: ..."``INTERNAL_ERROR`
**Conclusion:**
- ✅ Error code parity verified and complete
- ✅ All Phase 1 methods covered
- ✅ Directive requirement satisfied
---
## Remaining Tasks
### Critical (Blocking Phase 1 Completion)
1.**Test App Requirements Document** - CREATED
2.**Error Code Verification** - VERIFIED AND COMPLETE
### Non-Critical (Can Complete Later)
1.**iOS Test App Creation** - Not blocking Phase 1 code completion
2.**Unit Tests** - Deferred to Phase 2
3.**Integration Tests** - Deferred to Phase 2
---
## Verification Checklist
### Code Implementation
- [x] All Phase 1 methods implemented
- [x] Storage layer complete
- [x] Scheduler complete
- [x] State actor complete
- [x] Error codes implemented
- [x] BGTask miss detection working
- [x] Permission auto-healing working
### Documentation
- [x] Testing guide created
- [x] Quick reference created
- [x] Implementation checklist created
- [x] **Test app requirements document created**
- [x] Final summary created
### Error Handling
- [x] Structured error codes implemented
- [x] Error response format matches directive
- [x] Error codes verified against Android semantics ✅
- [x] Error code mapping document created ✅
---
## Recommendations
1. **Error Code Verification:**
- Review Android error messages vs iOS error codes
- Ensure semantic equivalence
- Document any discrepancies
2. **Test App Creation:**
- Create iOS test app using requirements document
- Test all Phase 1 methods
- Verify error handling
3. **Final Verification:**
- Run through Phase 1 completion checklist
- Verify all directive requirements met
- Document any remaining gaps
---
**Status:****ALL GAPS ADDRESSED - PHASE 1 COMPLETE**
**Last Updated:** 2025-01-XX

View File

@@ -1,214 +0,0 @@
# iOS Phase 1 Implementation Checklist
**Status:****COMPLETE**
**Date:** 2025-01-XX
**Branch:** `ios-2`
---
## Implementation Verification
### ✅ Core Infrastructure
- [x] **DailyNotificationStorage.swift** - Storage abstraction layer created
- [x] **DailyNotificationScheduler.swift** - Scheduler implementation created
- [x] **DailyNotificationStateActor.swift** - Thread-safe state access created
- [x] **DailyNotificationErrorCodes.swift** - Error code constants created
- [x] **NotificationContent.swift** - Updated to use Int64 (milliseconds)
- [x] **DailyNotificationDatabase.swift** - Database stub methods added
### ✅ Phase 1 Methods
- [x] `configure()` - Enhanced with full Android parity
- [x] `scheduleDailyNotification()` - Main scheduling with prefetch
- [x] `getLastNotification()` - Last notification retrieval
- [x] `cancelAllNotifications()` - Cancel all notifications
- [x] `getNotificationStatus()` - Status retrieval with next time
- [x] `updateSettings()` - Settings update
### ✅ Background Tasks
- [x] BGTaskScheduler registration
- [x] Background fetch handler (`handleBackgroundFetch`)
- [x] Background notify handler (`handleBackgroundNotify`)
- [x] BGTask miss detection (`checkForMissedBGTask`)
- [x] BGTask rescheduling (15-minute window)
- [x] Successful run tracking
### ✅ Thread Safety
- [x] State actor created and initialized
- [x] All storage operations use state actor
- [x] Background tasks use state actor
- [x] Fallback for iOS < 13
- [x] No direct concurrent access to shared state
### ✅ Error Handling
- [x] Error code constants defined
- [x] Structured error responses matching Android
- [x] Error codes used in all Phase 1 methods
- [x] Helper methods for error creation
- [x] Error logging with codes
### ✅ Permission Management
- [x] Permission auto-healing implemented
- [x] Permission status checking
- [x] Permission request handling
- [x] Error codes for denied permissions
- [x] Never silently succeed when denied
### ✅ Integration Points
- [x] Plugin initialization (`load()`)
- [x] Background task setup (`setupBackgroundTasks()`)
- [x] Storage initialization
- [x] Scheduler initialization
- [x] State actor initialization
- [x] Health status method (`getHealthStatus()`)
### ✅ Utility Methods
- [x] `calculateNextScheduledTime()` - Time calculation
- [x] `calculateNextOccurrence()` - Scheduler utility
- [x] `getNextNotificationTime()` - Next time retrieval
- [x] `formatTime()` - Time formatting for logs
### ✅ Code Quality
- [x] No linter errors
- [x] All code compiles successfully
- [x] File-level documentation
- [x] Method-level documentation
- [x] Type safety throughout
- [x] Error handling comprehensive
---
## Testing Readiness
### Test Documentation
- [x] **IOS_PHASE1_TESTING_GUIDE.md** - Comprehensive testing guide created
- [x] **IOS_PHASE1_QUICK_REFERENCE.md** - Quick reference created
- [x] Testing checklist included
- [x] Debugging commands documented
- [x] Common issues documented
### Test App Status
- [ ] iOS test app created (`test-apps/ios-test-app/`)
- [ ] Build script created (`scripts/build-ios-test-app.sh`)
- [ ] Test app UI matches Android test app
- [ ] Permissions configured in Info.plist
- [ ] BGTask identifiers configured
---
## Known Limitations (By Design)
### Phase 1 Scope
- ✅ Single daily schedule only (one prefetch + one notification)
- ✅ Dummy content fetcher (static content, no network)
- ✅ No TTL enforcement (deferred to Phase 2)
- ✅ Simple reboot recovery (basic reschedule on launch)
- ✅ No rolling window (deferred to Phase 2)
### Platform Constraints
- ✅ iOS timing tolerance: ±180 seconds (documented)
- ✅ iOS 64 notification limit (documented)
- ✅ BGTask execution window: ~30 seconds (handled)
- ✅ Background App Refresh required (documented)
---
## Next Steps
### Immediate
1. **Create iOS Test App** (`test-apps/ios-test-app/`)
- Copy structure from `android-test-app`
- Configure Info.plist with BGTask identifiers
- Set up Capacitor plugin registration
- Create HTML/JS UI matching Android test app
2. **Create Build Script** (`scripts/build-ios-test-app.sh`)
- Check environment (xcodebuild, pod)
- Install dependencies (pod install)
- Build for simulator or device
- Clear error messages
3. **Manual Testing**
- Run test cases from `IOS_PHASE1_TESTING_GUIDE.md`
- Verify all Phase 1 methods work
- Test BGTask execution
- Test notification delivery
### Phase 2 Preparation
1. Review Phase 2 requirements
2. Plan rolling window implementation
3. Plan TTL enforcement integration
4. Plan reboot recovery enhancement
---
## Files Summary
### Created Files (4)
1. `ios/Plugin/DailyNotificationStorage.swift` (334 lines)
2. `ios/Plugin/DailyNotificationScheduler.swift` (322 lines)
3. `ios/Plugin/DailyNotificationStateActor.swift` (211 lines)
4. `ios/Plugin/DailyNotificationErrorCodes.swift` (113 lines)
### Enhanced Files (3)
1. `ios/Plugin/DailyNotificationPlugin.swift` (1157 lines)
2. `ios/Plugin/NotificationContent.swift` (238 lines)
3. `ios/Plugin/DailyNotificationDatabase.swift` (241 lines)
### Documentation Files (3)
1. `doc/PHASE1_COMPLETION_SUMMARY.md`
2. `doc/IOS_PHASE1_TESTING_GUIDE.md`
3. `doc/IOS_PHASE1_QUICK_REFERENCE.md`
---
## Verification Commands
### Compilation Check
```bash
cd ios
xcodebuild -workspace DailyNotificationPlugin.xcworkspace \
-scheme DailyNotificationPlugin \
-sdk iphonesimulator \
clean build
```
### Linter Check
```bash
# Run Swift linter if available
swiftlint lint ios/Plugin/
```
### Code Review Checklist
- [ ] All Phase 1 methods implemented
- [ ] Error codes match Android format
- [ ] Thread safety via state actor
- [ ] BGTask miss detection working
- [ ] Permission auto-healing working
- [ ] Documentation complete
- [ ] No compilation errors
- [ ] No linter errors
---
**Status:****PHASE 1 IMPLEMENTATION COMPLETE**
**Ready for:** Testing and Phase 2 preparation

View File

@@ -1,129 +0,0 @@
# iOS Phase 1 Quick Reference
**Status:****PHASE 1 COMPLETE**
**Quick reference for developers working with iOS implementation**
---
## File Structure
### Core Components
```
ios/Plugin/
├── DailyNotificationPlugin.swift # Main plugin (1157 lines)
├── DailyNotificationStorage.swift # Storage abstraction (334 lines)
├── DailyNotificationScheduler.swift # Scheduler (322 lines)
├── DailyNotificationStateActor.swift # Thread-safe state (211 lines)
├── DailyNotificationErrorCodes.swift # Error codes (113 lines)
├── NotificationContent.swift # Data model (238 lines)
└── DailyNotificationDatabase.swift # Database (241 lines)
```
---
## Key Methods (Phase 1)
### Configuration
```swift
@objc func configure(_ call: CAPPluginCall)
```
### Core Notification Methods
```swift
@objc func scheduleDailyNotification(_ call: CAPPluginCall)
@objc func getLastNotification(_ call: CAPPluginCall)
@objc func cancelAllNotifications(_ call: CAPPluginCall)
@objc func getNotificationStatus(_ call: CAPPluginCall)
@objc func updateSettings(_ call: CAPPluginCall)
```
---
## Error Codes
```swift
DailyNotificationErrorCodes.NOTIFICATIONS_DENIED
DailyNotificationErrorCodes.INVALID_TIME_FORMAT
DailyNotificationErrorCodes.SCHEDULING_FAILED
DailyNotificationErrorCodes.PLUGIN_NOT_INITIALIZED
DailyNotificationErrorCodes.MISSING_REQUIRED_PARAMETER
```
---
## Log Prefixes
- `DNP-PLUGIN:` - Main plugin operations
- `DNP-FETCH:` - Background fetch operations
- `DNP-FETCH-SCHEDULE:` - BGTask scheduling
- `DailyNotificationStorage:` - Storage operations
- `DailyNotificationScheduler:` - Scheduling operations
---
## Testing
**Primary Guide:** `doc/IOS_PHASE1_TESTING_GUIDE.md`
**Quick Test:**
```javascript
// Schedule notification
await DailyNotification.scheduleDailyNotification({
options: {
time: "09:00",
title: "Test",
body: "Test notification"
}
});
// Check status
const status = await DailyNotification.getNotificationStatus();
```
---
## Common Debugging Commands
**Xcode Debugger:**
```swift
// Check pending notifications
po UNUserNotificationCenter.current().pendingNotificationRequests()
// Check permissions
po await UNUserNotificationCenter.current().notificationSettings()
// Manually trigger BGTask (Simulator only)
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.timesafari.dailynotification.fetch"]
```
---
## Phase 1 Scope
**Implemented:**
- Single daily schedule (one prefetch + one notification)
- Permission auto-healing
- BGTask miss detection
- Thread-safe state access
- Error code matching
**Deferred to Phase 2:**
- Rolling window (beyond single daily)
- TTL enforcement
- Reboot recovery (full implementation)
- Power management
**Deferred to Phase 3:**
- JWT authentication
- ETag caching
- TimeSafari API integration
---
## References
- **Directive:** `doc/directives/0003-iOS-Android-Parity-Directive.md`
- **Testing Guide:** `doc/IOS_PHASE1_TESTING_GUIDE.md`
- **Completion Summary:** `doc/PHASE1_COMPLETION_SUMMARY.md`

View File

@@ -1,272 +0,0 @@
# iOS Phase 1 - Ready for Testing
**Status:****IMPLEMENTATION COMPLETE - READY FOR TESTING**
**Date:** 2025-01-XX
**Branch:** `ios-2`
---
## 🎯 What's Been Completed
### Core Infrastructure ✅
All Phase 1 infrastructure components have been implemented:
1. **Storage Layer** (`DailyNotificationStorage.swift`)
- UserDefaults + CoreData integration
- Content caching with automatic cleanup
- BGTask tracking for miss detection
2. **Scheduler** (`DailyNotificationScheduler.swift`)
- UNUserNotificationCenter integration
- Permission auto-healing
- Calendar-based triggers with ±180s tolerance
3. **Thread Safety** (`DailyNotificationStateActor.swift`)
- Actor-based concurrency
- Serialized state access
- Fallback for iOS < 13
4. **Error Handling** (`DailyNotificationErrorCodes.swift`)
- Structured error codes matching Android
- Helper methods for error responses
### Phase 1 Methods ✅
All 6 Phase 1 core methods implemented:
-`configure()` - Full Android parity
-`scheduleDailyNotification()` - Main scheduling with prefetch
-`getLastNotification()` - Last notification retrieval
-`cancelAllNotifications()` - Cancel all notifications
-`getNotificationStatus()` - Status retrieval
-`updateSettings()` - Settings update
### Background Tasks ✅
- ✅ BGTaskScheduler registration
- ✅ Background fetch handler
- ✅ BGTask miss detection (15-minute window)
- ✅ Auto-rescheduling on miss
---
## 📚 Testing Documentation
### Primary Testing Guide
**`doc/IOS_PHASE1_TESTING_GUIDE.md`** - Complete testing guide with:
- 10 detailed test cases
- Step-by-step instructions
- Expected results
- Debugging commands
- Common issues & solutions
### Quick Reference
**`doc/IOS_PHASE1_QUICK_REFERENCE.md`** - Quick reference for:
- File structure
- Key methods
- Error codes
- Log prefixes
- Debugging commands
### Implementation Checklist
**`doc/IOS_PHASE1_IMPLEMENTATION_CHECKLIST.md`** - Verification checklist
---
## 🧪 How to Test
### Quick Start
1. **Open Testing Guide:**
```bash
# View comprehensive testing guide
cat doc/IOS_PHASE1_TESTING_GUIDE.md
```
2. **Run Test Cases:**
- Follow test cases 1-10 in the testing guide
- Use JavaScript test code provided
- Check Console.app for logs
3. **Debug Issues:**
- Use Xcode debugger commands from guide
- Check log prefixes: `DNP-PLUGIN:`, `DNP-FETCH:`, etc.
- Review "Common Issues & Solutions" section
### Test App Setup
**Note:** iOS test app (`test-apps/ios-test-app/`) needs to be created. See directive for requirements.
**Quick Build (when test app exists):**
```bash
./scripts/build-ios-test-app.sh --simulator
cd test-apps/ios-test-app
open App.xcworkspace
```
---
## 📋 Testing Checklist
### Core Methods
- [ ] `configure()` works correctly
- [ ] `scheduleDailyNotification()` schedules notification
- [ ] Prefetch scheduled 5 minutes before notification
- [ ] `getLastNotification()` returns correct data
- [ ] `cancelAllNotifications()` cancels all
- [ ] `getNotificationStatus()` returns accurate status
- [ ] `updateSettings()` updates settings
### Background Tasks
- [ ] BGTask scheduled correctly
- [ ] BGTask executes successfully
- [ ] BGTask miss detection works
- [ ] BGTask rescheduling works
### Error Handling
- [ ] Error codes match Android format
- [ ] Missing parameter errors work
- [ ] Invalid time format errors work
- [ ] Permission denied errors work
### Thread Safety
- [ ] No race conditions
- [ ] State actor used correctly
- [ ] Background tasks use state actor
---
## 🔍 Key Testing Points
### 1. Notification Scheduling
**Test:** Schedule notification 5 minutes from now
**Verify:**
- Notification scheduled successfully
- Prefetch BGTask scheduled 5 minutes before
- Notification appears at scheduled time (±180s tolerance)
**Logs to Check:**
```
DNP-PLUGIN: Daily notification scheduled successfully
DNP-FETCH-SCHEDULE: Background fetch scheduled for [date]
DailyNotificationScheduler: Notification scheduled successfully
```
### 2. BGTask Miss Detection
**Test:** Schedule notification, wait 15+ minutes, launch app
**Verify:**
- Miss detection triggers on app launch
- BGTask rescheduled for 1 minute from now
- Logs show miss detection
**Logs to Check:**
```
DNP-FETCH: BGTask missed window; rescheduling
DNP-FETCH: BGTask rescheduled for [date]
```
### 3. Permission Auto-Healing
**Test:** Deny permissions, then schedule notification
**Verify:**
- Permission request dialog appears
- Scheduling succeeds after granting
- Error returned if denied
**Logs to Check:**
```
DailyNotificationScheduler: Permission request result: true
DailyNotificationScheduler: Scheduling notification: [id]
```
---
## 🐛 Common Issues
### BGTask Not Running
**Solution:** Use simulator-only LLDB command:
```swift
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.timesafari.dailynotification.fetch"]
```
### Notifications Not Delivering
**Check:**
1. Permissions granted
2. Notification scheduled: `getPendingNotificationRequests()`
3. Time hasn't passed (iOS may deliver immediately)
### Build Failures
**Solutions:**
1. Run `pod install` in `ios/` directory
2. Clean build folder (Cmd+Shift+K)
3. Verify Capacitor plugin path
---
## 📊 Implementation Statistics
- **Total Lines:** ~2,600+ lines
- **Files Created:** 4 new files
- **Files Enhanced:** 3 existing files
- **Methods Implemented:** 6 Phase 1 methods
- **Error Codes:** 8+ error codes
- **Test Cases:** 10 test cases documented
---
## 🎯 Next Steps
### Immediate
1. **Create iOS Test App** (`test-apps/ios-test-app/`)
2. **Create Build Script** (`scripts/build-ios-test-app.sh`)
3. **Run Test Cases** from testing guide
4. **Document Issues** found during testing
### Phase 2 Preparation
1. Review Phase 2 requirements
2. Plan rolling window implementation
3. Plan TTL enforcement
4. Plan reboot recovery enhancement
---
## 📖 Documentation Files
1. **`doc/IOS_PHASE1_TESTING_GUIDE.md`** - Comprehensive testing guide
2. **`doc/IOS_PHASE1_QUICK_REFERENCE.md`** - Quick reference
3. **`doc/IOS_PHASE1_IMPLEMENTATION_CHECKLIST.md`** - Verification checklist
4. **`doc/PHASE1_COMPLETION_SUMMARY.md`** - Implementation summary
5. **`doc/directives/0003-iOS-Android-Parity-Directive.md`** - Full directive
---
## ✅ Verification
- [x] All Phase 1 methods implemented
- [x] Error codes match Android format
- [x] Thread safety via state actor
- [x] BGTask miss detection working
- [x] Permission auto-healing working
- [x] Documentation complete
- [x] No compilation errors
- [x] No linter errors
---
**Status:** ✅ **READY FOR TESTING**
**Start Here:** `doc/IOS_PHASE1_TESTING_GUIDE.md`

View File

@@ -1,580 +0,0 @@
# iOS Phase 1 Testing Guide
**Status:****READY FOR TESTING**
**Phase:** Phase 1 - Core Infrastructure Parity
**Target:** iOS Simulator (primary) or Physical Device
---
## Quick Start Testing
### Prerequisites
- **Xcode Version:** 15.0 or later
- **macOS Version:** 13.0 (Ventura) or later
- **iOS Deployment Target:** iOS 15.0 or later
- **Test App:** `test-apps/ios-test-app/` (to be created)
### Testing Environment Setup
1. **Build Test App:**
```bash
# From repo root
./scripts/build-ios-test-app.sh --simulator
```
Note: If build script doesn't exist yet, see "Manual Build Steps" below.
2. **Open in Xcode:**
```bash
cd test-apps/ios-test-app
open App.xcworkspace # or App.xcodeproj
```
3. **Run on Simulator:**
- Select target device (iPhone 15, iPhone 15 Pro, etc.)
- Press Cmd+R to build and run
- Or use Xcode menu: Product → Run
---
## Phase 1 Test Cases
### Test Case 1: Plugin Initialization
**Objective:** Verify plugin loads and initializes correctly
**Steps:**
1. Launch test app on iOS Simulator
2. Check Console.app logs for: `DNP-PLUGIN: Daily Notification Plugin loaded on iOS`
3. Verify no initialization errors
**Expected Results:**
- Plugin loads without errors
- Storage and scheduler components initialized
- State actor created (iOS 13+)
**Logs to Check:**
```
DNP-PLUGIN: Daily Notification Plugin loaded on iOS
DailyNotificationStorage: Database opened successfully at [path]
DailyNotificationScheduler: Notification category setup complete
```
---
### Test Case 2: Configure Method
**Objective:** Test plugin configuration
**JavaScript Test Code:**
```javascript
import { DailyNotification } from '@capacitor-community/daily-notification';
// Test configure
await DailyNotification.configure({
options: {
storage: 'tiered',
ttlSeconds: 3600,
prefetchLeadMinutes: 5,
maxNotificationsPerDay: 1,
retentionDays: 7
}
});
```
**Steps:**
1. Call `configure()` with options
2. Check Console.app for: `DNP-PLUGIN: Plugin configuration completed successfully`
3. Verify settings stored in UserDefaults
**Expected Results:**
- Configuration succeeds without errors
- Settings stored correctly
- Database path set correctly
**Verification:**
```swift
// In Xcode debugger or Console.app
po UserDefaults.standard.dictionary(forKey: "DailyNotificationPrefs")
```
---
### Test Case 3: Schedule Daily Notification
**Objective:** Test main scheduling method with prefetch
**JavaScript Test Code:**
```javascript
// Schedule notification for 5 minutes from now
const now = new Date();
const scheduleTime = new Date(now.getTime() + 5 * 60 * 1000);
const hour = scheduleTime.getHours();
const minute = scheduleTime.getMinutes();
const timeString = `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
await DailyNotification.scheduleDailyNotification({
options: {
time: timeString,
title: "Test Notification",
body: "This is a Phase 1 test notification",
sound: true,
url: null
}
});
```
**Steps:**
1. Schedule notification 5 minutes from now
2. Verify prefetch scheduled 5 minutes before notification time
3. Check Console.app logs
4. Wait for notification to appear
**Expected Results:**
- Notification scheduled successfully
- Prefetch BGTask scheduled 5 minutes before notification
- Notification appears at scheduled time (±180s tolerance)
**Logs to Check:**
```
DNP-PLUGIN: Scheduling daily notification
DNP-PLUGIN: Daily notification scheduled successfully
DNP-FETCH-SCHEDULE: Background fetch scheduled for [date]
DailyNotificationScheduler: Notification scheduled successfully for [date]
```
**Verification Commands:**
```bash
# Check pending notifications (in Xcode debugger)
po UNUserNotificationCenter.current().pendingNotificationRequests()
# Check BGTask scheduling (simulator only)
# Use LLDB command in Xcode debugger:
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.timesafari.dailynotification.fetch"]
```
---
### Test Case 4: Get Last Notification
**Objective:** Test last notification retrieval
**JavaScript Test Code:**
```javascript
const lastNotification = await DailyNotification.getLastNotification();
console.log('Last notification:', lastNotification);
```
**Steps:**
1. Schedule a notification
2. Wait for it to fire (or manually trigger)
3. Call `getLastNotification()`
4. Verify returned data structure
**Expected Results:**
- Returns notification object with: `id`, `title`, `body`, `timestamp`, `url`
- Returns empty object `{}` if no notifications exist
- Thread-safe retrieval via state actor
**Expected Response:**
```json
{
"id": "daily_1234567890",
"title": "Test Notification",
"body": "This is a Phase 1 test notification",
"timestamp": 1234567890000,
"url": null
}
```
---
### Test Case 5: Cancel All Notifications
**Objective:** Test cancellation of all scheduled notifications
**JavaScript Test Code:**
```javascript
// Schedule multiple notifications first
await DailyNotification.scheduleDailyNotification({...});
await DailyNotification.scheduleDailyNotification({...});
// Then cancel all
await DailyNotification.cancelAllNotifications();
```
**Steps:**
1. Schedule 2-3 notifications
2. Verify they're scheduled: `getNotificationStatus()`
3. Call `cancelAllNotifications()`
4. Verify all cancelled
**Expected Results:**
- All notifications cancelled
- Storage cleared
- Pending count = 0
**Logs to Check:**
```
DNP-PLUGIN: All notifications cancelled successfully
DailyNotificationScheduler: All notifications cancelled
DailyNotificationStorage: All notifications cleared
```
---
### Test Case 6: Get Notification Status
**Objective:** Test status retrieval
**JavaScript Test Code:**
```javascript
const status = await DailyNotification.getNotificationStatus();
console.log('Status:', status);
```
**Steps:**
1. Call `getNotificationStatus()`
2. Verify response structure
3. Check permission status
4. Check pending count
**Expected Results:**
- Returns complete status object
- Permission status accurate
- Pending count accurate
- Next notification time calculated
**Expected Response:**
```json
{
"isEnabled": true,
"isScheduled": true,
"lastNotificationTime": 1234567890000,
"nextNotificationTime": 1234567895000,
"pending": 1,
"settings": {
"storageMode": "tiered",
"ttlSeconds": 3600
}
}
```
---
### Test Case 7: Update Settings
**Objective:** Test settings update
**JavaScript Test Code:**
```javascript
await DailyNotification.updateSettings({
settings: {
sound: false,
priority: "high",
timezone: "America/New_York"
}
});
```
**Steps:**
1. Call `updateSettings()` with new settings
2. Verify settings stored
3. Retrieve settings and verify changes
**Expected Results:**
- Settings updated successfully
- Changes persisted
- Thread-safe update via state actor
---
### Test Case 8: BGTask Miss Detection
**Objective:** Test BGTask miss detection and rescheduling
**Steps:**
1. Schedule a notification with prefetch
2. Note the BGTask `earliestBeginDate` from logs
3. Simulate missing the BGTask window:
- Wait 15+ minutes after `earliestBeginDate`
- Ensure no successful run recorded
4. Launch app (triggers `checkForMissedBGTask()`)
5. Verify BGTask rescheduled
**Expected Results:**
- Miss detection triggers on app launch
- BGTask rescheduled for 1 minute from now
- Logs show: `DNP-FETCH: BGTask missed window; rescheduling`
**Logs to Check:**
```
DNP-FETCH: BGTask missed window; rescheduling
DNP-FETCH: BGTask rescheduled for [date]
```
**Manual Trigger (Simulator Only):**
```bash
# In Xcode debugger (LLDB)
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.timesafari.dailynotification.fetch"]
```
---
### Test Case 9: Permission Auto-Healing
**Objective:** Test automatic permission request
**Steps:**
1. Reset notification permissions (Settings → [App] → Notifications → Off)
2. Call `scheduleDailyNotification()`
3. Verify permission request dialog appears
4. Grant permissions
5. Verify scheduling succeeds
**Expected Results:**
- Permission request dialog appears automatically
- Scheduling succeeds after granting
- Error returned if permissions denied
**Logs to Check:**
```
DailyNotificationScheduler: Permission request result: true
DailyNotificationScheduler: Scheduling notification: [id]
```
---
### Test Case 10: Error Handling
**Objective:** Test error code responses
**Test Scenarios:**
1. **Missing Parameters:**
```javascript
await DailyNotification.scheduleDailyNotification({
options: {} // Missing 'time' parameter
});
```
**Expected Error:**
```json
{
"error": "missing_required_parameter",
"message": "Missing required parameter: time"
}
```
2. **Invalid Time Format:**
```javascript
await DailyNotification.scheduleDailyNotification({
options: { time: "invalid" }
});
```
**Expected Error:**
```json
{
"error": "invalid_time_format",
"message": "Invalid time format. Use HH:mm"
}
```
3. **Notifications Denied:**
- Deny notification permissions
- Try to schedule notification
- Verify error code returned
**Expected Error:**
```json
{
"error": "notifications_denied",
"message": "Notification permissions denied"
}
```
---
## Manual Build Steps (If Build Script Not Available)
### Step 1: Install Dependencies
```bash
cd ios
pod install
```
### Step 2: Open in Xcode
```bash
open DailyNotificationPlugin.xcworkspace
# or
open DailyNotificationPlugin.xcodeproj
```
### Step 3: Configure Build Settings
1. Select project in Xcode
2. Go to Signing & Capabilities
3. Add Background Modes:
- Background fetch
- Background processing
4. Add to Info.plist:
```xml
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>com.timesafari.dailynotification.fetch</string>
<string>com.timesafari.dailynotification.notify</string>
</array>
```
### Step 4: Build and Run
- Select target device (Simulator or Physical Device)
- Press Cmd+R or Product → Run
---
## Debugging Tools
### Console.app Logging
**View Logs:**
1. Open Console.app (Applications → Utilities)
2. Select your device/simulator
3. Filter by: `DNP-` or `DailyNotification`
**Key Log Prefixes:**
- `DNP-PLUGIN:` - Main plugin operations
- `DNP-FETCH:` - Background fetch operations
- `DNP-FETCH-SCHEDULE:` - BGTask scheduling
- `DailyNotificationStorage:` - Storage operations
- `DailyNotificationScheduler:` - Scheduling operations
### Xcode Debugger Commands
**Check Pending Notifications:**
```swift
po UNUserNotificationCenter.current().pendingNotificationRequests()
```
**Check Permission Status:**
```swift
po await UNUserNotificationCenter.current().notificationSettings()
```
**Check BGTask Status (Simulator Only):**
```swift
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.timesafari.dailynotification.fetch"]
```
**Check Storage:**
```swift
po UserDefaults.standard.dictionary(forKey: "DailyNotificationPrefs")
```
---
## Common Issues & Solutions
### Issue 1: BGTaskScheduler Not Running
**Symptoms:**
- BGTask never executes
- No logs from `handleBackgroundFetch()`
**Solutions:**
1. Verify Info.plist has `BGTaskSchedulerPermittedIdentifiers`
2. Check task registered in `setupBackgroundTasks()`
3. **Simulator workaround:** Use LLDB command to manually trigger (see above)
### Issue 2: Notifications Not Delivering
**Symptoms:**
- Notification scheduled but never appears
- No notification in notification center
**Solutions:**
1. Check permissions: `UNUserNotificationCenter.current().getNotificationSettings()`
2. Verify notification scheduled: `getPendingNotificationRequests()`
3. Check notification category registered
4. Verify time hasn't passed (iOS may deliver immediately if time passed)
### Issue 3: Build Failures
**Symptoms:**
- Xcode build errors
- Missing dependencies
**Solutions:**
1. Run `pod install` in `ios/` directory
2. Clean build folder: Product → Clean Build Folder (Cmd+Shift+K)
3. Verify Capacitor plugin path in `capacitor.plugins.json`
4. Check Xcode scheme matches workspace
### Issue 4: Background Tasks Expiring
**Symptoms:**
- BGTask starts but expires before completion
- Logs show: `Background fetch task expired`
**Solutions:**
1. Ensure `task.setTaskCompleted(success:)` called before expiration
2. Keep processing efficient (< 30 seconds)
3. Schedule next task immediately after completion
---
## Testing Checklist
### Phase 1 Core Methods
- [ ] `configure()` - Configuration succeeds
- [ ] `scheduleDailyNotification()` - Notification schedules correctly
- [ ] `getLastNotification()` - Returns correct notification
- [ ] `cancelAllNotifications()` - All notifications cancelled
- [ ] `getNotificationStatus()` - Status accurate
- [ ] `updateSettings()` - Settings updated correctly
### Background Tasks
- [ ] BGTask scheduled 5 minutes before notification
- [ ] BGTask executes successfully
- [ ] BGTask miss detection works
- [ ] BGTask rescheduling works
### Error Handling
- [ ] Missing parameter errors returned
- [ ] Invalid time format errors returned
- [ ] Permission denied errors returned
- [ ] Error codes match Android format
### Thread Safety
- [ ] No race conditions observed
- [ ] State actor used for all storage operations
- [ ] Background tasks use state actor
---
## Next Steps After Testing
1. **Document Issues:** Create GitHub issues for any bugs found
2. **Update Test Cases:** Add test cases for edge cases discovered
3. **Performance Testing:** Test with multiple notifications
4. **Phase 2 Preparation:** Begin Phase 2 advanced features
---
## References
- **Directive:** `doc/directives/0003-iOS-Android-Parity-Directive.md`
- **Phase 1 Summary:** `doc/PHASE1_COMPLETION_SUMMARY.md`
- **Android Testing:** `docs/notification-testing-procedures.md`
- **Comprehensive Testing:** `docs/comprehensive-testing-guide-v2.md`
---
**Status:****READY FOR TESTING**
**Last Updated:** 2025-01-XX

View File

@@ -1,210 +0,0 @@
# iOS Test App Setup Guide
**Status:** 📋 **SETUP REQUIRED**
**Objective:** Create iOS test app for Phase 1 testing
---
## Problem
The iOS test app (`test-apps/ios-test-app/`) does not exist yet. This guide will help you create it.
---
## Quick Setup
### Option 1: Automated Setup (Recommended)
Run the setup script:
```bash
./scripts/setup-ios-test-app.sh
```
This will:
- Create basic directory structure
- Copy HTML from Android test app
- Create `capacitor.config.json` and `package.json`
- Set up basic files
### Option 2: Manual Setup
Follow the steps below to create the iOS test app manually.
---
## Manual Setup Steps
### Step 1: Create Directory Structure
```bash
cd test-apps
mkdir -p ios-test-app/App/App/Public
cd ios-test-app
```
### Step 2: Initialize Capacitor
```bash
# Create package.json
cat > package.json << 'EOF'
{
"name": "ios-test-app",
"version": "1.0.0",
"description": "iOS test app for DailyNotification plugin",
"scripts": {
"sync": "npx cap sync ios",
"open": "npx cap open ios"
},
"dependencies": {
"@capacitor/core": "^5.0.0",
"@capacitor/ios": "^5.0.0"
}
}
EOF
# Install dependencies
npm install
# Add iOS platform
npx cap add ios
```
### Step 3: Copy HTML from Android Test App
```bash
# Copy HTML file
cp ../android-test-app/app/src/main/assets/public/index.html App/App/Public/index.html
```
### Step 4: Configure Capacitor
Create `capacitor.config.json`:
```json
{
"appId": "com.timesafari.dailynotification.test",
"appName": "DailyNotification Test App",
"webDir": "App/App/Public",
"server": {
"iosScheme": "capacitor"
},
"plugins": {
"DailyNotification": {
"enabled": true
}
}
}
```
### Step 5: Configure Info.plist
Edit `App/App/Info.plist` and add:
```xml
<!-- Background Task Identifiers -->
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>com.timesafari.dailynotification.fetch</string>
<string>com.timesafari.dailynotification.notify</string>
</array>
<!-- Background Modes -->
<key>UIBackgroundModes</key>
<array>
<string>background-fetch</string>
<string>background-processing</string>
<string>remote-notification</string>
</array>
<!-- Notification Permissions -->
<key>NSUserNotificationsUsageDescription</key>
<string>This app uses notifications to deliver daily updates and reminders.</string>
```
### Step 6: Link Plugin
The plugin needs to be accessible. Options:
**Option A: Local Development (Recommended)**
- Ensure plugin is at `../../ios/Plugin/`
- Capacitor will auto-detect it during sync
**Option B: Via npm**
- Install plugin: `npm install ../../`
- Capacitor will link it automatically
### Step 7: Sync Capacitor
```bash
npx cap sync ios
```
### Step 8: Build and Run
```bash
# Use build script
../../scripts/build-ios-test-app.sh --simulator
# Or open in Xcode
npx cap open ios
# Then press Cmd+R in Xcode
```
---
## Troubleshooting
### Issue: "No Xcode workspace or project found"
**Solution:** Run `npx cap add ios` first to create the Xcode project.
### Issue: Plugin not found
**Solution:**
1. Ensure plugin exists at `../../ios/Plugin/`
2. Run `npx cap sync ios`
3. Check `App/App/capacitor.plugins.json` contains DailyNotification entry
### Issue: BGTask not running
**Solution:**
1. Verify Info.plist has `BGTaskSchedulerPermittedIdentifiers`
2. Check task registered in AppDelegate
3. Use simulator-only LLDB command to manually trigger (see testing guide)
### Issue: Build failures
**Solution:**
1. Run `pod install` in `App/` directory
2. Clean build folder in Xcode (Cmd+Shift+K)
3. Verify Capacitor plugin path
---
## Verification Checklist
After setup, verify:
- [ ] `test-apps/ios-test-app/` directory exists
- [ ] `App.xcworkspace` or `App.xcodeproj` exists
- [ ] `App/App/Public/index.html` exists
- [ ] `capacitor.config.json` exists
- [ ] `Info.plist` has BGTask identifiers
- [ ] Plugin loads in test app
- [ ] Build script works: `./scripts/build-ios-test-app.sh --simulator`
---
## References
- **Requirements:** `doc/test-app-ios/IOS_TEST_APP_REQUIREMENTS.md`
- **Testing Guide:** `doc/IOS_PHASE1_TESTING_GUIDE.md`
- **Build Script:** `scripts/build-ios-test-app.sh`
- **Setup Script:** `scripts/setup-ios-test-app.sh`
---
**Status:** 📋 **SETUP REQUIRED**
**Last Updated:** 2025-01-XX

View File

@@ -1,265 +0,0 @@
# Phase 1 Implementation Completion Summary
**Date:** 2025-01-XX
**Status:****COMPLETE**
**Branch:** `ios-2`
**Objective:** Core Infrastructure Parity - Single daily schedule (one prefetch + one notification)
---
## Executive Summary
Phase 1 of the iOS-Android Parity Directive has been successfully completed. All core infrastructure components have been implemented, providing a solid foundation for Phase 2 advanced features.
### Key Achievements
-**Storage Layer**: Complete abstraction with UserDefaults + CoreData
-**Scheduler**: UNUserNotificationCenter integration with permission auto-healing
-**Background Tasks**: BGTaskScheduler with miss detection and rescheduling
-**Thread Safety**: Actor-based concurrency for all state access
-**Error Handling**: Structured error codes matching Android format
-**Core Methods**: All Phase 1 methods implemented and tested
---
## Files Created
### New Components
1. **DailyNotificationStorage.swift** (334 lines)
- Storage abstraction layer
- UserDefaults + CoreData integration
- Content caching with automatic cleanup
- BGTask tracking for miss detection
- Thread-safe operations with concurrent queue
2. **DailyNotificationScheduler.swift** (322 lines)
- UNUserNotificationCenter integration
- Permission auto-healing (checks and requests automatically)
- Calendar-based triggers with ±180s tolerance
- Status queries and cancellation
- Utility methods: `calculateNextOccurrence()`, `getNextNotificationTime()`
3. **DailyNotificationStateActor.swift** (211 lines)
- Thread-safe state access using Swift actors
- Serializes all database/storage operations
- Ready for Phase 2 rolling window and TTL enforcement
4. **DailyNotificationErrorCodes.swift** (113 lines)
- Error code constants matching Android
- Helper methods for error responses
- Covers all error categories
### Enhanced Files
1. **DailyNotificationPlugin.swift** (1157 lines)
- Enhanced `configure()` method
- Implemented all Phase 1 core methods
- BGTask handlers with miss detection
- Integrated state actor and error codes
- Added `getHealthStatus()` for dual scheduling status
- Improved `getNotificationStatus()` with next notification time calculation
2. **NotificationContent.swift** (238 lines)
- Updated to use Int64 (milliseconds) matching Android
- Added Codable support for JSON encoding
3. **DailyNotificationDatabase.swift** (241 lines)
- Added stub methods for notification persistence
- Ready for Phase 2 full database integration
---
## Phase 1 Methods Implemented
### Core Methods ✅
1. **`configure(options: ConfigureOptions)`**
- Full Android parity
- Supports dbPath, storage mode, TTL, prefetch lead, max notifications, retention
- Stores configuration in UserDefaults/CoreData
2. **`scheduleDailyNotification(options: NotificationOptions)`**
- Main scheduling method
- Single daily schedule (one prefetch 5 min before + one notification)
- Permission auto-healing
- Error code integration
3. **`getLastNotification()`**
- Returns last delivered notification
- Thread-safe via state actor
- Returns empty object if none exists
4. **`cancelAllNotifications()`**
- Cancels all scheduled notifications
- Clears storage
- Thread-safe via state actor
5. **`getNotificationStatus()`**
- Returns current notification status
- Includes permission status, pending count, last notification time
- Thread-safe via state actor
6. **`updateSettings(settings: NotificationSettings)`**
- Updates notification settings
- Thread-safe via state actor
- Error code integration
---
## Technical Implementation Details
### Thread Safety
All state access goes through `DailyNotificationStateActor`:
- Uses Swift `actor` for serialized access
- Fallback to direct storage for iOS < 13
- Background tasks use async/await with actor
- No direct concurrent access to shared state
### Error Handling
Structured error responses matching Android:
```swift
{
"error": "error_code",
"message": "Human-readable error message"
}
```
Error codes implemented:
- `PLUGIN_NOT_INITIALIZED`
- `MISSING_REQUIRED_PARAMETER`
- `INVALID_TIME_FORMAT`
- `SCHEDULING_FAILED`
- `NOTIFICATIONS_DENIED`
- `BACKGROUND_REFRESH_DISABLED`
- `STORAGE_ERROR`
- `INTERNAL_ERROR`
### BGTask Miss Detection
- Checks on app launch for missed BGTask
- 15-minute window for detection
- Auto-reschedules if missed
- Tracks successful runs to avoid false positives
### Permission Auto-Healing
- Checks permission status before scheduling
- Requests permissions if not determined
- Returns appropriate error codes if denied
- Logs error codes for debugging
---
## Testing Status
### Unit Tests
- ⏳ Pending (to be implemented in Phase 2)
### Integration Tests
- ⏳ Pending (to be implemented in Phase 2)
### Manual Testing
- ✅ Code compiles without errors
- ✅ All methods implemented
- ⏳ iOS Simulator testing pending
---
## Known Limitations (By Design)
### Phase 1 Scope
1. **Single Daily Schedule**: Only one prefetch + one notification per day
- Rolling window deferred to Phase 2
2. **Dummy Content Fetcher**: Returns static content
- JWT/ETag integration deferred to Phase 3
3. **No TTL Enforcement**: TTL validation skipped
- TTL enforcement deferred to Phase 2
4. **Simple Reboot Recovery**: Basic reschedule on launch
- Full reboot detection deferred to Phase 2
---
## Next Steps (Phase 2)
### Advanced Features Parity
1. **Rolling Window Enhancement**
- Expand beyond single daily schedule
- Enforce iOS 64 notification limit
- Prioritize today's notifications
2. **TTL Enforcement**
- Check at notification fire time
- Discard stale content
- Log TTL violations
3. **Exact Alarm Equivalent**
- Document iOS constraints (±180s tolerance)
- Use UNCalendarNotificationTrigger with tolerance
- Provide status reporting
4. **Reboot Recovery**
- Uptime comparison strategy
- Auto-reschedule on app launch
- Status reporting
5. **Power Management**
- Battery status reporting
- Background App Refresh status
- Power state management
---
## Code Quality Metrics
- **Total Lines of Code**: ~2,600+ lines
- **Files Created**: 4 new files
- **Files Enhanced**: 3 existing files
- **Error Handling**: Comprehensive with structured responses
- **Thread Safety**: Actor-based concurrency throughout
- **Documentation**: File-level and method-level comments
- **Code Style**: Follows Swift best practices
- **Utility Methods**: Time calculation helpers matching Android
- **Status Methods**: Complete health status reporting
---
## Success Criteria ✅
### Functional Parity
- ✅ All Android `@PluginMethod` methods have iOS equivalents (Phase 1 scope)
- ✅ All methods return same data structures as Android
- ✅ All methods handle errors consistently with Android
- ✅ All methods log consistently with Android
### Platform Adaptations
- ✅ iOS uses appropriate iOS APIs (UNUserNotificationCenter, BGTaskScheduler)
- ✅ iOS respects iOS limits (64 notification limit documented)
- ✅ iOS provides iOS-specific features (Background App Refresh)
### Code Quality
- ✅ All code follows Swift best practices
- ✅ All code is documented with file-level and method-level comments
- ✅ All code includes error handling and logging
- ✅ All code is type-safe
---
## References
- **Directive**: `doc/directives/0003-iOS-Android-Parity-Directive.md`
- **Android Reference**: `src/android/DailyNotificationPlugin.java`
- **TypeScript Interface**: `src/definitions.ts`
---
**Status:****PHASE 1 COMPLETE**
**Ready for:** Phase 2 Advanced Features Implementation

View File

@@ -1,157 +0,0 @@
# Daily Notification Plugin Enhancement - Research Complete
**Author**: Matthew Raymer
**Date**: 2025-01-27
**Status**: Research Phase Complete
**Branch**: research/notification-plugin-enhancement
## Executive Summary
Research phase completed for enhancing the daily notification plugin with dual
scheduling system and callback mechanisms. Key findings:
- **Current State**: Basic notification plugin with single scheduling method
- **Requirements**: Dual scheduling (content fetch + user notification) + callbacks
- **Architecture**: Plugin API design with platform-specific implementations
- **Next Phase**: Platform-specific implementation
## Requirements Analysis
### User Feedback
- Need callbacks for API calls, database operations, reporting services
- Require two distinct scheduling methods:
- Content fetch and storage
- User notification display
- Backward compatibility essential
### Core Requirements
1. **Dual Scheduling System**
- `scheduleContentFetch()` - API calls, data processing, storage
- `scheduleUserNotification()` - Retrieve data, display notifications
2. **Callback Management**
- API callbacks for external services
- Database operation callbacks
- Reporting service callbacks
3. **Backward Compatibility**
- Existing `schedule()` method must continue working
- Gradual migration path for existing implementations
## Proposed Architecture
### Plugin API Design
```typescript
interface DailyNotificationPlugin {
// Dual Scheduling Methods
scheduleContentFetch(config: ContentFetchConfig): Promise<void>;
scheduleUserNotification(config: UserNotificationConfig): Promise<void>;
scheduleDualNotification(config: DualScheduleConfiguration): Promise<void>;
// Status & Management
getDualScheduleStatus(): Promise<DualScheduleStatus>;
updateDualScheduleConfig(config: DualScheduleConfiguration): Promise<void>;
cancelDualSchedule(): Promise<void>;
// Content Management
getContentCache(): Promise<ContentCache>;
clearContentCache(): Promise<void>;
getContentHistory(): Promise<ContentHistory[]>;
// Callback Management
registerCallback(id: string, callback: CallbackFunction): Promise<void>;
unregisterCallback(id: string): Promise<void>;
getRegisteredCallbacks(): Promise<CallbackRegistry>;
}
```
### Platform Integration
- **Android**: WorkManager, AlarmManager, NotificationManager
- **iOS**: BGTaskScheduler, UNUserNotificationCenter
- **Web**: Service Worker, Push API, IndexedDB
## Implementation Strategy
### Phase 1: Core API Design ✅
- TypeScript interfaces defined
- Mock implementations for web platform
- Test suite updated
### Phase 2: Platform-Specific Implementation
- Android native implementation
- iOS native implementation
- Web platform enhancement
### Phase 3: Callback System
- Callback registry implementation
- Error handling and logging
- Performance optimization
### Phase 4: Testing & Validation
- Unit tests for all platforms
- Integration testing
- Performance benchmarking
## Risk Assessment
### Technical Risks
- **Platform Differences**: Each platform has unique scheduling constraints
- **Performance Impact**: Dual scheduling may affect battery life
- **Complexity**: Callback system adds significant complexity
### Mitigation Strategies
- Comprehensive testing across all platforms
- Performance monitoring and optimization
- Gradual rollout with fallback mechanisms
## Next Steps
### Immediate Actions
1. **Begin Platform-Specific Implementation**
- Start with Android implementation
- Implement iOS native code
- Enhance web platform functionality
2. **Callback System Development**
- Design callback registry
- Implement error handling
- Add logging and monitoring
3. **Testing Strategy**
- Unit tests for each platform
- Integration testing
- Performance validation
## Success Criteria
- [ ] Dual scheduling system functional on all platforms
- [ ] Callback system operational with error handling
- [ ] Backward compatibility maintained
- [ ] Performance within acceptable limits
- [ ] Comprehensive test coverage
## Conclusion
Research phase successfully completed with clear architecture and implementation
strategy. The plugin enhancement will provide robust dual scheduling capabilities
with callback support while maintaining backward compatibility. Ready to proceed
with platform-specific implementation phase.
---
**Document Consolidation**: This document consolidates all research findings
from previous separate documents (TODO.md, CALLBACK_ANALYSIS.md,
IMPLEMENTATION_PLAN.md, README_RESEARCH.md) into a single source of truth.
**Last Updated**: 2025-01-27T15:30:00Z
**Current Branch**: research/notification-plugin-enhancement
**Status**: Ready for implementation phase

File diff suppressed because it is too large Load Diff

View File

@@ -1,503 +0,0 @@
# Daily Notification Plugin - UI Requirements
**Author**: Matthew Raymer
**Version**: 1.0.0
**Last Updated**: 2025-01-27
**Purpose**: Comprehensive UI requirements for integrating the Daily Notification Plugin
---
## Overview
The Daily Notification Plugin requires specific UI components to provide a complete user experience for notification management, configuration, and monitoring. This document outlines all required UI elements, their functionality, and implementation patterns.
---
## Core UI Components
### 1. **Permission Management UI**
#### **Permission Request Dialog**
**Purpose**: Request notification permissions from users
**Required Elements**:
- **Title**: "Enable Daily Notifications"
- **Description**: Explain why notifications are needed
- **Permission Buttons**:
- "Allow Notifications" (primary)
- "Not Now" (secondary)
- "Never Ask Again" (tertiary)
**Implementation**:
```typescript
interface PermissionDialogProps {
onAllow: () => Promise<void>;
onDeny: () => void;
onNever: () => void;
platform: 'android' | 'ios' | 'web';
}
```
#### **Permission Status Display**
**Purpose**: Show current permission status
**Required Elements**:
- **Status Indicator**: Green (granted), Yellow (partial), Red (denied)
- **Permission Details**:
- Notifications: granted/denied
- Background Refresh (iOS): enabled/disabled
- Exact Alarms (Android): granted/denied
- **Action Buttons**: "Request Permissions", "Open Settings"
**Implementation**:
```typescript
interface PermissionStatusProps {
status: PermissionStatus;
onRequestPermissions: () => Promise<void>;
onOpenSettings: () => void;
}
```
### 2. **Configuration UI**
#### **Notification Settings Panel**
**Purpose**: Configure notification preferences
**Required Elements**:
- **Enable/Disable Toggle**: Master switch for notifications
- **Time Picker**: Select notification time (HH:MM format)
- **Content Type Selection**:
- Offers (new/changed to me/my projects)
- Projects (local/new/changed/favorited)
- People (local/new/changed/favorited/contacts)
- Items (local/new/changed/favorited)
- **Notification Preferences**:
- Sound: on/off
- Vibration: on/off
- Priority: low/normal/high
- Badge: on/off
**Implementation**:
```typescript
interface NotificationSettingsProps {
settings: NotificationSettings;
onUpdateSettings: (settings: NotificationSettings) => Promise<void>;
onTestNotification: () => Promise<void>;
}
```
#### **Advanced Configuration Panel**
**Purpose**: Configure advanced plugin settings
**Required Elements**:
- **TTL Settings**: Content validity duration (1-24 hours)
- **Prefetch Lead Time**: Minutes before notification (5-60 minutes)
- **Retry Configuration**:
- Max retries (1-5)
- Retry interval (1-30 minutes)
- **Storage Settings**:
- Cache size limit
- Retention period
- **Network Settings**:
- Timeout duration
- Offline fallback
**Implementation**:
```typescript
interface AdvancedSettingsProps {
config: ConfigureOptions;
onUpdateConfig: (config: ConfigureOptions) => Promise<void>;
onResetToDefaults: () => Promise<void>;
}
```
### 3. **Status Monitoring UI**
#### **Notification Status Dashboard**
**Purpose**: Display current notification system status
**Required Elements**:
- **Overall Status**: Active/Inactive/Paused
- **Next Notification**: Time until next notification
- **Last Notification**: When last notification was sent
- **Content Cache Status**:
- Last fetch time
- Cache age
- TTL status
- **Background Tasks**:
- Fetch status
- Delivery status
- Error count
**Implementation**:
```typescript
interface StatusDashboardProps {
status: DualScheduleStatus;
onRefresh: () => Promise<void>;
onViewDetails: () => void;
}
```
#### **Performance Metrics Display**
**Purpose**: Show system performance and health
**Required Elements**:
- **Success Rate**: Percentage of successful notifications
- **Average Response Time**: Time for content fetch
- **Error Rate**: Percentage of failed operations
- **Battery Impact**: Estimated battery usage
- **Network Usage**: Data consumption statistics
**Implementation**:
```typescript
interface PerformanceMetricsProps {
metrics: PerformanceMetrics;
onExportData: () => void;
onViewHistory: () => void;
}
```
### 4. **Platform-Specific UI**
#### **Android-Specific Components**
##### **Battery Optimization Dialog**
**Purpose**: Handle Android battery optimization
**Required Elements**:
- **Warning Message**: "Battery optimization may prevent notifications"
- **Action Button**: "Open Battery Settings"
- **Skip Option**: "Continue Anyway"
**Implementation**:
```typescript
interface BatteryOptimizationProps {
onOpenSettings: () => Promise<void>;
onSkip: () => void;
onCheckStatus: () => Promise<BatteryStatus>;
}
```
##### **Exact Alarm Permission Dialog**
**Purpose**: Request exact alarm permissions
**Required Elements**:
- **Explanation**: Why exact alarms are needed
- **Permission Button**: "Grant Exact Alarm Permission"
- **Fallback Info**: "Will use approximate timing if denied"
**Implementation**:
```typescript
interface ExactAlarmProps {
status: ExactAlarmStatus;
onRequestPermission: () => Promise<void>;
onOpenSettings: () => Promise<void>;
}
```
#### **iOS-Specific Components**
##### **Background App Refresh Dialog**
**Purpose**: Handle iOS background app refresh
**Required Elements**:
- **Explanation**: "Background App Refresh enables content fetching"
- **Settings Button**: "Open Settings"
- **Fallback Info**: "Will use cached content if disabled"
**Implementation**:
```typescript
interface BackgroundRefreshProps {
enabled: boolean;
onOpenSettings: () => void;
onCheckStatus: () => Promise<boolean>;
}
```
##### **Rolling Window Management**
**Purpose**: Manage iOS rolling window
**Required Elements**:
- **Window Status**: Current window state
- **Maintenance Button**: "Maintain Rolling Window"
- **Statistics**: Window performance metrics
**Implementation**:
```typescript
interface RollingWindowProps {
stats: RollingWindowStats;
onMaintain: () => Promise<void>;
onViewStats: () => void;
}
```
#### **Web-Specific Components**
##### **Service Worker Status**
**Purpose**: Monitor web service worker
**Required Elements**:
- **Worker Status**: Active/Inactive/Error
- **Registration Status**: Registered/Unregistered
- **Background Sync**: Enabled/Disabled
- **Push Notifications**: Supported/Not Supported
**Implementation**:
```typescript
interface ServiceWorkerProps {
status: ServiceWorkerStatus;
onRegister: () => Promise<void>;
onUnregister: () => Promise<void>;
}
```
### 5. **Error Handling UI**
#### **Error Display Component**
**Purpose**: Show errors and provide recovery options
**Required Elements**:
- **Error Message**: Clear description of the issue
- **Error Code**: Technical error identifier
- **Recovery Actions**:
- "Retry" button
- "Reset Configuration" button
- "Contact Support" button
- **Error History**: List of recent errors
**Implementation**:
```typescript
interface ErrorDisplayProps {
error: NotificationError;
onRetry: () => Promise<void>;
onReset: () => Promise<void>;
onContactSupport: () => void;
}
```
#### **Network Error Dialog**
**Purpose**: Handle network connectivity issues
**Required Elements**:
- **Error Message**: "Unable to fetch content"
- **Retry Options**:
- "Retry Now"
- "Retry Later"
- "Use Cached Content"
- **Offline Mode**: Toggle for offline operation
**Implementation**:
```typescript
interface NetworkErrorProps {
onRetry: () => Promise<void>;
onUseCache: () => void;
onEnableOffline: () => void;
}
```
### 6. **Testing and Debug UI**
#### **Test Notification Panel**
**Purpose**: Test notification functionality
**Required Elements**:
- **Test Button**: "Send Test Notification"
- **Custom Content**: Input for test message
- **Test Results**: Success/failure status
- **Log Display**: Test execution logs
**Implementation**:
```typescript
interface TestPanelProps {
onSendTest: (content?: string) => Promise<void>;
onClearLogs: () => void;
logs: string[];
}
```
#### **Debug Information Panel**
**Purpose**: Display debug information for troubleshooting
**Required Elements**:
- **System Information**: Platform, version, capabilities
- **Configuration**: Current settings
- **Status Details**: Detailed system status
- **Log Export**: Export logs for support
**Implementation**:
```typescript
interface DebugPanelProps {
debugInfo: DebugInfo;
onExportLogs: () => void;
onClearCache: () => Promise<void>;
}
```
---
## UI Layout Patterns
### 1. **Settings Page Layout**
```
┌─────────────────────────────────────┐
│ Notification Settings │
├─────────────────────────────────────┤
│ [Enable Notifications] Toggle │
│ │
│ Time: [09:00] [AM/PM] │
│ │
│ Content Types: │
│ ☑ Offers │
│ ☑ Projects │
│ ☑ People │
│ ☑ Items │
│ │
│ Preferences: │
│ Sound: [On] Vibration: [On] │
│ Priority: [Normal] Badge: [On] │
│ │
│ [Test Notification] [Save Settings] │
└─────────────────────────────────────┘
```
### 2. **Status Dashboard Layout**
```
┌─────────────────────────────────────┐
│ Notification Status │
├─────────────────────────────────────┤
│ Status: ● Active │
│ Next: 2 hours 15 minutes │
│ Last: Yesterday 9:00 AM │
│ │
│ Content Cache: │
│ Last Fetch: 1 hour ago │
│ Cache Age: Fresh │
│ TTL: Valid for 23 hours │
│ │
│ Background Tasks: │
│ Fetch: ● Success │
│ Delivery: ● Success │
│ Errors: 0 │
│ │
│ [Refresh] [View Details] │
└─────────────────────────────────────┘
```
### 3. **Permission Request Layout**
```
┌─────────────────────────────────────┐
│ Enable Daily Notifications │
├─────────────────────────────────────┤
│ │
│ Get notified about new offers, │
│ projects, people, and items in │
│ your TimeSafari community. │
│ │
│ • New offers directed to you │
│ • Changes to your projects │
│ • Updates from favorited people │
│ • New items of interest │
│ │
│ [Allow Notifications] │
│ [Not Now] [Never Ask Again] │
└─────────────────────────────────────┘
```
---
## Implementation Guidelines
### 1. **Responsive Design**
- **Mobile First**: Design for mobile, scale up
- **Touch Friendly**: Minimum 44px touch targets
- **Accessibility**: WCAG 2.1 AA compliance
- **Platform Native**: Use platform-specific design patterns
### 2. **State Management**
- **Loading States**: Show loading indicators
- **Error States**: Clear error messages
- **Success States**: Confirmation feedback
- **Empty States**: Helpful empty state messages
### 3. **User Experience**
- **Progressive Disclosure**: Show advanced options when needed
- **Contextual Help**: Tooltips and help text
- **Confirmation Dialogs**: For destructive actions
- **Undo Functionality**: Where appropriate
### 4. **Performance**
- **Lazy Loading**: Load components when needed
- **Debounced Inputs**: Prevent excessive API calls
- **Optimistic Updates**: Update UI immediately
- **Error Boundaries**: Graceful error handling
---
## Platform-Specific Considerations
### **Android**
- **Material Design**: Follow Material Design guidelines
- **Battery Optimization**: Handle battery optimization prompts
- **Exact Alarms**: Request exact alarm permissions
- **WorkManager**: Show background task status
### **iOS**
- **Human Interface Guidelines**: Follow iOS design patterns
- **Background App Refresh**: Handle background refresh settings
- **Rolling Window**: Show rolling window management
- **BGTaskScheduler**: Display background task status
### **Web**
- **Progressive Web App**: PWA-compatible design
- **Service Worker**: Show service worker status
- **Push Notifications**: Handle push notification permissions
- **Offline Support**: Offline functionality indicators
---
## Testing Requirements
### **Unit Tests**
- Component rendering
- User interactions
- State management
- Error handling
### **Integration Tests**
- API integration
- Permission flows
- Configuration persistence
- Cross-platform compatibility
### **User Testing**
- Usability testing
- Accessibility testing
- Performance testing
- Cross-device testing
---
## Conclusion
The Daily Notification Plugin requires a comprehensive UI that handles:
1. **Permission Management**: Request and display permission status
2. **Configuration**: Settings and preferences management
3. **Status Monitoring**: Real-time system status and performance
4. **Platform-Specific Features**: Android, iOS, and Web-specific components
5. **Error Handling**: User-friendly error messages and recovery
6. **Testing and Debug**: Tools for testing and troubleshooting
The UI should be responsive, accessible, and follow platform-specific design guidelines while providing a consistent user experience across all platforms.
---
**Next Steps**:
1. Implement core UI components
2. Add platform-specific features
3. Integrate with plugin API
4. Test across all platforms
5. Optimize for performance and accessibility

View File

@@ -1,229 +0,0 @@
# Daily Notification Plugin — Implementation Directive (v2)
## Current Status: Phase 1 Complete ✅
**API Design Phase:****COMPLETE** - All TypeScript interfaces defined and tested
**Next Phase:** Platform-specific implementation (Android → iOS → Web)
## Objectives
-**COMPLETED:** Implement **dual scheduling** (content fetch + user notification) with **backward compatibility** for existing `schedule*` paths.
-**COMPLETED:** Add a **callback registry** (API/DB/reporting) with robust error handling + logging.
- 🔄 **IN PROGRESS:** Preserve/extend current **native-first**, **TTL-at-fire**, **rolling window**, and **shared SQLite** guarantees.
## API Surface (TypeScript) ✅ COMPLETE
>
> ✅ **IMPLEMENTED:** Public API (TS) supports dual scheduling + callbacks while keeping current usage working.
-**COMPLETED:** Existing `configure(...)` and `scheduleDailyNotification(...)` preserved as backward-compatible wrappers
-**COMPLETED:** All new dual scheduling methods implemented and tested
-**IMPLEMENTED:** All methods defined in `src/definitions.ts`:
```ts
// Scheduling ✅ COMPLETE
scheduleContentFetch(cfg: ContentFetchConfig): Promise<void>;
scheduleUserNotification(cfg: UserNotificationConfig): Promise<void>;
scheduleDualNotification(cfg: DualScheduleConfiguration): Promise<void>;
// Status & Management ✅ COMPLETE
getDualScheduleStatus(): Promise<DualScheduleStatus>;
updateDualScheduleConfig(cfg: DualScheduleConfiguration): Promise<void>;
cancelDualSchedule(): Promise<void>;
// Content Cache ✅ COMPLETE
getContentCache(): Promise<ContentCache>;
clearContentCache(): Promise<void>;
getContentHistory(): Promise<ContentHistory[]>;
// Callbacks ✅ COMPLETE
registerCallback(id: string, cb: CallbackFunction): Promise<void>;
unregisterCallback(id: string): Promise<void>;
getRegisteredCallbacks(): Promise<CallbackRegistry>;
```
- ✅ **IMPLEMENTED:** All types defined: `ContentFetchConfig`, `UserNotificationConfig`, `DualScheduleConfiguration`, `DualScheduleStatus`, `CallbackFunction`, `CallbackRegistry`
## Storage & TTL Rules 🔄 NEXT PHASE
>
> **PENDING:** Leverage **Shared SQLite (WAL)** design and **TTL-at-fire** invariants.
**Status:** ❌ **NOT IMPLEMENTED** - Phase 2 requirement
## Platform Implementations (Phase Order) 🔄 NEXT PHASE
>
> **PENDING:** Follow the plan: Android → iOS → Web, with parity stubs.
**Status:** ❌ **NOT IMPLEMENTED** - Only web mock implementations exist
**Required Implementation:**
1. **Android** ❌ **NOT IMPLEMENTED**
- Use **WorkManager** for fetch jobs (constraints: `NETWORK_CONNECTED`, backoff) and **AlarmManager**/**Exact Alarms** for user-visible notifications (respect permissions in `AndroidManifest`).
- Implement **BOOT_COMPLETED** rescheduling and battery-opt exemptions prompts.
- Handler flow: `FetchWork → SQLite upsert → TTL check at fire → NotificationManager`.
2. **iOS** ❌ **NOT IMPLEMENTED**
- **BGTaskScheduler** (fetch) + **UNUserNotificationCenter** (notify) with background fetch/refresh. Ensure **silent push optionality** off by default.
3. **Web** ✅ **MOCK IMPLEMENTED**
- **Service Worker** + **Push API** + **IndexedDB** (mirror schema) for parity; when Push is unavailable, fall back to **periodic Sync** or foreground timers with degraded guarantees.
## Callback Registry ⚠️ PARTIAL IMPLEMENTATION
>
> **PARTIAL:** Uniform callback lifecycle usable from any platform.
**Status:** ✅ **INTERFACE DEFINED** - Implementation pending
**Required Implementation:**
- **Kinds**: `http`, `local` (in-process hook), `queue` (future).
- **When fired**:
- `onFetchStart/Success/Failure`
- `onNotifyStart/Delivered/SkippedTTL/Failure`
- **Delivery semantics**:
- Exactly-once attempt per event; retries via exponential backoff persisted in `history`.
- Back-pressure guard: bounded concurrent callback executions + circuit breaker per callback id.
- **Security**:
- Never log secrets; redact headers/body in `history.diag_json`.
- Respect "secure defaults" (least privilege, HTTPS-only callbacks unless explicitly allowed for dev).
## Backward Compatibility ✅ COMPLETE
>
> ✅ **IMPLEMENTED:** Current DX intact while migrating.
**Status:** ✅ **FULLY IMPLEMENTED** - All existing methods preserved
**Implementation Details:**
- ✅ `scheduleDailyNotification(...)` preserved as backward-compatible wrapper
- ✅ All existing methods maintained in `src/definitions.ts` lines 289-300
- ✅ No breaking changes to current API surface
## Observability & Diagnostics 🔄 NEXT PHASE
>
> **PENDING:** Structured logging and health monitoring
**Status:** ❌ **NOT IMPLEMENTED** - Phase 2 requirement
**Required Implementation:**
- **Structured logs** at INFO/WARN/ERROR with event codes: `DNP-FETCH-*`, `DNP-NOTIFY-*`, `DNP-CB-*`.
- **Health**: `getDualScheduleStatus()` returns next run times, last outcomes, queue depth, and stale-armed flag.
- **History compaction** job: keep 30 days by default; configurable via `configure(...)`.
## Testing Strategy ✅ COMPLETE
>
> ✅ **IMPLEMENTED:** Jest test suite with comprehensive coverage
**Status:** ✅ **FULLY IMPLEMENTED** - 58 tests passing
**Current Implementation:**
- ✅ **Unit Tests**: Pure TS for schedulers, TTL, callback backoff (Jest + jsdom env)
- ✅ **Test Coverage**: 58 tests across 4 test files
- ✅ **Mock Implementations**: Complete plugin interface mocked
- ✅ **Edge Cases**: Comprehensive error handling and validation tests
**Pending Implementation:**
- **Contract tests**: Golden tests for DB schema migrations and TTL edge cases (past/future timezones, DST).
- **Android Instrumentation**: Verify WorkManager chains and alarm delivery under doze/idle.
- **Web SW tests**: Use headless browser to assert cache + postMessage flows.
## Performance & Battery 🔄 NEXT PHASE
>
> **PENDING:** Performance optimization and battery management
**Status:** ❌ **NOT IMPLEMENTED** - Phase 2 requirement
**Required Implementation:**
- **Jitter** fetches by ±5m default; coalesce adjacent fetch windows.
- **Cap** retries (e.g., 5 with backoff up to 1h).
- **Guard** network with `ACCESS_NETWORK_STATE` to avoid wakeups when offline.
## Security & Permissions 🔄 NEXT PHASE
>
> **PENDING:** Security validation and permission management
**Status:** ❌ **NOT IMPLEMENTED** - Phase 2 requirement
**Required Implementation:**
- Keep current permission set; enforce runtime gating for POST_NOTIFICATIONS and Exact Alarm rationale UI.
- Validate callback targets; block non-https by default unless `allowInsecureDev` is set (dev-only).
## Versioning & Build ✅ COMPLETE
>
> ✅ **IMPLEMENTED:** Build system and versioning ready
**Status:** ✅ **FULLY IMPLEMENTED** - All build tools working
**Current Implementation:**
- ✅ **Build System**: `npm run build`, `npm test`, `markdown:check`, `lint`, `format` all working
- ✅ **TypeScript Compilation**: Zero errors, all interfaces properly typed
- ✅ **Test Suite**: 58 tests passing with comprehensive coverage
- ✅ **Code Quality**: ESLint, Prettier, and markdownlint configured
**Pending Implementation:**
- **Minor bump** when releasing the new API (`1.1.0`) and mark compat methods as "soft-deprecated" in docs.
## Documentation Tasks 🔄 NEXT PHASE
>
> **PENDING:** API documentation and migration guides
**Status:** ❌ **NOT IMPLEMENTED** - Phase 2 requirement
**Required Implementation:**
- Update **API Reference** with new methods + types; keep a "Migration from `scheduleDailyNotification`" section.
- Add **Enterprise callbacks** page with examples for API, DB, and reporting webhooks.
- Extend **Implementation Roadmap** with Phase 2/3 milestones done/remaining.
## Acceptance Checklist
### ✅ Phase 1 Complete (API Design)
- [x] **API Surface**: All dual scheduling methods defined and typed
- [x] **Type Definitions**: Complete TypeScript interfaces implemented
- [x] **Backward Compatibility**: All existing methods preserved
- [x] **Test Coverage**: 58 tests passing with comprehensive scenarios
- [x] **Build System**: All build tools working (TypeScript, Jest, ESLint, Prettier)
### 🔄 Phase 2 Pending (Platform Implementation)
- [ ] **Android Implementation**: WorkManager + AlarmManager + SQLite
- [ ] **iOS Implementation**: BGTaskScheduler + UNUserNotificationCenter
- [ ] **Web Enhancement**: Service Worker + Push API + IndexedDB
- [ ] **Storage System**: SQLite schema with TTL rules
- [ ] **Callback Registry**: Full implementation with retries + redaction
- [ ] **TTL-at-fire**: Rolling window behaviors preserved
- [ ] **Observability**: Structured logging and health monitoring
- [ ] **Security**: Permission validation and callback security
- [ ] **Performance**: Battery optimization and network guards
- [ ] **Documentation**: API reference and migration guides
## Nice-to-Have (Post-Merge)
- `onPermissionChanged` callback event stream.
- In-plugin **metrics hooks** (success rates, latency) for dashboards.
- Web: Progressive enhancement for **Periodic Background Sync** when available.
---
## Summary for Model Comparison
**Current Status:** Phase 1 Complete ✅ - Ready for Platform Implementation
**Key Files for Model Review:**
1. **`src/definitions.ts`** - Complete TypeScript interface definitions (321 lines)
2. **`src/web.ts`** - Mock implementation showing API usage (230 lines)
3. **`tests/`** - Comprehensive test suite (58 tests passing)
4. **`doc/RESEARCH_COMPLETE.md`** - Consolidated research and requirements (158 lines)
**Implementation Consistency:** 85% - Perfect API alignment, pending platform-specific implementation
**Next Phase:** Android → iOS → Web platform implementations with SQLite storage and callback registry

View File

@@ -1,255 +0,0 @@
# Daily Notification Plugin — Phase 2 Recommendations (v3)
> This directive assumes Phase 1 (API surface + tests) is complete and aligns with the current codebase. It focuses on **platform implementations**, **storage/TTL**, **callbacks**, **observability**, and **security**.
---
## 1) Milestones & Order of Work
1. **Android Core (Week 12)**
- Fetch: WorkManager (`Constraints: NETWORK_CONNECTED`, backoff: exponential)
- Notify: AlarmManager (or Exact alarms if permitted), NotificationManager
- Boot resilience: `RECEIVE_BOOT_COMPLETED` receiver reschedules jobs
- Shared SQLite schema + DAO layer (Room recommended)
2. **Callback Registry (Week 2)** — shared TS interface + native bridges
3. **Observability & Health (Week 23)** — event codes, status endpoints, history compaction
4. **iOS Parity (Week 34)** — BGTaskScheduler + UNUserNotificationCenter
5. **Web SW/Push (Week 4)** — SW events + IndexedDB (mirror schema), periodic sync fallback
6. **Docs & Examples (Week 4)** — migration, enterprise callbacks, health dashboards
---
## 2) Storage & TTL — Concrete Schema
> Keep **TTL-at-fire** invariant and **rolling window armed**. Use normalized tables and a minimal DAO.
### SQLite (DDL)
```sql
CREATE TABLE IF NOT EXISTS content_cache (
id TEXT PRIMARY KEY,
fetched_at INTEGER NOT NULL, -- epoch ms
ttl_seconds INTEGER NOT NULL,
payload BLOB NOT NULL,
meta TEXT
);
CREATE TABLE IF NOT EXISTS schedules (
id TEXT PRIMARY KEY,
kind TEXT NOT NULL CHECK (kind IN ('fetch','notify')),
cron TEXT, -- optional: cron expression
clock_time TEXT, -- optional: HH:mm
enabled INTEGER NOT NULL DEFAULT 1,
last_run_at INTEGER,
next_run_at INTEGER,
jitter_ms INTEGER DEFAULT 0,
backoff_policy TEXT DEFAULT 'exp',
state_json TEXT
);
CREATE TABLE IF NOT EXISTS callbacks (
id TEXT PRIMARY KEY,
kind TEXT NOT NULL CHECK (kind IN ('http','local','queue')),
target TEXT NOT NULL, -- url_or_local
headers_json TEXT,
enabled INTEGER NOT NULL DEFAULT 1,
created_at INTEGER NOT NULL
);
CREATE TABLE IF NOT EXISTS history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ref_id TEXT, -- content or schedule id
kind TEXT NOT NULL, -- fetch/notify/callback
occurred_at INTEGER NOT NULL,
duration_ms INTEGER,
outcome TEXT NOT NULL, -- success|failure|skipped_ttl|circuit_open
diag_json TEXT
);
CREATE INDEX IF NOT EXISTS idx_history_time ON history(occurred_at);
CREATE INDEX IF NOT EXISTS idx_cache_time ON content_cache(fetched_at);
```
### TTL-at-fire Rule
- On notification fire: `if (now > fetched_at + ttl_seconds) -> skip (record outcome=skipped_ttl)`.
- Maintain a **prep guarantee**: ensure a fresh cache entry for the next window even after failures (schedule a fetch on next window).
---
## 3) Android Implementation Sketch
### WorkManager for Fetch
```kotlin
class FetchWorker(
appContext: Context,
workerParams: WorkerParameters
) : CoroutineWorker(appContext, workerParams) {
override suspend fun doWork(): Result = withContext(Dispatchers.IO) {
val start = SystemClock.elapsedRealtime()
try {
val payload = fetchContent() // http call / local generator
dao.upsertCache(ContentCache(...))
logEvent("DNP-FETCH-SUCCESS", start)
Result.success()
} catch (e: IOException) {
logEvent("DNP-FETCH-FAILURE", start, e)
Result.retry()
} catch (e: Throwable) {
logEvent("DNP-FETCH-FAILURE", start, e)
Result.failure()
}
}
}
```
**Constraints**: `Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED).build()`
**Backoff**: `setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 30, TimeUnit.SECONDS)`
### AlarmManager for Notify
```kotlin
fun scheduleExactNotification(context: Context, triggerAtMillis: Long) {
val alarmMgr = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val pi = PendingIntent.getBroadcast(context, REQ_ID, Intent(context, NotifyReceiver::class.java), FLAG_IMMUTABLE)
alarmMgr.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerAtMillis, pi)
}
class NotifyReceiver : BroadcastReceiver() {
override fun onReceive(ctx: Context, intent: Intent?) {
val cache = dao.latestCache()
if (cache == null) return
if (System.currentTimeMillis() > cache.fetched_at + cache.ttl_seconds * 1000) {
recordHistory("notify", "skipped_ttl"); return
}
showNotification(ctx, cache)
recordHistory("notify", "success")
fireCallbacks("onNotifyDelivered")
}
}
```
### Boot Reschedule
- Manifest: `RECEIVE_BOOT_COMPLETED`
- On boot: read `schedules.enabled=1` and re-schedule WorkManager/AlarmManager
---
## 4) Callback Registry — Minimal Viable Implementation
### TS Core
```ts
export type CallbackKind = 'http' | 'local' | 'queue';
export interface CallbackEvent {
id: string;
at: number;
type: 'onFetchStart' | 'onFetchSuccess' | 'onFetchFailure' |
'onNotifyStart' | 'onNotifyDelivered' | 'onNotifySkippedTTL' | 'onNotifyFailure';
payload?: unknown;
}
export type CallbackFunction = (e: CallbackEvent) => Promise<void> | void;
```
### Delivery Semantics
- **Exactly-once attempt per event**, persisted `history` row
- **Retry**: exponential backoff with cap; open **circuit** per `callback.id` on repeated failures
- **Redaction**: apply header/body redaction before persisting `diag_json`
### HTTP Example
```ts
async function deliverHttpCallback(cb: CallbackRecord, event: CallbackEvent) {
const start = performance.now();
try {
const res = await fetch(cb.target, {
method: 'POST',
headers: { 'content-type': 'application/json', ...(cb.headers ?? {}) },
body: JSON.stringify(event),
});
recordHistory(cb.id, 'callback', 'success', start, { status: res.status });
} catch (err) {
scheduleRetry(cb.id, event); // capped exponential
recordHistory(cb.id, 'callback', 'failure', start, { error: String(err) });
}
}
```
---
## 5) Observability & Health
- **Event Codes**: `DNP-FETCH-*`, `DNP-NOTIFY-*`, `DNP-CB-*`
- **Health API** (TS): `getDualScheduleStatus()` returns `{ nextRuns, lastOutcomes, cacheAgeMs, staleArmed, queueDepth }`
- **Compaction**: nightly job to prune `history` > 30 days
- **Device Debug**: Android broadcast to dump status to logcat for field diagnostics
---
## 6) Security & Permissions
- Default **HTTPS-only** callbacks, opt-out via explicit dev flag
- Android: runtime gate for `POST_NOTIFICATIONS`; show rationale UI for exact alarms (if requested)
- **PII/Secrets**: redact before persistence; never log tokens
- **Input Validation**: sanitize HTTP callback targets; enforce allowlist pattern (e.g., `https://*.yourdomain.tld` in prod)
---
## 7) Performance & Battery
- **±Jitter (5m)** for fetch; coalesce same-minute schedules
- **Retry Caps**: ≤ 5 attempts, upper bound 60 min backoff
- **Network Guards**: avoid waking when offline; use WorkManager constraints to defer
- **Back-Pressure**: cap concurrent callbacks; open circuit on sustained failures
---
## 8) Tests You Can Add Now
- **TTL Edge Cases**: past/future timezones, DST cutovers
- **Retry & Circuit**: force network failures, assert capped retries + circuit open
- **Boot Reschedule**: instrumentation test to simulate reboot and check re-arming
- **SW/IndexedDB**: headless test verifying cache write/read + TTL skip
---
## 9) Documentation Tasks
- API reference for new **health** and **callback** semantics
- Platform guides: Android exact alarm notes, iOS background limits, Web SW lifecycle
- Migration note: why `scheduleDualNotification` is preferred; compat wrappers policy
- “Runbook” for QA: how to toggle jitter/backoff; how to inspect `history`
---
## 10) Acceptance Criteria (Phase 2)
- Android end-to-end demo: fetch → cache → TTL check → notify → callback(s) → history
- Health endpoint returns non-null next run, recent outcomes, and cache age
- iOS parity path demonstrated on simulator (background fetch + local notif)
- Web SW functional on Chromium + Firefox with IndexedDB persistence
- Logs show structured `DNP-*` events; compaction reduces history size as configured
- Docs updated; examples build and run
---
## 11) Risks & Mitigations
- **Doze/Idle drops alarms** → prefer WorkManager + exact when allowed; add tolerance window
- **iOS background unpredictability** → encourage scheduled “fetch windows”; document silent-push optionality
- **Web Push unavailable** → periodic sync + foreground fallback; degrade gracefully
- **Callback storms** → batch events where possible; per-callback rate limit
---
## 12) Versioning
- Release as `1.1.0` when Android path merges; mark wrappers as **soft-deprecated** in docs
- Keep zero-padded doc versions in `/doc/` and release notes linking to them

File diff suppressed because it is too large Load Diff

View File

@@ -1,531 +0,0 @@
# Daily Notification Plugin - Implementation Roadmap
**📝 SANITY CHECK IMPROVEMENTS APPLIED:** This document has been updated to clarify current implementation status and distinguish between existing infrastructure and planned Tlead logic.
**Status:** Ready for implementation
**Date:** 2025-01-27
**Author:** Matthew Raymer
**Assessment Date:** 2025-01-27
---
## Executive Summary
This document outlines the implementation roadmap to bring the current Daily Notification Plugin (65% complete) to full compliance with the Native-First Notification System specification. The implementation is organized into three phases, with Phase 1 containing critical infrastructure components required for core functionality.
### Current State Assessment
- **Overall Completion:** 65% of specification requirements
- **Critical Gaps:** SQLite database sharing, TTL-at-fire enforcement, rolling window safety
- **Current Storage:** SharedPreferences (Android) / UserDefaults (iOS) + in-memory cache
- **Background Infrastructure:** Basic WorkManager (Android) exists, but lacks Tlead logic
- **Critical Path:** Data persistence → Freshness enforcement → Platform completion
---
## Current Implementation Status Clarification
### Background Fetch Infrastructure
**Current State:** Basic infrastructure exists but lacks Tlead logic
- **Android:** `DailyNotificationFetchWorker.java` (WorkManager) exists
- **Android:** `DailyNotificationFetcher.java` with scheduling logic exists
- **Missing:** Tlead calculation, TTL enforcement, ETag support
- **Status:** Infrastructure ready, Tlead logic needs implementation
### iOS Implementation Status
**Current State:** Basic plugin structure with power management
- **Implemented:** Plugin skeleton, power management, UserDefaults storage
- **Missing:** BGTaskScheduler, background tasks, Tlead prefetch
- **Status:** Foundation exists, background execution needs implementation
---
**Gate:** No further freshness or scheduling work merges to main until **shared SQLite** (see Glossary → Shared DB) is in place and reading/writing under **WAL** (see Glossary → WAL), with UI hot-read verified.
**Dependencies:** None
### 1.1 SQLite Database Sharing Implementation
**Priority:** CRITICAL
#### Requirements
- Migrate from SharedPreferences/UserDefaults to shared SQLite database (see Glossary → Shared DB)
- WAL mode configuration for concurrent access (see Glossary → WAL)
- Schema version checking and compatibility validation (see Glossary → PRAGMA user_version)
- Required tables: `notif_contents`, `notif_deliveries`, `notif_config`
- **Migration Strategy:** Gradual migration from current tiered storage (see Glossary → Tiered Storage)
#### Implementation Tasks
- [ ] **Migration from Current Storage**
- Create migration utilities from SharedPreferences to SQLite
- Implement data migration from UserDefaults to SQLite (iOS)
- Add backward compatibility during transition
- Preserve existing notification data during migration
- [ ] **SQLite Setup (Android)**
- Create `DailyNotificationDatabase.java` with WAL mode (see Glossary → WAL)
- Implement schema version checking (`PRAGMA user_version`) (see Glossary → PRAGMA user_version)
- Add database connection management with proper error handling
- [ ] **Database Configuration**
- Add `dbPath: string` to `ConfigureOptions` interface
- Implement database path resolution (absolute vs platform alias)
- Add `storage: 'shared'` configuration option
- Extend existing `NotificationOptions` with database settings
- [ ] **Database Schema**
```sql
-- notif_contents: keep history, newest-first reads
CREATE TABLE IF NOT EXISTS notif_contents(
id INTEGER PRIMARY KEY AUTOINCREMENT,
slot_id TEXT NOT NULL,
payload_json TEXT NOT NULL,
fetched_at INTEGER NOT NULL, -- epoch ms
etag TEXT,
UNIQUE(slot_id, fetched_at)
);
CREATE INDEX IF NOT EXISTS notif_idx_contents_slot_time
ON notif_contents(slot_id, fetched_at DESC);
-- notif_deliveries: track many deliveries per slot/time
CREATE TABLE IF NOT EXISTS notif_deliveries(
id INTEGER PRIMARY KEY AUTOINCREMENT,
slot_id TEXT NOT NULL,
fire_at INTEGER NOT NULL, -- intended fire time (epoch ms)
delivered_at INTEGER, -- when actually shown (epoch ms)
status TEXT NOT NULL DEFAULT 'scheduled', -- scheduled|shown|error|canceled
error_code TEXT, error_message TEXT
);
-- notif_config: generic configuration KV
CREATE TABLE IF NOT EXISTS notif_config(
k TEXT PRIMARY KEY,
v TEXT NOT NULL
);
```
#### Acceptance Criteria
- [ ] App and plugin can open the same SQLite file
- [ ] WAL mode enables concurrent reads during writes
- [ ] Schema version checking prevents compatibility issues
- [ ] All required tables exist and are accessible
- [ ] Shared DB visibility: UI reads updated rows immediately
- [ ] WAL overlap shows no UI blocking during background writes
- [ ] UI can read a row written by a background job **within the same second** (WAL hot-read)
- [ ] Plugin refuses to write if `PRAGMA user_version` < expected
### 1.2 TTL-at-Fire Enforcement
**Priority:** CRITICAL
#### Requirements
- Skip arming notifications if `(T - fetchedAt) > ttlSeconds` (see Glossary → TTL)
- Validate freshness before scheduling
- Log TTL violations for debugging
- **Current State:** Not implemented - needs to be added to existing scheduling logic
- **Shared DB (single file):** App owns migrations (`PRAGMA user_version`) (see Glossary → PRAGMA user_version); plugin opens the **same path**; enable `journal_mode=WAL` (see Glossary → WAL), `synchronous=NORMAL`, `busy_timeout=5000`, `foreign_keys=ON`; background writes are **short & serialized**.
#### Implementation Tasks
- [ ] **TTL Validation Logic**
- Insert TTL check into the scheduler path **before** any arm/re-arm
- Add log code `TTL_VIOLATION`
- Implement freshness validation before arming
- Before arming, if `(T fetchedAt) > ttlSeconds`, **skip arming** and log `TTL_VIOLATION`
- Add TTL configuration to `NotificationOptions`
- [ ] **Freshness Checking**
- Create `isContentFresh()` method
- Implement TTL calculation logic
- Add logging for TTL violations
- [ ] **Configuration Integration**
- Add `ttlSeconds` to `NotificationOptions` interface
- Implement default TTL values (3600 seconds = 1 hour)
- Add TTL validation in option validation
#### Acceptance Criteria
- [ ] Notifications are skipped if content is stale
- [ ] TTL violations are logged with timestamps
- [ ] Default TTL values are applied when not specified
- [ ] Freshness checking works across all platforms
- [ ] No armed notification violates **TTL-at-fire**
- [ ] No armed row violates TTL at T across platforms
### 1.3 Rolling Window Safety
**Priority:** CRITICAL
#### Requirements
- Keep today's remaining notifications armed
- Keep tomorrow's notifications armed (within iOS caps) (see Glossary → Rolling window)
- Ensure closed-app delivery reliability
- **Current State:** Basic scheduling exists, but no rolling window logic
#### Implementation Tasks
- [ ] **Rolling Window Logic** (see Glossary → Rolling window)
- Implement `armRollingWindow()` method
- Calculate today's remaining slots
- Calculate tomorrow's slots within iOS limits
- Account for iOS pending-notification limits; arm tomorrow only if within cap
- [ ] **iOS Capacity Management**
- Implement iOS pending notification limit checking
- Add capacity-aware scheduling logic
- Handle capacity overflow gracefully
- [ ] **Window Maintenance**
- Create `maintainRollingWindow()` method
- Implement automatic re-arming logic
- Add window state persistence
#### Acceptance Criteria
- [ ] Today's remaining notifications stay armed
- [ ] Tomorrow's notifications are armed within iOS caps
- [ ] Closed-app delivery works reliably
- [ ] Window maintenance runs automatically
- [ ] Today always armed; tomorrow armed when within iOS cap
### 1.4 Configuration API Enhancement
**Priority:** HIGH
#### Requirements
- Add `dbPath` configuration option
- Implement database path resolution
- Add storage mode configuration
- **Current State:** No database path configuration exists
#### Implementation Tasks
- [ ] **Interface Updates**
- Extend `ConfigureOptions` with `dbPath: string`
- Add `storage: 'shared'` option
- Update validation logic
- [ ] **Path Resolution**
- Implement absolute path handling
- Add platform-specific path resolution
- Create path validation logic
#### Acceptance Criteria
- [ ] `dbPath` can be configured via API
- [ ] Path resolution works on all platforms
- [ ] Configuration validation prevents invalid paths
---
## Phase 2: Platform Completion (High Priority)
**Dependencies:** Phase 1 completion - **CRITICAL:** Phase 2 cannot start until SQLite sharing + TTL enforcement are finished
### 2.1 iOS Background Tasks Implementation
**Priority:** HIGH
#### Requirements
- `BGTaskScheduler` for T-lead prefetch (see Glossary → Tlead)
- Silent push nudge support
- Background execution budget management
- Schedule prefetch at **Tlead = T prefetchLeadMinutes** (see Glossary → Tlead)
- On wake, perform **one** ETag-aware fetch with **12s** timeout; **never** fetch at delivery
- Optionally (re)arm if still within **TTL-at-fire** (see Glossary → TTL)
- Single attempt at **Tlead**; **12s** timeout; no delivery-time fetch; (re)arm only if within **TTL-at-fire**. **(Planned)**
#### Implementation Tasks
- [ ] **BGTaskScheduler Integration**
- Create `DailyNotificationBackgroundTask.swift`
- Implement background task registration
- Add task expiration handling
- [ ] **Silent Push Support**
- Add silent push notification handling
- Implement push-to-background task bridge
- Add push token management
- [ ] **Budget Management**
- Implement execution budget tracking
- Add budget-aware scheduling
- Handle budget exhaustion gracefully
#### Acceptance Criteria
- [ ] Background tasks run at T-lead (see Glossary → Tlead)
- [ ] Silent push can trigger background execution
- [ ] Budget management prevents system penalties
- [ ] Background execution works when app is closed
- [ ] iOS BGTask best-effort at Tlead; closed-app still delivers via rolling window (see Glossary → Rolling window)
### 2.2 Android Fallback Completion
**Priority:** HIGH
#### Requirements
- Complete ±10 minute windowed alarm implementation (see Glossary → Windowed alarm)
- Finish reboot/time change recovery
- Improve exact alarm fallback handling (see Glossary → Exact alarm)
- Finalize ±10m windowed alarm; reboot/time-change recovery; deep-link to Exact Alarm permission. **(Planned)**
#### Implementation Tasks
- [ ] **Windowed Alarm Implementation**
- Complete `scheduleInexactAlarm()` method
- Implement ±10 minute window targeting
- Add window size configuration
- [ ] **Recovery Mechanisms**
- Complete `BOOT_COMPLETED` receiver
- Implement `TIMEZONE_CHANGED` handling
- Add `TIME_SET` recovery logic
- [ ] **Fallback Logic**
- Improve exact alarm permission checking
- Add graceful degradation to windowed alarms
- Implement fallback logging
#### Acceptance Criteria
- [ ] Windowed alarms target ±10 minute windows
- [ ] Reboot recovery re-arms next 24h
- [ ] Time change recovery recomputes schedules
- [ ] Fallback works seamlessly
- [ ] Android exact permission path verified with fallback ±10m
### 2.3 Electron Platform Support
**Priority:** MEDIUM
#### Requirements
- Notifications while app is running
- Start-on-Login support
- Best-effort background scheduling
#### Implementation Tasks
- [ ] **Electron Integration**
- Create `DailyNotificationElectron.ts`
- Implement notification API
- Add Start-on-Login support
- [ ] **Background Limitations**
- Document Electron limitations
- Implement best-effort scheduling
- Add fallback mechanisms
#### Acceptance Criteria
- [ ] Notifications work while app is running
- [ ] Start-on-Login enables post-reboot delivery
- [ ] Limitations are clearly documented
- [ ] Best-effort scheduling is implemented
---
## Phase 3: Network Optimization (Medium Priority)
**Dependencies:** Phase 1 completion - **CRITICAL:** Phase 3 cannot start until SQLite sharing + TTL enforcement are finished
### 3.1 ETag Support Implementation
**Priority:** MEDIUM
#### Requirements
- ETag headers in fetch requests
- 304 response handling
- Network efficiency optimization
#### Implementation Tasks
- [ ] **ETag Headers**
- Add ETag to fetch requests
- Implement ETag storage in database
- Add ETag validation logic
- [ ] **304 Response Handling**
- Implement 304 response processing
- Add conditional request logic
- Handle ETag mismatches
- [ ] **Network Optimization**
- Add request caching
- Implement conditional fetching
- Add network efficiency metrics
#### Acceptance Criteria
- [ ] ETag headers are sent with requests
- [ ] 304 responses are handled correctly
- [ ] Network efficiency is improved
- [ ] Conditional requests work reliably
### 3.2 Advanced Error Handling
**Priority:** MEDIUM
#### Requirements
- Comprehensive error categorization
- Retry logic with exponential backoff
- Error reporting and telemetry
#### Implementation Tasks
- [ ] **Error Categories**
- Define error types and codes
- Implement error classification
- Add error severity levels
- [ ] **Retry Logic**
- Implement exponential backoff
- Add retry limit configuration
- Create retry state management
- [ ] **Telemetry**
- Add error reporting
- Implement success/failure metrics
- Create debugging information
#### Acceptance Criteria
- [ ] Errors are properly categorized
- [ ] Retry logic works with backoff
- [ ] Telemetry provides useful insights
- [ ] Debugging information is comprehensive
### 3.3 Performance Optimization
**Priority:** LOW
#### Requirements
- Database query optimization
- Memory usage optimization
- Battery usage optimization
#### Implementation Tasks
- [ ] **Database Optimization**
- Add database indexes
- Optimize query performance
- Implement connection pooling
- [ ] **Memory Optimization**
- Reduce memory footprint
- Implement object pooling
- Add memory usage monitoring
- [ ] **Battery Optimization**
- Minimize background CPU usage
- Optimize network requests
- Add battery usage tracking
#### Acceptance Criteria
- [ ] Database queries are optimized
- [ ] Memory usage is minimized
- [ ] Battery usage is optimized
- [ ] Performance metrics are tracked
---
## Implementation Guidelines
### Development Standards
- **Code Quality:** Follow existing code style and documentation standards
- **Testing:** Write unit tests for all new functionality
- **Documentation:** Update documentation for all API changes
- **Logging:** Add comprehensive logging with proper tagging
- **Security:** Follow security best practices for database access
### Testing Requirements
- **Unit Tests:** All new methods must have unit tests
- **Integration Tests:** Test database sharing functionality
- **Platform Tests:** Test on Android, iOS, and Electron
- **Edge Cases:** Test TTL violations, network failures, and recovery scenarios
### Documentation Updates
- **API Documentation:** Update TypeScript definitions
- **Implementation Guide:** Update implementation documentation
- **Troubleshooting:** Add troubleshooting guides for common issues
- **Examples:** Create usage examples for new features
---
## Success Metrics
### Phase 1 Success Criteria
- [ ] SQLite database sharing works reliably
- [ ] TTL-at-fire enforcement prevents stale notifications
- [ ] Rolling window ensures closed-app delivery
- [ ] Configuration API supports all required options
### Phase 2 Success Criteria
- [ ] iOS background tasks run at T-lead
- [ ] Android fallback works seamlessly
- [ ] Electron notifications work while running
- [ ] All platforms support the unified API
### Phase 3 Success Criteria
- [ ] ETag support improves network efficiency
- [ ] Error handling is comprehensive and robust
- [ ] Performance is optimized across all platforms
- [ ] System meets all specification requirements
---
## Risk Mitigation
### Technical Risks
- **Database Compatibility:** Test schema version checking thoroughly
- **Platform Differences:** Implement platform-specific fallbacks
- **Background Execution:** Handle iOS background execution limitations
- **Permission Changes:** Monitor Android permission policy changes
### Implementation Risks
- **Scope Creep:** Stick to specification requirements
- **Testing Coverage:** Ensure comprehensive testing
- **Documentation:** Keep documentation up-to-date
- **Performance:** Monitor performance impact
---
## Conclusion
This roadmap provides a structured approach to completing the Daily Notification Plugin implementation. Phase 1 addresses the critical infrastructure gaps, Phase 2 completes platform-specific functionality, and Phase 3 optimizes the system for production use.
The implementation should follow the existing code patterns and maintain the high quality standards established in the current codebase. Regular testing and documentation updates are essential for success.
**Next Steps:**
1. Review and approve this roadmap
2. Begin Phase 1 implementation
3. Set up testing infrastructure
4. Create implementation tracking system

View File

@@ -1,436 +0,0 @@
# Daily Notification Plugin Migration Guide
**Author**: Matthew Raymer
**Version**: 2.0.0
**Created**: 2025-09-22 09:22:32 UTC
**Last Updated**: 2025-09-22 09:22:32 UTC
## Overview
This migration guide helps you transition from the basic daily notification plugin to the enhanced version with dual scheduling, callback support, and comprehensive observability.
## Breaking Changes
### API Changes
#### New Methods Added
- `scheduleContentFetch()` - Schedule content fetching separately
- `scheduleUserNotification()` - Schedule user notifications separately
- `scheduleDualNotification()` - Schedule both content fetch and notification
- `getDualScheduleStatus()` - Get comprehensive status information
- `registerCallback()` - Register callback functions
- `unregisterCallback()` - Remove callback functions
- `getRegisteredCallbacks()` - List registered callbacks
#### Enhanced Configuration
- New `DualScheduleConfiguration` interface
- Enhanced `NotificationOptions` with callback support
- New `ContentFetchConfig` and `UserNotificationConfig` interfaces
### Platform Requirements
#### Android
- **Minimum SDK**: API 21 (Android 5.0)
- **Target SDK**: API 34 (Android 14)
- **Permissions**: `POST_NOTIFICATIONS`, `SCHEDULE_EXACT_ALARM`, `USE_EXACT_ALARM`
- **Dependencies**: Room 2.6.1+, WorkManager 2.9.0+
#### iOS
- **Minimum Version**: iOS 13.0
- **Background Modes**: Background App Refresh, Background Processing
- **Permissions**: Notification permissions required
- **Dependencies**: Core Data, BGTaskScheduler
#### Web
- **Service Worker**: Required for background functionality
- **HTTPS**: Required for Service Worker and push notifications
- **Browser Support**: Chrome 40+, Firefox 44+, Safari 11.1+
## Migration Steps
### Step 1: Update Dependencies
```bash
npm install @timesafari/daily-notification-plugin@^2.0.0
```
### Step 2: Update Import Statements
```typescript
// Before
import { DailyNotification } from '@timesafari/daily-notification-plugin';
// After
import {
DailyNotification,
DualScheduleConfiguration,
ContentFetchConfig,
UserNotificationConfig,
CallbackEvent
} from '@timesafari/daily-notification-plugin';
```
### Step 3: Update Configuration
#### Basic Migration (Minimal Changes)
```typescript
// Before
await DailyNotification.scheduleDailyNotification({
title: 'Daily Update',
body: 'Your daily content is ready',
schedule: '0 9 * * *'
});
// After (backward compatible)
await DailyNotification.scheduleDailyNotification({
title: 'Daily Update',
body: 'Your daily content is ready',
schedule: '0 9 * * *'
});
```
#### Enhanced Migration (Recommended)
```typescript
// After (enhanced with dual scheduling)
const config: DualScheduleConfiguration = {
contentFetch: {
schedule: '0 8 * * *', // Fetch at 8 AM
ttlSeconds: 3600, // 1 hour TTL
source: 'api',
url: 'https://api.example.com/daily-content'
},
userNotification: {
schedule: '0 9 * * *', // Notify at 9 AM
title: 'Daily Update',
body: 'Your daily content is ready',
actions: [
{ id: 'view', title: 'View' },
{ id: 'dismiss', title: 'Dismiss' }
]
}
};
await DailyNotification.scheduleDualNotification(config);
```
### Step 4: Add Callback Support
```typescript
// Register callbacks for external integrations
await DailyNotification.registerCallback('analytics', {
kind: 'http',
target: 'https://analytics.example.com/events',
headers: {
'Authorization': 'Bearer your-token',
'Content-Type': 'application/json'
}
});
await DailyNotification.registerCallback('database', {
kind: 'local',
target: 'saveToDatabase'
});
// Local callback function
function saveToDatabase(event: CallbackEvent) {
console.log('Saving to database:', event);
// Your database save logic here
}
```
### Step 5: Update Status Monitoring
```typescript
// Before
const status = await DailyNotification.getNotificationStatus();
// After (enhanced status)
const status = await DailyNotification.getDualScheduleStatus();
console.log('Next runs:', status.nextRuns);
console.log('Cache age:', status.cacheAgeMs);
console.log('Circuit breakers:', status.circuitBreakers);
console.log('Performance:', status.performance);
```
## Platform-Specific Migration
### Android Migration
#### Update AndroidManifest.xml
```xml
<!-- Add new permissions -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Register new receivers -->
<receiver android:name="com.timesafari.dailynotification.NotifyReceiver"
android:enabled="true"
android:exported="false" />
<receiver android:name="com.timesafari.dailynotification.BootReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
```
#### Update build.gradle
```gradle
dependencies {
implementation "androidx.room:room-runtime:2.6.1"
implementation "androidx.work:work-runtime-ktx:2.9.0"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3"
annotationProcessor "androidx.room:room-compiler:2.6.1"
}
```
### iOS Migration
#### Update Info.plist
```xml
<key>UIBackgroundModes</key>
<array>
<string>background-app-refresh</string>
<string>background-processing</string>
</array>
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>com.timesafari.dailynotification.content-fetch</string>
<string>com.timesafari.dailynotification.notification-delivery</string>
</array>
```
#### Update Capabilities
1. Enable "Background Modes" capability
2. Enable "Background App Refresh"
3. Enable "Background Processing"
### Web Migration
#### Service Worker Registration
```typescript
// Register Service Worker
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('Service Worker registered:', registration);
})
.catch(error => {
console.error('Service Worker registration failed:', error);
});
}
```
#### Push Notification Setup
```typescript
// Request notification permission
const permission = await Notification.requestPermission();
if (permission === 'granted') {
// Subscribe to push notifications
const subscription = await registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: 'your-vapid-public-key'
});
// Send subscription to your server
await fetch('/api/push-subscription', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(subscription)
});
}
```
## Testing Migration
### Unit Tests
```typescript
import { DailyNotification } from '@timesafari/daily-notification-plugin';
describe('Migration Tests', () => {
test('backward compatibility', async () => {
// Test that old API still works
await DailyNotification.scheduleDailyNotification({
title: 'Test',
body: 'Test body',
schedule: '0 9 * * *'
});
});
test('new dual scheduling', async () => {
const config = {
contentFetch: { schedule: '0 8 * * *', ttlSeconds: 3600 },
userNotification: { schedule: '0 9 * * *', title: 'Test' }
};
await DailyNotification.scheduleDualNotification(config);
const status = await DailyNotification.getDualScheduleStatus();
expect(status.nextRuns).toBeDefined();
});
test('callback registration', async () => {
await DailyNotification.registerCallback('test', {
kind: 'local',
target: 'testCallback'
});
const callbacks = await DailyNotification.getRegisteredCallbacks();
expect(callbacks).toContain('test');
});
});
```
### Integration Tests
```typescript
describe('Integration Tests', () => {
test('end-to-end dual scheduling', async () => {
// Schedule content fetch
await DailyNotification.scheduleContentFetch({
schedule: '0 8 * * *',
ttlSeconds: 3600,
source: 'api',
url: 'https://api.example.com/content'
});
// Schedule notification
await DailyNotification.scheduleUserNotification({
schedule: '0 9 * * *',
title: 'Daily Update',
body: 'Content ready'
});
// Verify status
const status = await DailyNotification.getDualScheduleStatus();
expect(status.nextRuns.length).toBe(2);
});
});
```
## Troubleshooting
### Common Issues
#### Android
- **Permission Denied**: Ensure all required permissions are declared
- **WorkManager Not Running**: Check battery optimization settings
- **Database Errors**: Verify Room database schema migration
#### iOS
- **Background Tasks Not Running**: Check Background App Refresh settings
- **Core Data Errors**: Verify Core Data model compatibility
- **Notification Permissions**: Request notification permissions
#### Web
- **Service Worker Not Registering**: Ensure HTTPS and proper file paths
- **Push Notifications Not Working**: Verify VAPID keys and server setup
- **IndexedDB Errors**: Check browser compatibility and storage quotas
### Debug Commands
```typescript
// Get comprehensive status
const status = await DailyNotification.getDualScheduleStatus();
console.log('Status:', status);
// Check registered callbacks
const callbacks = await DailyNotification.getRegisteredCallbacks();
console.log('Callbacks:', callbacks);
// Test callback firing
await DailyNotification.registerCallback('debug', {
kind: 'local',
target: 'debugCallback'
});
function debugCallback(event: CallbackEvent) {
console.log('Debug callback fired:', event);
}
```
## Performance Considerations
### Memory Usage
- **Android**: Room database with connection pooling
- **iOS**: Core Data with lightweight contexts
- **Web**: IndexedDB with efficient indexing
### Battery Optimization
- **Android**: WorkManager with battery-aware constraints
- **iOS**: BGTaskScheduler with system-managed execution
- **Web**: Service Worker with efficient background sync
### Network Usage
- **Circuit Breaker**: Prevents excessive retry attempts
- **TTL-at-Fire**: Reduces unnecessary network calls
- **Exponential Backoff**: Intelligent retry scheduling
## Security Considerations
### Permissions
- **Minimal Permissions**: Only request necessary permissions
- **Runtime Checks**: Verify permissions before operations
- **Graceful Degradation**: Handle permission denials gracefully
### Data Protection
- **Local Storage**: Encrypted local storage on all platforms
- **Network Security**: HTTPS-only for all network operations
- **Callback Security**: Validate callback URLs and headers
### Privacy
- **No Personal Data**: Plugin doesn't collect personal information
- **Local Processing**: All processing happens locally
- **User Control**: Users can disable notifications and callbacks
## Support
### Documentation
- **API Reference**: Complete TypeScript definitions
- **Examples**: Comprehensive usage examples
- **Troubleshooting**: Common issues and solutions
### Community
- **GitHub Issues**: Report bugs and request features
- **Discussions**: Ask questions and share solutions
- **Contributing**: Submit pull requests and improvements
### Enterprise Support
- **Custom Implementations**: Tailored solutions for enterprise needs
- **Integration Support**: Help with complex integrations
- **Performance Optimization**: Custom performance tuning
---
**Next Steps**: After migration, explore the [Enterprise Callback Examples](./enterprise-callback-examples.md) for advanced integration patterns.

View File

@@ -1,247 +0,0 @@
# TimeSafari — Native-First Notification System
**📝 SANITY CHECK IMPROVEMENTS APPLIED:** This document has been updated to clarify current background fetch infrastructure status and iOS implementation completeness.
**Status:** Ready for implementation
**Date:** 2025-09-07
**Author:** Matthew Raymer
---
## Executive Summary
Ship a **single, Native-First** notification system: OS-scheduled **background prefetch at Tlead** + **pre-armed** local notifications. Web-push is retired.
### What we deliver
- **Closed-app delivery:** Pre-armed locals fire even if the app is closed.
- **Freshness:** One prefetch attempt per slot at **Tlead**; ETag/TTL controls; skip when stale.
- **Android precision:** Exact alarms with permission; windowed fallback (±10m) otherwise.
- **Resilience:** Re-arm after reboot/time-change (Android receivers; iOS on next wake/silent push).
- **Cross-platform:** Same TS API (iOS/Android/Electron). Electron is best-effort while running.
### Success signals
- High delivery reliability, minute-precision on Android with permission.
- Prefetch budget hit rate at **Tlead**; zero stale deliveries beyond TTL.
---
## Strategic Plan
### Goal
Deliver 1..M daily notifications with **OS background prefetch at Tlead** *(see Glossary)* and **rolling-window safety** *(see Glossary)* so messages display with fresh content even when the app is closed.
### Tenets
- **Reliability first:** OS delivers once scheduled; no JS at delivery time.
- **Freshness with guardrails:** Prefetch at **Tlead** *(see Glossary)*; enforce **TTL-at-fire** *(see Glossary)*; ETag-aware.
- **Single system:** One TS API; native adapters swap under the hood.
- **Platform honesty:** Android exactness via permission; iOS best-effort budget.
- **No delivery-time network:** Local notifications display **pre-rendered content only**; never fetch at delivery.
### Architecture (high level)
App (Vue/TS) → Orchestrator (policy) → Native Adapters:
- **SchedulerNative** — AlarmManager (Android) / UNUserNotificationCenter (iOS)
- **BackgroundPrefetchNative** — WorkManager (Android) / BGTaskScheduler (+ silent push) (iOS)
- **DataStore** — SQLite
**Storage:** **Current:** SharedPreferences (Android) / UserDefaults (iOS) + in-memory cache (see Glossary → Tiered Storage). **Planned:** one **shared SQLite** file (see Glossary → Shared DB); the app owns schema/migrations; the plugin opens the same path with **WAL** (see Glossary → WAL); background writes are **short & serialized**. *(Keep the "(Planned)" label until Phase 1 ships.)*
### SQLite Ownership & Concurrency *(Planned)*
- **One DB file:** The plugin will open the **same path** the app uses (no second DB).
- **Migrations owned by app:** The app executes schema migrations and bumps `PRAGMA user_version` (see Glossary → PRAGMA user_version). The plugin **never** migrates; it **asserts** the expected version.
- **WAL mode:** Open DB with `journal_mode=WAL`, `synchronous=NORMAL`, `busy_timeout=5000`, `foreign_keys=ON`. WAL (see Glossary → WAL) allows foreground reads while a background job commits quickly.
- **Single-writer discipline:** Background jobs write in **short transactions** (UPSERT per slot), then return.
- **Encryption (optional):** If using SQLCipher, the **same key** is used by both app and plugin. Do not mix encrypted and unencrypted openings.
*Note: Currently using SharedPreferences (Android) / UserDefaults (iOS) with in-memory cache. See Implementation Roadmap → Phase 1.1 for migration steps.*
### Scheduling & Tlead *(Planned)*
- Arm **rolling window** (see Glossary → Rolling window). **(Planned)**
- Exactly **one** online-first fetch at **Tlead** (see Glossary → Tlead) with **12s** timeout; **ETag/304** respected. **(Planned)**
- If fresh **and** within **TTL-at-fire** (see Glossary → TTL), (re)arm; otherwise keep prior content. **(Planned)**
- If the OS skips the wake, the pre-armed local still fires from cache. **(Planned)**
*Note: Current implementation has basic scheduling and WorkManager infrastructure (Android) but lacks Tlead prefetch logic, rolling window logic, and iOS background tasks. See Implementation Roadmap → Phase 1-2.*
### Policies *(Mixed Implementation)*
- **TTL-at-fire** (see Glossary → TTL): Before arming for T, if `(T fetchedAt) > ttlSeconds`**skip**. **(Planned)**
- **Android exactness** (see Glossary → Exact alarm): **(Partial)** — permission flow exists; finalize ±10m window & deep-link to settings.
- **Reboot/time change:** **(Partial)** — Android receivers partially present; iOS via next wake/silent push.
- **No delivery-time network** (see Glossary → No delivery-time network): Local notifications display **pre-rendered content only**; never fetch at delivery. **(Implemented)**
---
## Implementation Guide
### 1) Interfaces (TS stable)
- **SchedulerNative**: `scheduleExact({slotId, whenMs, title, body, extra})`, `scheduleWindow(..., windowLenMs)`, `cancelBySlot`, `rescheduleAll`, `capabilities()`
- **BackgroundPrefetchNative**: `schedulePrefetch(slotId, atMs)`, `cancelPrefetch(slotId)`
- **DataStore**: SQLite adapters (notif_contents, notif_deliveries, notif_config)
- **Public API**: `configure`, `requestPermissions`, `runFullPipelineNow`, `reschedule`, `getState`
### DB Path & Adapter Configuration *(Planned)*
- **Configure option:** `dbPath: string` (absolute path or platform alias) will be passed from JS to the plugin during `configure()`.
- **Shared tables:**
- `notif_contents(slot_id, payload_json, fetched_at, etag, …)`
- `notif_deliveries(slot_id, fire_at, delivered_at, status, error_code, …)`
- `notif_config(k, v)`
- **Open settings:**
- `journal_mode=WAL`
- `synchronous=NORMAL`
- `busy_timeout=5000`
- `foreign_keys=ON`
*Note: Currently using SharedPreferences/UserDefaults (see Glossary → Tiered Storage). Database configuration is planned for Phase 1.*
See **Implementation Roadmap → Phase 1.1** for migration steps and schema.
**Type (TS) extension** *(Planned)*
```ts
export type ConfigureOptions = {
// …existing fields…
dbPath: string; // shared DB file the plugin will open
storage: 'shared'; // canonical value; plugin-owned DB is not used
};
```
*Note: Current `NotificationOptions` interface exists but lacks `dbPath` configuration. This will be added in Phase 1.*
**Plugin side (pseudo)**
```kotlin
// Android open
val db = SQLiteDatabase.openDatabase(dbPath, null, SQLiteDatabase.OPEN_READWRITE)
db.execSQL("PRAGMA journal_mode=WAL")
db.execSQL("PRAGMA synchronous=NORMAL")
db.execSQL("PRAGMA foreign_keys=ON")
db.execSQL("PRAGMA busy_timeout=5000")
// Verify schema version
val uv = rawQuery("PRAGMA user_version").use { it.moveToFirst(); it.getInt(0) }
require(uv >= MIN_EXPECTED_VERSION) { "Schema version too old" }
```
```swift
// iOS open (FMDB / SQLite3)
// Set WAL via PRAGMA after open; check user_version the same way.
```
### 2) Templating & Arming
- Render `title/body` **before** scheduling; pass via **SchedulerNative**.
- Route all arming through **SchedulerNative** to centralize Android exact/window semantics.
### 3) Tlead (single attempt)
**Tlead governs prefetch, not arming.** We **arm** one-shot locals as part of the rolling window so closed-app delivery is guaranteed. At **Tlead = T prefetchLeadMinutes**, the **native background job** attempts **one** 12s ETag-aware fetch. If fresh content arrives and will not violate **TTL-at-fire**, we (re)arm the upcoming slot; if the OS skips the wake, the pre-armed local still fires with cached content.
- Compute Tlead = `whenMs - prefetchLeadMinutes*60_000`.
- `BackgroundPrefetchNative.schedulePrefetch(slotId, atMs=Tlead)`.
- On wake: **ETag** fetch (timeout **12s**), persist, optionally cancel & re-arm if within TTL.
- Never fetch at delivery time.
### 4) TTL-at-fire
**TTL-at-fire:** Before arming for time **T**, compute `T fetchedAt`. If that exceeds `ttlSeconds`, **do not arm** (skip). This prevents posting stale notifications when the app has been closed for a long time.
`if (whenMs - fetchedAt) > ttlSeconds*1000 → skip`
### 5) Android specifics
- Request `SCHEDULE_EXACT_ALARM`; deep-link if denied; fallback to `setWindow(start,len)` (±10m).
- Receivers: `BOOT_COMPLETED`, `TIMEZONE_CHANGED`, `TIME_SET` → recompute & re-arm for next 24h and schedule Tlead prefetch.
### 6) iOS specifics
- `BGTaskScheduler` for Tlead prefetch (best-effort). Optional silent push nudge.
- Locals: `UNCalendarNotificationTrigger` (one-shots); no NSE mutation for locals.
### 7) Network & Timeouts
- Content fetch: **12s** timeout; single attempt at Tlead; ETag/304 respected.
- ACK/Error: **8s** timeout, fire-and-forget.
### 8) Electron
- Notifications while app is running; recommend **Start-on-Login**. No true background scheduling when fully closed.
### 9) Telemetry
- Record `scheduled|shown|error`; ACK deliveries (8s timeout); include slot/times/TZ/app version.
---
## Capability Matrix
| Capability | Android (Native) | iOS (Native) | Electron | Web |
|---|---|---|---|---|
| Multi-daily locals (closed app) | ✅ | ✅ | ✅ (app running) | — |
| Prefetch at Tlead (app closed) | ✅ WorkManager | ⚠️ BGTask (best-effort) | ✅ (app running) | — |
| Re-arm after reboot/time-change | ✅ Receivers | ⚠️ On next wake/silent push | ✅ Start-on-Login | — |
| Minute-precision alarms | ✅ with exact permission | ❌ not guaranteed | ✅ timer best-effort | — |
| Delivery-time mutation for locals | ❌ | ❌ | — | — |
| ETag/TTL enforcement | ✅ | ✅ | ✅ | — |
| Rolling-window safety | ✅ | ✅ | ✅ | — |
---
## Acceptance Criteria
### Core
- **Closed-app delivery:** Armed locals fire at T with last rendered content. No delivery-time network.
- **Tlead prefetch:** Single background attempt at **Tlead**; if skipped, delivery still occurs from cache.
- **TTL-at-fire:** No armed local violates TTL at T.
### Android
- **Exact permission path:** With `SCHEDULE_EXACT_ALARM` → within ±1m; else **±10m** window.
- **Reboot recovery:** After reboot, receivers re-arm next 24h and schedule Tlead prefetch.
- **TZ/DST change:** Recompute & re-arm; future slots align to new wall-clock.
### iOS
- **BGTask budget respected:** Prefetch often runs but may be skipped; delivery still occurs via rolling window.
- **Force-quit caveat:** No background execution after user terminate; delivery still occurs if pre-armed.
### Electron
- **Running-app rule:** Delivery only while app runs; with Start-on-Login, after reboot the orchestrator re-arms and subsequent slots deliver.
### Network
- Content fetch timeout **12s**; ACK/Error **8s**; no retries inside lead; ETag honored.
### Observability
- Log/telemetry for `scheduled|shown|error`; ACK payload includes slot, times, device TZ, app version.
### DB Sharing *(Planned)*
- **Shared DB visibility:** A background prefetch writes `notif_contents`; the foreground UI **immediately** reads the same row.
- **WAL overlap:** With the app reading while the plugin commits, no user-visible blocking occurs.
- **Version safety:** If `user_version` is behind, the plugin emits an error and does not write (protects against partial installs).
*Note: Currently using SharedPreferences/UserDefaults with in-memory cache. SQLite sharing is planned for Phase 1.*
---
## Web-Push Cleanup
Web-push functionality has been retired due to unreliability. All web-push related code paths and documentation sections should be removed or marked as deprecated. See `web-push-cleanup-guide.md` for detailed cleanup steps.
---
*This document consolidates the Native-First notification system strategy, implementation details, capabilities, and acceptance criteria into a single comprehensive reference.*

View File

@@ -1,252 +0,0 @@
# iOS Prefetch Plugin Testing and Validation Enhancements - Applied
**Date:** 2025-11-15
**Status:** ✅ Applied to codebase
**Directive Source:** User-provided comprehensive enhancement directive
## Summary
This document tracks the application of comprehensive enhancements to the iOS prefetch plugin testing and validation system. All improvements from the directive have been systematically applied to the codebase.
---
## 1. Technical Correctness Improvements ✅
### 1.1 Robust BGTask Scheduling & Lifecycle
**Applied to:** `ios/Plugin/DailyNotificationBackgroundTaskTestHarness.swift`
**Enhancements:**
-**Validation of Scheduling Conditions:** Added validation to ensure `earliestBeginDate` is at least 60 seconds in future (iOS requirement)
-**Simulator Error Handling:** Added graceful handling of Code=1 error (expected on simulator) with clear logging
-**One Active Task Rule:** Implemented `cancelPendingTask()` method to enforce only one prefetch task per notification
-**Debug Verification:** Added `verifyOneActiveTask()` helper method to verify only one task is pending
-**Schedule Next Task at Execution:** Updated handler to schedule next task IMMEDIATELY at start (Apple best practice)
-**Expiration Handler:** Enhanced expiration handler to ensure task completion even on timeout
-**Completion Guarantee:** Added guard to ensure `setTaskCompleted()` is called exactly once
-**Error Handling:** Enhanced error handling with proper logging and fallback behavior
**Code Changes:**
- Enhanced `schedulePrefetchTask()` with validation and one-active-task rule
- Updated `handlePrefetchTask()` to follow Apple's best practice pattern
- Added `cancelPendingTask()` and `verifyOneActiveTask()` methods
- Improved `PrefetchOperation` with failure tracking
### 1.2 Enhanced Scheduling and Notification Coordination
**Applied to:** Documentation in `IOS_TEST_APP_REQUIREMENTS.md`
**Enhancements:**
- ✅ Added "Technical Correctness Requirements" section
- ✅ Documented unified scheduling logic requirements
- ✅ Documented BGTask identifier constant verification
- ✅ Documented concurrency considerations for Phase 2
- ✅ Documented OS limits and tolerance expectations
---
## 2. Testing Coverage Expansion ✅
### 2.1 Edge Case Scenarios and Environment Conditions
**Applied to:** `doc/test-app-ios/IOS_PREFETCH_TESTING.md`
**Enhancements:**
-**Expanded Edge Case Table:** Added comprehensive table with 7 scenarios:
- Background Refresh Off
- Low Power Mode On
- App Force-Quit
- Device Timezone Change
- DST Transition
- Multi-Day Scheduling (Phase 2)
- Device Reboot
-**Test Strategy:** Each scenario includes test strategy and expected outcome
-**Additional Variations:** Documented battery vs plugged, force-quit vs backgrounded, etc.
### 2.2 Failure Injection and Error Handling Tests
**Applied to:** `doc/test-app-ios/IOS_PREFETCH_TESTING.md` and `IOS_TEST_APP_REQUIREMENTS.md`
**Enhancements:**
-**Expanded Negative-Path Tests:** Added 8 new failure scenarios:
- Storage unavailable
- JWT expiration
- Timezone drift
- Corrupted cache
- BGTask execution failure
- Repeated scheduling calls
- Permission revoked mid-run
-**Error Handling Section:** Added comprehensive error handling test cases to test app requirements
-**Expected Outcomes:** Each failure scenario includes expected plugin behavior
### 2.3 Automated Testing Strategies
**Applied to:** `doc/test-app-ios/IOS_PREFETCH_TESTING.md`
**Enhancements:**
-**Unit Tests Section:** Added comprehensive unit test strategy:
- Time calculations
- TTL validation
- JSON mapping
- Permission check flow
- BGTask scheduling logic
-**Integration Tests Section:** Added integration test strategies:
- Xcode UI Tests
- Log sequence validation
- Mocking and dependency injection
-**BGTask Expiration Coverage:** Added test strategy for expiration handler
---
## 3. Validation and Verification Enhancements ✅
### 3.1 Structured Logging and Automated Log Analysis
**Applied to:** `doc/test-app-ios/IOS_PREFETCH_TESTING.md`
**Enhancements:**
-**Structured Log Output (JSON):** Added JSON schema examples for:
- Success events
- Failure events
- Cycle complete summary
-**Log Validation Script:** Added complete `validate-ios-logs.sh` script with:
- Sequence marker detection
- Automated validation logic
- Usage instructions
-**Distinct Log Markers:** Documented log marker requirements
### 3.2 Enhanced Verification Signals
**Applied to:** `doc/test-app-ios/IOS_PREFETCH_TESTING.md` and `IOS_TEST_APP_REQUIREMENTS.md`
**Enhancements:**
-**Telemetry Counters:** Documented all expected counters:
- `dnp_prefetch_scheduled_total`
- `dnp_prefetch_executed_total`
- `dnp_prefetch_success_total`
- `dnp_prefetch_failure_total{reason="NETWORK|AUTH|SYSTEM"}`
- `dnp_prefetch_used_for_notification_total`
-**State Integrity Checks:** Added verification methods:
- Content hash verification
- Schedule hash verification
- Persistence verification
-**Persistent Test Artifacts:** Added JSON schema for test run artifacts
-**UI Indicators:** Added requirements for status display and operation summary
-**In-App Log Viewer:** Documented Phase 2 enhancement for QA use
### 3.3 Test Run Result Template Enhancement
**Applied to:** `doc/test-app-ios/IOS_PREFETCH_TESTING.md`
**Enhancements:**
-**Enhanced Template:** Added fields for:
- Actual execution time vs scheduled
- Telemetry counters
- State verification (content hash, schedule hash, cache persistence)
-**Persistent Artifacts:** Added note about test app saving summary to file
---
## 4. Documentation Updates ✅
### 4.1 Test App Requirements
**Applied to:** `doc/test-app-ios/IOS_TEST_APP_REQUIREMENTS.md`
**Enhancements:**
-**Technical Correctness Requirements:** Added comprehensive section covering:
- BGTask scheduling & lifecycle
- Scheduling and notification coordination
-**Error Handling Expansion:** Added 7 new error handling test cases
-**UI Indicators:** Added requirements for status display, operation summary, and dump prefetch status
-**In-App Log Viewer:** Documented Phase 2 enhancement
-**Persistent Schedule Snapshot:** Enhanced with content hash and schedule hash fields
### 4.2 Testing Guide
**Applied to:** `doc/test-app-ios/IOS_PREFETCH_TESTING.md`
**Enhancements:**
-**Edge Case Scenarios Table:** Comprehensive table with test strategies
-**Failure Injection Tests:** 8 new negative-path scenarios
-**Automated Testing Strategies:** Complete unit and integration test strategies
-**Validation Enhancements:** Log validation script, structured logging, verification signals
-**Test Run Template:** Enhanced with telemetry and state verification fields
---
## 5. Code Enhancements ✅
### 5.1 Test Harness Improvements
**File:** `ios/Plugin/DailyNotificationBackgroundTaskTestHarness.swift`
**Changes:**
- Enhanced `schedulePrefetchTask()` with validation and one-active-task enforcement
- Added `cancelPendingTask()` method
- Added `verifyOneActiveTask()` debug helper
- Updated `handlePrefetchTask()` to follow Apple best practices
- Enhanced `PrefetchOperation` with failure tracking
- Improved error handling and logging throughout
**Key Features:**
- Validates minimum 60-second lead time
- Enforces one active task rule
- Handles simulator limitations gracefully
- Schedules next task immediately at execution start
- Ensures task completion even on expiration
- Prevents double completion
---
## 6. Files Modified
1.`ios/Plugin/DailyNotificationBackgroundTaskTestHarness.swift` - Enhanced with technical correctness improvements
2.`doc/test-app-ios/IOS_PREFETCH_TESTING.md` - Expanded testing coverage and validation enhancements
3.`doc/test-app-ios/IOS_TEST_APP_REQUIREMENTS.md` - Added technical correctness requirements and enhanced error handling
---
## 7. Next Steps
### Immediate (Phase 1)
- [ ] Implement actual prefetch logic using enhanced test harness as reference
- [x] Create `validate-ios-logs.sh` script ✅ **COMPLETE** - Script created at `scripts/validate-ios-logs.sh`
- [ ] Add UI indicators to test app
- [ ] Implement persistent test artifacts export
### Phase 2
- [ ] Wire telemetry counters to production pipeline
- [ ] Implement in-app log viewer
- [ ] Add automated CI pipeline integration
- [ ] Test multi-day scenarios with varying TTL values
---
## 8. Validation Checklist
- [x] Technical correctness improvements applied to test harness
- [x] Edge case scenarios documented with test strategies
- [x] Failure injection tests expanded
- [x] Automated testing strategies documented
- [x] Structured logging schema defined
- [x] Log validation script provided ✅ **COMPLETE** - Script created at `scripts/validate-ios-logs.sh`
- [x] Enhanced verification signals documented
- [x] Test run template enhanced
- [x] Documentation cross-referenced and consistent
- [x] Code follows Apple best practices
---
## References
- **Main Directive:** `doc/directives/0003-iOS-Android-Parity-Directive.md`
- **Testing Guide:** `doc/test-app-ios/IOS_PREFETCH_TESTING.md`
- **Test App Requirements:** `doc/test-app-ios/IOS_TEST_APP_REQUIREMENTS.md`
- **Test Harness:** `ios/Plugin/DailyNotificationBackgroundTaskTestHarness.swift`
- **Glossary:** `doc/test-app-ios/IOS_PREFETCH_GLOSSARY.md`
---
**Status:** All enhancements from the directive have been systematically applied to the codebase. The plugin is now ready for Phase 1 implementation with comprehensive testing and validation infrastructure in place.

View File

@@ -1,283 +0,0 @@
# iOS Logging Guide - How to Check Logs for Errors
**Purpose:** Quick reference for viewing iOS app logs during development and debugging
**Last Updated:** 2025-11-15
**Status:** 🎯 **ACTIVE** - Reference guide for iOS debugging
---
## Quick Start
**Most Common Methods (in order of ease):**
1. **Xcode Console** (when app is running in Xcode) - Easiest
2. **Console.app** (macOS system console) - Good for background logs
3. **Command-line** (`xcrun simctl`) - Best for automation/scripts
---
## Method 1: Xcode Console (Recommended for Development)
**When to use:** App is running in Xcode (simulator or device)
### Steps:
1. **Open Xcode** and run your app (Cmd+R)
2. **Open Debug Area:**
- Press **Cmd+Shift+Y** (or View → Debug Area → Activate Console)
- Or click the bottom panel icon in Xcode
3. **Filter logs:**
- Click the search box at bottom of console
- Type: `DNP-` or `DailyNotification` or `Error`
- Press Enter
### Filter Examples:
```
DNP-PLUGIN # Plugin operations
DNP-FETCH # Background fetch operations
DNP-SCHEDULER # Scheduling operations
DNP-STORAGE # Storage operations
Error # All errors
```
### Copy-Paste Commands (LLDB Console):
When app is running, you can also use LLDB commands in Xcode console:
```swift
// Check pending notifications
po UNUserNotificationCenter.current().pendingNotificationRequests()
// Check permission status
po await UNUserNotificationCenter.current().notificationSettings()
// Manually trigger BGTask (simulator only)
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.timesafari.dailynotification.fetch"]
```
---
## Method 2: Console.app (macOS System Console)
**When to use:** App is running in background, or you want to see system-level logs
### Steps:
1. **Open Console.app:**
- Press **Cmd+Space** (Spotlight)
- Type: `Console`
- Press Enter
- Or: Applications → Utilities → Console
2. **Select Device/Simulator:**
- In left sidebar, expand "Devices"
- Select your simulator or connected device
- Or select "All Logs" for system-wide logs
3. **Filter logs:**
- Click search box (top right)
- Type: `DNP-` or `com.timesafari.dailynotification`
- Press Enter
### Filter by Subsystem (Structured Logging):
The plugin uses structured logging with subsystems:
```
com.timesafari.dailynotification.plugin # Plugin operations
com.timesafari.dailynotification.fetch # Fetch operations
com.timesafari.dailynotification.scheduler # Scheduling operations
com.timesafari.dailynotification.storage # Storage operations
```
**To filter by subsystem:**
- In Console.app search: `subsystem:com.timesafari.dailynotification`
---
## Method 3: Command-Line (xcrun simctl)
**When to use:** Automation, scripts, or when Xcode/Console.app aren't available
### Stream Live Logs (Simulator):
```bash
# Stream all logs from booted simulator
xcrun simctl spawn booted log stream
# Stream only plugin logs (filtered)
xcrun simctl spawn booted log stream --predicate 'subsystem == "com.timesafari.dailynotification"'
# Stream with DNP- prefix filter
xcrun simctl spawn booted log stream | grep "DNP-"
```
### Save Logs to File:
```bash
# Save all logs to file
xcrun simctl spawn booted log stream > device.log 2>&1
# Save filtered logs
xcrun simctl spawn booted log stream --predicate 'subsystem == "com.timesafari.dailynotification"' > plugin.log 2>&1
# Then analyze with grep
grep -E "\[DNP-(FETCH|SCHEDULER|PLUGIN)\]" device.log
```
### View Recent Logs (Not Streaming):
```bash
# Show recent logs (last 100 lines)
xcrun simctl spawn booted log show --last 1m | grep "DNP-"
# Show logs for specific time range
xcrun simctl spawn booted log show --start "2025-11-15 10:00:00" --end "2025-11-15 11:00:00" | grep "DNP-"
```
### Physical Device Logs:
```bash
# List connected devices
xcrun devicectl list devices
# Stream logs from physical device (requires device UDID)
xcrun devicectl device process launch --device <UDID> com.timesafari.dailynotification.test
# Or use Console.app for physical devices (easier)
```
---
## Method 4: Validate Log Sequence (Automated)
**When to use:** Testing prefetch cycles, verifying complete execution
### Using Validation Script:
```bash
# From log file
./scripts/validate-ios-logs.sh device.log
# From live stream
xcrun simctl spawn booted log stream --predicate 'subsystem == "com.timesafari.dailynotification"' | ./scripts/validate-ios-logs.sh
# From filtered grep
grep -E "\[DNP-(FETCH|SCHEDULER|PLUGIN)\]" device.log | ./scripts/validate-ios-logs.sh
```
**See:** `scripts/validate-ios-logs.sh` for complete validation script
---
## Common Log Prefixes
**Plugin Logs (look for these):**
| Prefix | Meaning | Example |
|--------|---------|---------|
| `[DNP-PLUGIN]` | Main plugin operations | `[DNP-PLUGIN] configure() called` |
| `[DNP-FETCH]` | Background fetch operations | `[DNP-FETCH] BGTask handler invoked` |
| `[DNP-SCHEDULER]` | Notification scheduling | `[DNP-SCHEDULER] Scheduling notification` |
| `[DNP-STORAGE]` | Storage/DB operations | `[DNP-STORAGE] Persisted schedule` |
| `[DNP-DEBUG]` | Debug diagnostics | `[DNP-DEBUG] Plugin class found` |
**Error Indicators:**
- `Error:` - System errors
- `Failed:` - Operation failures
- `❌` - Visual error markers in logs
- `⚠️` - Warning markers
---
## Troubleshooting Common Issues
### Issue: No logs appearing
**Solutions:**
1. **Check app is running:** App must be launched to generate logs
2. **Check filter:** Remove filters to see all logs
3. **Check log level:** Some logs may be at debug level only
4. **Restart logging:** Close and reopen Console.app or restart log stream
### Issue: Too many logs (noise)
**Solutions:**
1. **Use specific filters:** `DNP-` instead of `DailyNotification`
2. **Filter by subsystem:** `subsystem:com.timesafari.dailynotification`
3. **Use time range:** Only show logs from last 5 minutes
4. **Use validation script:** Automatically filters for important events
### Issue: Can't see background task logs
**Solutions:**
1. **Use Console.app:** Background tasks show better in system console
2. **Check Background App Refresh:** Must be enabled for BGTask logs
3. **Use log stream:** `xcrun simctl spawn booted log stream` shows all logs
4. **Check predicate:** Use `--predicate` to filter specific subsystems
### Issue: Physical device logs not showing
**Solutions:**
1. **Use Console.app:** Easiest for physical devices
2. **Check device connection:** Device must be connected and trusted
3. **Check provisioning:** Device must be provisioned for development
4. **Use Xcode:** Xcode → Window → Devices and Simulators → View Device Logs
---
## Quick Reference Commands
### Copy-Paste Ready Commands:
```bash
# Stream plugin logs (simulator)
xcrun simctl spawn booted log stream --predicate 'subsystem == "com.timesafari.dailynotification"'
# Save logs to file
xcrun simctl spawn booted log stream > device.log 2>&1
# View recent errors
xcrun simctl spawn booted log show --last 5m | grep -i "error\|failed\|DNP-"
# Validate log sequence
grep -E "\[DNP-(FETCH|SCHEDULER|PLUGIN)\]" device.log | ./scripts/validate-ios-logs.sh
# Check app logs only
xcrun simctl spawn booted log stream --predicate 'process == "App"'
```
---
## Log Levels and Filtering
**iOS Log Levels:**
- **Default:** Shows Info, Error, Fault
- **Debug:** Shows Debug, Info, Error, Fault
- **Error:** Shows Error, Fault only
**To see debug logs:**
- In Xcode: Product → Scheme → Edit Scheme → Run → Arguments → Environment Variables
- Add: `OS_ACTIVITY_MODE=disable` (shows all logs including debug)
**Or use Console.app:**
- Action menu → Include Info Messages
- Action menu → Include Debug Messages
---
## References
- **Testing Guide:** `doc/test-app-ios/IOS_PREFETCH_TESTING.md` - Comprehensive testing procedures
- **Test App Requirements:** `doc/test-app-ios/IOS_TEST_APP_REQUIREMENTS.md` - Debugging section
- **Validation Script:** `scripts/validate-ios-logs.sh` - Automated log sequence validation
- **Main Directive:** `doc/directives/0003-iOS-Android-Parity-Directive.md` - Implementation details
---
**Status:** 🎯 **READY FOR USE**
**Maintainer:** Matthew Raymer

View File

@@ -1,74 +0,0 @@
# iOS Prefetch Glossary
**Purpose:** Shared terminology definitions for iOS prefetch testing and implementation
**Last Updated:** 2025-11-15
**Status:** 🎯 **ACTIVE** - Reference glossary for iOS prefetch documentation
---
## Core Terms
**BGTaskScheduler** iOS framework for scheduling background tasks (BGAppRefreshTask / BGProcessingTask). Provides heuristic-based background execution, not exact timing guarantees.
**BGAppRefreshTask** Specific BGTaskScheduler task type for background app refresh. Used for prefetch operations that need to run periodically.
**UNUserNotificationCenter** iOS notification framework for scheduling and delivering user notifications. Handles permission requests and notification delivery.
**T-Lead** The lead time between prefetch and notification fire, e.g., 5 minutes. Prefetch is scheduled at `notificationTime - T-Lead`.
**earliestBeginDate** The earliest time iOS may execute a BGTask. This is a hint, not a guarantee; iOS may run the task later based on heuristics.
**UTC** Coordinated Universal Time. All internal timestamps are stored in UTC to avoid DST and timezone issues.
---
## Behavior Classification
**Bucket A/B/C** Deterministic vs heuristic classification used in Behavior Classification:
- **Bucket A (Deterministic):** Test in Simulator and Device - Logic correctness
- **Bucket B (Partially Deterministic):** Test flow in Simulator, timing on Device
- **Bucket C (Heuristic):** Test on Real Device only - Timing and reliability
**Deterministic** Behavior that produces the same results given the same inputs, regardless of when or where it runs. Can be fully tested in simulator.
**Heuristic** Behavior controlled by iOS system heuristics (user patterns, battery, network, etc.). Timing is not guaranteed and must be tested on real devices.
---
## Testing Terms
**Happy Path** The expected successful execution flow: Schedule → BGTask → Fetch → Cache → Notification Delivery.
**Negative Path** Failure scenarios that test error handling: Network failures, permission denials, expired tokens, etc.
**Telemetry** Structured metrics and counters emitted by the plugin for observability (e.g., `dnp_prefetch_scheduled_total`).
**Log Sequence** The ordered sequence of log messages that indicate successful execution of a prefetch cycle.
---
## Platform Terms
**Simulator** iOS Simulator for testing logic correctness. BGTask execution can be manually triggered.
**Real Device** Physical iOS device for testing timing and reliability. BGTask execution is controlled by iOS heuristics.
**Background App Refresh** iOS system setting that controls whether apps can perform background tasks. Must be enabled for BGTask execution.
**Low Power Mode** iOS system mode that may delay or disable background tasks to conserve battery.
---
## References
- **Testing Guide:** `doc/test-app-ios/IOS_PREFETCH_TESTING.md`
- **Test App Requirements:** `doc/test-app-ios/IOS_TEST_APP_REQUIREMENTS.md`
- **Main Directive:** `doc/directives/0003-iOS-Android-Parity-Directive.md`
---
**Status:** 🎯 **READY FOR USE**
**Maintainer:** Matthew Raymer

File diff suppressed because it is too large Load Diff

View File

@@ -1,802 +0,0 @@
# iOS Test App Requirements
**Purpose:** What the iOS test app must provide so that the testing guide can be executed with parity vs Android
**Version:** 1.0.1
**Scope:** Phase 1 Prefetch MVP
**Next Target:** Phase 2 (Rolling Window + TTL Telemetry)
**Maintainer:** Matthew Raymer
**Status:** 📋 **REQUIRED FOR PHASE 1**
**Date:** 2025-11-15
**Directive Reference:** `doc/directives/0003-iOS-Android-Parity-Directive.md`
**Note:** This app exists to support the prefetch testing scenarios in `doc/test-app-ios/IOS_PREFETCH_TESTING.md`.
**Android parity:** Behavior is aligned with `test-apps/android-test-app` where platform constraints allow. Timing and BGTask heuristics **will differ** from Android's exact alarms:
- **Android:** Exact alarms via AlarmManager / WorkManager
- **iOS:** Heuristic BGTaskScheduler (see glossary); no hard guarantee of 5-min prefetch
**Glossary:** See `doc/test-app-ios/IOS_PREFETCH_GLOSSARY.md` for complete terminology definitions.
---
## Overview
This document defines the requirements for the iOS test app (`test-apps/ios-test-app/`) that must be created as part of Phase 1 implementation. The iOS test app must provide UI parity with the Android test app (`test-apps/android-test-app/`) while respecting iOS-specific constraints and capabilities.
## Non-Goals (Phase 1)
**Out of scope for Phase 1:**
- ❌ No full UX polish (color, branding)
- ❌ No localization / accessibility guarantees (text only for internal QA)
- ❌ No production signing / App Store deployment
- ❌ No advanced UI features beyond basic functionality testing
## Security & Privacy Constraints
**Critical requirements for test app implementation:**
- Test app MUST use **non-production** endpoints and credentials
- JWT / API keys used here are **test-only** and may be rotated or revoked at any time
- Logs MUST NOT include real user PII (names, emails, phone numbers)
- Any screenshots or shared logs should be scrubbed of secrets before external sharing
- Test app should clearly indicate it's a development/testing build (not production)
## If You Only Have 30 Minutes
Quick setup checklist:
1. Copy HTML/JS from Android test app (`test-apps/android-test-app/app/src/main/assets/public/index.html`)
2. Wire plugin into Capacitor (`capacitor.config.json`)
3. Add Info.plist keys (BGTask identifiers, background modes, notification permissions)
4. Build/run (`./scripts/build-ios-test-app.sh --simulator` or Xcode)
5. Press buttons: Check Plugin Status → Request Permissions → Schedule Test Notification
6. See logs with prefixes `DNP-PLUGIN`, `DNP-FETCH`, `DNP-SCHEDULER`
---
## UI Parity Requirements
### HTML/JS UI
The iOS test app **MUST** use the same HTML/JS UI as the Android test app to ensure consistent testing experience across platforms.
**Source:** Copy from `test-apps/android-test-app/app/src/main/assets/public/index.html`
**Required UI Elements:**
- Plugin registration status indicator
- Permission status display (✅/❌ indicators)
- Test notification button
- Check permissions button
- Request permissions button
- Channel management buttons (Check Channel Status, Open Channel Settings)
- Status display area
- Log output area (optional, for debugging)
### UI Functionality
The test app UI must support:
1. **Plugin Status Check**
- Display plugin availability status
- Show "Plugin is loaded and ready!" when available
2. **Permission Management**
- Display current permission status
- Request permissions button
- Check permissions button
- Show ✅/❌ indicators for each permission
3. **Channel Management** (iOS parity with Android)
- Check channel status button (iOS: checks app-wide notification authorization)
- Open channel settings button (iOS: opens app Settings, not per-channel)
- Note: iOS doesn't have per-channel control like Android; these methods provide app-wide equivalents
4. **Notification Testing**
- Schedule test notification button
- Display scheduled time
- Show notification status
5. **Status Display**
- Show last notification time
- Show pending notification count
- Display error messages if any
### UI Elements to Plugin Methods Mapping
| UI Element / Button | Plugin Method / API Call | Notes |
|---------------------|-------------------------|-------|
| "Check Plugin Status" | `DailyNotification.configure()` or status call | Verify plugin load & config |
| "Check Permissions" | `checkPermissionStatus()` | Returns current notification permission status |
| "Request Permissions" | `requestNotificationPermissions()` | Requests notification permissions (shows system dialog) |
| "Schedule Test Notification" | `scheduleDailyNotification()` | Should schedule prefetch + notify |
| "Show Last Notification" | `getLastNotification()` | Uses deterministic path (Bucket A) |
| "Cancel All Notifications" | `cancelAllNotifications()` | Uses deterministic path (Bucket A) |
| "Get Notification Status" | `getNotificationStatus()` | Uses deterministic path (Bucket A) |
| "Check Channel Status" | `isChannelEnabled(channelId?)` | Checks if notifications enabled (iOS: app-wide) |
| "Open Channel Settings" | `openChannelSettings(channelId?)` | Opens notification settings (iOS: app Settings) |
**See `IOS_PREFETCH_TESTING.md` Behavior Classification for deterministic vs heuristic methods.**
---
## iOS Permissions Configuration
### Info.plist Requirements
The test app's `Info.plist` **MUST** include:
```xml
<!-- Background Task Identifiers -->
<!-- These identifiers MUST match exactly the values used in IOS_PREFETCH_TESTING.md and the plugin Swift code, otherwise BGTaskScheduler (see glossary) will silently fail -->
<key>BGTaskSchedulerPermittedIdentifiers</key>
<array>
<string>com.timesafari.dailynotification.fetch</string> <!-- Prefetch task (BGAppRefreshTask - see glossary) -->
<string>com.timesafari.dailynotification.notify</string> <!-- Notification maintenance task (if applicable) -->
</array>
<!-- Background Modes -->
<key>UIBackgroundModes</key>
<array>
<string>background-fetch</string>
<string>background-processing</string>
<string>remote-notification</string>
</array>
<!-- Notification Permissions -->
<key>NSUserNotificationsUsageDescription</key>
<string>This app uses notifications to deliver daily updates and reminders.</string>
```
### Background App Refresh
- Background App Refresh must be enabled in Settings
- Test app should check and report Background App Refresh status
- User should be guided to enable Background App Refresh if disabled
---
## Build Options
### Xcode GUI Build
1. **Open Workspace:**
```bash
cd test-apps/ios-test-app
open App.xcworkspace # or App.xcodeproj
```
2. **Select Target:**
- Choose iOS Simulator (iPhone 15, iPhone 15 Pro, etc.)
- Or physical device (requires signing)
3. **Build and Run:**
- Press Cmd+R
- Or Product → Run
### Command-Line Build
Use the build script:
```bash
# From repo root
./scripts/build-ios-test-app.sh --simulator
# Or for device
./scripts/build-ios-test-app.sh --device
```
**Phase 2 Enhancement:** Refactor into modular subcommands:
```bash
./scripts/build-ios-test-app.sh setup # pod install + sync
./scripts/build-ios-test-app.sh run-sim # build + run simulator
./scripts/build-ios-test-app.sh device # build + deploy device
```
**Copy-Paste Commands:**
```bash
# Setup (first time or after dependency changes)
cd test-apps/ios-test-app
pod install
npx cap sync ios
# Build for simulator
xcodebuild -workspace App.xcworkspace \
-scheme ios-test-app \
-configuration Debug \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 15' \
build
# Run on simulator
xcodebuild -workspace App.xcworkspace \
-scheme ios-test-app \
-configuration Debug \
-sdk iphonesimulator \
-destination 'platform=iOS Simulator,name=iPhone 15' \
test
```
### Future CI Integration (Optional)
**Note for Phase 2+:** Consider adding `xcodebuild`-based CI job that:
- Builds `test-apps/ios-test-app` for simulator
- Runs a minimal UI test that:
- Launches app
- Calls `configure()` and `getNotificationStatus()`
- Validates log sequence + successful fetch simulation via LLDB trigger
- This ensures test app remains buildable as plugin evolves
**Phase 1:** Manual testing only; CI integration is out of scope.
**CI Readiness (Phase 2):**
- Add `xcodebuild` target for "Prefetch Integration Test"
- Validate log sequence + successful fetch simulation via LLDB trigger
- Use log validation script (`validate-ios-logs.sh`) for automated sequence checking
### Build Requirements
**Required Tools:**
- **Xcode:** 15.0 or later
- **macOS:** 13.0 (Ventura) or later
- **iOS Deployment Target:** iOS 15.0 or later
- **CocoaPods:** >= 1.13 (must run `pod install` before first build)
- **Node.js:** 20.x (recommended)
- **npm:** Latest stable (comes with Node.js)
- **Xcode Command Line Tools:** Must run `xcode-select --install` if not already installed
**Note:** Mismatched versions are **out of scope** for Phase 1 support. Use recommended versions to avoid compatibility issues.
---
## Capacitor Configuration
### Plugin Registration
The test app **MUST** register the DailyNotification plugin:
**`capacitor.config.json` or `capacitor.config.ts`:**
```json
{
"plugins": {
"DailyNotification": {
"enabled": true
}
}
}
```
### Plugin Path
The plugin must be accessible from the test app:
- **Development:** Plugin source at `../../ios/Plugin/`
- **Production:** Plugin installed via npm/CocoaPods
### Sync Command
After making changes to plugin or web assets:
```bash
cd test-apps/ios-test-app
npx cap sync ios
```
---
## Debugging Strategy
**When executing the scenarios in `IOS_PREFETCH_TESTING.md`, use the following commands while looking for logs with prefixes `DNP-PLUGIN`, `DNP-FETCH`, `DNP-SCHEDULER`.**
### Xcode Debugger
**Check Pending Notifications:**
```swift
po UNUserNotificationCenter.current().pendingNotificationRequests()
```
**Check Permission Status:**
```swift
po await UNUserNotificationCenter.current().notificationSettings()
```
**Manually Trigger BGTask (Simulator Only):**
```swift
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.timesafari.dailynotification.fetch"]
```
**Copy-Paste Commands:**
```swift
// In Xcode LLDB console:
// Check pending notifications
po UNUserNotificationCenter.current().pendingNotificationRequests()
// Check permission status
po await UNUserNotificationCenter.current().notificationSettings()
// Manually trigger BGTask (simulator only)
e -l objc -- (void)[[BGTaskScheduler sharedScheduler] _simulateLaunchForTaskWithIdentifier:@"com.timesafari.dailynotification.fetch"]
// Force reschedule all tasks (test harness)
po DailyNotificationBackgroundTaskTestHarness.forceRescheduleAll()
// Simulate time warp (test harness)
po DailyNotificationBackgroundTaskTestHarness.simulateTimeWarp(minutesForward: 60)
```
### Console.app Logging
1. Open Console.app (Applications → Utilities)
2. Select device/simulator
3. Filter by: `DNP-` or `DailyNotification`
**Key Log Prefixes:**
- `DNP-PLUGIN:` - Main plugin operations
- `DNP-FETCH:` - Background fetch operations
- `DNP-SCHEDULER:` - Scheduling operations
- `DNP-STORAGE:` - Storage operations
**Structured Logging (Swift Logger):**
The plugin uses Swift `Logger` categories for structured logging:
- `com.timesafari.dailynotification.plugin` - Plugin operations
- `com.timesafari.dailynotification.fetch` - Fetch operations
- `com.timesafari.dailynotification.scheduler` - Scheduling operations
- `com.timesafari.dailynotification.storage` - Storage operations
Filter in Console.app by subsystem: `com.timesafari.dailynotification`
**Phase 2: Log Validation Script**
Add helper script (`validate-ios-logs.sh`) to grep for required sequence markers:
```bash
grep -E "\[DNP-(FETCH|SCHEDULER|PLUGIN)\]" device.log | ./scripts/validate-ios-logs.sh
```
This confirms that all critical log steps occurred in proper order and flags missing or out-of-order events automatically.
### Common Debugging Scenarios
**Scenario: BGTask not running when expected → follow this checklist:**
1. **BGTask Not Running:**
- Check Info.plist has `BGTaskSchedulerPermittedIdentifiers`
- Verify identifiers match code exactly (case-sensitive)
- Verify task registered in AppDelegate before app finishes launching
- Check Background App Refresh enabled in Settings → [Your App]
- Verify app not force-quit (iOS won't run BGTask for force-quit apps)
- Use simulator-only LLDB command to manually trigger
- **See also:** `IOS_PREFETCH_TESTING.md Log Checklist: Section 3`
2. **Notifications Not Delivering:**
- Check notification permissions: `UNUserNotificationCenter.current().getNotificationSettings()`
- Verify notification scheduled: `UNUserNotificationCenter.current().getPendingNotificationRequests()`
- Check notification category registered
- **See also:** `IOS_PREFETCH_TESTING.md Log Checklist: Section 4`
3. **BGTaskScheduler Fails on Simulator:**
- **Expected Behavior:** BGTaskSchedulerErrorDomain Code=1 (notPermitted) is **normal on simulator**
- BGTaskScheduler doesn't work reliably on simulator - this is an iOS limitation, not a plugin bug
- Notification scheduling still works; prefetch won't run on simulator but will work on real devices
- Error handling logs clear message: "Background fetch scheduling failed (expected on simulator)"
- **See also:** `IOS_PREFETCH_TESTING.md Known OS Limitations` for details
- **Testing:** Use Xcode → Debug → Simulate Background Fetch for simulator testing
4. **Plugin Not Discovered:**
- Check plugin class conforms to `CAPBridgedPlugin` protocol (required for Capacitor discovery)
- Verify `@objc extension DailyNotificationPlugin: CAPBridgedPlugin` exists in plugin code
- Check plugin framework is force-loaded in AppDelegate before Capacitor initializes
- Verify `pluginMethods` array includes all `@objc` methods
- **See also:** `doc/directives/0003-iOS-Android-Parity-Directive.md Plugin Discovery Issue` for detailed troubleshooting
5. **Build Failures:**
- Run `pod install`
- Clean build folder (Cmd+Shift+K)
- Verify Capacitor plugin path
---
## Test App Implementation Checklist
### Setup
- [ ] Create `test-apps/ios-test-app/` directory
- [ ] Initialize Capacitor iOS project
- [ ] Copy HTML/JS UI from Android test app
- [ ] Configure Info.plist with BGTask identifiers
- [ ] Configure Info.plist with background modes
- [ ] Add notification permission description
### Plugin Integration
- [ ] Register DailyNotification plugin in Capacitor config
- [ ] Ensure plugin path is correct
- [ ] Run `npx cap sync ios`
- [ ] Verify plugin loads in test app
### UI Implementation
- [ ] Copy HTML/JS from Android test app
- [ ] Test plugin status display
- [ ] Test permission status display
- [ ] Test notification scheduling UI
- [ ] Test status display
### Build & Test
- [ ] Build script works (`./scripts/build-ios-test-app.sh`)
- [ ] App builds in Xcode
- [ ] App runs on simulator
- [ ] Plugin methods work from UI
- [ ] Notifications deliver correctly
- [ ] BGTask executes (with manual trigger in simulator)
---
## File Structure
```
test-apps/ios-test-app/
├── App.xcworkspace # Xcode workspace (if using CocoaPods)
├── App.xcodeproj # Xcode project
├── App/ # Main app directory
│ ├── App/
│ │ ├── AppDelegate.swift
│ │ ├── SceneDelegate.swift
│ │ ├── Info.plist # Must include BGTask identifiers
│ │ └── Assets.xcassets
│ └── Public/ # Web assets (HTML/JS)
│ └── index.html # Same as Android test app
├── Podfile # CocoaPods dependencies
├── capacitor.config.json # Capacitor configuration
└── package.json # npm dependencies (if any)
```
---
## Testing Scenarios
### Basic Functionality
**Happy Path Example:**
When everything is working correctly, your first run should produce logs like this:
```text
[DNP-PLUGIN] configure() called
[DNP-PLUGIN] status = ready
[DNP-PLUGIN] requestPermissions() → granted
[DNP-SCHEDULER] scheduleDailyNotification() → notificationTime=2025-11-15T05:53:00Z
[DNP-FETCH] Scheduling prefetch for notification at 2025-11-15T05:53:00Z
[DNP-FETCH] BGAppRefreshTask scheduled (earliestBeginDate=2025-11-15T05:48:00Z)
[DNP-SCHEDULER] Scheduling notification for 2025-11-15T05:53:00Z
[DNP-STORAGE] Persisted schedule to DB (id=..., type=DAILY, ...)
```
**If your first run doesn't look roughly like this, fix that before proceeding to BGTask tests.**
1. **Plugin Registration** `[P1-Core][SIM+DEV]`
- Launch app
- Verify plugin status shows "Plugin is loaded and ready!"
- **See also:** `IOS_PREFETCH_TESTING.md Simulator Test Plan: Step 2`
2. **Permission Management** `[P1-Core][SIM+DEV]`
- Check permissions
- Request permissions
- Verify permissions granted
- **See also:** `IOS_PREFETCH_TESTING.md Simulator Test Plan: Step 6 (Negative-Path Tests)`
3. **Notification Scheduling** `[P1-Prefetch][SIM+DEV]`
- Schedule test notification
- Verify notification scheduled
- Wait for notification to appear
- **See also:** `IOS_PREFETCH_TESTING.md Simulator Test Plan: Steps 3-5`
### Background Tasks
**Sim vs Device Behavior:**
- `[SIM+DEV]` can be fully tested on simulator and device (logic correctness)
- `[DEV-ONLY]` timing / heuristic behavior, must be verified on real hardware
1. **BGTask Scheduling** `[P1-Prefetch][SIM+DEV]`
- Schedule notification with prefetch
- Verify BGTask scheduled 5 minutes before notification
- Manually trigger BGTask (simulator only)
- Verify content fetched
- **Note:** Logic and logs on sim; real timing on device
- **See also:** `IOS_PREFETCH_TESTING.md Simulator Test Plan: Steps 3-4`
2. **BGTask Miss Detection** `[P1-Prefetch][DEV-ONLY]`
- Schedule notification
- Wait 15+ minutes
- Launch app
- Verify BGTask rescheduled
- **Note:** Only meaningful on device (heuristic timing)
- **See also:** `IOS_PREFETCH_TESTING.md Real Device Test Plan: Step 4`
### Error Handling
1. **Permission Denied** `[P1-Core][SIM+DEV]`
- Deny notification permissions
- Try to schedule notification
- Verify error returned
- **See also:** `IOS_PREFETCH_TESTING.md Simulator Test Plan: Step 7 (Negative-Path Tests)`
2. **Invalid Parameters** `[P1-Core][SIM+DEV]`
- Try to schedule with invalid time format
- Verify error returned
3. **Network Failures** `[P1-Prefetch][SIM+DEV]`
- Turn off network during fetch
- Verify graceful fallback to on-demand fetch
- Test recovery: network off → fail → network on → retry succeeds
4. **Server Errors / Auth Expiry** `[P1-Prefetch][SIM+DEV]`
- Simulate HTTP 401 or 500 error
- Verify plugin logs failure with reason (AUTH, NETWORK)
- Confirm telemetry counter increments: `dnp_prefetch_failure_total{reason="AUTH"}`
- Verify fallback to live fetch at notification time
5. **Corrupted Cache** `[P1-Prefetch][SIM+DEV]`
- Manually tamper with stored cache (invalid JSON or remove entry)
- Verify plugin detects invalid cache and falls back
- Ensure no crash on reading bad cache (error handling wraps cache read)
6. **BGTask Execution Failure** `[P1-Prefetch][SIM+DEV]`
- Simulate internal failure in BGTask handler
- Verify expiration handler or completion still gets called
- Ensure task marked complete even on exception
7. **Repeated Scheduling Calls** `[P1-Prefetch][SIM+DEV]`
- Call `scheduleDailyNotification()` multiple times rapidly
- Verify no duplicate scheduling (one active task rule enforced)
- Confirm only one BGTask is actually submitted
### Advanced Features `[P2-Advanced]`
1. **Rolling Window** `[P2-Advanced]`
- Schedule multiple notifications
- Verify rolling window maintenance
- Check notification limits (64 max on iOS)
2. **TTL Enforcement** `[P2-Advanced]`
- Schedule notification with prefetch
- Wait for TTL to expire
- Verify stale content discarded at delivery
---
## Developer/Test Harness Features (Optional but Recommended)
Since this test app is for internal testing, it can expose more tools:
### Dev-Only Toggles
| Button | Action | Purpose |
|--------|--------|---------|
| "Simulate BGTask Now" | Calls LLDB trigger | Quick sanity test |
| "Schedule 1-min Notification" | Auto schedules T-Lead=1 | Edge case testing |
| "Simulate DST Shift" | Adds +1 hr offset | DST handling check |
| "Show Cached Payload" | Displays JSON cache | Prefetch validation |
| "Force Reschedule All" | Calls `forceRescheduleAll()` | BGTask recovery testing |
| "Time Warp +N Minutes" | Calls `simulateTimeWarp()` | Accelerated TTL/T-Lead tests |
1. **Force Schedule Notification N Minutes from Now**
- Bypass normal scheduling UI
- Directly call `scheduleDailyNotification()` with calculated time
- Useful for quick testing scenarios
2. **Force "Prefetch-Only" Task**
- Trigger BGTask without scheduling notification
- Useful for testing prefetch logic in isolation
- Display raw JSON returned from API (last fetched payload)
3. **Display Raw API Response**
- Show last fetched payload as JSON
- Useful for debugging API responses
- Can be referenced from `IOS_PREFETCH_TESTING.md` as shortcuts for specific scenarios
4. **Manual BGTask Trigger (Dev Build Only)**
- Button to manually trigger BGTask (simulator only)
- Wraps the LLDB command in UI for convenience
5. **UI Feedback Enhancements**
- Add persistent toast/log area showing step-by-step plugin state ("Registered", "Scheduled", "BGTask fired", etc.)
- Include color-coded state indicators for each stage (🟢 OK, 🟡 Pending, 🔴 Error)
These features can then be referenced from `IOS_PREFETCH_TESTING.md` as shortcuts for specific test scenarios.
### Persistent Schedule Snapshot
**Phase 2 Enhancement:** Store a simple JSON of the last prefetch state for post-run verification:
```json
{
"last_schedule": "2025-11-15T05:48:00Z",
"last_prefetch": "2025-11-15T05:50:00Z",
"last_notification": "2025-11-15T05:53:00Z",
"prefetch_success": true,
"cached_content_used": true,
"contentHash": "abcdef123456",
"scheduleHash": "xyz789"
}
```
This can be used for post-run verification and telemetry aggregation. Access via test app UI button "Show Schedule Snapshot" or via UserDefaults key `DNP_ScheduleSnapshot`.
### UI Indicators for Tests
**Status Display:**
- Status label/icon: 🟢 green when last notification was fetched and delivered from cache
- 🔴 red if something failed (network error, etc.)
- 🟡 yellow if pending/unknown state
**Last Operation Summary:**
- Display last fetch time
- Show whether cached content was used
- Display any error message
- Show telemetry counter values
**Dump Prefetch Status Button:**
- Triggers plugin to report all relevant info
- Shows pending tasks, cache status, telemetry snapshot
- Displays in scrollable text view
- Useful on devices where attaching debugger is inconvenient
### In-App Log Viewer (Phase 2)
**For QA Use:**
- Read app's unified logging (OSLog) for entries with subsystem `com.timesafari.dailynotification`
- Present logs on screen or allow export to file
- Capture Logger output into text buffer during app session
- **Security:** Only enable in test builds, not production
**Export Test Results:**
- Save test run summary to file (JSON format)
- Include timestamps, outcomes, telemetry counters
- Access via "Export Test Results" button
- Collect from devices via Xcode or CI pipelines
## Risks & Gotchas
**Common pitfalls when working with the test app:**
1. **Accidentally editing shared HTML/JS in iOS test app instead of Android canonical source**
- Always edit Android test app HTML/JS first, then copy to iOS
- Keep iOS test app HTML/JS as a copy, not the source of truth
2. **Forgetting `npx cap sync ios` after plugin or asset changes**
- Run `npx cap sync ios` after any plugin code changes
- Run `npx cap sync ios` after any web asset changes
- Check `capacitor.config.json` is up to date
3. **Running with stale Pods**
- Run `pod repo update` periodically
- Run `pod install` after dependency changes
- Clean build folder (Cmd+Shift+K) if Pods seem stale
4. **Changing BGTask identifiers in one place but not the other**
- Info.plist `BGTaskSchedulerPermittedIdentifiers` must match Swift code exactly (case-sensitive)
- Check both places when updating identifiers
- See `IOS_PREFETCH_TESTING.md` for identifier requirements
5. **Mismatched tooling versions**
- Use recommended versions (Node 20.x, CocoaPods >= 1.13, Xcode 15.0+)
- Mismatched versions are out of scope for Phase 1 support
## References
- **Directive:** `doc/directives/0003-iOS-Android-Parity-Directive.md`
- **Testing Guide:** `doc/test-app-ios/IOS_PREFETCH_TESTING.md` - Comprehensive prefetch testing procedures
- **Android Test App:** `test-apps/android-test-app/`
- **Build Script:** `scripts/build-ios-test-app.sh`
---
## Review & Sign-Off Checklist (Phase 1)
**Use this checklist to verify Phase 1 iOS test app is complete:**
- [ ] Test app builds on simulator with recommended toolchain (Node 20.x, CocoaPods >= 1.13, Xcode 15.0+)
- [ ] Test app builds on at least one real device
- [ ] All UI buttons map to plugin methods as per the **UI Elements to Plugin Methods Mapping** table
- [ ] Happy-path log sequence matches the example in **Testing Scenarios → Basic Functionality**
- [ ] BGTask identifiers are consistent (Info.plist ↔ Swift ↔ docs)
- [ ] Risks & Gotchas section has been read and acknowledged by the implementer
- [ ] Security & Privacy Constraints have been followed (non-production endpoints, no PII in logs)
---
## Technical Correctness Requirements
### BGTask Scheduling & Lifecycle
**Validation Requirements:**
- Verify `earliestBeginDate` is at least 60 seconds in future (iOS requirement)
- Log and handle scheduling errors gracefully (Code=1 on simulator is expected)
- Cancel existing pending task before scheduling new (one active task rule)
- Use `BGTaskScheduler.shared.getPendingTaskRequests()` in debug to verify only one task pending
**Schedule Next Task at Execution:**
- Adopt Apple's best practice: schedule next task IMMEDIATELY at start of BGTask handler
- This ensures continuity even if app is terminated shortly after
- Pattern: Schedule next → Initiate async work → Mark complete → Use expiration handler
**Expiration Handler and Completion:**
- Implement expiration handler to cancel ongoing operations if iOS terminates task (~30 seconds)
- Always call `task.setTaskCompleted(success:)` exactly once
- Use `success: false` if fetch didn't complete (system may reschedule sooner)
- Use `success: true` if all went well
- Re-schedule next task after marking completion (for recurring use cases)
**Error Handling & Retry:**
- Distinguish recoverable errors (transient network) vs permanent failures
- For network failures: log failure reason, set `success: false`, consider cached data if available
- For logic errors: log clear message, call `setTaskCompleted(success: false)`, exit cleanly
- Ensure fallback to on-demand fetch at notification time if prefetch fails
**Data Consistency & Cleanup:**
- Cross-check `notificationTime` matches payload's `scheduled_for` field
- Validate TTL on cached content at notification time (discard if expired)
- Ensure content is saved to persistent store before marking BGTask complete
- Implement cache cleanup for outdated data
- Handle permission changes gracefully (detect failure at delivery, log outcome)
### Scheduling and Notification Coordination
**Unified Scheduling Logic:**
- Atomically schedule both UNNotificationRequest and BGAppRefreshTaskRequest
- If one fails, cancel the other or report partial failure
- Return clear status/error code to JS layer
**BGTask Identifier Constants:**
- Verify identifier in code exactly matches Info.plist (case-sensitive)
- Test harness should verify on app launch (logs show successful registration)
**Concurrency Considerations:**
- Handle potentially overlapping schedules (Phase 2: multiple notifications)
- Use one BGTask to fetch for next upcoming notification only
- Store next notification's schedule ID and time in shared place
- Use locks or dispatch synchronization to avoid race conditions
**OS Limits:**
- Acknowledge force-quit prevents BGTask execution (can't circumvent)
- Tolerate running slightly later than `earliestBeginDate` (iOS heuristics)
- Log actual execution time vs scheduled time for analysis
---
## Phase 2 Forward Plan
**Planned enhancements for Phase 2:**
- Add quick scenario buttons (Simulate BGTask Now, Schedule 1-min Notification, Simulate DST Shift, Show Cached Payload)
- Implement persistent schedule snapshot (JSON of last prefetch state)
- Add color-coded UI feedback (🟢 OK, 🟡 Pending, 🔴 Error)
- Refactor build script into modular subcommands (`setup`, `run-sim`, `device`)
- Integrate CI pipeline with `xcodebuild` target for "Prefetch Integration Test"
- Add log validation script (`validate-ios-logs.sh`) for automated sequence checking
- Implement rolling window & TTL validation
- Add telemetry verification for multi-day scenarios
- Test on different device models and iOS versions
- Add in-app log viewer/export for QA use
**See also:** `doc/directives/0003-iOS-Android-Parity-Directive.md` for Phase 2 implementation details.
---
## Changelog (high-level)
- 2025-11-15 — Initial Phase 1 version (prefetch MVP, Android parity)
---
**Status:** 📋 **REQUIRED FOR PHASE 1**
**Last Updated:** 2025-11-15