You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

22 KiB

Daily Notification Plugin Integration Plan

Author: Matthew Raymer
Date: 2025-11-03
Status: 🎯 PLANNING - Feature planning phase
Feature: Daily Notification Plugin Integration
Platform Scope: Capacitor-only (Android/iOS)


Executive Summary

This plan outlines the integration of @timesafari/daily-notification-plugin into the TimeSafari application using the PlatformService interface pattern. The feature is implemented on all platforms via PlatformService, but only Capacitor platforms provide full functionality. Web and Electron platforms return null for unsupported operations.

Key Requirements

  • Platform: All platforms (Capacitor provides full functionality, Web/Electron return null)
  • Architecture: PlatformService interface integration (all platforms implement, unsupported return null)
  • Components: Home view (diagnostics/status) + Schedule view (time setting)
  • Store: Pinia store for notification state management
  • Routes: New routes for schedule, notifications, history, settings views

Complexity Assessment

Technical Complexity: Medium

Code Changes

  • Medium: New Vue components, Pinia store, router routes
  • Pattern: Following PlatformService interface pattern (like camera, filesystem methods) - all platforms implement, unsupported return null
  • Integration: Plugin API integration with error handling

Platform Impact

  • Single Platform: Capacitor-only (Android/iOS)
  • Conditional Loading: Feature only loads on Capacitor platforms
  • Graceful Degradation: Web/Electron builds should not break when plugin unavailable

Testing Requirements

  • Comprehensive:
    • Plugin availability detection
    • Permission request flows
    • Notification scheduling
    • Status checking
    • Cross-platform validation (ensure web/electron unaffected)

Dependency Complexity

Internal Dependencies

  • Medium:
    • Router configuration (new routes)
    • Store creation (Pinia)
    • Component dependencies (ActionCard, StatusCard)
    • Logger integration (replace console.* with project logger)

External Dependencies

  • Medium:
    • @timesafari/daily-notification-plugin (external package)
    • Capacitor core APIs
    • Platform detection utilities

Infrastructure Dependencies

  • Low:
    • Package.json update (add plugin dependency)
    • Vite conditional imports for Capacitor builds only
    • No infrastructure changes required

Risk Factors

  1. Plugin Availability: Plugin may not be available in package registry

    • Mitigation: Verify package availability, consider local development setup
  2. Platform Implementation: All platforms must implement interface methods

    • Mitigation: Follow PlatformService pattern - Capacitor provides full implementation, Web/Electron return null or throw errors
  3. Web/Electron Compatibility: Feature must not break non-Capacitor builds

    • Mitigation: Use dynamic imports with platform checks, graceful fallbacks
  4. Store State Management: Notification state persistence

    • Mitigation: Follow existing Pinia patterns in codebase

Platform Analysis

Target Platform: Capacitor Only

Capacitor Requirements

  • Android: API 21+ (already supported)
  • iOS: 13+ (already supported)
  • Native platform detection: Capacitor.isNativePlatform()

Build Configuration

  • Vite Config: vite.config.capacitor.mts (already exists)
  • Build Command: npm run build:capacitor
  • Conditional Import Pattern: Dynamic import based on process.env.VITE_PLATFORM === 'capacitor'

Platform Detection Strategy

Pattern: PlatformService interface - all platforms implement methods

Components check PlatformService capabilities by calling methods and checking for null returns:

// Components check capability via PlatformService
const platformService = PlatformServiceFactory.getInstance();
const status = await platformService.getDailyNotificationStatus();

if (status === null) {
  // Notifications not supported on this platform - hide UI
  return;
}
// Continue with notification features

Why PlatformService Pattern?

  • Consistent with existing platform capabilities (camera, filesystem)
  • All platforms implement the interface (contract compliance)
  • Unsupported platforms return null or throw clear errors
  • Components handle capability detection via method results, not environment variables

Web/Electron Implementation Strategy

