Teacher-portal data layer: router loaders now, pgxsinkit later — never react-query or TanStack DB
Status: accepted
The teacher portal’s offering-management pages need a data layer. The obvious 2026
default for a TanStack shop — @tanstack/react-query — is deliberately rejected,
permanently, for this repo’s frontends.
Decision
Section titled “Decision”- v1 is online-only: each offering sub-route fetches through its TanStack Router
loader, which calls the typed client functions in
features/offerings/lib/client.ts; mutations call those functions and thenrouter.invalidate(). No client-side cache layer, no manual state surgery. - The typed client functions are the seam. When offline teacher authoring becomes
real, their internals become local reads/writes against PGlite synced by
pgxsinkit(viapackages/offline-data); their call sites survive unchanged. - The offline data layer is
pgxsinkit, full stop. We are fully committed to it: the canonical source lives in this workspace, so we evolve it to fit our needs (keeping it generic — it is open source).@tanstack/react-queryand@tanstack/dbare not candidates and are never introduced — pgxsinkit was created precisely because TanStack DB’s persistence was not production-ready, and adding Query now would create a third data layer that is neither the present pattern nor the future one. (TanStack Router and other TanStack projects remain in use where relevant.)
Context worth remembering
Section titled “Context worth remembering”- The schema already anticipates teacher-side sync:
learning_unitcarries LWW columns andoffering_membershipis a pgxsinkit sync-entry table. - Teacher offline will never be all-or-nothing. Draft authoring (structure tree, assessment composition) is plausibly offline; roster invites, membership status, publishing (structure freeze), transactional sibling renumbering, and hard-delete eligibility are inherently server-anchored. This mirrors the Delivery Profile split (offline-complete vs server-anchored) already in the domain language.
- Offline drafting is its own future design project (tree-edit conflict semantics under LWW — e.g. concurrent reparenting — are genuinely hard) and must not be introduced as a side effect of UX work.