# Background notifications — handoff

## Summary

Paarrot keeps users notified of Matrix activity when the app is in the background: desktop tray/favicon badges, system notifications (Electron/Tauri/Android), and Android **UnifiedPush** for reliable mobile push without Google FCM dependency.

## User-facing behavior

- Unread counts update favicon (Paarrot / unread / highlight variants)
- System notifications for mentions/DMs per notification settings
- Android: requires UnifiedPush distributor (e.g. ntfy); user prompted if missing
- Foreground/background state affects sync strategy

## Architecture

```
ClientNonUIFeatures.tsx
  → FaviconUpdater (roomToUnread atom)
  → notification listeners (tauri.ts sendNotification)
  → initPaarrotAPI + background sync lifecycle
backgroundSync.ts
  → UnifiedPush registration, pusher setup
  → setAppForegroundState / startBackgroundSync / stopBackgroundSync
tauri.ts / electron main
  → OS notification APIs, Android small icon ic_stat_paarrot
```

## Key files

| Path | Role |
|------|------|
| `cinny/src/app/pages/client/ClientNonUIFeatures.tsx` | Favicon, notifications, API init, background sync hooks |
| `cinny/src/app/utils/backgroundSync.ts` | Pushers, UnifiedPush, foreground state |
| `cinny/src/app/utils/tauri.ts` | Tauri/Capacitor notification helpers |
| `cinny/src/app/features/settings/notifications/SystemNotification.tsx` | Permission UX |
| `electron/main.js` | Tray, notification IPC (if applicable) |
| `src-tauri/src/main.rs` | Tauri Android shell |

## Data model

| Key | Storage | Purpose |
|-----|---------|---------|
| `paarrot.unifiedpush.*` | localStorage prefix | UP endpoint state |
| `com.paarrot.app.android` | Pusher app id base | Android pushers |
| Matrix pusher | Homeserver | HTTP push gateway |

## Dependencies

- UnifiedPush distributor app on Android
- Notification permission (browser/OS)
- Homeserver pusher support
- `matrix-js-sdk` sync

## Integration points

- **Settings → Notifications**: rules + system permission
- **DirectTab / sidebar**: custom Paarrot SVG favicon states
- **Deep links**: notification tap → `setupNotificationTapListener`

## Testing

### Manual

1. Desktop: background app; send mention; verify system notification.
2. Verify favicon switches unread/highlight with counts.
3. Android: install ntfy; verify push when app killed.
4. Toggle notification settings; verify respect mute rules.

### Automated

- None

## Known issues & gotchas

- UnifiedPush user education string in `backgroundSync.ts` if no distributor
- Multiple runtimes: `isTauri`, `isElectron`, `isCapacitorNative` branch logic
- Pusher registration races on fast login/logout
- Android small icon: `ic_stat_paarrot` must exist in Android resources
- Background wake (`MatrixSyncService`) must filter by push rules / unread_notifications; a push for one room used to notify for every new message in the sync batch

## Future work

- iOS push strategy
- Notification action buttons (reply, mark read)
- Per-room notification channels on Android

## Related docs

- Matrix push gateway docs (upstream)

## Add your extra things here

- Constants: `PUSHER_APP_ID_BASE`, `PUSHER_STORAGE_PREFIX` in `backgroundSync.ts`
- Logo assets: `paarrot.svg`, `paarrot-unread.svg`, `paarrot-highlight.svg` in `public/res/svg/`
- Android notify filter: mute / mentions / default-room behavior lives in `MatrixSyncService.resolveRoomNotifyMode`
