Browse Source
- 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 pathresearch/notification-plugin-enhancement
3 changed files with 1986 additions and 89 deletions
@ -1,150 +1,528 @@ |
|||||
# Daily Notification Plugin |
# 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 |
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. |
||||
- **Shared SQLite Storage**: Single database file with WAL mode for concurrent access |
|
||||
- **TTL-at-Fire Enforcement**: Skip stale notifications before delivery |
## Features |
||||
- **Rolling Window Safety**: Always keep today's notifications armed |
|
||||
- **Cross-Platform**: Unified API across Android, iOS, and Web |
### 🚀 **Core Features** |
||||
- **Production Ready**: Comprehensive error handling, performance optimization, and monitoring |
|
||||
|
- **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 |
||||
|
|
||||
|
### 📱 **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 |
||||
|
|
||||
|
```bash |
||||
|
npm install @timesafari/daily-notification-plugin |
||||
|
``` |
||||
|
|
||||
## Quick Start |
## Quick Start |
||||
|
|
||||
|
### Basic Usage |
||||
|
|
||||
```typescript |
```typescript |
||||
import { DailyNotification } from '@timesafari/daily-notification-plugin'; |
import { DailyNotification } from '@timesafari/daily-notification-plugin'; |
||||
|
|
||||
// Configure and schedule |
// Schedule a daily notification |
||||
await DailyNotification.configure({ |
await DailyNotification.scheduleDailyNotification({ |
||||
storage: 'shared', |
title: 'Daily Update', |
||||
ttlSeconds: 1800, |
body: 'Your daily content is ready', |
||||
prefetchLeadMinutes: 15 |
schedule: '0 9 * * *' // 9 AM daily |
||||
|
}); |
||||
|
``` |
||||
|
|
||||
|
### 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({ |
await DailyNotification.scheduleDailyNotification({ |
||||
url: 'https://api.example.com/daily-content', |
title: string; |
||||
time: '09:00', |
body: string; |
||||
title: 'Daily Update', |
schedule: string; // Cron expression |
||||
body: 'Your daily notification is ready' |
actions?: NotificationAction[]; |
||||
}); |
}); |
||||
``` |
``` |
||||
|
|
||||
## Installation |
#### `scheduleContentFetch(config)` |
||||
|
|
||||
```bash |
Schedule content fetching separately. |
||||
npm install @timesafari/daily-notification-plugin |
|
||||
|
```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>; |
||||
|
}); |
||||
``` |
``` |
||||
|
|
||||
## Documentation |
#### `scheduleUserNotification(config)` |
||||
|
|
||||
- **[Complete Usage Guide](USAGE.md)** - Comprehensive guide with examples and best practices |
Schedule user notifications separately. |
||||
- **[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 |
|
||||
|
|
||||
## Examples |
```typescript |
||||
|
await DailyNotification.scheduleUserNotification({ |
||||
|
schedule: string; // Cron expression |
||||
|
title: string; // Notification title |
||||
|
body: string; // Notification body |
||||
|
actions?: NotificationAction[]; |
||||
|
}); |
||||
|
``` |
||||
|
|
||||
- **Basic Usage**: `examples/usage.ts` |
#### `scheduleDualNotification(config)` |
||||
- **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` |
|
||||
|
|
||||
## Configuration |
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 |
### 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 |
```xml |
||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> |
||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" /> |
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" /> |
||||
<uses-permission android:name="android.permission.USE_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.RECEIVE_BOOT_COMPLETED" /> |
||||
<uses-permission android:name="android.permission.WAKE_LOCK" /> |
<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" /> |
<receiver android:name="com.timesafari.dailynotification.NotifyReceiver" |
||||
<uses-permission android:name="android.permission.INTERNET" /> |
android:enabled="true" |
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> |
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 |
### iOS Configuration |
||||
- Android Studio |
|
||||
- Android SDK |
|
||||
- Gradle |
|
||||
|
|
||||
### Building |
#### Info.plist |
||||
|
|
||||
```bash |
```xml |
||||
# Install dependencies |
<key>UIBackgroundModes</key> |
||||
npm install |
<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> |
||||
|
``` |
||||
|
|
||||
# Build the plugin |
#### Capabilities |
||||
npm run build |
|
||||
|
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) |
||||
|
}); |
||||
|
} |
||||
|
``` |
||||
|
|
||||
# Run tests |
## Testing |
||||
|
|
||||
|
### Unit Tests |
||||
|
|
||||
|
```bash |
||||
npm test |
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); |
||||
|
}); |
||||
|
}); |
||||
|
``` |
||||
|
|
||||
|
## 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(); |
||||
``` |
``` |
||||
daily-notification-plugin/ |
|
||||
├── android/ # Android implementation |
## Troubleshooting |
||||
│ ├── app/ # Main application module |
|
||||
│ └── build.gradle # Root build configuration |
### Common Issues |
||||
├── src/ # TypeScript source |
|
||||
├── tests/ # Test files |
#### Android |
||||
├── package.json # Package configuration |
|
||||
└── README.md # This file |
- **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 |
## 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 |
1. Fork the repository |
||||
2. Create your feature branch (`git checkout -b feature/amazing-feature`) |
2. Create a feature branch |
||||
3. Commit your changes (`git commit -m 'Add some amazing feature'`) |
3. Make your changes |
||||
4. Push to the branch (`git push origin feature/amazing-feature`) |
4. Add tests for new functionality |
||||
5. Open a Pull Request |
5. Ensure all tests pass |
||||
|
6. Submit a pull request |
||||
|
|
||||
## License |
## License |
||||
|
|
||||
This project is licensed under the MIT License - see the LICENSE file for details. |
MIT License - see [LICENSE](LICENSE) file for details. |
||||
|
|
||||
|
## Support |
||||
|
|
||||
## Author |
### Documentation |
||||
|
|
||||
Matthew Raymer |
- **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) |
||||
|
|
||||
## Security |
### Community |
||||
|
|
||||
This plugin follows security best practices: |
- **GitHub Issues**: Report bugs and request features |
||||
|
- **Discussions**: Ask questions and share solutions |
||||
|
- **Contributing**: Submit pull requests and improvements |
||||
|
|
||||
- Uses AndroidX for modern security features |
### Enterprise Support |
||||
- 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 |
|
||||
|
|
||||
## Changelog |
- **Custom Implementations**: Tailored solutions for enterprise needs |
||||
|
- **Integration Support**: Help with complex integrations |
||||
|
- **Performance Optimization**: Custom performance tuning |
||||
|
|
||||
### 1.0.0 |
--- |
||||
|
|
||||
- Initial release |
**Version**: 2.0.0 |
||||
- Basic notification scheduling |
**Last Updated**: 2025-09-22 09:22:32 UTC |
||||
- System state handling |
**Author**: Matthew Raymer |
||||
- Battery optimization support |
|
||||
- Background task management |
|
||||
- Rich logging system |
|
||||
|
File diff suppressed because it is too large
@ -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. |
Loading…
Reference in new issue