# 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`