feat(ui): desktop notifications via Web Push with per-category settings#353
Merged
Conversation
Five notification kinds now ride a single in-process notifier inside lerd-ui that fans every event out across both /api/ws (open tabs) and Web Push (closed PWA / minimised tabs): captured mail from Mailpit, queue/horizon/reverb worker failures, finished service operations (install, migrate, reinstall, update, rollback) with success/failed variants, registry update-available transitions, and ray()/dump() arrivals with the dumped content as a single-line preview in the body. Push is RFC 8291-encrypted, signed with a per-install VAPID key pair stored under ~/.local/share/lerd, fans out from the central dispatchNotification chokepoint, and prunes subscriptions automatically on 410/404. The service worker push handler is kind-agnostic, reading title, body, tag, url, and data straight off the payload so the SW never grows kind-specific branches. Settings live under System → Desktop notifications: master switch plus per-category toggles, a test-push button, and the subscribed-devices list with Forget actions. Per-kind preferences are stored both client-side in localStorage and server-side on the Subscription so closed-PWA Web Push honours the toggles too. Every visible string is translatable via Paraglide keys under notify_*, with the English fallback always travelling in the payload so the SW (no DOM, no Paraglide) keeps rendering correctly. Worker-failure detection no longer gates on whether a dashboard tab is visible; only the eventbus publish does. That way a closed-PWA developer still gets the push when a queue worker dies. Tests are TDD-first across both Go and Svelte with stub HTTPClient and real P-256 keys to exercise the encryption path without hitting the network.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an end-to-end desktop notification system to the lerd dashboard. Five kinds dispatch through a single in-process notifier inside
lerd-ui, fanning every event out over both/api/ws(open tabs) and Web Push (closed PWA / minimised tabs): captured mail, queue and framework worker failures, finished service operations (with separateop_doneandop_failedpayloads), service update transitions, andray()/dump()arrivals carrying the dumped content as a single-line preview.Push is RFC 8291 encrypted via
webpush-go, signed with a per-install VAPID key pair stored under~/.local/share/lerd. Subscriptions persist with their per-category preferences so closed-PWA delivery honours the toggles too; the server prunes endpoints automatically onHTTP 410 Gone/404 Not Found. The service worker push handler is kind-agnostic, reading title, body, tag, url, and data straight off the payload so it never grows kind-specific branches.A new Settings panel under System → Desktop notifications exposes the master switch, per-kind toggles (mail / worker failures / op done / service updates / dumps, with dumps off by default since it's typically noisy), a test-push button that always passes the category filter, and the subscribed-devices list with Forget actions. Every visible string travels with both an English fallback and a Paraglide key + params so the page localises through
m.notify_*while the SW (no DOM, no Paraglide) renders correctly with the English copy.Worker-failure detection used to short-circuit when no tab was visible, which made closed-PWA push pointless for that kind. The visibility gate is now only on the eventbus publish; detection and notification dispatch always run.