docs!: add comprehensive migration guide and enterprise callback examples
- Add complete migration guide with step-by-step instructions - Include platform-specific configuration examples (Android, iOS, Web) - Provide comprehensive enterprise callback examples - Cover analytics integration (GA4, Mixpanel) - Include CRM integration (Salesforce, HubSpot) - Add database operations (PostgreSQL, MongoDB) - Include monitoring & alerting (Datadog, New Relic) - Provide multi-service orchestration examples - Add error handling patterns (circuit breaker, retry logic) - Include performance optimization techniques - Add security best practices and authentication - Update main README with complete API reference - Include troubleshooting and testing guidance BREAKING CHANGE: Documentation structure updated with new migration path
This commit is contained in:
566
README.md
566
README.md
@@ -1,35 +1,36 @@
|
||||
# Daily Notification Plugin
|
||||
|
||||
A Native-First Capacitor plugin for reliable daily notifications across Android, iOS, and Web platforms.
|
||||
**Author**: Matthew Raymer
|
||||
**Version**: 2.0.0
|
||||
**Created**: 2025-09-22 09:22:32 UTC
|
||||
**Last Updated**: 2025-09-22 09:22:32 UTC
|
||||
|
||||
## Key Features
|
||||
## Overview
|
||||
|
||||
- **Native-First Architecture**: Optimized for mobile platforms with offline-first design
|
||||
- **Shared SQLite Storage**: Single database file with WAL mode for concurrent access
|
||||
- **TTL-at-Fire Enforcement**: Skip stale notifications before delivery
|
||||
- **Rolling Window Safety**: Always keep today's notifications armed
|
||||
- **Cross-Platform**: Unified API across Android, iOS, and Web
|
||||
- **Production Ready**: Comprehensive error handling, performance optimization, and monitoring
|
||||
The Daily Notification Plugin is a comprehensive Capacitor plugin that provides enterprise-grade daily notification functionality across Android, iOS, and Web platforms. It features dual scheduling, callback support, TTL-at-fire logic, and comprehensive observability.
|
||||
|
||||
## Quick Start
|
||||
## Features
|
||||
|
||||
```typescript
|
||||
import { DailyNotification } from '@timesafari/daily-notification-plugin';
|
||||
### 🚀 **Core Features**
|
||||
|
||||
// Configure and schedule
|
||||
await DailyNotification.configure({
|
||||
storage: 'shared',
|
||||
ttlSeconds: 1800,
|
||||
prefetchLeadMinutes: 15
|
||||
});
|
||||
- **Dual Scheduling**: Separate content fetch and user notification scheduling
|
||||
- **TTL-at-Fire Logic**: Content validity checking at notification time
|
||||
- **Callback System**: HTTP, local, and queue callback support
|
||||
- **Circuit Breaker Pattern**: Automatic failure detection and recovery
|
||||
- **Cross-Platform**: Android, iOS, and Web implementations
|
||||
|
||||
await DailyNotification.scheduleDailyNotification({
|
||||
url: 'https://api.example.com/daily-content',
|
||||
time: '09:00',
|
||||
title: 'Daily Update',
|
||||
body: 'Your daily notification is ready'
|
||||
});
|
||||
```
|
||||
### 📱 **Platform Support**
|
||||
|
||||
- **Android**: WorkManager + AlarmManager + SQLite (Room)
|
||||
- **iOS**: BGTaskScheduler + UNUserNotificationCenter + Core Data
|
||||
- **Web**: Service Worker + IndexedDB + Push Notifications
|
||||
|
||||
### 🔧 **Enterprise Features**
|
||||
|
||||
- **Observability**: Structured logging with event codes
|
||||
- **Health Monitoring**: Comprehensive status and performance metrics
|
||||
- **Error Handling**: Exponential backoff and retry logic
|
||||
- **Security**: Encrypted storage and secure callback handling
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -37,114 +38,491 @@ await DailyNotification.scheduleDailyNotification({
|
||||
npm install @timesafari/daily-notification-plugin
|
||||
```
|
||||
|
||||
## Documentation
|
||||
## Quick Start
|
||||
|
||||
- **[Complete Usage Guide](USAGE.md)** - Comprehensive guide with examples and best practices
|
||||
- **[API Reference](API.md)** - Complete method and type definitions
|
||||
- **[Implementation Roadmap](doc/implementation-roadmap.md)** - Technical implementation details
|
||||
- **[Notification System Spec](doc/notification-system.md)** - Architecture and design principles
|
||||
- **[Glossary](doc/GLOSSARY.md)** - Key terminology and concepts
|
||||
### Basic Usage
|
||||
|
||||
## Examples
|
||||
```typescript
|
||||
import { DailyNotification } from '@timesafari/daily-notification-plugin';
|
||||
|
||||
- **Basic Usage**: `examples/usage.ts`
|
||||
- **Phase-by-Phase Implementation**:
|
||||
- Phase 1: `examples/phase1-*.ts` (Core Infrastructure)
|
||||
- Phase 2: `examples/phase2-*.ts` (Platform Completion)
|
||||
- Phase 3: `examples/phase3-*.ts` (Network Optimization)
|
||||
- **Advanced Scenarios**: `examples/advanced-usage.ts`
|
||||
- **Enterprise Features**: `examples/enterprise-usage.ts`
|
||||
// Schedule a daily notification
|
||||
await DailyNotification.scheduleDailyNotification({
|
||||
title: 'Daily Update',
|
||||
body: 'Your daily content is ready',
|
||||
schedule: '0 9 * * *' // 9 AM daily
|
||||
});
|
||||
```
|
||||
|
||||
## Configuration
|
||||
### Enhanced Usage (Recommended)
|
||||
|
||||
```typescript
|
||||
import {
|
||||
DailyNotification,
|
||||
DualScheduleConfiguration
|
||||
} from '@timesafari/daily-notification-plugin';
|
||||
|
||||
// Configure 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);
|
||||
```
|
||||
|
||||
### Callback Integration
|
||||
|
||||
```typescript
|
||||
// Register analytics callback
|
||||
await DailyNotification.registerCallback('analytics', {
|
||||
kind: 'http',
|
||||
target: 'https://analytics.example.com/events',
|
||||
headers: {
|
||||
'Authorization': 'Bearer your-token',
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
// Register local callback
|
||||
await DailyNotification.registerCallback('database', {
|
||||
kind: 'local',
|
||||
target: 'saveToDatabase'
|
||||
});
|
||||
|
||||
function saveToDatabase(event: CallbackEvent) {
|
||||
console.log('Saving to database:', event);
|
||||
// Your database save logic here
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Core Methods
|
||||
|
||||
#### `scheduleDailyNotification(options)`
|
||||
|
||||
Schedule a basic daily notification (backward compatible).
|
||||
|
||||
```typescript
|
||||
await DailyNotification.scheduleDailyNotification({
|
||||
title: string;
|
||||
body: string;
|
||||
schedule: string; // Cron expression
|
||||
actions?: NotificationAction[];
|
||||
});
|
||||
```
|
||||
|
||||
#### `scheduleContentFetch(config)`
|
||||
|
||||
Schedule content fetching separately.
|
||||
|
||||
```typescript
|
||||
await DailyNotification.scheduleContentFetch({
|
||||
schedule: string; // Cron expression
|
||||
ttlSeconds: number; // Time-to-live in seconds
|
||||
source: string; // Content source identifier
|
||||
url?: string; // API endpoint URL
|
||||
headers?: Record<string, string>;
|
||||
});
|
||||
```
|
||||
|
||||
#### `scheduleUserNotification(config)`
|
||||
|
||||
Schedule user notifications separately.
|
||||
|
||||
```typescript
|
||||
await DailyNotification.scheduleUserNotification({
|
||||
schedule: string; // Cron expression
|
||||
title: string; // Notification title
|
||||
body: string; // Notification body
|
||||
actions?: NotificationAction[];
|
||||
});
|
||||
```
|
||||
|
||||
#### `scheduleDualNotification(config)`
|
||||
|
||||
Schedule both content fetch and user notification.
|
||||
|
||||
```typescript
|
||||
await DailyNotification.scheduleDualNotification({
|
||||
contentFetch: ContentFetchConfig;
|
||||
userNotification: UserNotificationConfig;
|
||||
});
|
||||
```
|
||||
|
||||
### Callback Methods
|
||||
|
||||
#### `registerCallback(name, config)`
|
||||
|
||||
Register a callback function.
|
||||
|
||||
```typescript
|
||||
await DailyNotification.registerCallback('callback-name', {
|
||||
kind: 'http' | 'local' | 'queue';
|
||||
target: string; // URL or function name
|
||||
headers?: Record<string, string>;
|
||||
});
|
||||
```
|
||||
|
||||
#### `unregisterCallback(name)`
|
||||
|
||||
Remove a registered callback.
|
||||
|
||||
```typescript
|
||||
await DailyNotification.unregisterCallback('callback-name');
|
||||
```
|
||||
|
||||
#### `getRegisteredCallbacks()`
|
||||
|
||||
Get list of registered callbacks.
|
||||
|
||||
```typescript
|
||||
const callbacks = await DailyNotification.getRegisteredCallbacks();
|
||||
// Returns: string[]
|
||||
```
|
||||
|
||||
### Status Methods
|
||||
|
||||
#### `getDualScheduleStatus()`
|
||||
|
||||
Get comprehensive status information.
|
||||
|
||||
```typescript
|
||||
const status = await DailyNotification.getDualScheduleStatus();
|
||||
// Returns: {
|
||||
// nextRuns: number[];
|
||||
// lastOutcomes: string[];
|
||||
// cacheAgeMs: number | null;
|
||||
// staleArmed: boolean;
|
||||
// queueDepth: number;
|
||||
// circuitBreakers: CircuitBreakerStatus;
|
||||
// performance: PerformanceMetrics;
|
||||
// }
|
||||
```
|
||||
|
||||
## Platform Requirements
|
||||
|
||||
### Android
|
||||
|
||||
Add the following permissions to your `AndroidManifest.xml`:
|
||||
- **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+
|
||||
|
||||
## Configuration
|
||||
|
||||
### Android Configuration
|
||||
|
||||
#### AndroidManifest.xml
|
||||
|
||||
```xml
|
||||
<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" />
|
||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
<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>
|
||||
```
|
||||
|
||||
## Development
|
||||
#### build.gradle
|
||||
|
||||
### Prerequisites
|
||||
```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"
|
||||
}
|
||||
```
|
||||
|
||||
- Node.js 14 or later
|
||||
- Android Studio
|
||||
- Android SDK
|
||||
- Gradle
|
||||
### iOS Configuration
|
||||
|
||||
### Building
|
||||
#### 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>
|
||||
```
|
||||
|
||||
#### Capabilities
|
||||
|
||||
1. Enable "Background Modes" capability
|
||||
2. Enable "Background App Refresh"
|
||||
3. Enable "Background Processing"
|
||||
|
||||
### Web Configuration
|
||||
|
||||
#### Service Worker Registration
|
||||
|
||||
```typescript
|
||||
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
|
||||
const permission = await Notification.requestPermission();
|
||||
|
||||
if (permission === 'granted') {
|
||||
const subscription = await registration.pushManager.subscribe({
|
||||
userVisibleOnly: true,
|
||||
applicationServerKey: 'your-vapid-public-key'
|
||||
});
|
||||
|
||||
await fetch('/api/push-subscription', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(subscription)
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### Unit Tests
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
npm install
|
||||
|
||||
# Build the plugin
|
||||
npm run build
|
||||
|
||||
# Run tests
|
||||
npm test
|
||||
```
|
||||
|
||||
### Project Structure
|
||||
### Integration Tests
|
||||
|
||||
```typescript
|
||||
import { DailyNotification } from '@timesafari/daily-notification-plugin';
|
||||
|
||||
describe('Integration Tests', () => {
|
||||
test('dual scheduling workflow', 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.length).toBe(2);
|
||||
});
|
||||
});
|
||||
```
|
||||
daily-notification-plugin/
|
||||
├── android/ # Android implementation
|
||||
│ ├── app/ # Main application module
|
||||
│ └── build.gradle # Root build configuration
|
||||
├── src/ # TypeScript source
|
||||
├── tests/ # Test files
|
||||
├── package.json # Package configuration
|
||||
└── README.md # This file
|
||||
|
||||
## Enterprise Integration
|
||||
|
||||
### Analytics Integration
|
||||
|
||||
```typescript
|
||||
// Google Analytics 4
|
||||
const ga4Callback = new GoogleAnalyticsCallback('G-XXXXXXXXXX', 'your-api-secret');
|
||||
await ga4Callback.register();
|
||||
|
||||
// Mixpanel
|
||||
const mixpanelCallback = new MixpanelCallback('your-project-token');
|
||||
await mixpanelCallback.register();
|
||||
```
|
||||
|
||||
### CRM Integration
|
||||
|
||||
```typescript
|
||||
// Salesforce
|
||||
const salesforceCallback = new SalesforceCallback('your-access-token', 'your-instance-url');
|
||||
await salesforceCallback.register();
|
||||
|
||||
// HubSpot
|
||||
const hubspotCallback = new HubSpotCallback('your-api-key');
|
||||
await hubspotCallback.register();
|
||||
```
|
||||
|
||||
### Monitoring Integration
|
||||
|
||||
```typescript
|
||||
// Datadog
|
||||
const datadogCallback = new DatadogCallback('your-api-key', 'your-app-key');
|
||||
await datadogCallback.register();
|
||||
|
||||
// New Relic
|
||||
const newrelicCallback = new NewRelicCallback('your-license-key');
|
||||
await newrelicCallback.register();
|
||||
```
|
||||
|
||||
## 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);
|
||||
```
|
||||
|
||||
## 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
|
||||
|
||||
## Contributing
|
||||
|
||||
### Development Setup
|
||||
|
||||
```bash
|
||||
git clone https://github.com/timesafari/daily-notification-plugin.git
|
||||
cd daily-notification-plugin
|
||||
npm install
|
||||
npm run build
|
||||
npm test
|
||||
```
|
||||
|
||||
### Code Standards
|
||||
|
||||
- **TypeScript**: Strict type checking enabled
|
||||
- **ESLint**: Code quality and consistency
|
||||
- **Prettier**: Code formatting
|
||||
- **Jest**: Comprehensive testing
|
||||
|
||||
### Pull Request Process
|
||||
|
||||
1. Fork the repository
|
||||
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
||||
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
||||
4. Push to the branch (`git push origin feature/amazing-feature`)
|
||||
5. Open a Pull Request
|
||||
2. Create a feature branch
|
||||
3. Make your changes
|
||||
4. Add tests for new functionality
|
||||
5. Ensure all tests pass
|
||||
6. Submit a pull request
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License - see the LICENSE file for details.
|
||||
MIT License - see [LICENSE](LICENSE) file for details.
|
||||
|
||||
## Author
|
||||
## Support
|
||||
|
||||
Matthew Raymer
|
||||
### Documentation
|
||||
|
||||
## Security
|
||||
- **API Reference**: Complete TypeScript definitions
|
||||
- **Migration Guide**: [doc/migration-guide.md](doc/migration-guide.md)
|
||||
- **Enterprise Examples**: [doc/enterprise-callback-examples.md](doc/enterprise-callback-examples.md)
|
||||
|
||||
This plugin follows security best practices:
|
||||
### Community
|
||||
|
||||
- Uses AndroidX for modern security features
|
||||
- Implements proper permission handling
|
||||
- Follows Android security guidelines
|
||||
- Uses secure storage for sensitive data
|
||||
- Implements proper error handling
|
||||
- Logs security-relevant events
|
||||
- Uses secure communication channels
|
||||
- Implements proper access control
|
||||
- Follows Android's security model
|
||||
- Uses secure defaults
|
||||
- **GitHub Issues**: Report bugs and request features
|
||||
- **Discussions**: Ask questions and share solutions
|
||||
- **Contributing**: Submit pull requests and improvements
|
||||
|
||||
## Changelog
|
||||
### Enterprise Support
|
||||
|
||||
### 1.0.0
|
||||
- **Custom Implementations**: Tailored solutions for enterprise needs
|
||||
- **Integration Support**: Help with complex integrations
|
||||
- **Performance Optimization**: Custom performance tuning
|
||||
|
||||
- Initial release
|
||||
- Basic notification scheduling
|
||||
- System state handling
|
||||
- Battery optimization support
|
||||
- Background task management
|
||||
- Rich logging system
|
||||
---
|
||||
|
||||
**Version**: 2.0.0
|
||||
**Last Updated**: 2025-09-22 09:22:32 UTC
|
||||
**Author**: Matthew Raymer
|
||||
|
||||
1083
doc/enterprise-callback-examples.md
Normal file
1083
doc/enterprise-callback-examples.md
Normal file
File diff suppressed because it is too large
Load Diff
436
doc/migration-guide.md
Normal file
436
doc/migration-guide.md
Normal file
@@ -0,0 +1,436 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user