Web Platform

  • Implementation: All notification methods implemented in WebPlatformService
  • Behavior: Methods return null for status/permissions, throw errors for scheduling
  • UI: Components check for null responses to hide notification UI
  • Plugin Import: No plugin imports - methods return null/throw errors directly

Electron Platform

  • Implementation: All notification methods implemented in ElectronPlatformService
  • Behavior: Methods return null for status/permissions, throw errors for scheduling
  • UI: Components check for null responses to hide notification UI
  • Plugin Import: No plugin imports - methods return null/throw errors directly

Architecture Design

PlatformService Integration

Key Pattern: Add notification methods directly to PlatformService interface, implemented on all platforms. Unsupported platforms return null or empty results.

This follows the same pattern as other platform capabilities (camera, filesystem) where all platforms implement the interface, but unsupported platforms return null/empty results.

// src/services/PlatformService.ts - Add to interface
export interface PlatformService {
  // ... existing methods ...

  // Daily notification operations
  /**
   * Get the status of scheduled daily notifications
   * @returns Promise resolving to notification status, or null if not supported
   */
  getDailyNotificationStatus(): Promise<NotificationStatus | null>;

  /**
   * Check notification permissions
   * @returns Promise resolving to permission status, or null if not supported
   */
  checkNotificationPermissions(): Promise<PermissionStatus | null>;

  /**
   * Request notification permissions
   * @returns Promise resolving to permission result, or null if not supported
   */
  requestNotificationPermissions(): Promise<PermissionResult | null>;

  /**
   * Schedule a daily notification
   * @param options - Notification scheduling options
   * @returns Promise that resolves when scheduled, or rejects if not supported
   */
  scheduleDailyNotification(options: ScheduleOptions): Promise<void>;

  /**
   * Cancel scheduled daily notification
   * @returns Promise that resolves when cancelled, or rejects if not supported
   */
  cancelDailyNotification(): Promise<void>;

  /**
   * Configure native fetcher for background operations
   * @param config - Native fetcher configuration
   * @returns Promise that resolves when configured, or null if not supported
   */
  configureNativeFetcher(config: NativeFetcherConfig): Promise<void | null>;

  /**
   * Update starred plans for background fetcher
   * @param plans - Starred plan IDs
   * @returns Promise that resolves when updated, or null if not supported
   */
  updateStarredPlans(plans: { planIds: string[] }): Promise<void | null>;
}

Implementation Pattern:

  • CapacitorPlatformService: Full implementation using @timesafari/daily-notification-plugin
  • WebPlatformService: Returns null for status/permissions, throws errors for scheduling operations
  • ElectronPlatformService: Returns null for status/permissions, throws errors for scheduling operations

PlatformService Interface Extensions

// Types/interfaces for notification operations
export interface NotificationStatus {
  isScheduled: boolean;
  scheduledTime?: string; // "HH:mm" format
  lastTriggered?: string;
  permissions: PermissionStatus;
}

export interface PermissionStatus {
  notifications: 'granted' | 'denied' | 'prompt';
  exactAlarms?: 'granted' | 'denied' | 'prompt'; // Android only
}

export interface PermissionResult {
  notifications: boolean;
  exactAlarms?: boolean; // Android only
}

export interface ScheduleOptions {
  time: string; // "HH:mm" format in local time
  title: string;
  body: string;
  sound?: boolean;
  priority?: 'high' | 'normal' | 'low';
}

export interface NativeFetcherConfig {
  apiServer: string;
  jwt: string;
  starredPlanHandleIds: string[];
}

Implementation Behavior:

  • Capacitor: Full implementation, all methods functional
  • Web/Electron: Status/permission methods return null, scheduling methods throw errors with clear messages

Component Architecture

Views Structure

src/views/
  ├── HomeView.vue (existing - modify to add notification diagnostics)
  ├── ScheduleView.vue (new - notification scheduling)
  ├── NotificationsView.vue (new - view scheduled notifications)
  ├── NotificationHistoryView.vue (new - notification history)
  └── NotificationSettingsView.vue (new - notification settings)

