Files
daily-notification-plugin/README.md

813 lines
24 KiB
Markdown

# Daily Notification Plugin
**Author**: Matthew Raymer
**Version**: 2.2.0
**Created**: 2025-09-22 09:22:32 UTC
**Last Updated**: 2025-10-08 06:02:45 UTC
## Overview
The Daily Notification Plugin is a comprehensive Capacitor plugin that provides enterprise-grade daily notification functionality across Android, iOS, and Electron platforms. It features dual scheduling, callback support, TTL-at-fire logic, and comprehensive observability.
### 🎯 **Native-First Architecture**
The plugin has been optimized for **native-first deployment** with the following key improvements:
**Platform Support:**
-**Android**: WorkManager + AlarmManager + SQLite
-**iOS**: BGTaskScheduler + UNUserNotificationCenter + Core Data
-**Electron**: Desktop notifications + SQLite/LocalStorage
-**Web (PWA)**: Removed for native-first focus
**Key Benefits:**
- **Simplified Architecture**: Focused on mobile and desktop platforms
- **Better Performance**: Optimized for native platform capabilities
- **Reduced Complexity**: Fewer platform-specific code paths
- **Cleaner Codebase**: Removed unused web-specific code (~90 lines)
## Implementation Status
### ✅ **Phase 2 Complete - Production Ready**
| Component | Status | Implementation |
|-----------|--------|----------------|
| **Android Core** | ✅ Complete | WorkManager + AlarmManager + SQLite |
| **iOS Parity** | ✅ Complete | BGTaskScheduler + UNUserNotificationCenter |
| **Web Service Worker** | ❌ Removed | Web support dropped for native-first architecture |
| **Callback Registry** | ✅ Complete | Circuit breaker + retry logic |
| **Observability** | ✅ Complete | Structured logging + health monitoring |
| **Documentation** | ✅ Complete | Migration guides + enterprise examples |
**All platforms are fully implemented with complete feature parity and enterprise-grade functionality.**
### 🧪 **Testing & Quality**
- **Test Coverage**: 58 tests across 4 test suites ✅
- **Build Status**: TypeScript compilation and Rollup bundling ✅
- **Code Quality**: ESLint and Prettier compliance ✅
- **Cross-Platform**: Unified API surface across all platforms ✅
## Features
### 🚀 **Core Features**
- **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
- **Static Daily Reminders**: Simple daily notifications without network content
- **Cross-Platform**: Android, iOS, and Electron implementations
### 📱 **Platform Support**
- **Android**: WorkManager + AlarmManager + SQLite (Room)
- **iOS**: BGTaskScheduler + UNUserNotificationCenter + Core Data
- **Web**: ❌ Removed (native-first architecture)
### 🔧 **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
- **Database Access**: Full TypeScript interfaces for plugin database access
- See [`docs/DATABASE_INTERFACES.md`](docs/DATABASE_INTERFACES.md) for complete API reference
- Plugin owns its SQLite database - access via Capacitor interfaces
- Supports schedules, content cache, callbacks, history, and configuration
### ⏰ **Static Daily Reminders**
- **No Network Required**: Completely offline reminder notifications
- **Simple Scheduling**: Easy daily reminder setup with HH:mm time format
- **Rich Customization**: Customizable title, body, sound, vibration, and priority
- **Persistent Storage**: Survives app restarts and device reboots
- **Cross-Platform**: Consistent API across Android, iOS, and Electron
- **Management**: Full CRUD operations for reminder management
## Installation
```bash
npm install @timesafari/daily-notification-plugin
```
Or install from Git repository:
```bash
npm install git+https://github.com/timesafari/daily-notification-plugin.git
```
The plugin follows the standard Capacitor Android structure - no additional path configuration needed!
## Quick Integration
**New to the plugin?** Start with the [Quick Integration Guide](./QUICK_INTEGRATION.md) for step-by-step setup instructions.
The quick guide covers:
- Installation and setup
- AndroidManifest.xml configuration (⚠️ **Critical**: NotifyReceiver registration)
- iOS configuration
- Basic usage examples
- Troubleshooting common issues
**For AI Agents**: See [AI Integration Guide](./AI_INTEGRATION_GUIDE.md) for explicit, machine-readable instructions with verification steps, error handling, and decision trees.
## Quick Start
### Basic Usage
```typescript
import { DailyNotification } from '@timesafari/daily-notification-plugin';
// Schedule a daily notification
await DailyNotification.scheduleDailyNotification({
title: 'Daily Update',
body: 'Your daily content is ready',
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
}
```
### Static Daily Reminders
For simple daily reminders that don't require network content:
```typescript
import { DailyNotification } from '@timesafari/daily-notification-plugin';
// Schedule a simple daily reminder
await DailyNotification.scheduleDailyReminder({
id: 'morning_checkin',
title: 'Good Morning!',
body: 'Time to check your TimeSafari community updates',
time: '09:00', // HH:mm format
sound: true,
vibration: true,
priority: 'normal',
repeatDaily: true
});
// Get all scheduled reminders
const result = await DailyNotification.getScheduledReminders();
console.log('Scheduled reminders:', result.reminders);
// Update an existing reminder
await DailyNotification.updateDailyReminder('morning_checkin', {
title: 'Updated Morning Reminder',
time: '08:30'
});
// Cancel a reminder
await DailyNotification.cancelDailyReminder('morning_checkin');
```
**Key Benefits of Static Reminders:**
-**No network dependency** - works completely offline
-**No content cache required** - direct notification display
-**Simple API** - easy to use for basic reminder functionality
-**Persistent** - survives app restarts and device reboots
## 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;
// }
```
### Android Diagnostic Methods
#### `isAlarmScheduled(options)`
Check if an alarm is scheduled for a specific trigger time. Useful for debugging and verification.
```typescript
const result = await DailyNotification.isAlarmScheduled({
triggerAtMillis: 1762421400000 // Unix timestamp in milliseconds
});
console.log(`Alarm scheduled: ${result.scheduled}`);
```
#### `getNextAlarmTime()`
Get the next scheduled alarm time from AlarmManager. Requires Android 5.0+ (API 21+).
```typescript
const result = await DailyNotification.getNextAlarmTime();
if (result.scheduled) {
const nextAlarm = new Date(result.triggerAtMillis);
console.log(`Next alarm: ${nextAlarm.toLocaleString()}`);
}
```
#### `testAlarm(options?)`
Schedule a test alarm that fires in a few seconds. Useful for verifying alarm delivery works correctly.
```typescript
// Schedule test alarm for 10 seconds from now
const result = await DailyNotification.testAlarm({ secondsFromNow: 10 });
console.log(`Test alarm scheduled for ${result.secondsFromNow} seconds`);
console.log(`Will fire at: ${new Date(result.triggerAtMillis).toLocaleString()}`);
```
## Capacitor Compatibility Matrix
| Plugin Version | Capacitor Version | Status | Notes |
|----------------|-------------------|--------|-------|
| 1.0.0+ | 6.2.1+ | ✅ **Recommended** | Latest stable, full feature support |
| 1.0.0+ | 6.0.0 - 6.2.0 | ✅ **Supported** | Full feature support |
| 1.0.0+ | 5.7.8 | ⚠️ **Legacy** | Deprecated, upgrade recommended |
### Quick Smoke Test
For immediate validation of plugin functionality:
- **Android**: [Manual Smoke Test - Android](./docs/manual_smoke_test.md#android-platform-testing)
- **iOS**: [Manual Smoke Test - iOS](./docs/manual_smoke_test.md#ios-platform-testing)
- **Electron**: [Manual Smoke Test - Electron](./docs/manual_smoke_test.md#electron-platform-testing)
### Manual Smoke Test Documentation
Complete testing procedures: [docs/manual_smoke_test.md](./docs/manual_smoke_test.md)
## 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
### Electron
- **Minimum Version**: Electron 20+
- **Desktop Notifications**: Native desktop notification APIs
- **Storage**: SQLite or LocalStorage fallback
- **Permissions**: Desktop notification permissions
## Capacitor Compatibility Matrix
| Plugin Version | Capacitor Version | Android | iOS | Electron | Status |
|----------------|-------------------|---------|-----|----------|--------|
| 2.2.x | 6.2.x | ✅ | ✅ | ✅ | **Current** |
| 2.1.x | 6.1.x | ✅ | ✅ | ✅ | Supported |
| 2.0.x | 6.0.x | ✅ | ✅ | ✅ | Supported |
| 1.x.x | 5.x.x | ⚠️ | ⚠️ | ❌ | Deprecated |
### Installation Guide
**For TimeSafari PWA Integration:**
```bash
# Install the plugin
npm install @timesafari/daily-notification-plugin
# For workspace development (recommended)
npm install --save-dev @timesafari/daily-notification-plugin
```
**Workspace Linking (Development):**
```bash
# Link plugin for local development
npm link @timesafari/daily-notification-plugin
# Or use pnpm workspace
pnpm add @timesafari/daily-notification-plugin --filter timesafari-app
```
**Capacitor Integration:**
```typescript
// In your Capacitor app
import { DailyNotification } from '@timesafari/daily-notification-plugin';
// Initialize the plugin
await DailyNotification.configure({
storage: 'tiered',
ttlSeconds: 1800,
enableETagSupport: true
});
```
### Static Daily Reminder Methods
#### `scheduleDailyReminder(options)`
Schedule a simple daily reminder without network content.
```typescript
await DailyNotification.scheduleDailyReminder({
id: string; // Unique reminder identifier
title: string; // Notification title
body: string; // Notification body
time: string; // Time in HH:mm format (e.g., "09:00")
sound?: boolean; // Enable sound (default: true)
vibration?: boolean; // Enable vibration (default: true)
priority?: 'low' | 'normal' | 'high'; // Priority level (default: 'normal')
repeatDaily?: boolean; // Repeat daily (default: true)
timezone?: string; // Optional timezone
});
```
#### `cancelDailyReminder(reminderId)`
Cancel a scheduled daily reminder.
```typescript
await DailyNotification.cancelDailyReminder('morning_checkin');
```
#### `getScheduledReminders()`
Get all scheduled reminders.
```typescript
const result = await DailyNotification.getScheduledReminders();
console.log('Reminders:', result.reminders);
```
#### `updateDailyReminder(reminderId, options)`
Update an existing daily reminder.
```typescript
await DailyNotification.updateDailyReminder('morning_checkin', {
title: 'Updated Title',
time: '08:30',
priority: 'high'
});
```
## Configuration
### Android Configuration
#### AndroidManifest.xml
**⚠️ CRITICAL**: The `NotifyReceiver` registration is **required** for alarm-based notifications to work. Without it, alarms will fire but notifications won't be displayed.
```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" />
<!-- NotifyReceiver for AlarmManager-based notifications -->
<!-- REQUIRED: Without this, alarms fire but notifications won't display -->
<receiver android:name="com.timesafari.dailynotification.NotifyReceiver"
android:enabled="true"
android:exported="false">
</receiver>
<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>
```
**Note**: The `NotifyReceiver` must be registered in your app's `AndroidManifest.xml`, not just in the plugin's manifest. If notifications aren't appearing even though alarms are scheduled, check that `NotifyReceiver` is properly registered.
#### 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 Configuration
#### 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
npm test
```
### 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();
```
## 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
- **Web Support**: Web platform support was removed for native-first architecture
### 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**: ❌ Removed (native-first architecture)
### 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 a feature branch
3. Make your changes
4. Add tests for new functionality
5. Ensure all tests pass
6. Submit a pull request
## License
MIT License - see [LICENSE](LICENSE) file for details.
## Support
### Documentation
- **API Reference**: Complete TypeScript definitions
- **Database Interfaces**: [`docs/DATABASE_INTERFACES.md`](docs/DATABASE_INTERFACES.md) - Complete guide to accessing plugin database from TypeScript/webview
- **Database Consolidation Plan**: [`android/DATABASE_CONSOLIDATION_PLAN.md`](android/DATABASE_CONSOLIDATION_PLAN.md) - Database schema consolidation roadmap
- **Database Implementation**: [`docs/DATABASE_INTERFACES_IMPLEMENTATION.md`](docs/DATABASE_INTERFACES_IMPLEMENTATION.md) - Implementation summary and status
- **Migration Guide**: [doc/migration-guide.md](doc/migration-guide.md)
- **Integration Guide**: [INTEGRATION_GUIDE.md](INTEGRATION_GUIDE.md) - Complete integration instructions
- **Building Guide**: [BUILDING.md](BUILDING.md) - Comprehensive build instructions and troubleshooting
- **AAR Integration Troubleshooting**: [docs/aar-integration-troubleshooting.md](docs/aar-integration-troubleshooting.md) - Resolving duplicate class issues
- **Android App Analysis**: [docs/android-app-analysis.md](docs/android-app-analysis.md) - Comprehensive analysis of /android/app structure and /www integration
- **ChatGPT Analysis Guide**: [docs/chatgpt-analysis-guide.md](docs/chatgpt-analysis-guide.md) - Structured prompts for AI analysis of the Android test app
- **Android App Improvement Plan**: [docs/android-app-improvement-plan.md](docs/android-app-improvement-plan.md) - Implementation plan for architecture improvements and testing enhancements
- **Implementation Guide**: [doc/STARRED_PROJECTS_POLLING_IMPLEMENTATION.md](doc/STARRED_PROJECTS_POLLING_IMPLEMENTATION.md) - Generic polling interface
- **UI Requirements**: [doc/UI_REQUIREMENTS.md](doc/UI_REQUIREMENTS.md) - Complete UI component requirements
- **Host App Examples**: [examples/hello-poll.ts](examples/hello-poll.ts) - Generic polling integration
- **Background Data Fetching Plan**: [doc/BACKGROUND_DATA_FETCHING_PLAN.md](doc/BACKGROUND_DATA_FETCHING_PLAN.md) - Complete Option A implementation guide
### 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
---
**Version**: 2.0.0
**Last Updated**: 2025-09-22 09:22:32 UTC
**Status**: Phase 2 Complete - Production Ready
**Author**: Matthew Raymer