Matthew Raymer 3512c58c2f fix(test-app): resolve StatusCard reactivity and improve plugin status detection
- Fix StatusCard component to properly react to prop changes by using computed() instead of ref()
- Improve plugin detection in HomeView using proper ES6 import instead of window object access
- Add comprehensive status mapping from plugin response to app store format
- Add detailed logging for plugin status, permissions, and exact alarm status
- Add separate Permissions status line in system status display
- Enhance error handling and debugging information for plugin operations

This resolves the issue where StatusCard was not updating when plugin status changed,
and improves the overall reliability of plugin detection and status reporting.
2025-10-18 12:33:09 +00:00
2025-09-22 07:27:01 +00:00

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

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

npm install @timesafari/daily-notification-plugin

Quick Start

Basic Usage

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
});
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

// 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:

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).

await DailyNotification.scheduleDailyNotification({
  title: string;
  body: string;
  schedule: string; // Cron expression
  actions?: NotificationAction[];
});

scheduleContentFetch(config)

Schedule content fetching separately.

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.

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.

await DailyNotification.scheduleDualNotification({
  contentFetch: ContentFetchConfig;
  userNotification: UserNotificationConfig;
});

Callback Methods

registerCallback(name, config)

Register a callback function.

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.

await DailyNotification.unregisterCallback('callback-name');

getRegisteredCallbacks()

Get list of registered callbacks.

const callbacks = await DailyNotification.getRegisteredCallbacks();
// Returns: string[]

Status Methods

getDualScheduleStatus()

Get comprehensive status information.

const status = await DailyNotification.getDualScheduleStatus();
// Returns: {
//   nextRuns: number[];
//   lastOutcomes: string[];
//   cacheAgeMs: number | null;
//   staleArmed: boolean;
//   queueDepth: number;
//   circuitBreakers: CircuitBreakerStatus;
//   performance: PerformanceMetrics;
// }

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:

Manual Smoke Test Documentation

Complete testing procedures: docs/manual_smoke_test.md

High-Performance Emulator Testing

For optimal Android emulator performance on Linux systems with NVIDIA graphics:

# Launch emulator with GPU acceleration
cd test-apps
./launch-emulator-gpu.sh

Features:

  • Hardware GPU acceleration for smoother UI
  • Vulkan graphics API support
  • NVIDIA GPU offloading
  • Fast startup and clean state
  • Optimized for development workflow

See test-apps/SETUP_GUIDE.md for detailed configuration.

Troubleshooting GPU Issues:

  • EMULATOR_TROUBLESHOOTING.md - Comprehensive GPU binding solutions
  • Alternative GPU modes: OpenGL, ANGLE, Mesa fallback
  • Performance verification and optimization tips

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:

# Install the plugin
npm install @timesafari/daily-notification-plugin

# For workspace development (recommended)
npm install --save-dev @timesafari/daily-notification-plugin

Workspace Linking (Development):

# 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:

// 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.

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.

await DailyNotification.cancelDailyReminder('morning_checkin');

getScheduledReminders()

Get all scheduled reminders.

const result = await DailyNotification.getScheduledReminders();
console.log('Reminders:', result.reminders);

updateDailyReminder(reminderId, options)

Update an existing daily reminder.

await DailyNotification.updateDailyReminder('morning_checkin', {
  title: 'Updated Title',
  time: '08:30',
  priority: 'high'
});

Configuration

Android Configuration

AndroidManifest.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" />

<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>

build.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

<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

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

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

npm test

Integration Tests

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

// 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

// 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

// 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

// 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

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 file for details.

Support

Documentation

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

Description
No description provided
Readme MIT 9.8 MiB
Languages
Java 44.8%
TypeScript 17.6%
Swift 13.5%
Kotlin 8.5%
Vue 4.5%
Other 11.1%