Supporting Components

src/components/cards/
  ├── ActionCard.vue (new - reusable action card)
  └── StatusCard.vue (new - reusable status card)

Store Structure

src/stores/
  └── app.ts (new - Pinia store for app-wide state)
    - notificationStatus: NotificationStatus | null
    - platform: 'web' | 'capacitor' | 'electron'
    - setNotificationStatus(status): void

Router Integration

// src/router/index.ts - Add new routes
{
  path: "/schedule",
  name: "schedule",
  component: () => import("../views/ScheduleView.vue"),
},
{
  path: "/notifications",
  name: "notifications",
  component: () => import("../views/NotificationsView.vue"),
},
{
  path: "/history",
  name: "notification-history",
  component: () => import("../views/NotificationHistoryView.vue"),
},
{
  path: "/settings",
  name: "settings",
  component: () => import("../views/NotificationSettingsView.vue"),
},

Phase Breakdown

Phase 1: Foundation & Infrastructure

Complexity: Low-Medium
Goals: Set up factory architecture, store, and conditional loading

Tasks

  1. Package Dependency

    • Add @timesafari/daily-notification-plugin to package.json
    • Verify package availability/version
    • Document in dependencies section
  2. PlatformService Interface Extension

    • Add notification methods to PlatformService interface
    • Define notification types/interfaces (NotificationStatus, ScheduleOptions, etc.)
    • Implement in CapacitorPlatformService using @timesafari/daily-notification-plugin
    • Implement in WebPlatformService with null returns / error throws
    • Implement in ElectronPlatformService with null returns / error throws
  3. Pinia Store Setup

    • Create src/stores/app.ts with notification state
    • Define NotificationStatus interface
    • Implement setNotificationStatus() action
    • Add platform detection to store
  4. Native Fetcher Configuration Integration

    • Update HomeView configureNativeFetcher() to use active DID management
    • Replace TEST_USER_ZERO_CONFIG references with $getActiveIdentity()
    • Replace generateEndorserJWT with createEndorserJwtForDid() from src/libs/endorserServer.ts
    • Get apiServer and starredPlanHandleIds from $accountSettings()
  5. Router Routes

    • Add route definitions for schedule, notifications, history, settings
    • Test route navigation

Acceptance Criteria

  • PlatformService interface extended with notification methods
  • CapacitorPlatformService implements notification methods using plugin
  • WebPlatformService and ElectronPlatformService return null/throw errors appropriately
  • Pinia store created and tested
  • HomeView configureNativeFetcher() updated to use active DID (no TEST_USER_ZERO_CONFIG)
  • Routes added and accessible
  • No build errors in web/electron builds

Phase 2: Core Components

Complexity: Medium
Goals: Create reusable components and main views

Tasks

  1. Reusable Components

    • Create ActionCard.vue component
    • Create StatusCard.vue component
    • Follow project styling patterns
    • Add TypeScript interfaces
  2. Home View Integration

    • Modify existing HomeView.vue OR create new notification home view
    • Integrate plugin diagnostics
    • Add system status display
    • Connect to Pinia store
    • Replace console.* with project logger
  3. Schedule View

    • Create ScheduleView.vue (provided code as reference)
    • Integrate with PlatformService via PlatformServiceFactory
    • Add error handling
    • Replace console.* with project logger
    • Add loading states
  4. AccountViewView Integration ACCEPTED: Option A

    • Add separate "Daily Notifications" section
    • Check platform capabilities before showing UI
    • Add toggle switch for enabling/disabling notifications
    • Add HTML5 time input for scheduling time
    • Integrate with PlatformService via PlatformServiceFactory
    • Save/load settings from settings table

Acceptance Criteria

  • ActionCard and StatusCard components created
  • Home view shows notification diagnostics
  • Schedule view allows notification scheduling
  • AccountViewView has separate "Daily Notifications" section (Option A accepted)
  • Notification section checks PlatformService capabilities before showing
  • Toggle and time input functional in AccountViewView
  • All logging uses project logger
  • Error handling implemented
  • Loading states visible

