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:
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 12–14, iOS 15–18)
|
||||
- [ ] **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 (5–15m & 1–6h) 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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 1–2)**
|
||||
- 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 2–3)** — event codes, status endpoints, history compaction
|
||||
4. **iOS Parity (Week 3–4)** — 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
@@ -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 T–lead 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 T–lead logic
|
||||
- **Critical Path:** Data persistence → Freshness enforcement → Platform completion
|
||||
|
||||
---
|
||||
|
||||
## Current Implementation Status Clarification
|
||||
|
||||
### Background Fetch Infrastructure
|
||||
|
||||
**Current State:** Basic infrastructure exists but lacks T–lead logic
|
||||
|
||||
- **Android:** `DailyNotificationFetchWorker.java` (WorkManager) exists
|
||||
- **Android:** `DailyNotificationFetcher.java` with scheduling logic exists
|
||||
- **Missing:** T–lead calculation, TTL enforcement, ETag support
|
||||
- **Status:** Infrastructure ready, T–lead 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, T–lead 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 → T–lead)
|
||||
- Silent push nudge support
|
||||
- Background execution budget management
|
||||
- Schedule prefetch at **T–lead = T − prefetchLeadMinutes** (see Glossary → T–lead)
|
||||
- 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 **T–lead**; **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 → T–lead)
|
||||
- [ ] Silent push can trigger background execution
|
||||
- [ ] Budget management prevents system penalties
|
||||
- [ ] Background execution works when app is closed
|
||||
- [ ] iOS BGTask best-effort at T–lead; 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
|
||||
@@ -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.
|
||||
@@ -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 T–lead** + **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 **T–lead**; 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 **T–lead**; zero stale deliveries beyond TTL.
|
||||
|
||||
---
|
||||
|
||||
## Strategic Plan
|
||||
|
||||
### Goal
|
||||
|
||||
Deliver 1..M daily notifications with **OS background prefetch at T–lead** *(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 **T–lead** *(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 & T–lead *(Planned)*
|
||||
|
||||
- Arm **rolling window** (see Glossary → Rolling window). **(Planned)**
|
||||
- Exactly **one** online-first fetch at **T–lead** (see Glossary → T–lead) 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 T–lead 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) T–lead (single attempt)
|
||||
|
||||
**T–lead governs prefetch, not arming.** We **arm** one-shot locals as part of the rolling window so closed-app delivery is guaranteed. At **T–lead = 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 T–lead = `whenMs - prefetchLeadMinutes*60_000`.
|
||||
- `BackgroundPrefetchNative.schedulePrefetch(slotId, atMs=T–lead)`.
|
||||
- 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 T–lead prefetch.
|
||||
|
||||
### 6) iOS specifics
|
||||
|
||||
- `BGTaskScheduler` for T–lead 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 T–lead; 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 T–lead (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.
|
||||
- **T–lead prefetch:** Single background attempt at **T–lead**; 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 T–lead 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.*
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user