# Notification System Overview **Date**: 2026-01-23 **Purpose**: Understanding notification architecture and implementation guide for daily-notification-plugin --- ## Executive Summary Your app has **two separate notification systems** that coexist: 1. **Web Push Notifications** (Web/PWA platforms) - Uses service workers, VAPID keys, and a push server - Requires the "Notification Push Server" setting - Server-based delivery 2. **Native Notifications** (iOS/Android via DailyNotificationPlugin) - Uses native OS notification APIs - On-device scheduling (no server needed) - The "Notification Push Server" setting is **NOT used** for native The system automatically selects the correct implementation based on platform using `Capacitor.isNativePlatform()`. --- ## Notification Push Server Setting ### Location - **File**: `src/views/AccountViewView.vue` (lines 506-549) - **UI Section**: Advanced Settings → "Notification Push Server" - **Database Field**: `settings.webPushServer` ### Purpose The "Notification Push Server" setting **ONLY applies to Web Push notifications** (web/PWA platforms). It configures: 1. **VAPID Key Retrieval**: The server URL used to fetch VAPID (Voluntary Application Server Identification) keys 2. **Subscription Endpoint**: Where push subscriptions are sent 3. **Push Message Delivery**: The server that sends push messages to browsers ### How It Works (Web Push Flow) ``` User enables notification ↓ PushNotificationPermission.vue opens ↓ Fetches VAPID key from: {webPushServer}/web-push/vapid ↓ Subscribes to browser push service ↓ Sends subscription + time + message to: {webPushServer}/web-push/subscribe ↓ Server stores subscription and schedules push messages ↓ Server sends push messages at scheduled time via browser push service ``` ### Key Code Locations **AccountViewView.vue** (lines 1473-1479): ```typescript async onClickSavePushServer(): Promise { await this.$saveSettings({ webPushServer: this.webPushServerInput, }); this.webPushServer = this.webPushServerInput; this.notify.warning(ACCOUNT_VIEW_CONSTANTS.INFO.RELOAD_VAPID); } ``` **PushNotificationPermission.vue** (lines 177-221): - Retrieves `webPushServer` from settings - Fetches VAPID key from `{webPushServer}/web-push/vapid` - Uses VAPID key to subscribe to push notifications **PushNotificationPermission.vue** (lines 556-575): - Sends subscription to `/web-push/subscribe` endpoint (relative URL, handled by service worker) ### Important Notes - ⚠️ **This setting is NOT used for native iOS/Android notifications** - The setting defaults to `DEFAULT_PUSH_SERVER` if not configured - Changing the server requires reloading VAPID keys (hence the warning message) - Local development (`http://localhost`) skips VAPID key retrieval --- ## Daily Notification Plugin Integration ### Current Status ✅ **Infrastructure Complete**: - Plugin registered (`src/plugins/DailyNotificationPlugin.ts`) - Service abstraction layer created (`src/services/notifications/`) - Platform detection working - Native implementation ready (`NativeNotificationService.ts`) 🔄 **UI Integration Needed**: - `PushNotificationPermission.vue` still uses web push logic - AccountViewView notification toggles need platform detection - Settings storage needs to handle both systems ### Architecture ``` NotificationService.getInstance() ↓ Platform Detection (Capacitor.isNativePlatform()) ↓ ┌─────────────────────┬─────────────────────┐ │ Native Platform │ Web Platform │ │ (iOS/Android) │ (Web/PWA) │ ├─────────────────────┼─────────────────────┤ │ NativeNotification │ WebPushNotification │ │ Service │ Service │ │ │ │ │ Uses: │ Uses: │ │ - DailyNotification │ - Service Workers │ │ Plugin │ - VAPID Keys │ │ - Native OS APIs │ - Push Server │ │ - On-device alarms │ - Server scheduling │ └─────────────────────┴─────────────────────┘ ``` ### Key Differences | Feature | Native (Plugin) | Web Push | |---------|----------------|----------| | **Server Required** | ❌ No | ✅ Yes (Notification Push Server) | | **Scheduling** | On-device | Server-side | | **Offline Delivery** | ✅ Yes | ❌ No (requires network) | | **Background Support** | ✅ Full | ⚠️ Limited (browser-dependent) | | **Permission Model** | OS-level | Browser-level | | **Settings Storage** | Local only | Local + server subscription | --- ## Implementation Recommendations ### 1. Update PushNotificationPermission Component **Current State**: Only handles web push **Recommended Changes**: ```typescript // In PushNotificationPermission.vue import { NotificationService } from '@/services/notifications'; import { Capacitor } from '@capacitor/core'; async open(pushType: string, callback?: ...) { const isNative = Capacitor.isNativePlatform(); if (isNative) { // Use native notification service const service = NotificationService.getInstance(); const granted = await service.requestPermissions(); if (granted) { // Show time picker UI // Then schedule via service.scheduleDailyNotification() } } else { // Existing web push logic // ... current implementation ... } } ``` ### 2. Update AccountViewView Notification Toggles **Current State**: Always uses `PushNotificationPermission` component (web push) **Recommended Changes**: ```typescript // In AccountViewView.vue import { NotificationService } from '@/services/notifications'; import { Capacitor } from '@capacitor/core'; async showNewActivityNotificationChoice(): Promise { const isNative = Capacitor.isNativePlatform(); if (isNative) { // Use native service directly const service = NotificationService.getInstance(); // Show time picker, then schedule } else { // Use existing PushNotificationPermission component (this.$refs.pushNotificationPermission as PushNotificationPermission) .open(DAILY_CHECK_TITLE, ...); } } ``` ### 3. Settings Storage Strategy **Current Settings Fields** (from `src/db/tables/settings.ts`): - `notifyingNewActivityTime` - Time string for daily check - `notifyingReminderTime` - Time string for reminder - `notifyingReminderMessage` - Reminder message text - `webPushServer` - Push server URL (web only) **Recommendation**: These settings work for both systems: - ✅ `notifyingNewActivityTime` - Works for both (native stores locally, web sends to server) - ✅ `notifyingReminderTime` - Works for both - ✅ `notifyingReminderMessage` - Works for both - ⚠️ `webPushServer` - Only used for web push (hide on native platforms) ### 4. Platform-Aware UI **Recommendations**: 1. **Hide "Notification Push Server" setting on native platforms**: ```vue