Phase 3: Supporting Views & Configuration

Complexity: Medium
Goals: Complete all views and native fetcher configuration

Tasks

  1. Supporting Views

    • Create NotificationsView.vue (list scheduled notifications)
    • Create NotificationHistoryView.vue (notification history)
    • Create NotificationSettingsView.vue (settings/preferences)
  2. Native Fetcher Configuration

    • Integrate configureNativeFetcher() in HomeView
    • Use $getActiveIdentity() to get active DID (replace TEST_USER_ZERO_CONFIG)
    • Use createEndorserJwtForDid() for JWT generation
    • Get apiServer and starredPlanHandleIds from $accountSettings()
    • Add error handling for configuration failures
  3. Permission Management

    • Implement permission request flow
    • Handle permission denial gracefully
    • Update status after permission changes

Acceptance Criteria

  • All supporting views created and functional
  • Native fetcher configuration working
  • Permission requests handled properly
  • Status updates after permission changes
  • Error handling for all failure cases

Phase 4: Testing & Validation

Complexity: Medium-High
Goals: Comprehensive testing across platforms and scenarios

Tasks

  1. Capacitor Testing

    • Test plugin availability detection
    • Test notification scheduling on Android
    • Test notification scheduling on iOS
    • Test permission requests
    • Test status updates
    • Test native fetcher configuration
  2. Cross-Platform Validation

    • Verify web build doesn't break
    • Verify Electron build doesn't break
    • Verify feature is hidden on non-Capacitor platforms
    • Test graceful degradation
  3. Integration Testing

    • Test full scheduling workflow
    • Test status checking workflow
    • Test navigation between views
    • Test store state persistence
  4. Error Scenarios

    • Test plugin unavailable scenarios
    • Test permission denied scenarios
    • Test network failures (for native fetcher)
    • Test invalid configuration scenarios

Acceptance Criteria

  • All Capacitor tests passing
  • Web/Electron builds unaffected
  • Integration tests passing
  • Error scenarios handled gracefully
  • Documentation updated

Milestones

Milestone 1: Foundation Complete

Success Criteria:

  • Factory service operational
  • Store created and tested
  • Routes accessible
  • No build regressions

Milestone 2: Core Features Operational

Success Criteria:

  • Home view shows diagnostics
  • Schedule view functional
  • Plugin integration working
  • Logging standardized

Milestone 3: Full Feature Set

Success Criteria:

  • All views created and functional
  • Native fetcher configured
  • Permissions managed properly
  • Status updates working

Milestone 4: Production Ready

Success Criteria:

  • All tests passing
  • Cross-platform validation complete
  • Error handling robust
  • Documentation complete

Testing Strategy

Unit Tests

  • Factory service platform detection
  • Store actions and state management
  • Component rendering and interactions

Integration Tests

  • Plugin API calls
  • Permission flows
  • Status updates
  • Navigation between views

Platform Tests

  • Capacitor Android: Notification scheduling, permissions, status
  • Capacitor iOS: Notification scheduling, permissions, status
  • Web: Feature hidden, no errors
  • Electron: Feature hidden, no errors

E2E Tests (Playwright)

  • Full notification scheduling workflow
  • Permission request flow
  • Status checking workflow
  • Error handling scenarios

Dependencies

External Dependencies

  • @timesafari/daily-notification-plugin (to be added)
  • @capacitor/core (already in project)
  • vue (already in project)
  • vue-router (already in project)
  • pinia (already in project)

Internal Dependencies

  • Logger service (@/utils/logger)
  • Platform detection utilities
  • Router configuration
  • Existing component patterns

Configuration Dependencies

  • Active DID Management: Use $getActiveIdentity() from PlatformServiceMixin (existing)
  • JWT Generation: Use createEndorserJwtForDid(activeDid, payload) from src/libs/endorserServer.ts (existing)
  • Settings Access: Use $accountSettings() for apiServer and starredPlanHandleIds (existing)
  • No new config files needed: Replace TEST_USER_ZERO_CONFIG references with active DID and settings

