feat(notifications): integrate DailyNotificationPlugin with UI for native platforms
Integrate DailyNotificationPlugin with notification UI to enable native notifications on iOS/Android while maintaining web push for web/PWA. - Add platform detection to PushNotificationPermission component - Implement native notification flow via NotificationService - Hide push server setting on native platforms (not needed) - Add time conversion (AM/PM to 24-hour) for native plugin - Add comprehensive documentation Breaking Changes: None (backward compatible)
This commit is contained in:
378
doc/notification-system-overview.md
Normal file
378
doc/notification-system-overview.md
Normal file
@@ -0,0 +1,378 @@
|
||||
# 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<void> {
|
||||
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<void> {
|
||||
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
|
||||
<h2 v-if="!isNativePlatform" class="text-slate-500 text-sm font-bold mb-2">
|
||||
Notification Push Server
|
||||
</h2>
|
||||
```
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user