Notification Push Server

``` 2. **Update help text** to explain platform differences 3. **Show different messaging** based on platform: - Native: "Notifications are scheduled on your device" - Web: "Notifications are sent via push server" --- ## Notification Types Your app supports two notification types: ### 1. Daily Check (`DAILY_CHECK_TITLE`) - **Purpose**: Notify user of new activity/updates - **Message**: Auto-generated by server (web) or app (native) - **Settings Field**: `notifyingNewActivityTime` ### 2. Direct Push (`DIRECT_PUSH_TITLE`) - **Purpose**: Daily reminder with custom message - **Message**: User-provided (max 100 characters) - **Settings Fields**: `notifyingReminderTime`, `notifyingReminderMessage` Both types can be enabled simultaneously. --- ## Code Flow Examples ### Native Notification Flow (Recommended Implementation) ```typescript // 1. Get service instance const service = NotificationService.getInstance(); // 2. Request permissions const granted = await service.requestPermissions(); if (!granted) { // Show error, guide to settings return; } // 3. Schedule notification await service.scheduleDailyNotification({ time: '09:00', // HH:mm format (24-hour) title: 'Daily Check-In', body: 'Time to check your TimeSafari activity', priority: 'normal' }); // 4. Save to settings await this.$saveSettings({ notifyingNewActivityTime: '09:00' }); // 5. Check status const status = await service.getStatus(); console.log('Enabled:', status.enabled); console.log('Time:', status.scheduledTime); ``` ### Web Push Flow (Current Implementation) ```typescript // 1. Open PushNotificationPermission component (this.$refs.pushNotificationPermission as PushNotificationPermission) .open(DAILY_CHECK_TITLE, async (success, timeText) => { if (success) { // Component handles: // - VAPID key retrieval from webPushServer // - Service worker subscription // - Sending subscription to server // Just save the time await this.$saveSettings({ notifyingNewActivityTime: timeText }); } }); ``` --- ## Testing Checklist ### Native (iOS/Android) - [ ] Request permissions works - [ ] Notification appears at scheduled time - [ ] Notification survives app close - [ ] Notification survives device reboot - [ ] Both notification types can be enabled - [ ] Cancellation works correctly ### Web Push - [ ] VAPID key retrieval works - [ ] Service worker subscription works - [ ] Subscription sent to server - [ ] Push messages received at scheduled time - [ ] Works with different push server URLs ### Platform Detection - [ ] Correct service selected on iOS - [ ] Correct service selected on Android - [ ] Correct service selected on web - [ ] Settings UI shows/hides appropriately --- ## Key Files Reference ### Core Notification Services - `src/services/notifications/NotificationService.ts` - Factory/selector - `src/services/notifications/NativeNotificationService.ts` - Native implementation - `src/services/notifications/WebPushNotificationService.ts` - Web implementation (stub) ### UI Components - `src/components/PushNotificationPermission.vue` - Web push UI (needs update) - `src/views/AccountViewView.vue` - Settings UI (lines 506-549 for push server) ### Settings & Constants - `src/db/tables/settings.ts` - Settings schema - `src/constants/app.ts` - `DEFAULT_PUSH_SERVER` constant - `src/libs/util.ts` - `DAILY_CHECK_TITLE`, `DIRECT_PUSH_TITLE` ### Plugin - `src/plugins/DailyNotificationPlugin.ts` - Plugin registration --- ## Next Steps 1. **Update `PushNotificationPermission.vue`** to detect platform and use appropriate service 2. **Update `AccountViewView.vue`** notification toggles to use platform detection 3. **Hide "Notification Push Server" setting** on native platforms 4. **Test on real devices** (iOS and Android) 5. **Update documentation** with platform-specific instructions --- ## Questions & Answers **Q: Do I need to configure the Notification Push Server for native apps?** A: No. The setting is only for web push. Native notifications are scheduled on-device. **Q: Can both notification systems be active at the same time?** A: No, they're mutually exclusive per platform. The app automatically selects the correct one. **Q: How do I test native notifications?** A: Use `NotificationService.getInstance()` and test on a real device (simulators have limitations). **Q: What happens if I change the push server URL?** A: Only affects web push. Users need to re-subscribe to push notifications with the new server. **Q: Can I use the same settings fields for both systems?** A: Yes! The time and message fields work for both. Only `webPushServer` is web-specific. --- **Last Updated**: 2026-01-23