mirror of
https://github.com/Sea-Haven-Industries/shoc-frontend-new.git
synced 2026-10-03 16:43:23 +00:00
81 lines
4.3 KiB
Markdown
81 lines
4.3 KiB
Markdown
# 0001. Cross-tab QueryClient sync via `@tanstack/query-broadcast-client-experimental`
|
|
|
|
## Status
|
|
|
|
Accepted
|
|
|
|
## Context
|
|
|
|
The SeaHaven admin SPA is frequently used with multiple browser tabs open
|
|
against the same work-order board (e.g. a dispatcher triaging the board in one
|
|
tab while editing a work order in another). Each tab owns its own TanStack
|
|
Query `QueryClient` cache, so a mutation performed in one tab (status change,
|
|
dispatch creation, comment, vendor patch, etc.) does not invalidate or update
|
|
the cache in sibling tabs. Users were seeing stale board/detail data until a
|
|
manual refresh or the next background refetch.
|
|
|
|
We need a way to keep `QueryClient` caches roughly in sync across tabs of the
|
|
same origin, without introducing a new state-management layer (Redux is
|
|
disallowed by this repo's conventions) or a server-push mechanism.
|
|
|
|
## Decision
|
|
|
|
Use TanStack's own experimental broadcast client,
|
|
[`@tanstack/query-broadcast-client-experimental`](https://tanstack.com/query),
|
|
wired up in a single dedicated setup module,
|
|
`src/lib/query/setup-query-broadcast.ts`. The module:
|
|
|
|
- Wraps `broadcastQueryClient({ queryClient, broadcastChannel })`, keyed to a
|
|
single named channel (`seahaven-admin-query`).
|
|
- No-ops outside the browser (SSR/build) and under Vitest (`import.meta.env.MODE
|
|
=== "test"`), so it never runs in unit tests or node-based tooling.
|
|
- Is invoked once from `src/lib/query/query-client.ts` against the app's
|
|
singleton `QueryClient`, so every tab that loads the SPA subscribes to the
|
|
same channel automatically — no per-feature wiring required.
|
|
|
|
This piggybacks on the query cache we already have (no parallel store), uses
|
|
the library that owns the `QueryClient` we already depend on, and requires
|
|
close to zero application code (~20 lines) to adopt.
|
|
|
|
### Alternatives considered
|
|
|
|
- **Custom `BroadcastChannel` + manual `queryClient.invalidateQueries` calls**
|
|
— full control over payloads, but requires hand-rolling
|
|
serialization/versioning of query keys and mutation results, and keeping
|
|
every future mutation hook wired to broadcast. More code to own and more
|
|
surface area for subtle cache-desync bugs.
|
|
- **No cross-tab sync** — simplest option, but leaves the stale-tab UX problem
|
|
unresolved; users would need to manually refresh or wait for
|
|
`refetchOnWindowFocus`/`staleTime` to catch up, which is not reliable enough
|
|
for a live dispatch board.
|
|
- **Full WebSocket-based real-time sync** — solves both cross-tab and
|
|
cross-user staleness, but is a materially larger investment (server-side
|
|
push infra, connection lifecycle, auth over the socket) that is out of scope
|
|
for the current admin SPA and not justified by the actual problem (same
|
|
browser, same user, same origin).
|
|
|
|
## Consequences
|
|
|
|
- **Positive**: sibling tabs reflect mutations (status changes, dispatch
|
|
actions, comments, patches) without a manual refresh; the integration is
|
|
isolated to one setup file and does not touch domain/query-key code.
|
|
- **Risk — package lifecycle**: the dependency is explicitly "experimental" in
|
|
the TanStack ecosystem; its API may change or be deprecated between minor
|
|
versions. `@tanstack/query-broadcast-client-experimental`,
|
|
`@tanstack/react-query`, and `@tanstack/react-query-devtools` are pinned to
|
|
the **exact same version** in `package.json` (no `^` range). All three
|
|
resolve to the identical `@tanstack/query-core` version at that pin, which
|
|
keeps the `QueryClient` type used by `setupQueryBroadcast` structurally
|
|
identical to the one constructed in `query-client.ts` — a caret range lets
|
|
npm resolve the broadcast client and React Query against two different
|
|
`query-core` versions independently, which breaks `QueryClient` type
|
|
identity (TS2322) even though both packages build fine in isolation. Bump
|
|
all three together and re-evaluate on every TanStack Query upgrade.
|
|
- **Risk — same-origin only**: `BroadcastChannel` only syncs tabs on the same
|
|
origin; it does not sync across different users/sessions or devices. This is
|
|
acceptable for the current requirement (single user, multiple tabs).
|
|
- **Rollback plan**: remove the `@tanstack/query-broadcast-client-experimental`
|
|
dependency from `package.json` and delete the call to `setupQueryBroadcast`
|
|
in `src/lib/query/query-client.ts` (and the `setup-query-broadcast.ts` module
|
|
itself). No other code depends on it, so rollback is a single, isolated
|
|
change with no data migration.
|