fix: route update alerts through notification providers#1938
Conversation
📝 WalkthroughWalkthroughUpdate availability now uses the canonical notification provider pipeline with durable subscriptions, provider-scoped delivery, cached replay on user subscription, and shared frontend handling. Dedicated update notification settings were removed, while native permission management, mobile event selection, and related documentation were added or updated. ChangesUpdate notification pipeline
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cde566226e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
cde5662 to
04c797a
Compare
|
Claude finished @carlosflorencio's task in 1s —— View job I'll analyze this and get back to you. |
Cloudflare Pages docs previewBuilt from docs commit Stable PR alias: https://docs-pr-1938.landing-87j.pages.dev/docs |
There was a problem hiding this comment.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
docs/decisions/0039-native-desktop-integration-boundary.md (1)
49-56: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick winKeep session-failure outside the “selected events” list.
This wording groups
session-failurewith user-selected events, butdocs/specs/desktop-tauri-app/spec.mddefines it as an independent safety alert whenever Local is enabled. Clarify the sentence so implementations do not gate session-failure on an event subscription.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/decisions/0039-native-desktop-integration-boundary.md` around lines 49 - 56, Update the desktop-owned launch notification description to separate session-failure from the user-selected turn-finished, clarification-requested, and update-available events. State that session-failure is always delivered through the native notifier whenever Local is enabled, without being gated by event subscriptions, while preserving the existing suppression and channel behavior for the selected events.
🧹 Nitpick comments (1)
apps/web/lib/desktop/native-notification-client.ts (1)
26-39: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider guarding
permission.get()/request()likeshow().
show()short-circuits whentransport.isAvailable()is false, butpermission.get()/permission.request()don't, so a future caller that skips theisAvailable()check gets an unhandled rejection instead of a safe fallback. All current callers guard correctly, so this isn't an active bug today.♻️ Optional defensive guard
permission: { get(): Promise<NativeNotificationPermission> { + if (!transport.isAvailable()) return Promise.resolve("prompt"); return transport.invoke( "get_native_notification_permission", ) as Promise<NativeNotificationPermission>; }, request(): Promise<NativeNotificationPermission> { + if (!transport.isAvailable()) return Promise.resolve("prompt"); return transport.invoke( "request_native_notification_permission", ) as Promise<NativeNotificationPermission>; }, },🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/web/lib/desktop/native-notification-client.ts` around lines 26 - 39, Update the permission.get() and permission.request() methods in nativeNotifications to guard against unavailable transport like show(), returning the established safe fallback instead of invoking transport when transport.isAvailable() is false. Preserve the existing native permission behavior when the transport is available.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/backend/internal/notifications/providers/local.go`:
- Around line 37-38: Extend the notification forwarding test around the payload
construction in the local provider to register a subscribed WebSocket client,
decode its queued notification, and assert that the forwarded payload preserves
both the version and url fields. Retain the existing no-subscriber coverage and
ensure the new assertions exercise the subscribed-client path.
In `@apps/backend/internal/system/updates/service.go`:
- Around line 395-406: The synchronous notifier call in
Service.notifyUpdateAvailable blocks websocket subscription responses because
HandleUpdateAvailable may wait on slow providers. Update
apps/backend/internal/system/updates/service.go:395-406 to enforce a bounded
timeout or dispatch the notification through a bounded asynchronous queue,
returning the subscription callback promptly; preserve the existing
updateAvailable and nil-notifier checks. The wiring in
apps/backend/internal/backendapp/main.go:786-794 requires no direct change if
the fix is contained in notifyUpdateAvailable.
In `@apps/web/components/settings/notification-permission-section.tsx`:
- Around line 120-144: The exported useNotificationPermission hook lacks direct
test coverage for its branching behavior. Add a dedicated *.test.ts test file
covering refreshPermission’s error state, native permission path, browser
Notification permission path, unsupported environment, and caught exceptions,
using the project’s established hook-testing utilities and mocking
nativeNotifications as needed.
- Around line 63-77: The icon-only refresh Button in the notification permission
section lacks an accessible name. Add a clear accessible label, such as
aria-label or title, directly to the Button wrapping IconRefresh, while
preserving its existing refresh behavior and tooltip.
In `@docs/public/websocket-api.md`:
- Line 763: Update the system.update_available payload documentation in the
subscribed user event table to mark url as optional, while keeping the remaining
payload fields and subscription guidance unchanged.
In `@docs/specs/platform/notifications.md`:
- Around line 97-99: Update the notification-provider API description to avoid
implying that only the two semantic events and system.update_available exist;
state that the available-event catalog includes these events, or explicitly add
office.inbox_item. Keep the provider create/update persistence behavior
unchanged.
---
Outside diff comments:
In `@docs/decisions/0039-native-desktop-integration-boundary.md`:
- Around line 49-56: Update the desktop-owned launch notification description to
separate session-failure from the user-selected turn-finished,
clarification-requested, and update-available events. State that session-failure
is always delivered through the native notifier whenever Local is enabled,
without being gated by event subscriptions, while preserving the existing
suppression and channel behavior for the selected events.
---
Nitpick comments:
In `@apps/web/lib/desktop/native-notification-client.ts`:
- Around line 26-39: Update the permission.get() and permission.request()
methods in nativeNotifications to guard against unavailable transport like
show(), returning the established safe fallback instead of invoking transport
when transport.isAvailable() is false. Preserve the existing native permission
behavior when the transport is available.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 79b1acee-e82e-4f58-a03a-3bbceb5a8a94
⛔ Files ignored due to path filters (4)
apps/desktop/src-tauri/gen/schemas/acl-manifests.jsonis excluded by!**/gen/**apps/desktop/src-tauri/gen/schemas/capabilities.jsonis excluded by!**/gen/**apps/desktop/src-tauri/gen/schemas/desktop-schema.jsonis excluded by!**/gen/**apps/desktop/src-tauri/gen/schemas/linux-schema.jsonis excluded by!**/gen/**
📒 Files selected for processing (71)
apps/backend/internal/backendapp/main.goapps/backend/internal/gateway/websocket/hub.goapps/backend/internal/gateway/websocket/hub_broadcast_test.goapps/backend/internal/gateway/websocket/hub_user_subscription_test.goapps/backend/internal/notifications/providers/local.goapps/backend/internal/notifications/providers/local_test.goapps/backend/internal/notifications/providers/provider.goapps/backend/internal/notifications/service/service.goapps/backend/internal/notifications/service/service_test.goapps/backend/internal/notifications/store/sqlite.goapps/backend/internal/notifications/store/sqlite_test.goapps/backend/internal/persistence/meta.goapps/backend/internal/persistence/meta_test.goapps/backend/internal/persistence/postgres_meta_test.goapps/backend/internal/system/system.goapps/backend/internal/system/updates/handler.goapps/backend/internal/system/updates/handler_notify_test.goapps/backend/internal/system/updates/notify_dispatch_test.goapps/backend/internal/system/updates/notify_settings.goapps/backend/internal/system/updates/notify_settings_test.goapps/backend/internal/system/updates/notify_store.goapps/backend/internal/system/updates/notify_store_test.goapps/backend/internal/system/updates/service.goapps/desktop/src-tauri/build.rsapps/desktop/src-tauri/capabilities/default.jsonapps/desktop/src-tauri/permissions/autogenerated/get_native_notification_permission.tomlapps/desktop/src-tauri/permissions/autogenerated/request_native_notification_permission.tomlapps/desktop/src-tauri/src/backend.rsapps/desktop/src-tauri/src/main.rsapps/desktop/src-tauri/src/native_notifications.rsapps/web/components/settings/notification-permission-section.tsxapps/web/components/settings/notifications-settings-actions.test.tsxapps/web/components/settings/notifications-settings-actions.tsapps/web/components/settings/notifications-settings.tsxapps/web/components/settings/system/update-notifications-card.test.tsxapps/web/components/settings/system/update-notifications-card.tsxapps/web/e2e/tests/settings/mobile-notification-events.spec.tsapps/web/e2e/tests/system/update-notifications-settings.spec.tsapps/web/hooks/use-update-available-toast.test.tsapps/web/hooks/use-update-available-toast.tsapps/web/lib/api/domains/system-api.test.tsapps/web/lib/api/domains/system-api.tsapps/web/lib/desktop/native-notification-client.test.tsapps/web/lib/desktop/native-notification-client.tsapps/web/lib/notifications/events.tsapps/web/lib/state/hydration/hydrator.test.tsapps/web/lib/state/hydration/hydrator.tsapps/web/lib/state/slices/system/system-slice.tsapps/web/lib/state/slices/system/types.tsapps/web/lib/state/slices/ui/types.tsapps/web/lib/types/backend.tsapps/web/lib/types/system.tsapps/web/lib/ws/handlers/notifications.test.tsapps/web/lib/ws/handlers/notifications.tsapps/web/lib/ws/handlers/system-events.test.tsapps/web/lib/ws/handlers/system-events.tsapps/web/src/settings-routes.test.tsapps/web/src/settings-routes.tsxdocs/decisions/0039-native-desktop-integration-boundary.mddocs/decisions/2026-07-24-semantic-notification-events.mddocs/plans/update-notification-reliability/plan.mddocs/plans/update-notification-reliability/task-01-provider-event-and-delivery.mddocs/plans/update-notification-reliability/task-02-update-replay-and-wiring.mddocs/plans/update-notification-reliability/task-03-native-permission-bridge.mddocs/plans/update-notification-reliability/task-04-frontend-provider-delivery.mddocs/plans/update-notification-reliability/task-05-mobile-e2e-and-docs.mddocs/public/operations.mddocs/public/websocket-api.mddocs/specs/desktop-tauri-app/spec.mddocs/specs/platform/notifications.mddocs/specs/system-page/spec.md
💤 Files with no reviewable changes (21)
- apps/backend/internal/system/updates/notify_settings_test.go
- apps/web/lib/ws/handlers/system-events.test.ts
- apps/web/components/settings/system/update-notifications-card.test.tsx
- apps/backend/internal/system/updates/notify_settings.go
- apps/web/lib/types/system.ts
- apps/web/components/settings/system/update-notifications-card.tsx
- apps/backend/internal/system/updates/notify_store.go
- apps/backend/internal/system/updates/notify_store_test.go
- apps/web/lib/state/hydration/hydrator.test.ts
- apps/backend/internal/persistence/meta.go
- apps/backend/internal/system/updates/handler_notify_test.go
- apps/web/lib/state/slices/system/types.ts
- apps/backend/internal/system/system.go
- apps/web/e2e/tests/system/update-notifications-settings.spec.ts
- apps/web/lib/state/slices/system/system-slice.ts
- apps/backend/internal/persistence/postgres_meta_test.go
- apps/backend/internal/system/updates/handler.go
- apps/backend/internal/persistence/meta_test.go
- apps/web/lib/ws/handlers/system-events.ts
- apps/web/lib/api/domains/system-api.ts
- apps/web/lib/api/domains/system-api.test.ts
|
Claude finished @carlosflorencio's task in 0s —— View job I'll analyze this and get back to you. |
|
Claude finished @carlosflorencio's task in 0s —— View job I'll analyze this and get back to you. |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
docs/plans/update-notification-reliability/task-04-frontend-provider-delivery.md (1)
27-38: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winCover all changed notification paths in verification.
The plan lists
apps/web/lib/ws/handlers/system-events.test.tsas a touched test, but the verification command does not run it. Add that test, or explicitly document that another task/CI job owns it; otherwise the completed task can miss regressions in update-event routing.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/plans/update-notification-reliability/task-04-frontend-provider-delivery.md` around lines 27 - 38, The Verification command omits the touched system-events test, leaving update-event routing unverified. Add apps/web/lib/ws/handlers/system-events.test.ts to the listed Vitest targets, or explicitly document that another task or CI job owns its execution.docs/specs/system-page/spec.md (1)
44-46: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low valueUse the shared Notifications route wording.
The actual page lives under
/settings/general/notifications, but the spec has drifted between this section and section 140. Use one consistent label there; keeping it asNotifications settings pageis safer than a breadcrumb-style path.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@docs/specs/system-page/spec.md` around lines 44 - 46, Update the notification-page reference in the section near the diff to use the consistent label “Notifications settings page,” matching the wording used in section 140, and avoid breadcrumb-style route wording.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/backend/internal/notifications/providers/local_test.go`:
- Around line 45-51: Register t.Cleanup immediately after starting the hub.Run
goroutine in the local notification provider tests, before dialing or any fatal
assertion. The cleanup must cancel cancelHub and wait for hubDone, and the same
ordering must be applied to the additional setup referenced around lines 70–83.
In `@apps/backend/internal/notifications/store/sqlite.go`:
- Around line 104-107: Update repository initialization and its operation chain
to accept and propagate the startup context into
migrateUpdateAvailableSubscriptions. Replace the context.Background() call in
the migration flow with that propagated context, while preserving the existing
migrateLegacySubscriptions error handling.
---
Nitpick comments:
In
`@docs/plans/update-notification-reliability/task-04-frontend-provider-delivery.md`:
- Around line 27-38: The Verification command omits the touched system-events
test, leaving update-event routing unverified. Add
apps/web/lib/ws/handlers/system-events.test.ts to the listed Vitest targets, or
explicitly document that another task or CI job owns its execution.
In `@docs/specs/system-page/spec.md`:
- Around line 44-46: Update the notification-page reference in the section near
the diff to use the consistent label “Notifications settings page,” matching the
wording used in section 140, and avoid breadcrumb-style route wording.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 747c88fa-c50d-4c1a-a5c2-56bfb6d730c1
⛔ Files ignored due to path filters (4)
apps/desktop/src-tauri/gen/schemas/acl-manifests.jsonis excluded by!**/gen/**apps/desktop/src-tauri/gen/schemas/capabilities.jsonis excluded by!**/gen/**apps/desktop/src-tauri/gen/schemas/desktop-schema.jsonis excluded by!**/gen/**apps/desktop/src-tauri/gen/schemas/linux-schema.jsonis excluded by!**/gen/**
📒 Files selected for processing (72)
apps/backend/internal/backendapp/main.goapps/backend/internal/gateway/websocket/hub.goapps/backend/internal/gateway/websocket/hub_broadcast_test.goapps/backend/internal/gateway/websocket/hub_user_subscription_test.goapps/backend/internal/notifications/providers/local.goapps/backend/internal/notifications/providers/local_test.goapps/backend/internal/notifications/providers/provider.goapps/backend/internal/notifications/service/service.goapps/backend/internal/notifications/service/service_test.goapps/backend/internal/notifications/store/sqlite.goapps/backend/internal/notifications/store/sqlite_test.goapps/backend/internal/persistence/meta.goapps/backend/internal/persistence/meta_test.goapps/backend/internal/persistence/postgres_meta_test.goapps/backend/internal/system/system.goapps/backend/internal/system/updates/handler.goapps/backend/internal/system/updates/handler_notify_test.goapps/backend/internal/system/updates/notify_dispatch_test.goapps/backend/internal/system/updates/notify_settings.goapps/backend/internal/system/updates/notify_settings_test.goapps/backend/internal/system/updates/notify_store.goapps/backend/internal/system/updates/notify_store_test.goapps/backend/internal/system/updates/service.goapps/desktop/src-tauri/build.rsapps/desktop/src-tauri/capabilities/default.jsonapps/desktop/src-tauri/permissions/autogenerated/get_native_notification_permission.tomlapps/desktop/src-tauri/permissions/autogenerated/request_native_notification_permission.tomlapps/desktop/src-tauri/src/backend.rsapps/desktop/src-tauri/src/main.rsapps/desktop/src-tauri/src/native_notifications.rsapps/web/components/settings/notification-permission-section.test.tsxapps/web/components/settings/notification-permission-section.tsxapps/web/components/settings/notifications-settings-actions.test.tsxapps/web/components/settings/notifications-settings-actions.tsapps/web/components/settings/notifications-settings.tsxapps/web/components/settings/system/update-notifications-card.test.tsxapps/web/components/settings/system/update-notifications-card.tsxapps/web/e2e/tests/settings/mobile-notification-events.spec.tsapps/web/e2e/tests/system/update-notifications-settings.spec.tsapps/web/hooks/use-update-available-toast.test.tsapps/web/hooks/use-update-available-toast.tsapps/web/lib/api/domains/system-api.test.tsapps/web/lib/api/domains/system-api.tsapps/web/lib/desktop/native-notification-client.test.tsapps/web/lib/desktop/native-notification-client.tsapps/web/lib/notifications/events.tsapps/web/lib/state/hydration/hydrator.test.tsapps/web/lib/state/hydration/hydrator.tsapps/web/lib/state/slices/system/system-slice.tsapps/web/lib/state/slices/system/types.tsapps/web/lib/state/slices/ui/types.tsapps/web/lib/types/backend.tsapps/web/lib/types/system.tsapps/web/lib/ws/handlers/notifications.test.tsapps/web/lib/ws/handlers/notifications.tsapps/web/lib/ws/handlers/system-events.test.tsapps/web/lib/ws/handlers/system-events.tsapps/web/src/settings-routes.test.tsapps/web/src/settings-routes.tsxdocs/decisions/0039-native-desktop-integration-boundary.mddocs/decisions/2026-07-24-semantic-notification-events.mddocs/plans/update-notification-reliability/plan.mddocs/plans/update-notification-reliability/task-01-provider-event-and-delivery.mddocs/plans/update-notification-reliability/task-02-update-replay-and-wiring.mddocs/plans/update-notification-reliability/task-03-native-permission-bridge.mddocs/plans/update-notification-reliability/task-04-frontend-provider-delivery.mddocs/plans/update-notification-reliability/task-05-mobile-e2e-and-docs.mddocs/public/operations.mddocs/public/websocket-api.mddocs/specs/desktop-tauri-app/spec.mddocs/specs/platform/notifications.mddocs/specs/system-page/spec.md
💤 Files with no reviewable changes (20)
- apps/web/e2e/tests/system/update-notifications-settings.spec.ts
- apps/backend/internal/system/updates/notify_settings_test.go
- apps/web/lib/types/system.ts
- apps/web/components/settings/system/update-notifications-card.tsx
- apps/backend/internal/system/updates/notify_store_test.go
- apps/web/lib/ws/handlers/system-events.test.ts
- apps/backend/internal/system/updates/notify_settings.go
- apps/backend/internal/system/updates/notify_store.go
- apps/web/lib/api/domains/system-api.test.ts
- apps/backend/internal/persistence/postgres_meta_test.go
- apps/backend/internal/system/updates/handler_notify_test.go
- apps/backend/internal/persistence/meta.go
- apps/web/lib/state/hydration/hydrator.test.ts
- apps/web/lib/ws/handlers/system-events.ts
- apps/backend/internal/persistence/meta_test.go
- apps/web/lib/state/slices/system/types.ts
- apps/web/lib/state/slices/system/system-slice.ts
- apps/web/components/settings/system/update-notifications-card.test.tsx
- apps/backend/internal/system/updates/handler.go
- apps/web/lib/api/domains/system-api.ts
🚧 Files skipped from review as they are similar to previous changes (42)
- apps/desktop/src-tauri/src/main.rs
- docs/plans/update-notification-reliability/task-02-update-replay-and-wiring.md
- apps/desktop/src-tauri/capabilities/default.json
- apps/desktop/src-tauri/build.rs
- docs/public/websocket-api.md
- apps/desktop/src-tauri/permissions/autogenerated/request_native_notification_permission.toml
- apps/backend/internal/gateway/websocket/hub_user_subscription_test.go
- apps/backend/internal/notifications/providers/local.go
- docs/plans/update-notification-reliability/task-03-native-permission-bridge.md
- apps/desktop/src-tauri/permissions/autogenerated/get_native_notification_permission.toml
- docs/plans/update-notification-reliability/task-05-mobile-e2e-and-docs.md
- docs/plans/update-notification-reliability/task-01-provider-event-and-delivery.md
- apps/desktop/src-tauri/src/backend.rs
- apps/backend/internal/gateway/websocket/hub_broadcast_test.go
- apps/web/lib/state/hydration/hydrator.ts
- apps/backend/internal/system/system.go
- apps/web/components/settings/notifications-settings-actions.ts
- apps/web/lib/state/slices/ui/types.ts
- apps/web/lib/types/backend.ts
- apps/web/lib/desktop/native-notification-client.ts
- docs/decisions/2026-07-24-semantic-notification-events.md
- docs/public/operations.md
- apps/web/lib/desktop/native-notification-client.test.ts
- apps/web/components/settings/notification-permission-section.tsx
- apps/backend/internal/notifications/store/sqlite_test.go
- apps/web/hooks/use-update-available-toast.test.ts
- docs/decisions/0039-native-desktop-integration-boundary.md
- docs/plans/update-notification-reliability/plan.md
- apps/web/lib/notifications/events.ts
- apps/backend/internal/system/updates/notify_dispatch_test.go
- apps/web/lib/ws/handlers/notifications.ts
- apps/web/components/settings/notifications-settings.tsx
- apps/backend/internal/gateway/websocket/hub.go
- apps/web/hooks/use-update-available-toast.ts
- docs/specs/desktop-tauri-app/spec.md
- apps/web/lib/ws/handlers/notifications.test.ts
- apps/web/components/settings/notifications-settings-actions.test.tsx
- apps/web/e2e/tests/settings/mobile-notification-events.spec.ts
- apps/backend/internal/notifications/service/service.go
- apps/web/src/settings-routes.tsx
- apps/backend/internal/notifications/service/service_test.go
- apps/backend/internal/system/updates/service.go
|
Claude finished @carlosflorencio's task in 0s —— View job I'll analyze this and get back to you. |
Update alerts introduced in #1924 bypassed the notification-provider contract and could be lost
during startup or denied native delivery. This routes releases through canonical provider
subscriptions, durable occurrence delivery, cached replay, and an in-app fallback.
Important Changes
system.update_availablewith the release version as the provider-scoped occurrence ID.visible when native or browser delivery is unavailable.
unchanged until explicitly selected.
Validation
make fmtmake typecheckmake testmake lintcargo fmt --checkcargo check --features desktop-runtimecargo test --features desktop-runtimepnpm e2e:run tests/settings/mobile-notification-events.spec.ts -- --project=mobile-chromenode --test scripts/validate-public-docs.test.mjsnode scripts/validate-public-docs.mjsDiagram
flowchart LR Poll[Release poll] --> Cache[Durable cached release] Cache --> Notify[Notification service] Notify --> Local[Local provider] Notify --> System[System provider] Notify --> Apprise[Apprise provider] Local -->|frame queued| History[Provider delivery history] Local -->|no eligible queue| Pending[Release Local claim] Subscribe[Default user subscribes] --> Replay[Replay cached release] Pending --> Replay Replay --> NotifyPossible Improvements
Low risk: singleton default-provider creation is serialized within the application's notification
service; a future multi-process deployment should enforce the invariant in the database.
Checklist
apps/web/), I have added or updated Playwright e2e tests inapps/web/e2e/and verified them withmake test-e2e.docs/public/**and updated them or noted why no docs change is needed.Screenshots
Desktop
Mobile