35 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), AccountViewView integration (settings UI)
- 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
- UI Integration: AccountViewView modification with new notification section
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)
- AccountViewView UI integration
Dependency Complexity
Internal Dependencies
- Medium:
- Router configuration (new routes)
- Store creation (Pinia)
- Component dependencies (ActionCard, StatusCard)
- Logger integration (replace console.* with project logger)
- AccountViewView modifications
- Settings schema updates
External Dependencies
- Medium:
@timesafari/daily-notification-plugin(external package)@capacitor/core(already in project)- 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
-
Plugin Availability: Plugin may not be available in package registry
- Mitigation: Verify package availability, consider local development setup
-
Platform Implementation: All platforms must implement interface methods
- Mitigation: Follow PlatformService pattern - Capacitor provides full implementation, Web/Electron return null or throw errors
-
Web/Electron Compatibility: Feature must not break non-Capacitor builds
- Mitigation: Use dynamic imports with platform checks, graceful fallbacks
-
Store State Management: Notification state persistence
- Mitigation: Follow existing Pinia patterns in codebase
-
AccountViewView Integration: UI changes must not affect existing functionality
- Mitigation: Use platform capability detection, hide UI on unsupported platforms
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
nullor 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
nullfor status/permissions, throw errors for scheduling - UI: Components check for
nullresponses 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
nullfor status/permissions, throw errors for scheduling - UI: Components check for
nullresponses 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
nullfor status/permissions, throws errors for scheduling operations - ElectronPlatformService: Returns
nullfor 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)
└── AccountViewView.vue (existing - add Daily Notifications section)
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"),
},
AccountViewView Integration Strategy
Overview
Integrate daily notification scheduling into AccountViewView.vue, allowing users to configure notification times directly from their account settings.
Integration Approach ✅ ACCEPTED
Decision: Create a separate "Daily Notifications" section
This approach adds a dedicated "Daily Notifications" section that checks PlatformService capabilities. On Capacitor platforms, it provides full functionality. On other platforms, the UI is hidden when PlatformService returns null for notification methods.
Key Benefits:
- Uses PlatformService interface pattern (consistent with camera, filesystem)
- Platform-specific features properly isolated
- Can use native time picker (better UX on mobile)
- Future-proof: Easy to extend with additional notification features
- Graceful degradation on unsupported platforms
UI Component Design
1. Platform Capability Detection
// In AccountViewView component
async checkNotificationSupport(): Promise<boolean> {
const platformService = PlatformServiceFactory.getInstance();
const status = await platformService.getDailyNotificationStatus();
return status !== null; // null means not supported
}
2. State Management
// Component properties
nativeNotificationEnabled: boolean = false;
nativeNotificationTime: string = ""; // Display format: "9:00 AM"
nativeNotificationTimeStorage: string = ""; // Plugin format: "09:00"
nativeNotificationTitle: string = "Daily Update";
nativeNotificationMessage: string = "Your daily notification is ready!";
notificationsSupported: boolean = false; // Computed from PlatformService
3. Template Section
<!-- New Daily Notifications section -->
<section
v-if="notificationsSupported"
id="sectionDailyNotifications"
class="bg-slate-100 rounded-md overflow-hidden px-4 py-4 mt-8 mb-8"
aria-labelledby="dailyNotificationsHeading"
>
<h2 id="dailyNotificationsHeading" class="mb-2 font-bold">
Daily Notifications
<button
class="text-slate-400 fa-fw cursor-pointer"
aria-label="Learn more about native notifications"
@click.stop="showNativeNotificationInfo"
>
<font-awesome icon="question-circle" aria-hidden="true" />
</button>
</h2>
<div class="flex items-center justify-between">
<div>Daily Notification</div>
<!-- Toggle switch -->
<div
class="relative ml-2 cursor-pointer"
role="switch"
:aria-checked="nativeNotificationEnabled"
@click="toggleNativeNotification()"
>
<!-- Custom toggle UI -->
</div>
</div>
<!-- Show current time when enabled -->
<div v-if="nativeNotificationEnabled" class="mt-2">
<div class="flex items-center justify-between">
<span>Scheduled for: {{ nativeNotificationTime }}</span>
<button
class="text-blue-500 text-sm"
@click="editNativeNotificationTime()"
>
Edit Time
</button>
</div>
</div>
</section>
4. Time Input ✅ SELECTED: HTML5 Time Input
Decision: Use HTML5 <input type="time"> for native mobile experience
<input
type="time"
v-model="nativeNotificationTimeStorage"
class="rounded border border-slate-400 px-2 py-2"
/>
Benefits:
- Native mobile time picker UI on Capacitor platforms
- Simpler implementation (no custom time parsing needed)
- Automatic 24-hour format output (compatible with plugin)
- System handles locale-specific time formatting
- Better UX on mobile devices
Note: HTML5 time input provides time in "HH:mm" format (24-hour) which matches the plugin's expected format perfectly.
5. Time Format Conversion (Using System Time)
Key Principle: Use device's local system time - no timezone conversions needed. The plugin handles system time natively.
// Convert "09:00" (plugin storage format) to "9:00 AM" (display)
function formatTimeForDisplay(time24: string): string {
const [hours, minutes] = time24.split(':');
const hourNum = parseInt(hours);
const isPM = hourNum >= 12;
const displayHour = hourNum === 0 ? 12 : hourNum > 12 ? hourNum - 12 : hourNum;
return `${displayHour}:${minutes} ${isPM ? 'PM' : 'AM'}`;
}
// HTML5 time input provides "HH:mm" in local time - use directly
// No UTC conversion needed - plugin handles local timezone
function getTimeFromInput(timeInput: string): string {
// timeInput is already in "HH:mm" format from <input type="time">
// This is in the user's local timezone - pass directly to plugin
return timeInput; // e.g., "09:00" in user's local time
}
Time Handling:
- PlatformService Integration: Uses device's local system time directly - NO UTC conversion needed. The plugin schedules notifications on the device itself, using the device's timezone.
Implementation Principles:
- HTML5
<input type="time">provides time in device's local timezone - Plugin receives time in "HH:mm" format and schedules relative to device's local time
- No manual timezone conversion or UTC calculations needed
- System automatically handles:
- Timezone changes
- Daylight saving time transitions
- Device timezone updates
- User sets "9:00 AM" in their local time → plugin schedules for 9:00 AM local time every day
Data Flow
1. Initialization
async initializeState() {
// ... existing initialization ...
const platformService = PlatformServiceFactory.getInstance();
// Check if notifications are supported on this platform
const status = await platformService.getDailyNotificationStatus();
if (status === null) {
// Notifications not supported - don't initialize
this.notificationsSupported = false;
return;
}
this.notificationsSupported = true;
// Load from settings
const nativeNotificationTime = settings.nativeNotificationTime || "";
this.nativeNotificationEnabled = !!nativeNotificationTime;
this.nativeNotificationTimeStorage = nativeNotificationTime;
if (nativeNotificationTime) {
this.nativeNotificationTime = formatTimeForDisplay(nativeNotificationTime);
}
// Update UI with current status
this.notificationStatus = status;
}
2. Enable Notification
async enableNativeNotification() {
try {
const platformService = PlatformServiceFactory.getInstance();
// 1. Request permissions if needed
const permissions = await platformService.checkNotificationPermissions();
if (permissions === null || permissions.notifications !== 'granted') {
const result = await platformService.requestNotificationPermissions();
if (result === null || !result.notifications) {
throw new Error("Notification permissions denied");
}
}
// 2. Schedule notification via PlatformService
// Time is in device's local system time (from HTML5 time input)
// PlatformService handles timezone and scheduling internally
await platformService.scheduleDailyNotification({
time: this.nativeNotificationTimeStorage, // "09:00" in local time
title: this.nativeNotificationTitle,
body: this.nativeNotificationMessage,
sound: true,
priority: 'high'
});
// 3. Save to settings
await this.$saveSettings({
nativeNotificationTime: this.nativeNotificationTimeStorage,
nativeNotificationTitle: this.nativeNotificationTitle,
nativeNotificationMessage: this.nativeNotificationMessage,
});
// 4. Update UI state
this.nativeNotificationEnabled = true;
this.notify.success("Daily notification scheduled successfully", TIMEOUTS.SHORT);
} catch (error) {
logger.error("Failed to enable notification:", error);
this.notify.error("Failed to schedule notification. Please try again.", TIMEOUTS.LONG);
}
}
3. Disable Notification
async disableNativeNotification() {
try {
const platformService = PlatformServiceFactory.getInstance();
// 1. Cancel notification via PlatformService
await platformService.cancelDailyNotification();
// 2. Clear settings
await this.$saveSettings({
nativeNotificationTime: "",
nativeNotificationTitle: "",
nativeNotificationMessage: "",
});
// 3. Update UI state
this.nativeNotificationEnabled = false;
this.nativeNotificationTime = "";
this.nativeNotificationTimeStorage = "";
this.notify.success("Daily notification disabled", TIMEOUTS.SHORT);
} catch (error) {
logger.error("Failed to disable native notification:", error);
this.notify.error("Failed to disable notification. Please try again.", TIMEOUTS.LONG);
}
}
4. Edit Time
Approach: Use inline HTML5 time input for quick edits
async editNativeNotificationTime() {
// Show inline HTML5 time input for quick changes
// For complex editing (title, message), navigate to ScheduleView
this.showTimeEdit = true;
}
Implementation Note: HTML5 time input provides native mobile picker experience when shown inline, making it ideal for quick time adjustments in AccountViewView.
Settings Schema
New Settings Fields
// Add to Settings interface in src/db/tables/settings.ts
interface Settings {
// ... existing fields ...
// Native notification settings (Capacitor only)
nativeNotificationTime?: string; // "09:00" format (24-hour)
nativeNotificationTitle?: string; // Default: "Daily Update"
nativeNotificationMessage?: string; // Default message
}
Settings Persistence
- Store in
settingstable via$saveSettings() - Use same pattern as
notifyingNewActivityTime - Persist across app restarts
- Sync with plugin state on component mount
UI/UX Considerations
Visual Design
- Section Style: Match existing notification section (
bg-slate-100 rounded-md) - Toggle Switch: Reuse existing custom toggle pattern
- Time Display: Show in user-friendly format ("9:00 AM")
- Edit Button: Small, subtle link/button to edit time
User Feedback
- Success: Toast notification when scheduled successfully
- Error: Clear error message with troubleshooting guidance
- Loading: Show loading state during plugin operations
- Permission Request: Handle gracefully if denied
Accessibility
- ARIA Labels: Proper labels for all interactive elements
- Keyboard Navigation: Full keyboard support
- Screen Reader: Clear announcements for state changes
Implementation Decisions ✅
Time Input Format ✅
- Selected: HTML5
<input type="time">for Capacitor platforms - Rationale: Native mobile experience, simpler code, automatic 24-hour format
Edit Approach ✅
- Selected: Inline HTML5 time input for quick edits in AccountViewView
- Note: For complex editing (title, message changes), users can navigate to dedicated ScheduleView
Settings Field Names ✅
- Selected:
nativeNotificationTime,nativeNotificationTitle,nativeNotificationMessage - Rationale: Clear distinction from web push notification fields
Notification Title/Message ✅
- Selected: Allow customization, default to "Daily Update" / "Your daily notification is ready!"
- Rationale: Flexibility for users, sensible defaults
Phase Breakdown
Phase 1: Foundation & Infrastructure
Complexity: Low-Medium
Goals: Set up factory architecture, store, and conditional loading
Tasks
-
Package Dependency
- Add
@timesafari/daily-notification-plugintopackage.json - Verify package availability/version
- Document in dependencies section
- Add
-
PlatformService Interface Extension
- Add notification methods to
PlatformServiceinterface - Define notification types/interfaces (NotificationStatus, ScheduleOptions, etc.)
- Implement in
CapacitorPlatformServiceusing@timesafari/daily-notification-plugin - Implement in
WebPlatformServicewith null returns / error throws - Implement in
ElectronPlatformServicewith null returns / error throws
- Add notification methods to
-
Pinia Store Setup
- Create
src/stores/app.tswith notification state - Define
NotificationStatusinterface - Implement
setNotificationStatus()action - Add platform detection to store
- Create
-
Native Fetcher Configuration Integration
- Update HomeView
configureNativeFetcher()to use active DID management - Replace
TEST_USER_ZERO_CONFIGreferences with$getActiveIdentity() - Replace
generateEndorserJWTwithcreateEndorserJwtForDid()fromsrc/libs/endorserServer.ts - Get
apiServerandstarredPlanHandleIdsfrom$accountSettings()
- Update HomeView
-
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 & AccountViewView Integration
Complexity: Medium
Goals: Create reusable components, main views, and AccountViewView integration
Tasks
-
Reusable Components
- Create
ActionCard.vuecomponent - Create
StatusCard.vuecomponent - Follow project styling patterns
- Add TypeScript interfaces
- Create
-
Home View Integration
- Modify existing
HomeView.vueOR create new notification home view - Integrate plugin diagnostics
- Add system status display
- Connect to Pinia store
- Replace
console.*with project logger
- Modify existing
-
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
- Create
-
AccountViewView Integration ✅ ACCEPTED
- Add separate "Daily Notifications" section
- Check platform capabilities before showing UI (
v-if="notificationsSupported") - Add computed property for platform capability detection
- Add toggle switch for enabling/disabling notifications
- Add HTML5 time input for scheduling time
- Integrate with PlatformService via PlatformServiceFactory
- Save/load settings from
settingstable - Implement time format conversion (display vs storage)
- Add enable/disable notification methods
- Add edit time functionality
- Add permission request flow
- Add error handling and user feedback
Acceptance Criteria
- ActionCard and StatusCard components created
- Home view shows notification diagnostics
- Schedule view allows notification scheduling
- AccountViewView has separate "Daily Notifications" section
- Notification section checks PlatformService capabilities before showing
- Toggle and time input functional in AccountViewView
- Settings persist across app restarts
- Plugin state syncs with settings
- All logging uses project logger
- Error handling implemented
- Loading states visible
- UI matches existing design patterns
Phase 3: Supporting Views & Configuration
Complexity: Medium
Goals: Complete all views and native fetcher configuration
Tasks
-
Supporting Views
- Create
NotificationsView.vue(list scheduled notifications) - Create
NotificationHistoryView.vue(notification history) - Create
NotificationSettingsView.vue(settings/preferences)
- Create
-
Native Fetcher Configuration
- Integrate
configureNativeFetcher()in HomeView - Use
$getActiveIdentity()to get active DID (replace TEST_USER_ZERO_CONFIG) - Use
createEndorserJwtForDid()for JWT generation - Get
apiServerandstarredPlanHandleIdsfrom$accountSettings() - Add error handling for configuration failures
- Integrate
-
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
-
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
- Test AccountViewView integration on Capacitor
-
Cross-Platform Validation
- Verify web build doesn't break
- Verify Electron build doesn't break
- Verify feature is hidden on non-Capacitor platforms
- Verify AccountViewView section hidden on web/electron
- Test graceful degradation
-
Integration Testing
- Test full scheduling workflow
- Test status checking workflow
- Test navigation between views
- Test store state persistence
- Test AccountViewView enable/disable/edit workflows
-
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
- AccountViewView integration verified on all platforms
- Integration tests passing
- Error scenarios handled gracefully
- Documentation updated
Milestones
Milestone 1: Foundation Complete
Success Criteria:
- PlatformService interface extended
- Store created and tested
- Routes accessible
- No build regressions
Milestone 2: Core Features Operational
Success Criteria:
- Home view shows diagnostics
- Schedule view functional
- AccountViewView integration complete
- 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
- AccountViewView notification section rendering
Integration Tests
- Plugin API calls
- Permission flows
- Status updates
- Navigation between views
- AccountViewView enable/disable/edit workflows
Platform Tests
- Capacitor Android: Notification scheduling, permissions, status, AccountViewView UI
- Capacitor iOS: Notification scheduling, permissions, status, AccountViewView UI
- Web: Feature hidden, no errors, AccountViewView section hidden
- Electron: Feature hidden, no errors, AccountViewView section hidden
E2E Tests (Playwright)
- Full notification scheduling workflow
- Permission request flow
- Status checking workflow
- Error handling scenarios
- AccountViewView notification configuration workflow
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
- AccountViewView component
- Settings schema and persistence
Configuration Dependencies
- Active DID Management: Use
$getActiveIdentity()fromPlatformServiceMixin(existing) - JWT Generation: Use
createEndorserJwtForDid(activeDid, payload)fromsrc/libs/endorserServer.ts(existing) - Settings Access: Use
$accountSettings()forapiServerandstarredPlanHandleIds(existing) - No new config files needed: Replace
TEST_USER_ZERO_CONFIGreferences with active DID and settings
Implementation Notes
Code Quality Standards
- Logging: Use
loggerfrom@/utils/logger, notconsole.* - 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
QRScannerFactoryfor 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 Pattern: Check capabilities via method results, not environment variables
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
nullor throw errors - Components check for
nullresponses 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
- Verify AccountViewView section properly hidden
Risk 4: Configuration Dependencies (RESOLVED)
Mitigation:
- Use existing active DID management: Use
$getActiveIdentity()fromPlatformServiceMixinto get currently selected DID - Use existing JWT generation: Use
createEndorserJwtForDid(activeDid, payload)fromsrc/libs/endorserServer.ts - Use existing settings: Get
apiServerandstarredPlanHandleIdsfrom$accountSettings() - No config files needed: The HomeView component code references
TEST_USER_ZERO_CONFIG, but should instead use the currently active DID and settings
Risk 5: AccountViewView Integration Issues
Mitigation:
- Use platform capability detection before showing UI
- Test on all platforms to ensure proper hiding
- Follow existing UI patterns for consistency
- Add comprehensive error handling
Success Criteria Summary
- Plugin integrated using PlatformService architecture
- Feature works on Capacitor (Android/iOS)
- Feature hidden/graceful on Web/Electron
- All components created and functional
- AccountViewView integration complete 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
- Verify Plugin Package: Confirm
@timesafari/daily-notification-pluginavailability - Update HomeView Configuration: Replace
TEST_USER_ZERO_CONFIGreferences in HomeView with existing active DID management ($getActiveIdentity(),createEndorserJwtForDid(),$accountSettings()) - Extend PlatformService: Add notification methods to PlatformService interface and implement in all platform services
- Set Up Store: Create Pinia store for notification state
- Begin Phase 1 Implementation: Start with foundation tasks
- AccountViewView Integration: Implement Daily Notifications section in Phase 2
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 requirementssrc/services/QRScanner/QRScannerFactory.ts- Factory pattern referencesrc/views/AccountViewView.vue- Target component for integration