Implementation Notes

Code Quality Standards

  • Logging: Use logger from @/utils/logger, not console.*
  • File Documentation: Add file-level documentation headers
  • Method Documentation: Rich method-level documentation
  • Type Safety: Full TypeScript typing
  • PEP8/Prettier: Follow code style guidelines
  • Line Length: Keep methods < 80 columns when possible

Architecture Patterns to Follow

  • Factory Pattern: Like QRScannerFactory for conditional loading
  • Service Interface: Abstract interface with platform implementations
  • Store Pattern: Pinia store for state management
  • Composition API vs Class: Use provided code style (Composition API for HomeView, Class for ScheduleView)

PlatformService Integration Strategy

Pattern: Direct integration into PlatformService interface (like camera, filesystem methods)

// In components - use PlatformServiceFactory pattern
import { PlatformServiceFactory } from '@/services/PlatformServiceFactory';

const platformService = PlatformServiceFactory.getInstance();

// Check if notifications are supported
const status = await platformService.getDailyNotificationStatus();
if (status === null) {
  // Notifications not supported on this platform - hide UI
  return;
}

// Schedule notification
await platformService.scheduleDailyNotification({
  time: "09:00",
  title: "Daily Update",
  body: "Your daily notification is ready!",
});

Key Points:

  • Methods available on all PlatformService implementations
  • CapacitorPlatformService provides full implementation
  • WebPlatformService/ElectronPlatformService return null or throw errors
  • Components check for null responses to hide/show UI appropriately
  • No separate factory needed - uses existing PlatformServiceFactory pattern

Risk Mitigation

Risk 1: Plugin Package Unavailable

Mitigation:

  • Verify package exists and is accessible
  • Consider local development setup if needed
  • Document package installation requirements

Risk 2: Platform Detection Failures

Mitigation:

  • Use proven patterns from QRScannerFactory
  • Test on all platforms
  • Add fallback logic

Risk 3: Web/Electron Build Breaks

Mitigation:

  • Use dynamic imports exclusively
  • Test web/electron builds after each phase
  • Ensure no static plugin imports

Risk 4: Configuration Dependencies (RESOLVED)

Mitigation:

  • Use existing active DID management: Use $getActiveIdentity() from PlatformServiceMixin to get currently selected DID
  • Use existing JWT generation: Use createEndorserJwtForDid(activeDid, payload) from src/libs/endorserServer.ts
  • Use existing settings: Get apiServer and starredPlanHandleIds from $accountSettings()
  • No config files needed: The HomeView component code references TEST_USER_ZERO_CONFIG, but should instead use the currently active DID and settings

Success Criteria Summary

  • Plugin integrated using factory architecture
  • Feature works on Capacitor (Android/iOS)
  • Feature hidden/graceful on Web/Electron
  • All components created and functional
  • Store manages notification state
  • Router routes accessible
  • Logging standardized (no console.*)
  • Error handling robust
  • Cross-platform testing complete
  • Documentation updated
  • No build regressions

Next Steps

  1. Verify Plugin Package: Confirm @timesafari/daily-notification-plugin availability
  2. Update HomeView Configuration: Replace TEST_USER_ZERO_CONFIG references in HomeView with existing active DID management ($getActiveIdentity(), createEndorserJwtForDid(), $accountSettings())
  3. Extend PlatformService: Add notification methods to PlatformService interface and implement in all platform services
  4. Set Up Store: Create Pinia store for notification state
  5. Begin Phase 1 Implementation: Start with foundation tasks

See also:

  • .cursor/rules/meta_feature_planning.mdc - Feature planning workflow
  • .cursor/rules/app/architectural_patterns.mdc - Architecture patterns
  • .cursor/rules/app/timesafari_platforms.mdc - Platform requirements
  • src/services/QRScanner/QRScannerFactory.ts - Factory pattern reference