Two compounding issues were kicking installed/standalone maintenance
PWA sessions out into the portal's framed browser view on re-login:
- manifest scope was the app's own base path instead of "/", so any
same-origin navigation outside it (like the old redirect to
/login) dropped the standalone window into a regular browser tab
- AuthGate unconditionally hard-navigated window.top to the central
/login on session expiry, even when not embedded in the portal
iframe, which is exactly the navigation the doc warns against
AuthGate now only bounces to central login when actually embedded
(and passes ?from= so it returns to this app afterwards); standalone
or directly-opened tabs get an in-app login form and never navigate
away. Also wired up the previously-dead inactivity auto-logout timer
(disabled for installed PWAs, configurable per device otherwise).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
When a task is created or reassigned to a staff member, a push notification
is sent to any devices they have subscribed on. Keys are auto-generated on
first boot and stored in the config table (no manual VAPID setup needed).
- Backend: web-push dep, push_subscriptions table, lib/push.js (VAPID +
send), routes/push.js (vapid-key / subscribe / unsubscribe endpoints),
push notify wired into task-core createTask and tasks PATCH reassignment
- Frontend: switched vite-plugin-pwa to injectManifest strategy, custom
sw.js handles precache + push event + notificationclick, usePushSubscription
hook requests permission and registers subscription on login
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Wire up vite-plugin-pwa so Docker builds generate the web manifest
and service worker (was missing, causing installs to show portal icon).
Adds UpdateBanner with version-based polling via health endpoint.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- nginx try_files: remove $uri/ so the Vite assets/ build directory
doesn't shadow the /assets React route and trigger a 403
- Remove VitePWA plugin (leftover from scaffold, not needed for internal app)
- Strip PWA-specific nginx location blocks (manifest, sw.js, registerSW.js)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>