3.3 KiB
3.3 KiB
Frontend conventions checklist (quick reference)
The authoritative rules are client/CLAUDE.md and the frontend-designer
skill (invoke it for any visual work). This is a tick-list. If anything here seems to conflict with
those, they win.
Boundaries & structure
- Never add a layout above
[locale];src/app/[locale]/layout.tsxis the root layout. - Respect the RSC/client boundary: no
next/headers,next-intl/server, or@/lib/cookies/serverin client components; no@/lib/cookies/clientin an RSC. - New route group / provider / top-level
src/folder ⇒ update the Project Structure tree inclient/CLAUDE.md.
Data fetching & caching (prevent extra fetches and re-renders)
- Fetch only through
clientFetch/serverFetch(@/lib/api); domain calls live insrc/services/{domain}/apis/. Never rawfetch(). - Server state is TanStack Query: a
keys.tsfactory per domain, deliberatestaleTime/gcTime, and cache invalidation on mutation (invalidateQueries/setQueryData) so you never refetch data you already hold. Prefer prefetch/initialDatafrom RSC where it removes a client round-trip. - One hook per file (
use{Action}.ts),useQuery/useMutation. Don't toast 401/403/5xx in hooks (the fetch layer already does) — only domain-specific 4xx messages. - Minimise re-renders: stable references (
useCallback/useMemoonly where it pays),selectto subscribe to slices, colocate state low, lift only when shared. Don't put fast-changing state in a high context provider.
UI composition
- Concrete MUI primitives stay MUI — use
Button,Avatar,Paper,TextField, etc. (or the existingApp*wrappers); never invent a new root-level Button/Avatar. - Composite/shareable components (built from primitives, reused in >1 place — a nurse card, an
OTP input, a price-breakdown, a step header) live at the right shared level (
src/components/…), not inline in a page or buried in a leaf. A component imported from >1 place gets a co-located*.test.tsx. - Page-only, never-reused composition can stay in the page.
i18n, theme, direction
- Every user-visible string is a key in both
messages/en.jsonandmessages/fa.json(in sync).fais default and RTL — design RTL-first; verify mirroring. - Colours come from
tokens.css(var(--bal-…)/ brand tokens), never hardcoded insx. Use the pre-builtAPP_THEME_LTR/RTL; nevercreateTheme()in a component. - MUI v9 API only (
sx={{ mb: 4 }}, no v5/v6-only props).
Quality
- Magic strings → named constants (
src/constants/or a colocatedconstants.ts). - Cookies/app state only through the cookie manager; never
document.cookie/localStoragefor auth. - No dead code (unused vars/imports are lint errors). Comment the why, not the what.
npm run checkgreen;npm run test:cigreen when a shared component changed.- Types come from the published contract in
dev/contracts/— don't guess server shapes; if a shape is missing, append a request todev/shared-working-context/frontend/requests/for-backend.mdand mock behind theservices/{domain}seam meanwhile.