The SSE + in-page toast/sound system only works while the tab's JS is actually running — Chrome (and other browsers) freeze a backgrounded tab's JS after a stretch of inactivity to save power, so notifications silently stop regardless of how correct the SSE/toast code is. A Service Worker is the only mechanism that keeps receiving events independent of the tab's own lifecycle, so this adds a real Web Push pipeline: - New `push_subscriptions` table (one row per browser/device a user has subscribed from; endpoint is unique so re-subscribing overwrites rather than accumulating stale rows). - VAPID keypair config (lib/push/vapid.ts) — reads VAPID_PUBLIC_KEY/VAPID_PRIVATE_KEY/VAPID_SUBJECT from the environment; push is silently disabled (never throws) if they're unset, matching this codebase's existing "an optional integration outage must never break the core flow" pattern (see the LDAP auth comment). - public/sw.js: a minimal service worker — `push` -> showNotification, `notificationclick` -> focus or open the ticket. - API routes: GET /api/push/vapid-public-key (client needs it to call pushManager.subscribe), POST/DELETE /api/push/subscribe. - lib/push/client.ts: registers the service worker and subscribes, called from the notification bell after granting permission and again on mount for returning users who already granted it. - lib/tickets/service.ts: appendMessage() now also fires a push (fire- and-forget, never awaited by the caller) to every admin plus the ticket's assignee whenever a *customer* message arrives — same "who should know" rule as the in-page toast (lib/tickets/visibility.ts). Failed sends are inspected: a 404/410 (push service no longer recognizes the subscription) prunes the row; anything else is just logged, since it might be transient. Verified server-side end-to-end on this VM: saved a subscription via the API, created a customer ticket, and confirmed the push attempt actually fires (web-push validated and rejected a deliberately-malformed test key, proving the send path is wired correctly) without blocking or crashing ticket creation. Couldn't verify the full real-browser subscribe-and-receive path or an actual OS popup from here — this VM has no desktop/notification service, and headless Chromium's Notification permission can't be reliably granted in this sandbox (unrelated to the app code); that last mile needs verifying on a real machine. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012o9j9RezxbZVKQMrB7oRLY
55 lines
1.0 KiB
JSON
55 lines
1.0 KiB
JSON
{
|
|
"version": "7",
|
|
"dialect": "sqlite",
|
|
"entries": [
|
|
{
|
|
"idx": 0,
|
|
"version": "6",
|
|
"when": 1785068349476,
|
|
"tag": "0000_superb_the_fallen",
|
|
"breakpoints": true
|
|
},
|
|
{
|
|
"idx": 1,
|
|
"version": "6",
|
|
"when": 1785070407727,
|
|
"tag": "0001_mushy_purple_man",
|
|
"breakpoints": true
|
|
},
|
|
{
|
|
"idx": 2,
|
|
"version": "6",
|
|
"when": 1785072485453,
|
|
"tag": "0002_broad_stellaris",
|
|
"breakpoints": true
|
|
},
|
|
{
|
|
"idx": 3,
|
|
"version": "6",
|
|
"when": 1785076018169,
|
|
"tag": "0003_absurd_zemo",
|
|
"breakpoints": true
|
|
},
|
|
{
|
|
"idx": 4,
|
|
"version": "6",
|
|
"when": 1785085538509,
|
|
"tag": "0004_familiar_kronos",
|
|
"breakpoints": true
|
|
},
|
|
{
|
|
"idx": 5,
|
|
"version": "6",
|
|
"when": 1785138258070,
|
|
"tag": "0005_colorful_gorilla_man",
|
|
"breakpoints": true
|
|
},
|
|
{
|
|
"idx": 6,
|
|
"version": "6",
|
|
"when": 1786130418783,
|
|
"tag": "0006_big_daredevil",
|
|
"breakpoints": true
|
|
}
|
|
]
|
|
} |