fix(push): make web push subscription explicit and eager (LC-343) #456

Merged
nrupard merged 2 commits from fix/LC-343-push-subscription-flow into main 2026-06-26 14:59:44 +02:00
Member

Root cause of non-delivery: the push subscription was chicken-and-egg lazy. tryRegisterPush() only ran from fireNotification(), which only fires on a background Mentioned event, and only after Notification.permission is already 'granted'. There was no affordance to grant permission and no registration on page load, so a user who had not received a background mention while already permission-granted never had a push_subscriptions row created. With no row, push::dispatch had nothing to send to, so push never fired regardless of LETS_CHAT_SECRET_KEY, the notify_push_enabled toggle, or the VAPID key being present.

Fixes the activation/subscription flow (web/desktop only; APNs/FCM stay deferred per LC-91):

  • Explicit opt-in: a new "Enable desktop notifications" button in Settings > Notifications (shown only when push_available) calls window.__lcEnablePush, which requests Notification permission on the user gesture and subscribes immediately, creating the push_subscriptions row without waiting for a future mention.
  • Eager re-subscribe on page load: an already-opted-in (notify_push_enabled) and permission-granted browser now re-registers its subscription on every full page load, decoupled from the first-background-mention path.
  • No more silent failures: tryRegisterPush reports each stage (unsupported / blocked / denied / unavailable / failed / ok) into a settings status line and logs failures at console.error instead of the old console.warn-only swallow.
  • Settings still cleanly shows "unavailable" and disables the toggle/hides the button when push_available() is false (LETS_CHAT_SECRET_KEY unset).

New en/es catalog keys for the button, help text, and status messages; the JS-embedded status strings avoid apostrophes/quotes so the HTML escaper does not mangle them inside the script body.

#LC-343

Root cause of non-delivery: the push subscription was chicken-and-egg lazy. tryRegisterPush() only ran from fireNotification(), which only fires on a *background* Mentioned event, and only after Notification.permission is already 'granted'. There was no affordance to grant permission and no registration on page load, so a user who had not received a background mention while already permission-granted never had a push_subscriptions row created. With no row, push::dispatch had nothing to send to, so push never fired regardless of LETS_CHAT_SECRET_KEY, the notify_push_enabled toggle, or the VAPID key being present. Fixes the activation/subscription flow (web/desktop only; APNs/FCM stay deferred per LC-91): - Explicit opt-in: a new "Enable desktop notifications" button in Settings > Notifications (shown only when push_available) calls window.__lcEnablePush, which requests Notification permission on the user gesture and subscribes immediately, creating the push_subscriptions row without waiting for a future mention. - Eager re-subscribe on page load: an already-opted-in (notify_push_enabled) and permission-granted browser now re-registers its subscription on every full page load, decoupled from the first-background-mention path. - No more silent failures: tryRegisterPush reports each stage (unsupported / blocked / denied / unavailable / failed / ok) into a settings status line and logs failures at console.error instead of the old console.warn-only swallow. - Settings still cleanly shows "unavailable" and disables the toggle/hides the button when push_available() is false (LETS_CHAT_SECRET_KEY unset). New en/es catalog keys for the button, help text, and status messages; the JS-embedded status strings avoid apostrophes/quotes so the HTML escaper does not mangle them inside the script body. #LC-343
fix(push): make web push subscription explicit and eager (LC-343)
Some checks failed
check-secrets / TruffleHog (pull_request) Successful in 4s
check-secrets / Nosey parker (pull_request) Successful in 5s
check-secrets / Kingfisher (pull_request) Failing after 5s
check-secrets / Nosey parker (push) Successful in 4s
check-secrets / TruffleHog (push) Successful in 4s
check-secrets / Kingfisher (push) Failing after 12s
Check / clippy + fmt + tests (pull_request) Successful in 10m3s
2a4d73e7c3
Root cause of non-delivery: the push subscription was chicken-and-egg lazy. tryRegisterPush() only ran from fireNotification(), which only fires on a *background* Mentioned event, and only after Notification.permission is already 'granted'. There was no affordance to grant permission and no registration on page load, so a user who had not received a background mention while already permission-granted never had a push_subscriptions row created. With no row, push::dispatch had nothing to send to, so push never fired regardless of LETS_CHAT_SECRET_KEY, the notify_push_enabled toggle, or the VAPID key being present.

Fixes the activation/subscription flow (web/desktop only; APNs/FCM stay deferred per LC-91):

- Explicit opt-in: a new "Enable desktop notifications" button in Settings > Notifications (shown only when push_available) calls window.__lcEnablePush, which requests Notification permission on the user gesture and subscribes immediately, creating the push_subscriptions row without waiting for a future mention.
- Eager re-subscribe on page load: an already-opted-in (notify_push_enabled) and permission-granted browser now re-registers its subscription on every full page load, decoupled from the first-background-mention path.
- No more silent failures: tryRegisterPush reports each stage (unsupported / blocked / denied / unavailable / failed / ok) into a settings status line and logs failures at console.error instead of the old console.warn-only swallow.
- Settings still cleanly shows "unavailable" and disables the toggle/hides the button when push_available() is false (LETS_CHAT_SECRET_KEY unset).

New en/es catalog keys for the button, help text, and status messages; the JS-embedded status strings avoid apostrophes/quotes so the HTML escaper does not mangle them inside the script body.

#LC-343
fix(push): stop the subscribe status from over-promising delivery (LC-343)
Some checks failed
check-secrets / TruffleHog (pull_request) Successful in 4s
check-secrets / Nosey parker (push) Successful in 5s
check-secrets / Kingfisher (push) Failing after 5s
check-secrets / Kingfisher (pull_request) Failing after 6s
check-secrets / TruffleHog (push) Successful in 7s
check-secrets / Nosey parker (pull_request) Successful in 23s
Check / clippy + fmt + tests (pull_request) Successful in 11m34s
Create release / Create release from merged PR (pull_request) Has been skipped
367fb892ec
The "Enable desktop notifications" button subscribed the browser and always reported settings-push-status-ok ("This device will receive push notifications"), but push::dispatch early-returns unless the SAVED notify_push_enabled is on. A user who clicked the button with the toggle off (or flipped it on but never submitted the preferences form) got a green success line while the server silently dropped every push. Report the new settings-push-status-ok-toggle-off variant when pushEnabled (which mirrors the saved toggle) is false, so the success line tells them to turn the toggle on and save; the plain ok line stays for the already-saved-on case. The subscription itself still succeeds in both cases (data-lc-push-ok stays 1).

Also move the status strings out of JS string literals and into data-* attributes on the cfg div, read via getAttribute. The template HTML-escaper makes a translation containing a quote or apostrophe safe there; the previous inline form only worked because every string happened to avoid quotes, which a future locale or translator would not guarantee.

i18n_catalog and routes_settings_feedback pass; the new key is defined in both en and es so locale parity holds.

#LC-343

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
nrupard scheduled this pull request to auto merge when all checks succeed 2026-06-26 14:51:46 +02:00
nrupard deleted branch fix/LC-343-push-subscription-flow 2026-06-26 14:59:44 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/lets-chat!456
No description provided.