37afab867a
Task #554. Adds a full Web Push stack on top of the existing Socket.IO notification fan-out so the iPad PWA (and any installed browser) receives system notifications when Tx OS is closed or backgrounded. Backend - New `push_subscriptions` table (userId + unique endpoint + p256dh/auth keys + ua + timestamps), exported from `@workspace/db`. - `artifacts/api-server/src/lib/push.ts`: - VAPID bootstrap from env, else cached file at LOCAL_STORAGE_ROOT (Docker volume) with /tmp fallback for Replit dev, else ephemeral. - `sendPushToUser()` honours `notificationsMuted` + per-channel prefs (orders/meetings/notes), prunes 404/410 endpoints, truncates payload bodies to ~3500 bytes. - **De-dup gate:** skips push when the user has any active Socket.IO connection (uses `io.in(\`user:\${uid}\`).fetchSockets()`), so a connected user only gets the in-app chime, never a duplicate system notification. - `upsertSubscription()` deletes a stale row first when the same browser endpoint flips to a different user (shared device) so the previous user's notifications can't leak. - Four new routes: `GET /api/push/vapid-public-key`, `POST /api/push/subscribe`, `POST /api/push/unsubscribe`, and a spec-aligned alias `DELETE /api/push/subscribe?endpoint=...` (auth-gated, Zod-validated). - Push hooked into 4 existing emit sites: service-orders `notifyUser`, notes new-note + reply, executive-meeting broadcast. Frontend - `artifacts/tx-os/public/sw.js`: push + notificationclick only (no asset caching). All URLs (icon, badge, navigation target) resolved against `self.registration.scope`, so the SW works at root or under a subpath without code changes. - SW registration in `main.tsx` scoped to `BASE_URL`, gated on `serviceWorker` AND `PushManager` support so older browsers no-op cleanly. - `use-push-subscription` hook (enable/disable/refresh + status). - New `PushEnablePrompt` card mounted in `App` — appears on first launch when supported + permission still "default", one-tap enable, dismiss persists for 14 days. Silent on unsupported devices. - `PushToggleRow` added inside Notification Settings. - ar/en strings: `notifSettings.push.*` and `common.later`. Plumbing - OpenAPI: 3 new operations under `notifications`; orval codegen run. - `docker-compose.yml` passes VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY / VAPID_SUBJECT through to the api service. - `pnpm --filter @workspace/db run push` applied the schema. - web-push + @types/web-push installed in api-server. Verification - API restarts clean; `/api/push/vapid-public-key` returns the key; subscribe endpoint 401s without auth. - New `artifacts/api-server/tests/push.test.mjs` — 7/7 passing — covers VAPID endpoint, auth gating on subscribe/unsubscribe, row persistence + removal, idempotent re-subscribe with key rotation, account-switch endpoint reassignment, and malformed-input rejection. - New `artifacts/api-server/tests/push-410-unit.test.ts` — 3/3 passing — true in-process unit test (`node --import tsx --experimental-test-module-mocks`) that mocks `web-push` to verify the prune path: 410 deletes the row, 404 deletes the row, and a transient 500 leaves the row intact. `tsx` added as a devDep and the test:run script picks up `*.test.ts` alongside the existing `.mjs` suites. - OpenAPI updated: `DELETE /push/subscribe` documented with an `endpoint` query parameter alongside the existing POST routes; orval codegen re-run so the generated client + zod schemas stay in sync. - Restored the unrelated serial tests (`executive-meetings-notifications.test.mjs`, `setup-wizard.test.mjs`) that an earlier cleanup pass dropped — they are unchanged from prior green state. - Architect rounds addressed: 1. race + payload size. 2. dedup gate + first-launch UX + SW base-path + initial tests. 3. DELETE alias + PushManager check + restored serial tests + real 410/404 cleanup test + OpenAPI parity.
121 lines
4.3 KiB
YAML
121 lines
4.3 KiB
YAML
packages:
|
|
- artifacts/*
|
|
- lib/*
|
|
- lib/integrations/*
|
|
- scripts
|
|
|
|
autoInstallPeers: false
|
|
|
|
catalog:
|
|
'@tailwindcss/vite': ^4.1.14
|
|
'@tanstack/react-query': ^5.90.21
|
|
'@types/node': ^25.3.3
|
|
'@types/react': ^19.2.0
|
|
'@types/react-dom': ^19.2.0
|
|
'@vitejs/plugin-react': ^5.0.4
|
|
class-variance-authority: ^0.7.1
|
|
clsx: ^2.1.1
|
|
drizzle-orm: ^0.45.2
|
|
framer-motion: ^12.23.24
|
|
lucide-react: ^0.545.0
|
|
react: 19.1.0
|
|
react-dom: 19.1.0
|
|
tailwind-merge: ^3.3.1
|
|
tailwindcss: ^4.1.14
|
|
tsx: 4.21.0
|
|
vite: ^7.3.2
|
|
zod: 3.25.76
|
|
|
|
minimumReleaseAge: 1440
|
|
|
|
minimumReleaseAgeExclude: []
|
|
|
|
onlyBuiltDependencies:
|
|
- '@swc/core'
|
|
- esbuild
|
|
- msw
|
|
- unrs-resolver
|
|
|
|
overrides:
|
|
'@esbuild-kit/esm-loader': npm:tsx@^4.21.0
|
|
'@expo/ngrok-bin>@expo/ngrok-bin-darwin-arm64': '-'
|
|
'@expo/ngrok-bin>@expo/ngrok-bin-darwin-x64': '-'
|
|
'@expo/ngrok-bin>@expo/ngrok-bin-freebsd-ia32': '-'
|
|
'@expo/ngrok-bin>@expo/ngrok-bin-freebsd-x64': '-'
|
|
'@expo/ngrok-bin>@expo/ngrok-bin-linux-arm': '-'
|
|
'@expo/ngrok-bin>@expo/ngrok-bin-linux-arm64': '-'
|
|
'@expo/ngrok-bin>@expo/ngrok-bin-linux-ia32': '-'
|
|
'@expo/ngrok-bin>@expo/ngrok-bin-sunos-x64': '-'
|
|
'@expo/ngrok-bin>@expo/ngrok-bin-win32-ia32': '-'
|
|
'@expo/ngrok-bin>@expo/ngrok-bin-win32-x64': '-'
|
|
'@tailwindcss/oxide>@tailwindcss/oxide-android-arm64': '-'
|
|
'@tailwindcss/oxide>@tailwindcss/oxide-darwin-arm64': '-'
|
|
'@tailwindcss/oxide>@tailwindcss/oxide-darwin-x64': '-'
|
|
'@tailwindcss/oxide>@tailwindcss/oxide-freebsd-x64': '-'
|
|
'@tailwindcss/oxide>@tailwindcss/oxide-linux-arm-gnueabihf': '-'
|
|
'@tailwindcss/oxide>@tailwindcss/oxide-linux-arm64-gnu': '-'
|
|
'@tailwindcss/oxide>@tailwindcss/oxide-linux-arm64-musl': '-'
|
|
'@tailwindcss/oxide>@tailwindcss/oxide-linux-x64-musl': '-'
|
|
'@tailwindcss/oxide>@tailwindcss/oxide-win32-arm64-msvc': '-'
|
|
'@tailwindcss/oxide>@tailwindcss/oxide-win32-x64-msvc': '-'
|
|
esbuild: 0.27.3
|
|
esbuild>@esbuild/aix-ppc64: '-'
|
|
esbuild>@esbuild/android-arm: '-'
|
|
esbuild>@esbuild/android-arm64: '-'
|
|
esbuild>@esbuild/android-x64: '-'
|
|
esbuild>@esbuild/darwin-arm64: '-'
|
|
esbuild>@esbuild/darwin-x64: '-'
|
|
esbuild>@esbuild/freebsd-arm64: '-'
|
|
esbuild>@esbuild/freebsd-x64: '-'
|
|
esbuild>@esbuild/linux-arm: '-'
|
|
esbuild>@esbuild/linux-arm64: '-'
|
|
esbuild>@esbuild/linux-ia32: '-'
|
|
esbuild>@esbuild/linux-loong64: '-'
|
|
esbuild>@esbuild/linux-mips64el: '-'
|
|
esbuild>@esbuild/linux-ppc64: '-'
|
|
esbuild>@esbuild/linux-riscv64: '-'
|
|
esbuild>@esbuild/linux-s390x: '-'
|
|
esbuild>@esbuild/netbsd-arm64: '-'
|
|
esbuild>@esbuild/netbsd-x64: '-'
|
|
esbuild>@esbuild/openbsd-arm64: '-'
|
|
esbuild>@esbuild/openbsd-x64: '-'
|
|
esbuild>@esbuild/openharmony-arm64: '-'
|
|
esbuild>@esbuild/sunos-x64: '-'
|
|
esbuild>@esbuild/win32-arm64: '-'
|
|
esbuild>@esbuild/win32-ia32: '-'
|
|
esbuild>@esbuild/win32-x64: '-'
|
|
lightningcss>lightningcss-android-arm64: '-'
|
|
lightningcss>lightningcss-darwin-arm64: '-'
|
|
lightningcss>lightningcss-darwin-x64: '-'
|
|
lightningcss>lightningcss-freebsd-x64: '-'
|
|
lightningcss>lightningcss-linux-arm-gnueabihf: '-'
|
|
lightningcss>lightningcss-linux-arm64-gnu: '-'
|
|
lightningcss>lightningcss-linux-arm64-musl: '-'
|
|
lightningcss>lightningcss-linux-x64-musl: '-'
|
|
lightningcss>lightningcss-win32-arm64-msvc: '-'
|
|
lightningcss>lightningcss-win32-x64-msvc: '-'
|
|
rollup>@rollup/rollup-android-arm-eabi: '-'
|
|
rollup>@rollup/rollup-android-arm64: '-'
|
|
rollup>@rollup/rollup-darwin-arm64: '-'
|
|
rollup>@rollup/rollup-darwin-x64: '-'
|
|
rollup>@rollup/rollup-freebsd-arm64: '-'
|
|
rollup>@rollup/rollup-freebsd-x64: '-'
|
|
rollup>@rollup/rollup-linux-arm-gnueabihf: '-'
|
|
rollup>@rollup/rollup-linux-arm-musleabihf: '-'
|
|
rollup>@rollup/rollup-linux-arm64-gnu: '-'
|
|
rollup>@rollup/rollup-linux-arm64-musl: '-'
|
|
rollup>@rollup/rollup-linux-loong64-gnu: '-'
|
|
rollup>@rollup/rollup-linux-loong64-musl: '-'
|
|
rollup>@rollup/rollup-linux-ppc64-gnu: '-'
|
|
rollup>@rollup/rollup-linux-ppc64-musl: '-'
|
|
rollup>@rollup/rollup-linux-riscv64-gnu: '-'
|
|
rollup>@rollup/rollup-linux-riscv64-musl: '-'
|
|
rollup>@rollup/rollup-linux-s390x-gnu: '-'
|
|
rollup>@rollup/rollup-linux-x64-musl: '-'
|
|
rollup>@rollup/rollup-openbsd-x64: '-'
|
|
rollup>@rollup/rollup-openharmony-arm64: '-'
|
|
rollup>@rollup/rollup-win32-arm64-msvc: '-'
|
|
rollup>@rollup/rollup-win32-ia32-msvc: '-'
|
|
rollup>@rollup/rollup-win32-x64-gnu: '-'
|
|
rollup>@rollup/rollup-win32-x64-msvc: '-'
|