PWA: installable webclient, offline shell, web push
Installability:
- public/manifest.webmanifest (standalone, theme #16161E) + PNG icons
  generated from logo.svg (regular + maskable, served via /images mount)
- index.html: manifest link, theme-color, apple-touch-icon

Offline shell:
- hand-rolled sw.js (no workbox): navigation = network-first (3s race)
  with cached-shell fallback + background refresh (a stale cached shell
  would 404 on entry chunks after a deploy); /assets/* cache-first
  (content-hashed); /images/* cache-first capped; /api,/ws,/auth,/push,
  /content pass-through
- vite closeBundle plugin stamps __NAVI_BUILD_VERSION__ (digest of
  index.html + asset names) into dist/sw.js; sw.js served no-store so
  every deploy reactivates the SW and activation evicts old caches
- SW registration in main.js, PROD only (dev HMR untouched)
- OfflineBanner (useOnline composable) over the app shell

Web push (VAPID, pywebpush):
- navi/push/ package: push_subscriptions table (postgres, boot-time DDL),
  PushSubscriptionStore, PushService (async fan-out, to_thread sends,
  404/410 prunes dead endpoints, per-session cooldown)
- routes: GET /push/vapid-key, POST/DELETE /push/subscribe (auth-gated)
- trigger in orchestrator run_agent + run_recall: push on StreamEnd when
  no WebSocket client watches the session; fire-and-forget, never
  disturbs the run; anonymous fallback only when auth is off
- client: usePush composable + Notifications settings panel (enable/
  disable via PushManager.subscribe with the server VAPID key)
- notification click focuses the app at /#<session_id> (hash routing
  opens the right chat); payload body is a markdown-stripped <=140-char
  preview

NAVIVAPID keys empty = push fully disabled (graceful, like other optional
integrations). dist/ artifacts committed per repo convention.

Tests: pytest push store/service/routes/trigger (+23), vitest usePush
(83 webclient tests green). Full suite 1143 passed.
1 parent 8d46651 commit 53109a19f73120924db3417956a369d4127d04b0
@Eugene Sukhodolskiy Eugene Sukhodolskiy authored 7 hours ago
Showing 47 changed files
View
deploy/env.template
View
docs/config.md
View
docs/index.md
View
docs/push.md 0 → 100644
View
navi/api/deps.py
View
navi/api/routes/push.py 0 → 100644
View
navi/config.py
View
navi/core/container.py
View
navi/core/orchestrator.py
View
navi/main.py
View
navi/push/__init__.py 0 → 100644
View
navi/push/_ddl.py 0 → 100644
View
navi/push/service.py 0 → 100644
View
navi/push/store.py 0 → 100644
View
pyproject.toml
View
tests/unit/api/test_push_routes.py 0 → 100644
View
tests/unit/core/test_push_trigger.py 0 → 100644
View
tests/unit/push/test_push_service.py 0 → 100644
View
tests/unit/push/test_push_store.py 0 → 100644
View
webclient/dist/assets/index-B0mItcA1.js 100644 → 0
Not supported
View
webclient/dist/assets/index-CAAl2O29.css 0 → 100644
View
webclient/dist/assets/index-DyevEXq3.js 0 → 100644
Not supported
View
webclient/dist/assets/index-RBbsjxIZ.css 100644 → 0
View
webclient/dist/images/icon-192.png 0 → 100644
View
webclient/dist/images/icon-512.png 0 → 100644
View
webclient/dist/images/icon-maskable-192.png 0 → 100644
View
webclient/dist/images/icon-maskable-512.png 0 → 100644
View
webclient/dist/index.html
View
webclient/dist/manifest.webmanifest 0 → 100644
View
webclient/dist/sw.js 0 → 100644
View
webclient/index.html
View
webclient/public/images/icon-192.png 0 → 100644
View
webclient/public/images/icon-512.png 0 → 100644
View
webclient/public/images/icon-maskable-192.png 0 → 100644
View
webclient/public/images/icon-maskable-512.png 0 → 100644
View
webclient/public/manifest.webmanifest 0 → 100644
View
webclient/public/sw.js 0 → 100644
View
webclient/src/App.vue
View
webclient/src/api/index.js
View
webclient/src/components/settings/NotificationSettingsPanel.vue 0 → 100644
View
webclient/src/components/settings/SettingsView.vue
View
webclient/src/components/ui/OfflineBanner.vue 0 → 100644
View
webclient/src/composables/useOnline.js 0 → 100644
View
webclient/src/composables/usePush.js 0 → 100644
View
webclient/src/main.js
View
webclient/tests/unit/composables/usePush.test.js 0 → 100644
View
webclient/vite.config.js