Part 31 — Notifications, Push Wake, Background Delivery & OS Lifecycle Architecture
Reusable P2P Communication Platform
Status: Architecture specification
Part: 31
Primary language: Rust
Primary purpose: define a secure, battery-efficient, cross-platform notification and background-delivery architecture for messaging, calls, files, emergency traffic, and system events
Primary goals: wake-only push, local notifications, reliable background synchronization, privacy-preserving notification previews, Android/iOS lifecycle integration, call notifications, foreground-service behavior, offline fetch after wake, notification de-duplication, battery-aware scheduling, and strict separation between push infrastructure and actual encrypted content delivery
1. Purpose
A production P2P messenger cannot assume that the application process is always running.
On mobile operating systems, the app may be:
foreground
background
suspended
killed
battery-restricted
network-restricted
Yet the user still expects:
new-message notification
incoming-call notification
missed-call notification
file-transfer completion
security alerts
emergency alerts
The architecture must therefore support background wake and notification delivery without turning push infrastructure into the message transport or weakening E2EE.
The governing principle is:
Push wakes the application; it does not carry the authoritative user message.
2. Architectural Position
Remote Peer
│
▼
Encrypted Message / Call Event
│
├── Direct P2P if app is reachable
│
└── Encrypted mailbox / relay if app sleeps
│
▼
Push Wake Service
│
▼
OS wakes app
│
▼
Rust Background Sync
│
▼
Fetch encrypted pending state
│
▼
Verify / Decrypt / Persist
│
▼
Local Notification
3. Push Is Not Message Delivery
Bad architecture:
push payload contains plaintext message
Recommended:
push payload:
wake reason
opaque account/device token
coarse event class
Then:
app wakes
→ authenticates
→ fetches encrypted message
→ verifies
→ persists
→ notifies user
4. Why This Matters
If push payload contains message text:
push provider sees content
OS notification stack may expose content
delivery semantics become tied to cloud push
Wake-only push preserves:
P2P-first architecture
E2EE
self-hosting options
provider independence
5. Notification Categories
#![allow(unused)] fn main() { pub enum NotificationKind { Message, Mention, FileTransfer, IncomingCall, MissedCall, SecurityAlert, DeviceAdded, DeviceRevoked, EmergencyAlert, System, } }
6. Notification Importance
#![allow(unused)] fn main() { pub enum NotificationImportance { Silent, Normal, High, Critical, } }
Do not allow arbitrary plugins to request Critical.
Part 17/28 policy re-authorizes.
7. Background Runtime States
#![allow(unused)] fn main() { pub enum AppLifecycleState { Foreground, Background, Suspended, Terminated, HeadlessWake, } }
8. Rust Owns Logical Lifecycle
Platform adapters report:
foreground
background
wake
network restored
power mode changed
Rust decides:
what work to run
what queues to flush
whether to notify
9. Platform Adapter Boundary
#![allow(unused)] fn main() { pub trait PlatformNotificationBackend { async fn show( &self, notification: LocalNotification, ) -> Result<NotificationId, NotificationError>; async fn cancel( &self, id: NotificationId, ) -> Result<(), NotificationError>; } }
10. Push Adapter Boundary
#![allow(unused)] fn main() { pub trait PushWakeBackend { async fn register_device( &self, ) -> Result<PushWakeToken, PushError>; async fn unregister_device( &self, ) -> Result<(), PushError>; } }
11. Push Token Is Not Identity
Do not equate:
push token
with:
AccountId
DeviceId
Push tokens are platform/provider routing identifiers.
12. Push Token Rotation
Mobile push tokens may change.
Rust must support:
register new
invalidate old
publish token change
without creating new device identity.
13. Push Token Privacy
Avoid storing push token in broadly readable peer metadata.
Prefer:
trusted notification service mapping
or encrypted/self-hosted routing.
14. Wake Token
If using a self-hosted wake service, define:
#![allow(unused)] fn main() { pub struct WakeToken([u8; 32]); }
Rotatable and unrelated to device identity.
15. Push Payload
Keep minimal:
#![allow(unused)] fn main() { pub struct PushWakeHint { pub version: u8, pub reason: WakeReason, pub opaque_token: OpaqueWakeToken, } }
16. Wake Reasons
#![allow(unused)] fn main() { pub enum WakeReason { PendingMessage, IncomingCall, SecurityEvent, EmergencyEvent, GenericSync, } }
17. No Sensitive Push Metadata
Avoid putting:
sender
message text
file name
conversation ID
contact name
into push payload unless product explicitly accepts the metadata trade-off.
18. Android Push
Common Android architecture:
push provider
→ platform callback
→ small Kotlin/Java bridge if required
→ Rust wake entrypoint
The bridge should pass:
opaque wake reason/token
not message content.
19. Kotlin Role
Kotlin may be needed for:
FCM callback
notification channel creation
foreground-service bootstrap
PendingIntent actions
Rust remains authoritative for:
message state
call state
notification policy
deduplication
sync
20. Android Background Execution
Android may restrict arbitrary background execution.
Use the correct platform mechanism:
push callback
foreground service for active call
scheduled background work
short background task
depending operation.
21. Do Not Fight the OS
Do not build:
permanent hidden background loop
that tries to bypass Android power management.
This causes:
battery drain
OEM kills
store-policy risk
unreliable behavior
22. Android Foreground Service
Use for legitimate ongoing work such as:
active audio/video call
user-visible transfer if required
not for keeping idle messenger permanently alive.
23. Foreground Service Types
Declare only required Android foreground-service categories.
Release pipeline Part 27 should validate them.
24. Active Call Service
Part 29 call session may bind to:
foreground service
while active.
If UI process/activity recreates:
call controller remains canonical
if service/daemon architecture preserves it.
25. Incoming Call Notification
Flow:
wake hint
↓
Rust fetch/validate call offer
↓
call policy
↓
platform incoming-call notification
Do not show ringing UI from unauthenticated push content alone.
26. Call Validation Before Ring
Before ringing:
authenticate caller
check blocklist
check rate limits
check call expiry
check permissions/policy
27. Notification Actions
Possible:
Reply
Mark Read
Accept Call
Decline Call
Mute
Actions route back into Rust commands.
28. Action Idempotency
Repeated OS action callback must be safe.
Example:
Mark Read twice
should not create duplicate events.
29. Direct Reply
If supporting notification quick reply:
OS input
→ Rust command
→ durable message outbox
→ normal E2EE send
Do not send directly from platform callback bypassing message pipeline.
30. Notification IDs
Stable local ID:
#![allow(unused)] fn main() { pub struct NotificationId(u64); }
Use deterministic grouping/dedup where useful.
31. Conversation Notification Grouping
Group by:
conversation
rather than one notification per message indefinitely.
32. Notification Collapse
If 20 new messages arrive:
1 conversation notification
with summary.
33. Global Summary
Optional:
5 conversations have unread messages
34. Notification Privacy Modes
#![allow(unused)] fn main() { pub enum NotificationPreviewMode { Full, SenderOnly, Generic, } }
35. Full Preview
Example:
Alice: Are you coming?
36. Sender Only
Example:
New message from Alice
37. Generic
Example:
New message
38. Locked vs Unlocked Device
Platform adapter may support:
full preview when unlocked
generic when locked
depending OS capability.
39. Sensitive Conversations
Allow per-conversation:
hide preview
40. Emergency Notifications
Part 17 policy may map verified emergency events to:
High/Critical
with stronger attention behavior where platform allows.
41. Emergency Authenticity
Critical notification must never be produced merely because push payload says:
"emergency"
Rust verifies authority signature first.
42. Security Alerts
Examples:
new device added
device revoked
identity changed
recovery used
These may deserve high-priority local notifications.
43. Notification Sound
Rust policy selects semantic sound category.
Platform backend maps to OS channel/sound.
44. Vibration
Same semantic model.
45. Android Notification Channels
Create stable channels:
Messages
Calls
Security
Emergency
Transfers
OS/user can customize them.
46. Do Not Create Endless Channels
Android notification channels persist.
Use a stable small set.
47. Channel Migration
If channel semantics change:
version carefully
but avoid creating new channel every app update.
48. Notification Badge
Unread count derives from durable conversation/read state.
Do not keep separate badge truth.
49. Badge Projection
durable unread projection
→ badge count
50. Notification De-Duplication
Same logical event may arrive via:
direct
relay
mailbox
push wake
device sync
Use stable event/message/call IDs.
51. Message Notification Dedup
Key:
MessageId
52. Call Notification Dedup
Key:
CallId
53. Security Notification Dedup
Key:
SecurityEventId
54. Notification State Store
Small local durable store:
#![allow(unused)] fn main() { pub struct NotificationProjection { pub source_id: EventId, pub notification_id: NotificationId, pub shown: bool, pub dismissed: bool, } }
55. Why Persist Some Notification State
OS/app process may restart.
Persist enough to avoid:
showing same security alert repeatedly
56. Do Not Persist Ephemeral UI Details
No need to store:
animation state
notification expanded state
57. Background Sync Trigger
Wake event should enqueue:
BackgroundSyncReason
not perform large logic in OS callback.
58. Background Sync Reason
#![allow(unused)] fn main() { pub enum BackgroundSyncReason { PushWake(WakeReason), NetworkRestored, ScheduledMaintenance, UserAction, AppForegrounded, } }
59. Background Sync Scheduler
#![allow(unused)] fn main() { pub struct BackgroundSyncScheduler { // coalesces requests } }
60. Coalescing
If 10 pushes arrive quickly:
run one sync
not 10 independent fetches.
61. Sync State
#![allow(unused)] fn main() { pub enum BackgroundSyncState { Idle, Scheduled, Running, Backoff, } }
62. Sync Work
Typical wake sync:
open local DB
load identity
establish transport/mailbox connection
fetch pending envelopes
verify
decrypt
persist
advance receipts
create notifications
flush outbox if allowed
close/idle
63. Minimal Wake
Do not start:
camera
video decoder
plugin marketplace
full search indexing
for a simple message wake.
64. Wake Budget
OS may give short execution window.
Prioritize:
security
message persistence
call signaling
emergency
before secondary tasks.
65. Background Work Priority
1. Incoming call
2. Emergency/security
3. Pending message fetch
4. Receipts/outbox
5. File continuation
6. Maintenance
66. File Transfers in Background
Large transfers should obey platform rules.
Possible:
pause
foreground-service transfer
resume later
depending user intent and OS.
67. User-Initiated Transfer
If user explicitly starts large upload/download:
background continuation
may be justified.
68. Opportunistic Background Sync
Do not keep radio awake for low-value background cache cleanup.
69. Battery-Aware Scheduling
Part 13 applies.
Examples:
battery saver
→ skip thumbnail prefetch
critical battery
→ only message/call/security/emergency
70. Network-Aware Background Sync
On metered/cellular:
fetch message metadata/content
delay large attachments
according to auto-download policy.
71. Offline Wake
Push may arrive but network unavailable.
Store:
pending sync intent
and retry when network returns.
72. Retry
Use:
bounded exponential backoff + jitter
73. Retry Is Not Notification Spam
Do not show repeated:
sync failed
notifications unless user action is needed.
74. Network Restored Event
Platform/network monitor triggers:
resume background sync
flush outbox
75. Mailbox Fetch
If using encrypted mailbox:
wake
→ fetch opaque envelopes
→ verify/decrypt
→ persist
76. Mailbox Cursor
Use durable cursor/checkpoint.
77. Duplicate Mailbox Envelope
Message ID dedup prevents duplicate UI notification.
78. Push Loss
Push delivery is not guaranteed.
Therefore the app also syncs on:
foreground
network reconnect
periodic allowed background opportunity
peer reconnect
79. Push Delay
A delayed push should not cause stale typing/call offer to appear.
Call offer expiry and ephemeral TTL still apply.
80. Push Provider Outage
Messaging still works when:
app already active/reachable
LAN/direct path available
manual foreground sync
Push is acceleration, not correctness.
81. Self-Hosted Push/Wake
For sovereign deployment, architecture may support:
self-hosted wake gateway
where platform allows.
On Android, device push integration may still rely on OS/provider constraints depending app distribution/device environment.
82. Desktop Notifications
Desktop apps usually do not need cloud push.
If daemon/app running:
peer event
→ Rust runtime
→ OS notification
83. Desktop Background
Options:
tray app
daemon
system service
according to product.
84. Linux Notification Backend
Use desktop notification service where available.
Headless node may use:
logs
admin alerts
email/webhook plugin
instead of desktop popups.
85. Windows Notification Backend
Use native Windows notification APIs through Rust/platform adapter.
86. macOS Notification Backend
Use native notification center APIs through Rust/Apple adapter.
87. iOS Architecture
If iOS is added:
APNs wake/notification
background execution limits
CallKit integration
behind Rust-owned state/policy.
88. Browser Notifications
If web-compatible host exists:
Service Worker
Web Push
Notification API
can map into same semantic layer.
Browser remains a separate platform adapter.
89. Headless Notifications
Daemon can emit:
admin event
local IPC event
system journal
optional webhook/email extension
No GUI assumption.
90. Embedded Linux Node
Emergency/edge node may drive:
LED
buzzer
local display
admin alert
through Part 20 platform adapters.
91. Notification Policy Engine
#![allow(unused)] fn main() { pub trait NotificationPolicyEngine { fn decide( &self, event: &NotificationCandidate, ctx: &NotificationContext, ) -> NotificationDecision; } }
92. Notification Candidate
#![allow(unused)] fn main() { pub struct NotificationCandidate { pub kind: NotificationKind, pub source_id: EventId, pub conversation: Option<ConversationId>, pub sender: Option<AccountId>, pub urgency: NotificationImportance, } }
93. Notification Context
Includes:
app foreground
conversation visible
DND
notification preview mode
peer muted
OS lock state if available
battery
94. Suppress When Conversation Open
If user already viewing conversation:
do not show duplicate OS notification
Maybe use:
in-app sound/badge
depending settings.
95. Muted Conversation
Muted conversation:
persist unread state
but suppress sound/pop-up according to mute policy.
96. Mention Override
Group mention may override ordinary mute if user config allows.
97. DND
App-level DND can suppress:
messages
calls
except explicitly allowed categories.
98. OS DND
Respect OS-level notification controls.
Do not attempt to bypass.
99. Emergency Exceptions
Only use critical/override OS pathways where:
platform permits
user/admin policy permits
authority is verified
100. Notification Candidate Pipeline
Durable Event
↓
Deduplicate
↓
Privacy Policy
↓
Mute/DND Policy
↓
Foreground Visibility Check
↓
Importance Mapping
↓
Platform Notification
101. Notification Content Builder
Separate semantic event from presentation.
#![allow(unused)] fn main() { pub trait NotificationRenderer { fn render( &self, candidate: &NotificationCandidate, privacy: NotificationPreviewMode, ) -> LocalNotification; } }
102. Local Notification
#![allow(unused)] fn main() { pub struct LocalNotification { pub title: String, pub body: String, pub importance: NotificationImportance, pub group: Option<NotificationGroupKey>, pub actions: Vec<NotificationAction>, } }
103. Sensitive Text
Title/body are constructed only after:
E2EE verification/decryption
privacy policy
104. Generic Fallback
If message cannot yet be decrypted but wake is trusted:
New message
may be shown.
105. Decryption Failure
Do not show corrupted ciphertext contents.
Show:
Unable to process message
only if user action needed.
106. Notification Click
Click opens semantic destination:
conversation
call screen
security center
transfer screen
107. Deep Link
Use internal typed destination:
#![allow(unused)] fn main() { pub enum NotificationDestination { Conversation(ConversationId), Call(CallId), SecurityEvent(SecurityEventId), Transfer(TransferId), } }
108. Do Not Trust Raw Intent Strings
Platform intent/action payloads are untrusted input.
Validate IDs and action type.
109. Cold Start from Notification
Flow:
OS launches app
↓
platform adapter parses intent
↓
Rust validates destination
↓
runtime initializes
↓
navigation occurs
110. Cold Start Race
Notification click may arrive before DB/runtime ready.
Queue:
PendingLaunchAction
until startup reaches appropriate phase.
111. Startup Phases
platform bootstrap
secure store
DB
identity
runtime
navigation
112. Background Headless Entry
Push callback should be able to start a lightweight Rust background entrypoint without rendering full Dioxus UI.
113. Headless Wake Runtime
#![allow(unused)] fn main() { pub struct HeadlessWakeRuntime { // minimal services } }
114. Headless Services
Load only:
identity
secure store
network
mailbox
message persistence
call signaling
notification policy
115. Do Not Start UI
No Dioxus initialization required for headless wake if platform integration permits.
116. Dioxus Reconciliation
When UI later opens:
read durable DB projections
and naturally reflects messages received during background wake.
117. Background Call Offer
If call offer arrives during headless wake:
verify
persist minimal call state
show incoming-call notification
118. Call Accept from Notification
Action:
Accept
may need to start:
foreground call service
audio runtime
Dioxus/Call UI
depending platform.
119. Call Decline
Can often complete headlessly:
send reject
persist history
cancel notification
120. Missed Call
If call expires before answer:
cancel incoming-call UI
show missed-call notification
if policy permits.
121. Notification Cancellation
When message read elsewhere:
cancel/update local notification
through multi-device read sync if appropriate.
122. Notification Synchronization Across Devices
Do not try to remotely command OS notification trays directly.
Sync durable state:
message read
call answered elsewhere
then each device updates its own local notification UI.
123. Answered Elsewhere
Part 29:
phone ringing
desktop answers
Phone receives:
AnsweredElsewhere
then cancels call notification.
124. Read Elsewhere
If desktop reads conversation:
phone may clear notification
after read sync.
125. Notification Race
Message arrives and user opens conversation at same time.
Use durable read state + notification dedup to avoid stale popup.
126. Debounce Notification
A short delay can allow:
message arrives
conversation already open
to suppress unnecessary OS notification.
Keep delay tiny.
127. Notification Rate Limits
Prevent peer from generating unlimited notifications.
Per peer/conversation quotas.
128. Unknown Peer Notification Policy
Unknown sender may get:
silent request notification
rather than normal alert.
129. Spam Conversation
If repeated notifications from same unknown peer:
collapse
rate-limit
130. File Transfer Notifications
Examples:
Download complete
Upload failed
Storage full
Only user-relevant events.
131. Transfer Progress
Avoid per-percent OS notifications.
Use:
persistent progress notification
only for long-running explicit transfer if platform UX warrants it.
132. Background Transfer Failure
If automatic background download fails:
usually no user notification
unless user explicitly initiated it.
133. Security Notification Priority
Examples:
new device
identity reset
recovery used
should be more prominent than ordinary file completion.
134. Notification Storage Limits
Keep bounded notification projection.
Old notification state can be pruned.
135. Pruning
Safe to remove state for:
old dismissed ordinary notifications
after retention period.
Keep durable security audit separately.
136. Notification Actions Security
Action token should bind:
notification ID
event ID
action type
expiry
to prevent forged external intents.
137. Android PendingIntent Safety
Use immutable/mutable flags correctly and explicit intents where possible.
Keep platform details inside adapter.
138. External Intent Attack
Do not let arbitrary third-party app trigger:
send message
accept call
mark arbitrary message read
through exported components.
139. Exported Components
Part 27 release audit validates only necessary exported Android components.
140. Background Service Authentication
Internal IPC between platform service and Rust runtime should be local and authenticated by process/app boundary.
141. Plugin Notifications
Plugins may request notifications only through permissioned semantic API.
142. Plugin Permission
RegisterNotifications
from Parts 21/24.
143. Plugin Priority Limit
Plugin cannot produce:
Critical emergency
Security alert
Incoming call
unless explicitly authorized.
144. Plugin Notification Rate
Bound per plugin.
145. WASM Notification API
WASM receives semantic:
request-notification
host applies:
permission
rate limit
privacy
importance clamp
146. Notification Telemetry
Do not send:
notification content
sender names
message text
as analytics.
Aggregate metrics only if enabled.
147. Useful Metrics
push wake received
sync started
sync succeeded
message notification shown
call notification shown
notification deduped
148. Push Provider Diagnostics
Track:
token registration failure
wake delay class
provider unavailable
without logging token.
149. Token Logging
Never log full push token.
Use redacted hash if troubleshooting requires identity.
150. Wake Latency
Measure:
remote event
→ wake
→ fetch
→ notification
with privacy-safe local telemetry.
151. Notification Latency Budget
For ordinary messages:
seconds acceptable
For incoming calls:
much lower
Call wake path gets higher priority.
152. Incoming Call Fast Path
push wake
→ validate offer
→ ring
Skip low-priority sync.
153. Emergency Fast Path
wake
→ verify authority/signature
→ persist
→ alert
before background maintenance.
154. Security Fast Path
wake
→ verify security event
→ persist
→ alert
155. Message Fetch Batching
If multiple messages pending:
fetch in batch
persist transactionally
build grouped notification
156. Notification Summary
Example:
Alice: 3 new messages
instead of 3 separate popups.
157. Foreground In-App Notifications
When app foreground:
toast/banner
conversation update
sound
may replace OS notification.
158. In-App Banner
Dioxus UI component consumes:
NotificationCandidate
after policy decides OS/in-app presentation.
159. Dioxus Is Presentation Only
It does not own:
notification dedup
unread truth
push token
background sync
160. Notification Center State
App may show:
security events
missed calls
transfer alerts
from durable projections, not OS tray introspection.
161. Badge Count
Derived from:
unread conversations
pending calls/security alerts
according to product.
162. Notification Mute
Per conversation:
1 hour
8 hours
1 week
forever
stored durably.
163. Mention Exceptions
Optional.
164. Call Mute
User may allow:
messages muted
calls still ring
or mute both.
Separate settings.
165. Emergency Exceptions
User/admin policy determines whether emergency alerts bypass ordinary mute.
166. Quiet Hours
Optional app-level schedule.
#![allow(unused)] fn main() { pub struct QuietHours { pub start: LocalTime, pub end: LocalTime, } }
167. Time Zone Changes
Quiet hours use local time zone.
Recalculate on zone change.
168. Critical Security Events During Quiet Hours
May override quiet hours if user policy permits.
169. Background Maintenance
Tasks such as:
cache cleanup
expired DTN GC
plugin update check
should not be tied to push notifications.
Use platform background scheduler where available.
170. Work Classes
#![allow(unused)] fn main() { pub enum BackgroundWorkClass { Urgent, UserVisible, Sync, Maintenance, } }
171. Urgent
incoming call
emergency
security
172. UserVisible
user-started file transfer
173. Sync
messages
receipts
outbox
174. Maintenance
cache cleanup
index compaction
update checks
175. Scheduler Policy
OS/platform adapter maps semantic work class to:
foreground service
background task
job scheduler
push wake
176. Android WorkManager
If used, treat it as platform scheduling implementation detail.
Rust should receive:
BackgroundWorkClass
rather than depend on WorkManager types throughout core.
177. iOS Background Tasks
Same abstraction.
178. Desktop Scheduler
Can use Tokio/service timer because desktop daemon is typically long-lived.
179. Embedded Scheduler
Part 20 can run directly under systemd/runtime.
180. Background Work Idempotency
Every background task should be safe to restart.
181. Crash During Sync
Durable message/event pipeline ensures:
resume
dedup
on next wake.
182. Crash During Notification Build
Message already persisted.
Next startup can reconstruct whether notification still needed.
183. Notification Candidate Reconstruction
From durable state:
unread message
not yet notified
can regenerate candidate.
184. Notification Exactly-Once Is Not Required
OS notifications are best-effort UI.
Correctness is:
message persisted once
Notification may be:
shown once ideally
but duplicate suppression is a UX concern, not data-integrity authority.
185. Scheduled Reminder Notifications
If product later supports reminders:
separate scheduled-notification subsystem
not mixed with push wake.
186. Notification Localization
Platform-visible text should support localization.
Rust semantic events use localization keys.
187. Localization Key
#![allow(unused)] fn main() { pub struct NotificationTextKey(&'static str); }
188. Localized Rendering
Platform/UI layer resolves:
locale
pluralization
189. Sensitive Localization
Do not accidentally include raw message text in generic privacy mode.
190. Notification Accessibility
Ensure:
clear title
meaningful action labels
screen-reader compatibility
191. Notification Action Count
Keep small.
Too many actions reduce clarity.
192. Incoming Call UX
Actions:
Accept
Decline
Maybe:
Message
later.
193. Message UX
Actions:
Reply
Mark Read
where supported.
194. Security Alert UX
Action:
Review
not generic dismiss-only if significant.
195. Emergency Alert UX
Action:
View details
Acknowledge
only if protocol semantics support it.
196. Notification Sound Privacy
Custom contact names in spoken notifications may expose private data.
Leave to OS/user settings.
197. Headset Notification
Do not route message audio over call audio incorrectly.
Platform audio focus policy handles.
198. Notification During Call
Ordinary message notification should be subtle.
Do not interrupt audio path unnecessarily.
199. Emergency During Call
Policy may elevate.
Still avoid crashing/restarting media pipeline.
200. Notification During Screen Share
Privacy-sensitive.
Option:
hide message previews while screen sharing
201. Screen-Share Privacy Mode
Part 29 can signal:
screen_share_active
Notification policy switches to:
Generic
automatically if enabled.
202. Lock-Screen Privacy Mode
Same concept.
203. App Lock
If app has biometric/PIN lock:
notification preview may automatically downgrade
204. Background Message Decryption
If device is locked but secure keystore permits decryption:
message can persist
Whether preview is shown depends privacy mode.
205. Hardware Key Requires Unlock
If key unavailable until user unlocks:
store ciphertext
show generic notification
decrypt later
206. Security Trade-Off
High-security profile may intentionally sacrifice rich background previews.
207. Push Wake Registration
At startup/account login:
obtain token
bind to DeviceId securely
publish to wake service
208. Token Binding
Wake service mapping:
opaque device routing ID
→ push token
should not require conversation plaintext.
209. Token Revocation
On logout/device revocation:
unregister token
210. Stale Token Cleanup
Wake service removes invalid provider tokens.
211. Multi-Device Wake
Message for account may wake:
all active authorized devices
or only devices requiring delivery.
212. Device Delivery Policy
If server/mailbox already knows device fan-out:
wake each pending recipient device
213. Avoid Wake Storm
Coalesce multiple pending messages per device.
214. Wake Suppression
If device has active P2P connection:
no push needed
unless delivery/liveness fails.
215. Online Heuristic
Presence is advisory.
Wake service may suppress push only when it has stronger short-lived evidence that device is reachable.
216. Push Race
Direct message arrives just before push.
When push wakes:
sync finds nothing
This is fine.
217. Push Duplicate
Multiple pushes for same pending state:
coalesced background sync
218. Push Authentication
Push payload itself may not be strongly confidential.
Treat as untrusted wake hint.
Actual fetched content is authenticated by Part 28.
219. Malicious Push Provider
Worst case should be:
spurious wakes
not:
forged message content
forged call identity
Rate-limit wake processing.
220. Wake Abuse Protection
Bound:
sync frequency
CPU
network
notification creation
even if push provider or token abused.
221. Notification Flood Defense
Per:
peer
conversation
plugin
event class
rate limits.
222. Notification Coalescing Windows
Example:
message group within 1–3 s
depending UX.
223. Call Notifications Are Not Coalesced Like Messages
Every valid incoming call is distinct by CallId.
224. Security Alerts
Should not be hidden inside ordinary message summary.
225. Emergency Alerts
Separate channel/group.
226. Durable Notification Preferences
Store:
global notifications enabled
message sound
call sound
security alerts
preview mode
quiet hours
per-conversation mute
227. Preference Sync
Some preferences can sync across user's devices.
OS-specific channel state does not.
228. OS Preference vs App Preference
OS can disable notifications independently.
App should detect/report:
notifications disabled at system level
where platform allows.
229. Notification Permission
Android/iOS may require user permission.
Rust receives:
#![allow(unused)] fn main() { pub enum NotificationPermission { Granted, Denied, NotDetermined, } }
230. Permission UX
Ask when user reaches a feature that benefits from notifications.
Avoid unnecessary first-launch prompt if product UX prefers contextual permission request.
231. Denied Permission
Messaging still works.
App may show in-app explanation/settings path.
232. Incoming Calls Without Notification Permission
Platform behavior may be constrained.
Architecture should expose:
CallingAvailability::NotificationsUnavailable
internally if this affects reachability.
233. Notification Health
Diagnostics:
permission
push token registered
last wake
last sync
OS notifications enabled
234. User-Facing Doctor
Example:
Notifications are disabled by Android settings.
Incoming calls may not ring while the app is closed.
235. Developer Diagnostics
Include:
wake provider
token age
background restriction
battery optimization status
last successful background fetch
where platform permits.
236. OEM Battery Restrictions
Some Android OEMs aggressively kill background apps.
Do not rely on undocumented hacks.
Diagnostics may explain:
system battery restriction may delay notifications
237. Battery Optimization Exemption
Do not request exemption by default.
Only if justified by product functionality and platform policy.
238. Foreground Service User Visibility
Foreground service must have truthful user-visible notification where required.
239. Background Transfer Service
If user explicitly starts long transfer, foreground service may be appropriate.
240. Notification Channels and Rust IDs
Map stable semantic:
Message
Call
Security
Emergency
Transfer
to platform-specific identifiers.
241. Platform Mapping Table
#![allow(unused)] fn main() { pub struct PlatformNotificationChannelMap { // semantic kind → platform channel ID } }
242. No Platform IDs in Domain Core
Domain code should not know:
"messages_v3"
Android channel string.
243. Notification Serialization
Internal IPC can use:
Postcard
for compact typed messages.
Push payload may use provider-required format.
244. JSON Push Wrapper
If provider requires JSON:
outer push envelope JSON
inner opaque wake token
No plaintext message content.
245. Background Sync Protocol
Use existing:
mailbox/sync
protocols.
Do not invent push-specific message retrieval protocol unnecessarily.
246. Notification Database Tables
Possible:
notification_projection
notification_preferences
push_registration
background_sync_checkpoint
247. push_registration
Stores:
provider
token reference/encrypted token
registered_at
last_verified
248. Token Storage
Treat as sensitive metadata.
Encrypt at rest if practical.
249. Notification Projection Retention
Short retention for ordinary notifications.
Longer security audit is separate.
250. Background Sync Checkpoint
Durable:
mailbox cursor
outbox state
sync epoch
251. Crash Recovery
Part 09 applies:
persist before notify
252. Persist Before Notification
Correct order:
receive
verify
decrypt
persist
commit
then notify
Never show a message notification for data not durably accepted.
253. Why Persist First
If app crashes after notification but before DB write:
user taps notification
message missing
Persist-first avoids this.
254. Read Action
Notification "Mark Read":
advance durable read cursor
then cancel/update notification
255. Reply Action
Notification reply:
persist outbound message
then attempt send
256. Call Accept
Incoming call accept is different:
validate call still live
then transition Part 29 state
257. Expired Call Action
If user taps Accept after call expired:
show missed/ended state
not attempt stale connection.
258. Emergency Acknowledge
If protocol supports ACK:
persist ACK intent
send securely
259. Notification Testing
Required:
foreground
background
suspended
cold start
process killed
network offline
battery saver
multiple messages
multi-device read
call answered elsewhere
260. Android Device Matrix
Test:
Pixel-like stock Android
Samsung
Xiaomi/Redmi
OnePlus/Realme
Motorola
because background behavior varies.
261. Push Delay Test
Send 100 wake events under:
screen off
Doze
battery saver
Wi-Fi
cellular
measure latency distribution.
262. Notification Privacy Test
Lock device.
Verify:
Full
SenderOnly
Generic
behave correctly.
263. Duplicate Message Test
Deliver same message:
direct + mailbox + wake
one notification.
264. Push Duplicate Test
Send same wake repeatedly.
One background sync coalesced.
265. Message Burst Test
100 messages across 5 conversations.
Expected:
bounded notification count
grouped summaries
no UI freeze
266. Unknown Peer Flood
Thousands of unknown message requests.
Expected:
rate-limited notification behavior
267. Incoming Call Flood
Unknown caller sends repeated offers.
Expected:
Part 28/29 rate limiting
no endless ringing
268. Answered Elsewhere Test
Phone + desktop ring.
Desktop answers.
Phone notification cancels quickly.
269. Read Elsewhere Test
Desktop reads.
Phone message notification updates/cancels.
270. Background Decryption Test
Hardware key unavailable until unlock.
Expected:
ciphertext stored
generic notification
decrypt after unlock
if platform/key policy configured that way.
271. Crash After Persist Before Notify
On restart:
reconstruct candidate
notify if still unread/relevant
272. Crash After Notify
No duplicate notification beyond dedup policy.
273. Offline Push Test
Wake received with no network.
Pending sync waits until connectivity returns.
274. Provider Outage Test
App foreground/direct connectivity still works.
275. Notification Permission Revoked
Runtime detects and diagnostics explain.
276. Foreground Conversation Test
Message arrives while conversation open.
No redundant OS notification.
277. Screen-Share Privacy Test
Message arrives during active screen share.
Preview automatically generic if policy enabled.
278. Performance
Background wake path should use minimal:
RAM
CPU
radio time
279. Cold Wake Target
Aim for:
minimal startup subset
rather than full app initialization.
280. Allocation Policy
Notification handling is not a hot media path.
Favor correctness/clarity over exotic zero-copy.
281. Resource Limits
Part 08 bounds:
pending wake requests
notification projection
sync concurrency
push retries
282. Background Sync Concurrency
Usually:
one sync per account/device
with coalescing.
283. Multi-Account Future
If multi-account supported:
per-account sync queue
global concurrency cap
284. Headless Lock
Use an async mutex/lease to avoid two background syncs racing.
285. Watchdog
Background sync has deadline.
If exceeded:
cancel safely
retry later
286. Cancellation
Every background task must be cancellation-safe.
287. Partial Fetch
Persist each validated batch transactionally.
Do not lose all progress because wake window ended.
288. Sync Cursor Advancement
Advance cursor only after batch durable commit.
289. Notification Generation After Batch
Generate candidates for committed messages only.
290. Notification Ordering
Within conversation:
message sequence
not push arrival order.
291. Call Priority Over Message Burst
If incoming call and 50 messages pending:
validate/ring call first
292. Emergency Priority Over Ordinary Sync
Same.
293. Security Priority
New device/revocation may need prompt attention.
294. Suggested Workspace
crates/
├── comm-notification-core/
├── comm-notification-policy/
├── comm-background-sync/
├── comm-push-core/
├── comm-push-android/
├── comm-push-apple/
├── comm-notify-android/
├── comm-notify-linux/
├── comm-notify-windows/
├── comm-notify-apple/
├── comm-notification-diagnostics/
└── comm-notification-testkit/
295. comm-notification-core
Owns:
semantic notification types
importance
destination
actions
privacy modes
296. comm-notification-policy
Owns:
mute
DND
foreground suppression
privacy
rate limits
importance mapping
297. comm-background-sync
Owns:
wake coalescing
sync scheduling
deadlines
mailbox fetch
outbox flush
298. comm-push-core
Owns:
push registration abstraction
opaque wake token
wake reasons
299. Platform Push Crates
Own unavoidable provider/platform APIs.
300. comm-notification-testkit
Provides:
fake lifecycle
fake push
fake OS notifier
fake clock
network partition
multi-device scenarios
301. Public Commands
#![allow(unused)] fn main() { pub enum NotificationCommand { RegisterPush, UnregisterPush, HandleWake(PushWakeHint), MarkRead(NotificationId), Reply { notification: NotificationId, text: String, }, AcceptCall(CallId), DeclineCall(CallId), } }
302. Public Events
#![allow(unused)] fn main() { pub enum NotificationEvent { PushRegistered, PushRegistrationFailed, WakeReceived, SyncStarted, SyncCompleted, NotificationShown(NotificationId), NotificationCancelled(NotificationId), } }
303. Implementation Phases
Phase 1 — Local Notifications
semantic notifications
privacy modes
message grouping
Dioxus integration
Phase 2 — Android Push Wake
registration
wake callback
minimal bridge
headless Rust sync
Phase 3 — Background Sync
mailbox fetch
outbox
receipts
dedup
Phase 4 — Calls
incoming call
accept/decline
foreground service
answered elsewhere
Phase 5 — Security / Emergency
priority channels
verified security alerts
emergency fast path
Phase 6 — Multi-Device
read elsewhere
notification cancellation
device delivery
Phase 7 — Desktop / Apple
native notification backends
APNs/CallKit later
Phase 8 — Hardening
Doze
OEM restrictions
provider outage
flood tests
privacy tests
cold-start tests
304. Initial Production Recommendation
For Android v1:
wake-only push
headless Rust background fetch
message notifications
incoming-call notifications
security notifications
generic/full preview modes
conversation grouping
read/reply actions
foreground call service
Do not initially attempt:
plaintext push messages
per-message provider payloads
permanent hidden background daemon
complex plugin notification privileges
305. Definition of Done
Part 31 is complete when:
- push is used as a wake hint rather than authoritative message transport
- push payloads contain no message plaintext by default
- messages are verified/decrypted/persisted before notification
- background wake can run without full Dioxus UI startup
- duplicate pushes coalesce into one sync
- direct/mailbox/push duplicate delivery produces one logical notification
- message notification grouping is conversation-aware
- notification preview privacy has Full/SenderOnly/Generic modes
- incoming calls are authenticated before ringing
- call accept/decline actions route into Part 29
- answered-elsewhere cancels other device call notifications
- read-elsewhere can clear local message notification
- active calls use appropriate Android foreground-service integration
- battery saver and OS background restrictions are respected
- background file work is user-visible/foreground only when justified
- notification channels are stable and bounded
- plugins cannot self-elevate notification priority
- critical/emergency notifications require policy authorization
- push/provider outages do not break foreground/direct P2P messaging
- background sync is idempotent, bounded, and crash-safe
- Android permission/system-notification state is diagnosable
- notification content is not included in telemetry/logging
- cold-start, Doze, OEM restriction, duplicate, flood, offline, and multi-device tests exist
306. Relationship to Earlier Parts
Part 31 integrates with:
02 — Multi-Device Identity
03 — Routing Policy
04 — Offline Event Log
06 — DTN
07 — Capability Negotiation
08 — Resource Limits
09 — Crash Recovery
11 — Relay / Mailbox Infrastructure
13 — Battery-Aware Scheduling
16 — Daemon / Headless Runtime
17 — Emergency Priority
18 — Diagnostics
20 — Embedded Linux
21 — Third-Party Extensions
22 — WASM Components
24 — Plugin Ecosystem
27 — Android Build / Packaging
28 — E2EE / Security
29 — Realtime Calls
30 — Presence / Receipts / Ephemeral State
307. Final Architecture
Remote Encrypted Event
│
┌───────────┴───────────┐
│ │
App Reachable App Sleeping
│ │
Direct P2P Wake-Only Push
│ │
└───────────┬───────────┘
│
Rust Background Sync
│
Fetch / Verify / E2EE
│
Persist
│
Notification Policy
│
┌──────────┴──────────┐
│ │
In-App UI OS Notification
Incoming call:
Push Wake
↓
Fetch Call Offer
↓
Authenticate Caller
↓
Check Abuse / Privacy
↓
Show Incoming Call
↓
Accept / Decline
↓
Part 29 Call Controller
308. Final Principle
The notification system should never become a hidden centralized messaging layer.
The correct model is:
Push:
"wake up, something may be pending"
Rust runtime:
fetch
authenticate
decrypt
persist
decide
OS notification:
inform the user
That preserves the core architecture:
P2P-first
E2EE
local-first
offline-capable
self-hostable
battery-aware
while still giving users the mobile responsiveness they expect from a production messenger.