Skip to Content
FrontendArchitecture

Architecture

Rules

  1. Data direction — Components → Hooks (React Query) → lib/actions/*fetchWrapper*.
  2. No server data in stores — stores hold only IDs/filters/UI flags.
  3. Shareable view state in URL — filters/sort/page live in query params.
  4. Hooks are pure — no toasts/router in services; components own UX.
  5. One list shape
type PageResult<T> = { items: T[]; page?: number; totalPages?: number; nextCursor?: string; hasNextPage: boolean; };
  1. Test at seams — adapters few, services most, hooks behavior, a handful of E2E.
🧭

One list shape keeps services interchangeable and hooks simple.

Bad vs Good

Duplicate shapes per endpoint; pagination in components; inconsistent invalidation.

URL state policy

  • Query params: ?q=...&sort=...&page=...
  • Encoded objects kept shallow; arrays supported via repeated keys.

Where logic lives

  • Components: presentation, inputs, toasts, routing.
  • Hooks: network behavior, cache keys, invalidation, debouncing.
  • Services (lib/actions): map API → typed shapes, small transforms.
  • Adapters: base URL, headers, auth, handleResponse error mapping.

Implementation Plan (Day 1 → Week 2)

  • Day 1–2: add useInfiniteList, useMutationEx, useDisclosure, useDebouncedValue, useUrlState. ESLint guardrail: disallow fetchWrapper* outside lib/actions.
  • Day 3–4: standardize list PageResult in services; add usePostsInfinite; write tests #1–5.
  • Day 5: lists/chat domain hooks; write tests #6–9.
  • Week 2: Playwright golden path; enforce PR checklist.

Developer PR Checklist

  • Server data via React Query hook (no stores).
  • Shareable UI state in URL (useUrlState).
  • Service returns PageResult; no toasts inside service.
  • Mutation invalidates correct keys.
  • Tests added at the right seam.
  • fetchWrapper* used only in lib/actions.
Last updated on