# 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
