ReactJS Project Coding Standards (v1.0)

{“4c28597f-7ad3-4046-98ce-bd206fbce579”:{“id”:”4c28597f-7ad3-4046-98ce-bd206fbce579″,”type”:”Paragraph”,”value”:[{“id”:”368143d5-4e99-447a-ac6a-00de7f964ab0″,”type”:”paragraph”,”children”:[{“text”:”Opinionated, production‑ready conventions for modern React 18 apps. Designed for Vite/TypeScript + ESLint/Prettier + Testing Library/Playwright. Adapt to your stack as needed.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:0}},”a32c8947-759f-4bb5-8187-9ba4bd878955″:{“id”:”a32c8947-759f-4bb5-8187-9ba4bd878955″,”type”:”Paragraph”,”value”:[{“id”:”ecbd9760-dd4c-4c06-8601-79ee4ccc0184″,”type”:”paragraph”,”children”:[{“text”:” “}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:1}},”972f33ae-d2e1-4f96-9e14-5d2c5e651d44″:{“id”:”972f33ae-d2e1-4f96-9e14-5d2c5e651d44″,”type”:”Paragraph”,”value”:[{“id”:”118979df-8c8c-407b-ac5c-1e542563c1a2″,”type”:”paragraph”,”children”:[{“text”:”Baseline”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:2}},”0ef212bd-83c8-4df0-b087-e1b3ef9b2737″:{“id”:”0ef212bd-83c8-4df0-b087-e1b3ef9b2737″,”type”:”BulletedList”,”value”:[{“id”:”63d811ce-b9ea-4016-934c-29e624ad6071″,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”Runtime”},{“text”:”: React 18, Node ≥ 18 LTS.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:3}},”1d7b8a39-730f-4896-978e-44fe3e3c336e”:{“id”:”1d7b8a39-730f-4896-978e-44fe3e3c336e”,”type”:”BulletedList”,”value”:[{“id”:”5769e7d9-a406-474c-a7f5-beffa71a8053″,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”Bundler”},{“text”:”: Vite (preferred) or Next.js App Router (note where Next.js differs).”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:4}},”70a878f7-855c-4859-8628-758f895483b6″:{“id”:”70a878f7-855c-4859-8628-758f895483b6″,”type”:”BulletedList”,”value”:[{“id”:”8d74e3c2-fedb-4b84-9692-f5ffcb5ff349″,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”Language”},{“text”:”: “},{“bold”:true,”text”:”TypeScript”},{“text”:” first.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:5}},”82ac8391-e8a2-48a9-b0cf-c1426b8a3504″:{“id”:”82ac8391-e8a2-48a9-b0cf-c1426b8a3504″,”type”:”BulletedList”,”value”:[{“id”:”5a9ca618-ad4b-4014-a863-e40c57595148″,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”State”},{“text”:”: Local state with hooks; global via “},{“bold”:true,”text”:”Zustand”},{“text”:” or “},{“bold”:true,”text”:”Redux Toolkit”},{“text”:” when justified.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:6}},”a5dd808c-75bf-4c86-b238-be001bff2cf3″:{“id”:”a5dd808c-75bf-4c86-b238-be001bff2cf3″,”type”:”BulletedList”,”value”:[{“id”:”08590385-b20d-4ba7-a275-d02ab57f84fc”,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”Routing”},{“text”:”: React Router v6+ (or Next.js routing if on Next).”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:7}},”06c4d552-2139-4319-8a8c-29195ceb62f1″:{“id”:”06c4d552-2139-4319-8a8c-29195ceb62f1″,”type”:”BulletedList”,”value”:[{“id”:”46aeab1c-29b7-42cc-89b6-c31cbf1dbc56″,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”Styling”},{“text”:”: Tailwind CSS + CSS Modules (or CSS-in-JS if legacy). No global CSS except resets and design tokens.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:8}},”3af684bd-6c74-4153-89d5-1522584f9594″:{“id”:”3af684bd-6c74-4153-89d5-1522584f9594″,”type”:”BulletedList”,”value”:[{“id”:”564e4d4c-bdea-474b-9785-b5e2d5a4c197″,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”HTTP”},{“text”:”: “},{“text”:”fetch”},{“text”:” with a tiny wrapper (retry, timeout) or “},{“bold”:true,”text”:”TanStack Query”},{“text”:” for server state.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:9}},”d0c379ba-1f30-4186-ad81-3a1c4cb1e0d3″:{“id”:”d0c379ba-1f30-4186-ad81-3a1c4cb1e0d3″,”type”:”BulletedList”,”value”:[{“id”:”6591f5fb-dbb4-48e4-b1f1-bdb94dc4eb31″,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”Tests”},{“text”:”: Unit+component with Vitest + Testing Library; e2e with Playwright.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:10}},”1d27bb35-f5f3-4b49-9251-14fcf4ba367b”:{“id”:”1d27bb35-f5f3-4b49-9251-14fcf4ba367b”,”type”:”BulletedList”,”value”:[{“id”:”5f00f513-2914-47e7-be23-5c88d7517dd6″,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”Formatting”},{“text”:”: Prettier; “},{“bold”:true,”text”:”ESLint”},{“text”:” for rules.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:11}},”91ecef00-3916-4437-9066-83f8a078b24a”:{“id”:”91ecef00-3916-4437-9066-83f8a078b24a”,”type”:”BulletedList”,”value”:[{“id”:”2d441c3a-d140-4ee2-9bf3-1721ce77d390″,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”Commits”},{“text”:”: Conventional Commits + PR templates.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:12}},”7268a5d3-ea04-4c90-916b-3ad741607fdd”:{“id”:”7268a5d3-ea04-4c90-916b-3ad741607fdd”,”type”:”Paragraph”,”value”:[{“id”:”3b540c11-506c-483c-b48d-3161fed6e3e4″,”type”:”paragraph”,”children”:[{“text”:” “}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:13}},”669699a2-b259-46c6-840c-446802b6b231″:{“id”:”669699a2-b259-46c6-840c-446802b6b231″,”type”:”Paragraph”,”value”:[{“id”:”981a18bb-ff9b-40bd-8f18-cf58e239e961″,”type”:”paragraph”,”children”:[{“text”:”1) Project Structure”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:14}},”d3bfec94-c175-4ead-a7a6-d808eaeb4e54″:{“id”:”d3bfec94-c175-4ead-a7a6-d808eaeb4e54″,”type”:”Paragraph”,”value”:[{“id”:”a91eb3fc-41dc-4730-9592-c897e41f58e9″,”type”:”paragraph”,”children”:[{“text”:”src/”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”app/ “},{“text”:”                “},{“text”:”# app entry, providers, router”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”components/”},{“text”:”          “},{“text”:”# reusable presentational components”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”features/”},{“text”:”            “},{“text”:”# vertical slices (auth/, todos/, billing/ …)”},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”/”},{“text”:”\n”},{“text”:” “},{“text”:”      “},{“text”:”api/ “},{“text”:”            “},{“text”:”# query/mutations for this feature”},{“text”:”\n”},{“text”:” “},{“text”:”      “},{“text”:”components/”},{“text”:”      “},{“text”:”# feature-specific UI”},{“text”:”\n”},{“text”:” “},{“text”:”      “},{“text”:”hooks/ “},{“text”:”          “},{“text”:”# custom hooks”},{“text”:”\n”},{“text”:” “},{“text”:”      “},{“text”:”store/ “},{“text”:”          “},{“text”:”# feature state (zustand/rtk)”},{“text”:”\n”},{“text”:” “},{“text”:”      “},{“text”:”types/ “},{“text”:”          “},{“text”:”# feature TS types”},{“text”:”\n”},{“text”:” “},{“text”:”      “},{“text”:”utils/ “},{“text”:”          “},{“text”:”# feature helpers”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”pages/ “},{“text”:”              “},{“text”:”# route-level components (if not using Next)”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”hooks/ “},{“text”:”              “},{“text”:”# cross-cutting hooks”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”lib/ “},{“text”:”                “},{“text”:”# framework-agnostic libs (date, storage, logger)”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”styles/”},{“text”:”              “},{“text”:”# tailwind.css, tokens, globals”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”assets/”},{“text”:”              “},{“text”:”# images, fonts”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”test/”},{“text”:”                “},{“text”:”# test utils, mocks”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”index.tsx”},{“text”:”            “},{“text”:”# bootstrap”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:15}},”7696b660-4e0b-4019-a0e1-95a389cd6143″:{“id”:”7696b660-4e0b-4019-a0e1-95a389cd6143″,”type”:”Paragraph”,”value”:[{“id”:”90278a82-0ff3-4073-a475-f1199d01d361″,”type”:”paragraph”,”children”:[{“text”:”Rules”,”bold”:true},{“text”:” – One feature per folder; avoid massive “},{“text”:”components/”},{“text”:” bins. – Each folder exports an “},{“text”:”index.ts”,”bold”:true},{“text”:” barrel when it improves DX; avoid cyclic deps. – Relative imports limited to same feature; cross-feature imports use path aliases (e.g., “},{“text”:”@/lib/logger”},{“text”:”).”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:16}},”55192a46-a62a-4b98-91a3-47325176c3d8″:{“id”:”55192a46-a62a-4b98-91a3-47325176c3d8″,”type”:”Paragraph”,”value”:[{“id”:”fbcbeda5-591f-48ea-8e26-074952512b9b”,”type”:”paragraph”,”children”:[{“text”:” “}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:17}},”646db9b2-a31f-496c-9ef4-eadb6512d36c”:{“id”:”646db9b2-a31f-496c-9ef4-eadb6512d36c”,”type”:”Paragraph”,”value”:[{“id”:”86d8f37f-02dd-4f58-b66a-cf777af22b05″,”type”:”paragraph”,”children”:[{“text”:”2) Naming & Files”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:18}},”9954a702-a1c6-4995-bcc8-46c10d32e67d”:{“id”:”9954a702-a1c6-4995-bcc8-46c10d32e67d”,”type”:”BulletedList”,”value”:[{“id”:”ef2307e2-e0d9-4314-8389-38bea162a2ad”,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”Files”},{“text”:”kebab-case.tsx”},{“text”:” / “},{“text”:”kebab-case.ts”},{“text”:”.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:19}},”a61cdd54-1809-476a-bb0b-1be913c84fed”:{“id”:”a61cdd54-1809-476a-bb0b-1be913c84fed”,”type”:”BulletedList”,”value”:[{“id”:”12471c86-f2a1-4621-8669-4a534ab2449d”,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”Components”},{“text”:”: “},{“text”:”PascalCase”},{“text”:” for component names; one component per file unless small helper components.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:20}},”bc0cd4ab-b887-4080-9f7a-a04e7d000945″:{“id”:”bc0cd4ab-b887-4080-9f7a-a04e7d000945″,”type”:”BulletedList”,”value”:[{“id”:”c5d97945-fabf-48cd-a9e7-52507c8c201c”,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”Hooks”},{“text”:”: “},{“text”:”useXxx.ts”},{“text”:” starting with “},{“text”:”use”},{“text”:”.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:21}},”41076a49-5b47-494e-b475-4c47f82ebd0d”:{“id”:”41076a49-5b47-494e-b475-4c47f82ebd0d”,”type”:”BulletedList”,”value”:[{“id”:”e71d7a29-ba3a-462f-b0ae-5629cb95b817″,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”Types”},{“text”:”: “},{“text”:”Xxx”},{“text”:”, interfaces over types for object shapes that are extended; no “},{“text”:”I”},{“text”:” prefix.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:22}},”9090993b-27d2-432b-a468-25073616369d”:{“id”:”9090993b-27d2-432b-a468-25073616369d”,”type”:”BulletedList”,”value”:[{“id”:”05ccedb4-f7f4-4cba-af87-41fb21d251da”,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”Tests”},{“text”:”: “},{“text”:”*.test.ts”},{“text”:” or “},{“text”:”*.test.tsx”},{“text”:” colocated with code or in “},{“text”:”__tests__”},{“text”:” next to it.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:23}},”abbbe807-4b7c-487d-abc8-0810de63429b”:{“id”:”abbbe807-4b7c-487d-abc8-0810de63429b”,”type”:”BulletedList”,”value”:[{“id”:”30e7ed31-334d-4862-af78-e080849b2208″,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”Styles”},{“text”:”: “},{“text”:”Component.module.css”},{“text”:” with locally-scoped classes.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:24}},”431130a4-d6ab-49d6-adfb-ff064761b35e”:{“id”:”431130a4-d6ab-49d6-adfb-ff064761b35e”,”type”:”BulletedList”,”value”:[{“id”:”771d0c47-2761-4c59-813c-a9a69caf175c”,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”Env files”},{“text”:”: “},{“text”:”.env”},{“text”:”, “},{“text”:”.env.development”},{“text”:”, “},{“text”:”.env.production”},{“text”:” – never commit secrets.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:25}},”a2d0641f-1414-449e-ad6e-47c3f51bc5a9″:{“id”:”a2d0641f-1414-449e-ad6e-47c3f51bc5a9″,”type”:”Paragraph”,”value”:[{“id”:”51775743-60ed-48de-a79d-b7d7dbff583c”,”type”:”paragraph”,”children”:[{“text”:” “}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:26}},”8dfc2678-4800-4fed-92fc-7bdd38e2a726″:{“id”:”8dfc2678-4800-4fed-92fc-7bdd38e2a726″,”type”:”Paragraph”,”value”:[{“id”:”a95373dc-4c80-4497-9bfb-e97249aa8cfb”,”type”:”paragraph”,”children”:[{“text”:”3) TypeScript Rules”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:27}},”161c35e3-8133-488d-b0a8-405ba86e6e27″:{“id”:”161c35e3-8133-488d-b0a8-405ba86e6e27″,”type”:”BulletedList”,”value”:[{“id”:”a95b408b-2856-4b59-bdec-95cfafa84eb9″,”type”:”bulleted-list”,”children”:[{“text”:”strict: true”},{“text”:” in “},{“text”:”tsconfig.json”},{“text”:”.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:28}},”82b42d07-1ee8-45ff-a907-b6dfb5d154df”:{“id”:”82b42d07-1ee8-45ff-a907-b6dfb5d154df”,”type”:”BulletedList”,”value”:[{“id”:”3ff66359-7286-4217-82b3-a390bfa383bb”,”type”:”bulleted-list”,”children”:[{“text”:”Avoid “},{“text”:”any”},{“text”:”. Prefer “},{“text”:”unknown”},{“text”:” or generics.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:29}},”759f9a11-a6dc-4323-8274-2f5c032e406e”:{“id”:”759f9a11-a6dc-4323-8274-2f5c032e406e”,”type”:”BulletedList”,”value”:[{“id”:”b39edd1b-db98-44d2-b365-0feba2f79c44″,”type”:”bulleted-list”,”children”:[{“text”:”Use “},{“bold”:true,”text”:”discriminated unions”},{“text”:” for state machines; avoid boolean flags explosion.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:30}},”5139869a-69d8-4684-ae30-6c461d882a61″:{“id”:”5139869a-69d8-4684-ae30-6c461d882a61″,”type”:”BulletedList”,”value”:[{“id”:”7693a328-be3f-4f14-a670-2ac7bbc55694″,”type”:”bulleted-list”,”children”:[{“text”:”Component props are “},{“text”:”type Props = { … }”},{“text”:” and exported.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:31}},”d29beeee-b1c9-419f-ab84-1918177148ad”:{“id”:”d29beeee-b1c9-419f-ab84-1918177148ad”,”type”:”BulletedList”,”value”:[{“id”:”6d34f520-b88a-44ab-a8ba-5cbdffc52a4b”,”type”:”bulleted-list”,”children”:[{“text”:”No default exports for components; named exports only (simplifies refactors).”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:32}},”190c836d-82d0-41ca-8f5e-9a80251f68c2″:{“id”:”190c836d-82d0-41ca-8f5e-9a80251f68c2″,”type”:”BulletedList”,”value”:[{“id”:”5347adfe-6052-4230-b186-d6c2ac1d6756″,”type”:”bulleted-list”,”children”:[{“text”:”Narrow types at boundaries (API, storage) and parse with “},{“bold”:true,”text”:”Zod”},{“text”:” (or valibot/yup).”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:33}},”027361ac-5bad-455d-9092-6af5cb969e0b”:{“id”:”027361ac-5bad-455d-9092-6af5cb969e0b”,”type”:”Paragraph”,”value”:[{“id”:”c549cc5c-c356-4cf1-b71f-caa2dd358467″,”type”:”paragraph”,”children”:[{“text”:”Example tsconfig (core excerpt)”,”bold”:true}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:34}},”f3ad30d5-1952-4973-aa16-f90137dabb2b”:{“id”:”f3ad30d5-1952-4973-aa16-f90137dabb2b”,”type”:”Paragraph”,”value”:[{“id”:”32516bc3-26e0-4cfc-8fd9-6b7b96ef23a0″,”type”:”paragraph”,”children”:[{“text”:”{“},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”\”compilerOptions\””},{“text”:”:”},{“text”:” “},{“text”:”{“},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”\”target\””},{“text”:”:”},{“text”:” “},{“text”:”\”ES2022\””},{“text”:”,”},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”\”lib\””},{“text”:”:”},{“text”:” “},{“text”:”[“},{“text”:”\”ES2022\””},{“text”:”,”},{“text”:” “},{“text”:”\”DOM\””},{“text”:”,”},{“text”:” “},{“text”:”\”DOM.Iterable\””},{“text”:”]”},{“text”:”,”},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”\”jsx\””},{“text”:”:”},{“text”:” “},{“text”:”\”react-jsx\””},{“text”:”,”},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”\”module\””},{“text”:”:”},{“text”:” “},{“text”:”\”ESNext\””},{“text”:”,”},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”\”moduleResolution\””},{“text”:”:”},{“text”:” “},{“text”:”\”Bundler\””},{“text”:”,”},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”\”strict\””},{“text”:”:”},{“text”:” “},{“text”:”true”,”bold”:true},{“text”:”,”},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”\”noUncheckedIndexedAccess\””},{“text”:”:”},{“text”:” “},{“text”:”true”,”bold”:true},{“text”:”,”},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”\”exactOptionalPropertyTypes\””},{“text”:”:”},{“text”:” “},{“text”:”true”,”bold”:true},{“text”:”,”},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”\”useUnknownInCatchVariables\””},{“text”:”:”},{“text”:” “},{“text”:”true”,”bold”:true},{“text”:”,”},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”\”baseUrl\””},{“text”:”:”},{“text”:” “},{“text”:”\”.\””},{“text”:”,”},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”\”paths\””},{“text”:”:”},{“text”:” “},{“text”:”{“},{“text”:” “},{“text”:”\”@/*\””},{“text”:”:”},{“text”:” “},{“text”:”[“},{“text”:”\”src/*\””},{“text”:”]”},{“text”:” “},{“text”:”}”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”}”},{“text”:”\n”},{“text”:” “},{“text”:”}”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:35}},”b4270b75-414a-431e-9a90-43c7d0b16e1a”:{“id”:”b4270b75-414a-431e-9a90-43c7d0b16e1a”,”type”:”Paragraph”,”value”:[{“id”:”007a6bbd-e25a-4cb4-87cd-8a913ea7c9c4″,”type”:”paragraph”,”children”:[{“text”:” “}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:36}},”a9fa731f-b9e6-4ec6-b28d-abf5c29765fa”:{“id”:”a9fa731f-b9e6-4ec6-b28d-abf5c29765fa”,”type”:”Paragraph”,”value”:[{“id”:”8af55da0-71e0-476c-8a25-ddcf7c8c00e1″,”type”:”paragraph”,”children”:[{“text”:”4) React Components”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:37}},”ab1d0d6d-6b03-4e9a-8cb0-1f070162efd6″:{“id”:”ab1d0d6d-6b03-4e9a-8cb0-1f070162efd6″,”type”:”BulletedList”,”value”:[{“id”:”10a8adab-5e73-446c-b95e-3b45a8401dbc”,”type”:”bulleted-list”,”children”:[{“text”:”Functional components with hooks; no class components.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:38}},”a2a44bd3-7902-431b-a87f-34d88b3d50ff”:{“id”:”a2a44bd3-7902-431b-a87f-34d88b3d50ff”,”type”:”BulletedList”,”value”:[{“id”:”ee263a4f-e63d-43e6-a229-e31e7cf6822c”,”type”:”bulleted-list”,”children”:[{“text”:”Keep components “},{“bold”:true,”text”:”pure”},{“text”:”; side effects inside hooks.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:39}},”4eb61f85-0e34-44ef-ad26-bca5664e1caf”:{“id”:”4eb61f85-0e34-44ef-ad26-bca5664e1caf”,”type”:”BulletedList”,”value”:[{“id”:”833490f3-b642-492d-a023-7e6520d74ba2″,”type”:”bulleted-list”,”children”:[{“text”:”Prefer “},{“bold”:true,”text”:”composition”},{“text”:” over props explosion. Use “},{“text”:”children”},{“text”:” and slot-like props.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:40}},”a1f03371-90ed-4eaa-95e9-d1a804d10c7f”:{“id”:”a1f03371-90ed-4eaa-95e9-d1a804d10c7f”,”type”:”BulletedList”,”value”:[{“id”:”38094d9d-0ce7-4747-9a14-932c48e84aed”,”type”:”bulleted-list”,”children”:[{“text”:”Props surface: minimize optional props; provide sensible defaults.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:41}},”c9cf383d-a7be-4bd0-aaf8-7b29ce33bbda”:{“id”:”c9cf383d-a7be-4bd0-aaf8-7b29ce33bbda”,”type”:”BulletedList”,”value”:[{“id”:”99fe0df7-71f3-4387-8f62-13b39658c099″,”type”:”bulleted-list”,”children”:[{“text”:”Avoid “},{“text”:”React.FC”},{“text”:” type (unnecessary). Type children explicitly when needed.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:42}},”b9b0d21f-f16f-483f-b116-f3b4df5eb95a”:{“id”:”b9b0d21f-f16f-483f-b116-f3b4df5eb95a”,”type”:”BulletedList”,”value”:[{“id”:”7919fc04-8d4e-4f32-b7c5-4cacf0aaedb3″,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”Memoization”},{“text”:”: Only when profiling shows benefit; otherwise avoid premature “},{“text”:”memo”},{“text”:”, “},{“text”:”useCallback”},{“text”:”, “},{“text”:”useMemo”},{“text”:”.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:43}},”53c3dda7-a4e4-4a86-86f7-447973d491f8″:{“id”:”53c3dda7-a4e4-4a86-86f7-447973d491f8″,”type”:”BulletedList”,”value”:[{“id”:”029dadc6-88db-49bd-a3d9-f976f769443b”,”type”:”bulleted-list”,”children”:[{“text”:”Use “},{“bold”:true,”text”:”Error Boundaries”},{“text”:” at route/feature boundaries.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:44}},”6c91c029-5ab0-4b0e-a9f4-6d0c7a349954″:{“id”:”6c91c029-5ab0-4b0e-a9f4-6d0c7a349954″,”type”:”Paragraph”,”value”:[{“id”:”2cd1cef3-8468-497b-b09c-e48631d3d681″,”type”:”paragraph”,”children”:[{“text”:”Component Template”,”bold”:true}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:45}},”44a722e9-1d14-46d8-a87f-8c573fae608f”:{“id”:”44a722e9-1d14-46d8-a87f-8c573fae608f”,”type”:”Paragraph”,”value”:[{“id”:”e1bf0118-a13c-4eea-afb2-9802dcd2ee6b”,”type”:”paragraph”,”children”:[{“text”:”export type ButtonProps = {“},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”onClick?: () => void;”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”disabled?: boolean;”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”size?: \”sm\” | \”md\” | \”lg\”;”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”children: React.ReactNode;”},{“text”:”\n”},{“text”:” “},{“text”:”};”},{“text”:”\n”},{“text”:” “},{“text”:”\n”},{“text”:” “},{“text”:”export function Button({ onClick, disabled = false, size = \”md\”, children }: ButtonProps) {“},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”return (“},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”“},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”);”},{“text”:”\n”},{“text”:” “},{“text”:”}”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:46}},”3b8f2d5e-da68-451c-b65c-33b95a1eb603″:{“id”:”3b8f2d5e-da68-451c-b65c-33b95a1eb603″,”type”:”Paragraph”,”value”:[{“id”:”a2935066-5dcb-4a78-9cca-f452e905d1fa”,”type”:”paragraph”,”children”:[{“text”:” “}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:47}},”7285e969-373c-46fc-b5c6-14257d6de67b”:{“id”:”7285e969-373c-46fc-b5c6-14257d6de67b”,”type”:”Paragraph”,”value”:[{“id”:”a3134764-8a85-4882-9365-0e89df99b1b0″,”type”:”paragraph”,”children”:[{“text”:”5) Hooks”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:48}},”6ccf2d13-105c-477a-a50f-55e7cdc45654″:{“id”:”6ccf2d13-105c-477a-a50f-55e7cdc45654″,”type”:”BulletedList”,”value”:[{“id”:”8fd152c6-3029-42c3-82e9-0e70e6fb778e”,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”Custom hooks”},{“text”:” encapsulate reusable logic; names start with “},{“text”:”use”},{“text”:”.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:49}},”2113bc9c-0006-4297-b5c5-3ae6097344b4″:{“id”:”2113bc9c-0006-4297-b5c5-3ae6097344b4″,”type”:”BulletedList”,”value”:[{“id”:”1ce9069b-2836-4a47-b117-60a48a324411″,”type”:”bulleted-list”,”children”:[{“text”:”Side-effects go in “},{“text”:”useEffect”},{“text”:” with accurate dependency arrays; “},{“bold”:true,”text”:”no”},{“text”:” exhaustive-deps disabling except with justification.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:50}},”e0711cfe-e690-4986-b016-0b0c53710757″:{“id”:”e0711cfe-e690-4986-b016-0b0c53710757″,”type”:”BulletedList”,”value”:[{“id”:”7e22c17c-5779-4719-a73b-1eb6662481b8″,”type”:”bulleted-list”,”children”:[{“text”:”Create “},{“text”:”useMounted”},{“text”:”, “},{“text”:”useEvent”},{“text”:”, “},{“text”:”useDebounce”},{“text”:” utilities as needed.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:51}},”d630e1b2-9627-4a06-b2cd-25103094ece2″:{“id”:”d630e1b2-9627-4a06-b2cd-25103094ece2″,”type”:”Paragraph”,”value”:[{“id”:”7ec4d11c-c6a5-403f-9466-8c354ac94f32″,”type”:”paragraph”,”children”:[{“text”:” “}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:52}},”2db8a5e3-844e-4501-b76b-83cbcaf819a2″:{“id”:”2db8a5e3-844e-4501-b76b-83cbcaf819a2″,”type”:”Paragraph”,”value”:[{“id”:”3d4874fc-c08d-4bb6-912f-09f01297b1d5″,”type”:”paragraph”,”children”:[{“text”:”6) State Management”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:53}},”5c892df3-2626-47a6-88f0-f4ea434aff1e”:{“id”:”5c892df3-2626-47a6-88f0-f4ea434aff1e”,”type”:”BulletedList”,”value”:[{“id”:”38faca83-d6bf-4a14-b95e-989783041f8e”,”type”:”bulleted-list”,”children”:[{“text”:”Prefer “},{“bold”:true,”text”:”component state”},{“text”:” and “},{“bold”:true,”text”:”context”},{“text”:” for local/shared UI state.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:54}},”3f373ac0-6377-42cd-9be3-afeabe8846b0″:{“id”:”3f373ac0-6377-42cd-9be3-afeabe8846b0″,”type”:”BulletedList”,”value”:[{“id”:”399f0078-6474-4b19-9a2b-64e9ba99f322″,”type”:”bulleted-list”,”children”:[{“text”:”Use “},{“bold”:true,”text”:”TanStack Query”},{“text”:” for server cache (loading, error, caching, retries) – “},{“bold”:true,”text”:”do not”},{“text”:” put server cache into Redux/Zustand.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:55}},”c3b1fd45-b807-4fdf-96f5-ee056fa32d3e”:{“id”:”c3b1fd45-b807-4fdf-96f5-ee056fa32d3e”,”type”:”BulletedList”,”value”:[{“id”:”30bef311-4624-45cc-b1e4-74c3d842098f”,”type”:”bulleted-list”,”children”:[{“text”:”Use “},{“bold”:true,”text”:”Zustand/Redux Toolkit”},{“text”:” for client business state that multiple features need.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:56}},”68cc30df-2ef3-464e-868c-bd9fe337f1ff”:{“id”:”68cc30df-2ef3-464e-868c-bd9fe337f1ff”,”type”:”Paragraph”,”value”:[{“id”:”484300ae-39f9-4ee3-8c1e-64ae625bfd29″,”type”:”paragraph”,”children”:[{“text”:” “}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:57}},”475ad3fa-44fe-417f-bc41-6267c48a1c6a”:{“id”:”475ad3fa-44fe-417f-bc41-6267c48a1c6a”,”type”:”Paragraph”,”value”:[{“id”:”0baaaca4-b06c-499f-af08-5d58ac151b83″,”type”:”paragraph”,”children”:[{“text”:”7) Styling & Design System”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:58}},”af0e5891-474d-4761-a53f-f04b8cfc0bf3″:{“id”:”af0e5891-474d-4761-a53f-f04b8cfc0bf3″,”type”:”BulletedList”,”value”:[{“id”:”7b545140-bac8-4fd1-a830-c104fe4d0ac8″,”type”:”bulleted-list”,”children”:[{“text”:”Tailwind for spacing/typography/colors; extract repeated patterns as components.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:59}},”b391c6d1-cb2c-495e-9e74-52d41bd776e7″:{“id”:”b391c6d1-cb2c-495e-9e74-52d41bd776e7″,”type”:”BulletedList”,”value”:[{“id”:”9bcebe8b-7b0e-4449-bb09-68b7007bf581″,”type”:”bulleted-list”,”children”:[{“text”:”Create a minimal “},{“bold”:true,”text”:”design tokens”},{“text”:” file (colors, radii, shadows) and reference via Tailwind config.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:60}},”2c95ad2c-ab23-4286-92e9-8c48dfe8c101″:{“id”:”2c95ad2c-ab23-4286-92e9-8c48dfe8c101″,”type”:”BulletedList”,”value”:[{“id”:”972c4766-9384-4e48-bc5a-a25d00df167f”,”type”:”bulleted-list”,”children”:[{“text”:”Prefer “},{“bold”:true,”text”:”class-variance-authority”},{“text”:” or simple utilities for variant styles over long conditional chains.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:61}},”70c5b31c-ded9-484c-abf1-1c4f49400e06″:{“id”:”70c5b31c-ded9-484c-abf1-1c4f49400e06″,”type”:”BulletedList”,”value”:[{“id”:”3eb6a027-ba57-44be-96e5-cde8e51917ed”,”type”:”bulleted-list”,”children”:[{“text”:”Avoid deep nesting; keep DOM accessible.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:62}},”9f776af1-ff07-4079-9f2f-ee1877cd0862″:{“id”:”9f776af1-ff07-4079-9f2f-ee1877cd0862″,”type”:”Paragraph”,”value”:[{“id”:”0a2bc253-68ff-4311-ac44-4a658003e898″,”type”:”paragraph”,”children”:[{“text”:”Tailwind Class Ordering”,”bold”:true},{“text”:”: Use “},{“text”:”eslint-plugin-tailwindcss”},{“text”:” for consistency.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:63}},”a312c2bb-6067-45e4-ad3a-b8192cff78fc”:{“id”:”a312c2bb-6067-45e4-ad3a-b8192cff78fc”,”type”:”Paragraph”,”value”:[{“id”:”d3f4b4f9-635f-425b-b714-86dccc5bdff6″,”type”:”paragraph”,”children”:[{“text”:” “}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:64}},”c5b52afe-5502-4fd5-8a1c-497ffd7b7041″:{“id”:”c5b52afe-5502-4fd5-8a1c-497ffd7b7041″,”type”:”Paragraph”,”value”:[{“id”:”7e98c544-77bc-4a55-9edf-a6d9804a87a4″,”type”:”paragraph”,”children”:[{“text”:”8) Accessibility (a11y)”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:65}},”7cd12cc5-7b23-40dd-a1d0-a9f2b13ade54″:{“id”:”7cd12cc5-7b23-40dd-a1d0-a9f2b13ade54″,”type”:”BulletedList”,”value”:[{“id”:”e92b9d9e-3108-40ee-b459-440459e82d6a”,”type”:”bulleted-list”,”children”:[{“text”:”All interactive elements are real elements: “},{“text”:”);”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”await userEvent.click(screen.getByRole(‘button’, { name: ‘Go’ }));”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”expect(onClick).toHaveBeenCalled();”},{“text”:”\n”},{“text”:” “},{“text”:”});”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:103}},”e0e76653-78c4-4ad9-ad02-7f413413aba4″:{“id”:”e0e76653-78c4-4ad9-ad02-7f413413aba4″,”type”:”Paragraph”,”value”:[{“id”:”fbc39e38-0399-46cd-963b-85aad4838136″,”type”:”paragraph”,”children”:[{“text”:” “}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:104}},”42d50f84-d4c0-49d2-95da-a8512eb5f6a4″:{“id”:”42d50f84-d4c0-49d2-95da-a8512eb5f6a4″,”type”:”Paragraph”,”value”:[{“id”:”af97bae1-2b6f-4dbb-b016-0de09fe2550f”,”type”:”paragraph”,”children”:[{“text”:”14) Git, Commits & PRs”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:105}},”a9843ea7-00d9-4de1-af22-3c5813c0d2a9″:{“id”:”a9843ea7-00d9-4de1-af22-3c5813c0d2a9″,”type”:”BulletedList”,”value”:[{“id”:”8042b9d7-06d0-4b5c-82ea-25b1432fbe59″,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”Branch naming”},{“text”:”feat/-“},{“text”:”, “},{“text”:”fix/”},{“text”:”, “},{“text”:”chore/”},{“text”:”, “},{“text”:”docs/”},{“text”:”.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:106}},”553d82ca-4c77-4958-9a36-05a8f25cfbbf”:{“id”:”553d82ca-4c77-4958-9a36-05a8f25cfbbf”,”type”:”BulletedList”,”value”:[{“id”:”da4ec598-1134-49e4-ada2-a203d7ee99ad”,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”Conventional Commits”},{“text”:”feat: add payment retry”},{“text”:”, “},{“text”:”fix(auth): handle 401″},{“text”:”.”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:107}},”33ab3ddb-0d27-421b-86f6-5156bc01c887″:{“id”:”33ab3ddb-0d27-421b-86f6-5156bc01c887″,”type”:”BulletedList”,”value”:[{“id”:”b477a6b9-05fa-4ba3-ab14-29894248eacc”,”type”:”bulleted-list”,”children”:[{“bold”:true,”text”:”PR size”},{“text”:”: < 400 LOC preferred; keep focused."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":108}},"75caf0ea-005b-40a8-bd75-6c5105c351ab":{"id":"75caf0ea-005b-40a8-bd75-6c5105c351ab","type":"BulletedList","value":[{"id":"760ec3c5-8fd0-43b3-8f5e-2f193613e21d","type":"bulleted-list","children":[{"text":"PR must include: scope, screenshots (UI), test plan, risk & rollback."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":109}},"dd459f99-eede-49ae-8d13-a94b2fd3de16":{"id":"dd459f99-eede-49ae-8d13-a94b2fd3de16","type":"Paragraph","value":[{"id":"4fd231df-1828-46f8-a1fa-7d2f3b466d6a","type":"paragraph","children":[{"text":"PR Template","bold":true}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":110}},"911614b8-3bb5-4d94-9f6f-4d69ebd355fe":{"id":"911614b8-3bb5-4d94-9f6f-4d69ebd355fe","type":"Paragraph","value":[{"id":"ae1f2055-e85a-463e-83f3-c5455b26040f","type":"paragraph","children":[{"text":"## What & Why"},{"text":"\n"},{"text":" "},{"text":"\n"},{"text":" "},{"text":"## Screenshots / Videos"},{"text":"\n"},{"text":" "},{"text":"\n"},{"text":" "},{"text":"## Test Plan"},{"text":"\n"},{"text":" "},{"text":"- [ ] Unit tests pass"},{"text":"\n"},{"text":" "},{"text":"- [ ] E2E scenario X"},{"text":"\n"},{"text":" "},{"text":"\n"},{"text":" "},{"text":"## Risk & Rollback"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":111}},"9030f3a4-0ee9-4f42-afe4-9e6ecfa7e3b1":{"id":"9030f3a4-0ee9-4f42-afe4-9e6ecfa7e3b1","type":"Paragraph","value":[{"id":"00dc81d1-f4f3-4144-b452-955b5b39b34a","type":"paragraph","children":[{"text":" "}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":112}},"19cdb0df-375a-44d3-9ee5-e515ab7e6099":{"id":"19cdb0df-375a-44d3-9ee5-e515ab7e6099","type":"Paragraph","value":[{"id":"e0cff654-9e2b-4149-b191-44a98d760b3d","type":"paragraph","children":[{"text":"15) Linting & Formatting"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":113}},"57ea6b5c-4678-4b1b-b8cc-ff3b445f2b53":{"id":"57ea6b5c-4678-4b1b-b8cc-ff3b445f2b53","type":"Paragraph","value":[{"id":"870d2d65-3b27-4e03-9ed4-a4711b321a3f","type":"paragraph","children":[{"text":".eslintrc.cjs","bold":true},{"text":" (excerpt)"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":114}},"c5abb437-4b5f-4656-bc3d-acf7863a6c17":{"id":"c5abb437-4b5f-4656-bc3d-acf7863a6c17","type":"Paragraph","value":[{"id":"0acf23ad-208e-4455-8723-b8055783f191","type":"paragraph","children":[{"text":"module"},{"text":"."},{"text":"exports"},{"text":" "},{"text":"="},{"text":" {"},{"text":"\n"},{"text":" "},{"text":"  "},{"text":"root"},{"text":":"},{"text":" "},{"text":"true","bold":true},{"text":","},{"text":"\n"},{"text":" "},{"text":"  "},{"text":"parser"},{"text":":"},{"text":" "},{"text":"'@typescript-eslint/parser'"},{"text":","},{"text":"\n"},{"text":" "},{"text":"  "},{"text":"plugins"},{"text":":"},{"text":" ["},{"text":"'@typescript-eslint'"},{"text":","},{"text":" "},{"text":"'react'"},{"text":","},{"text":" "},{"text":"'react-hooks'"},{"text":","},{"text":" "},{"text":"'jsx-a11y'"},{"text":","},{"text":" "},{"text":"'import'"},{"text":","},{"text":" "},{"text":"'tailwindcss'"},{"text":"]"},{"text":","},{"text":"\n"},{"text":" "},{"text":"  "},{"text":"extends"},{"text":":"},{"text":" ["},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"'eslint:recommended'"},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"'plugin:@typescript-eslint/recommended'"},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"'plugin:react/recommended'"},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"'plugin:react-hooks/recommended'"},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"'plugin:jsx-a11y/recommended'"},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"'plugin:import/recommended'"},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"'plugin:import/typescript'"},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"'plugin:tailwindcss/recommended'"},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"'prettier'"},{"text":"\n"},{"text":" "},{"text":"  "},{"text":"]"},{"text":","},{"text":"\n"},{"text":" "},{"text":"  "},{"text":"settings"},{"text":":"},{"text":" { "},{"text":"react"},{"text":":"},{"text":" { "},{"text":"version"},{"text":":"},{"text":" "},{"text":"'detect'"},{"text":" }"},{"text":","},{"text":" "},{"text":"'import/resolver'"},{"text":":"},{"text":" { "},{"text":"typescript"},{"text":":"},{"text":" "},{"text":"true","bold":true},{"text":" } }"},{"text":","},{"text":"\n"},{"text":" "},{"text":"  "},{"text":"rules"},{"text":":"},{"text":" {"},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"'react/react-in-jsx-scope'"},{"text":":"},{"text":" "},{"text":"'off'"},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"'react/prop-types'"},{"text":":"},{"text":" "},{"text":"'off'"},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"'import/order'"},{"text":":"},{"text":" ["},{"text":"\n"},{"text":" "},{"text":"      "},{"text":"'error'"},{"text":","},{"text":"\n"},{"text":" "},{"text":"      "},{"text":"{"},{"text":"\n"},{"text":" "},{"text":"        "},{"text":"groups"},{"text":":"},{"text":" [["},{"text":"'builtin'"},{"text":","},{"text":" "},{"text":"'external'"},{"text":"]"},{"text":","},{"text":" ["},{"text":"'internal'"},{"text":"]"},{"text":","},{"text":" ["},{"text":"'parent'"},{"text":","},{"text":" "},{"text":"'sibling'"},{"text":","},{"text":" "},{"text":"'index'"},{"text":"]]"},{"text":","},{"text":"\n"},{"text":" "},{"text":"        "},{"text":"'newlines-between'"},{"text":":"},{"text":" "},{"text":"'always'"},{"text":","},{"text":"\n"},{"text":" "},{"text":"        "},{"text":"alphabetize"},{"text":":"},{"text":" { "},{"text":"order"},{"text":":"},{"text":" "},{"text":"'asc'"},{"text":","},{"text":" "},{"text":"caseInsensitive"},{"text":":"},{"text":" "},{"text":"true","bold":true},{"text":" }"},{"text":"\n"},{"text":" "},{"text":"      "},{"text":"}"},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"]"},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"'@typescript-eslint/explicit-module-boundary-types'"},{"text":":"},{"text":" "},{"text":"'off'"},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"'tailwindcss/classnames-order'"},{"text":":"},{"text":" "},{"text":"'warn'"},{"text":"\n"},{"text":" "},{"text":"  "},{"text":"}"},{"text":"\n"},{"text":" "},{"text":"}"},{"text":";"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":115}},"9acb6efe-8c41-451e-bfce-7f9a854937da":{"id":"9acb6efe-8c41-451e-bfce-7f9a854937da","type":"Paragraph","value":[{"id":"f81ff7ab-917f-45f0-982b-5cb89f4a04f2","type":"paragraph","children":[{"text":".prettierrc","bold":true}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":116}},"c2d4d56f-1d4c-4cc1-80bc-208826a8b87e":{"id":"c2d4d56f-1d4c-4cc1-80bc-208826a8b87e","type":"Paragraph","value":[{"id":"3b356d65-af9c-4dfa-b3e1-91b010b721e1","type":"paragraph","children":[{"text":"{"},{"text":"\n"},{"text":" "},{"text":"  "},{"text":"\"singleQuote\""},{"text":":"},{"text":" "},{"text":"true","bold":true},{"text":","},{"text":"\n"},{"text":" "},{"text":"  "},{"text":"\"semi\""},{"text":":"},{"text":" "},{"text":"true","bold":true},{"text":","},{"text":"\n"},{"text":" "},{"text":"  "},{"text":"\"trailingComma\""},{"text":":"},{"text":" "},{"text":"\"all\""},{"text":","},{"text":"\n"},{"text":" "},{"text":"  "},{"text":"\"printWidth\""},{"text":":"},{"text":" "},{"text":"100"},{"text":","},{"text":"\n"},{"text":" "},{"text":"  "},{"text":"\"tabWidth\""},{"text":":"},{"text":" "},{"text":"2"},{"text":"\n"},{"text":" "},{"text":"}"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":117}},"00ac6df2-9252-4ad7-808e-56dac09f7323":{"id":"00ac6df2-9252-4ad7-808e-56dac09f7323","type":"Paragraph","value":[{"id":"2a9b09f7-1ad5-423d-8ecd-7ca60e7fdd04","type":"paragraph","children":[{"text":".editorconfig","bold":true}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":118}},"789aa001-052a-4ccd-9dfc-0dde22ee3ab3":{"id":"789aa001-052a-4ccd-9dfc-0dde22ee3ab3","type":"Paragraph","value":[{"id":"914c2547-ab72-4230-ac54-6e4bbfaeafc3","type":"paragraph","children":[{"text":"root = true"},{"text":"\n"},{"text":" "},{"text":"[*]"},{"text":"\n"},{"text":" "},{"text":"end_of_line = lf"},{"text":"\n"},{"text":" "},{"text":"insert_final_newline = true"},{"text":"\n"},{"text":" "},{"text":"charset = utf-8"},{"text":"\n"},{"text":" "},{"text":"indent_style = space"},{"text":"\n"},{"text":" "},{"text":"indent_size = 2"},{"text":"\n"},{"text":" "},{"text":"trim_trailing_whitespace = true"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":119}},"71f935dd-ea8b-4c7b-a649-5423c7ae0424":{"id":"71f935dd-ea8b-4c7b-a649-5423c7ae0424","type":"Paragraph","value":[{"id":"87ab623b-54ec-4b58-a639-c3d1ae65075a","type":"paragraph","children":[{"text":" "}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":120}},"fce5e8e2-1989-4813-be3f-b87b81a0c463":{"id":"fce5e8e2-1989-4813-be3f-b87b81a0c463","type":"Paragraph","value":[{"id":"a4906941-2aae-4029-b794-7f08c04d6e5d","type":"paragraph","children":[{"text":"16) Environment & Configuration"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":121}},"a8879bbe-5cda-4cc4-876d-af2972ecbd14":{"id":"a8879bbe-5cda-4cc4-876d-af2972ecbd14","type":"BulletedList","value":[{"id":"82a9937b-d078-4e00-ac2c-3a391782011f","type":"bulleted-list","children":[{"text":"All runtime config via "},{"text":"import.meta.env"},{"text":" (Vite) with "},{"text":"VITE_"},{"text":" prefix."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":122}},"ac82e743-e35f-4529-be53-e391c69e1280":{"id":"ac82e743-e35f-4529-be53-e391c69e1280","type":"BulletedList","value":[{"id":"0ce52aa7-fe8c-4702-aa9b-2c67c3ac4660","type":"bulleted-list","children":[{"text":"Provide a "},{"text":"src/lib/config.ts"},{"text":" that reads envs once and freezes the object."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":123}},"674f026b-fe05-4a24-9db6-e25ed41646b6":{"id":"674f026b-fe05-4a24-9db6-e25ed41646b6","type":"BulletedList","value":[{"id":"9db09583-c1e2-4d0b-a27e-6ca06482a365","type":"bulleted-list","children":[{"text":"Document required envs in "},{"text":".env.example"},{"text":"."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":124}},"920c0d59-2c40-4d67-b2fb-9d27cfc33f75":{"id":"920c0d59-2c40-4d67-b2fb-9d27cfc33f75","type":"Paragraph","value":[{"id":"90223c82-f29c-4178-8560-7514191d0257","type":"paragraph","children":[{"text":" "}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":125}},"1a2c2c7b-4cfe-4060-b494-c841453d8807":{"id":"1a2c2c7b-4cfe-4060-b494-c841453d8807","type":"Paragraph","value":[{"id":"ea444e87-0330-4c0d-9f44-694c8da4bddb","type":"paragraph","children":[{"text":"17) Dates, Numbers, i18n"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":126}},"0c487c02-530d-45d0-89f0-eacf0921f790":{"id":"0c487c02-530d-45d0-89f0-eacf0921f790","type":"BulletedList","value":[{"id":"10f6d062-887e-406c-8c46-ae601e6e2247","type":"bulleted-list","children":[{"text":"Use "},{"text":"Intl.*"},{"text":" APIs; avoid heavy moment.js. For parsing/formatting, "},{"text":"date-fns"},{"text":" or "},{"text":"luxon"},{"text":"."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":127}},"4a762f79-31f6-4a21-89da-cf51b4226d12":{"id":"4a762f79-31f6-4a21-89da-cf51b4226d12","type":"BulletedList","value":[{"id":"a96f2707-0222-469e-a024-77287059b643","type":"bulleted-list","children":[{"text":"i18n via "},{"text":"@formatjs/intl"},{"text":" or "},{"text":"i18next"},{"text":". No hard-coded copy; strings under "},{"text":"src/i18n"},{"text":"."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":128}},"7c3e7818-ac91-49c6-91d8-50f396ee7ba7":{"id":"7c3e7818-ac91-49c6-91d8-50f396ee7ba7","type":"Paragraph","value":[{"id":"f5eebf32-f682-4552-83d2-54386d4137ac","type":"paragraph","children":[{"text":" "}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":129}},"63b23490-8c28-4c3b-9758-1719074783bf":{"id":"63b23490-8c28-4c3b-9758-1719074783bf","type":"Paragraph","value":[{"id":"dfac63b0-ba19-417b-8e57-c363e852f4b7","type":"paragraph","children":[{"text":"18) Forms"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":130}},"40a47cba-83e5-45da-9ed5-c015c3899796":{"id":"40a47cba-83e5-45da-9ed5-c015c3899796","type":"BulletedList","value":[{"id":"54507fe3-8f7d-4d7f-96dd-f4a0edcfc407","type":"bulleted-list","children":[{"text":"Use "},{"bold":true,"text":"react-hook-form"},{"text":" with "},{"bold":true,"text":"zod"},{"text":" resolver for validation."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":131}},"917cf025-841a-4e73-b93e-4681178f20e6":{"id":"917cf025-841a-4e73-b93e-4681178f20e6","type":"BulletedList","value":[{"id":"977bec27-3861-408e-88aa-6e57996e19ff","type":"bulleted-list","children":[{"text":"Show field-level errors; disable submit while submitting; optimistic UI when safe."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":132}},"06c6f22d-103d-4cb7-8054-ac944f1d67f6":{"id":"06c6f22d-103d-4cb7-8054-ac944f1d67f6","type":"Paragraph","value":[{"id":"f834e82a-83bd-4d51-a0ac-3aea1ef4fc6b","type":"paragraph","children":[{"text":" "}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":133}},"fe2ccc93-8a82-4255-9f6f-98517a2d5f73":{"id":"fe2ccc93-8a82-4255-9f6f-98517a2d5f73","type":"Paragraph","value":[{"id":"c182ca5a-10aa-4d80-a038-468dd0428b52","type":"paragraph","children":[{"text":"19) Feature Flags"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":134}},"ca3dea42-af5a-40a7-accd-f8c267aef2b8":{"id":"ca3dea42-af5a-40a7-accd-f8c267aef2b8","type":"BulletedList","value":[{"id":"a0cc5a20-6a7d-4017-9722-9ebb15517a95","type":"bulleted-list","children":[{"text":"Boolean flags via a single provider ("},{"text":"lib/flags.ts"},{"text":") and remote JSON; evaluate at runtime."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":135}},"a0849325-5172-4307-9032-e059f7da8def":{"id":"a0849325-5172-4307-9032-e059f7da8def","type":"Paragraph","value":[{"id":"97db5c47-78d5-448a-af6d-41b4963aac77","type":"paragraph","children":[{"text":" "}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":136}},"3a6235a1-9fcc-43ed-8f55-f99e0a40ed67":{"id":"3a6235a1-9fcc-43ed-8f55-f99e0a40ed67","type":"Paragraph","value":[{"id":"5b722470-03ad-4d56-8591-15380734ca30","type":"paragraph","children":[{"text":"20) CI/CD"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":137}},"ed4f9ef3-9ba6-43ce-b667-0bcdc858301b":{"id":"ed4f9ef3-9ba6-43ce-b667-0bcdc858301b","type":"BulletedList","value":[{"id":"317738bd-7bd1-417d-99f3-fdce3f695a6a","type":"bulleted-list","children":[{"text":"Pipelines must run: typecheck, lint, unit tests, build, and e2e (on main or nightly)."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":138}},"6b98d53b-9bf8-4a2b-b328-64565b1346b5":{"id":"6b98d53b-9bf8-4a2b-b328-64565b1346b5","type":"BulletedList","value":[{"id":"72f9e3a4-f172-4b8a-a25d-26288bd5f12e","type":"bulleted-list","children":[{"text":"Prevent merge on failures; upload coverage artifact; preview deployments for UI PRs."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":139}},"ddd72410-0f9b-4106-ba81-6286c3ed48fd":{"id":"ddd72410-0f9b-4106-ba81-6286c3ed48fd","type":"Paragraph","value":[{"id":"0a57d702-7c1b-441f-a7a9-0d797d136a26","type":"paragraph","children":[{"text":" "}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":140}},"78142ee1-7e86-42e0-b2d5-57266076f187":{"id":"78142ee1-7e86-42e0-b2d5-57266076f187","type":"Paragraph","value":[{"id":"bfc426a5-d310-43e3-b3a2-cc061493ab7f","type":"paragraph","children":[{"text":"21) Code Review Checklist (Reviewer)"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":141}},"6d457d24-f457-4f0a-b1a9-dc02355c17f6":{"id":"6d457d24-f457-4f0a-b1a9-dc02355c17f6","type":"BulletedList","value":[{"id":"496cd788-70a0-4c3b-a4ee-e8efc1a27156","type":"bulleted-list","children":[{"text":"Scope small, focused"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":142}},"2b405abf-d486-42f9-98df-34005f7dfe59":{"id":"2b405abf-d486-42f9-98df-34005f7dfe59","type":"BulletedList","value":[{"id":"38f95edc-86eb-4912-bb5f-4000de76b311","type":"bulleted-list","children":[{"text":"Naming + structure consistent"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":143}},"a30e5eb1-c31e-4958-89d3-0f4892763802":{"id":"a30e5eb1-c31e-4958-89d3-0f4892763802","type":"BulletedList","value":[{"id":"d8f239df-56c8-4e95-9363-7089b8f4730f","type":"bulleted-list","children":[{"text":"Types accurate, no "},{"text":"any"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":144}},"1d49c146-ff66-4150-883a-5731cfd601e5":{"id":"1d49c146-ff66-4150-883a-5731cfd601e5","type":"BulletedList","value":[{"id":"f539ce3c-f420-488a-9f98-d7954e657706","type":"bulleted-list","children":[{"text":"Effects & dependencies correct; no stale closures"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":145}},"a833bbc2-894b-46cc-9b09-65c16cae4e74":{"id":"a833bbc2-894b-46cc-9b09-65c16cae4e74","type":"BulletedList","value":[{"id":"5ec4e9e9-ff1a-4d7f-9939-7996fe9c026e","type":"bulleted-list","children":[{"text":"a11y: roles, labels, focus, contrast"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":146}},"2ab0e53a-88a9-45f3-840a-51b6372013d4":{"id":"2ab0e53a-88a9-45f3-840a-51b6372013d4","type":"BulletedList","value":[{"id":"83e1aec0-b73f-4c60-b1b6-a755f7e82b3e","type":"bulleted-list","children":[{"text":"Tests: added/updated and meaningful"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":147}},"b2c0eb69-8196-483a-aae1-491c35914ce6":{"id":"b2c0eb69-8196-483a-aae1-491c35914ce6","type":"BulletedList","value":[{"id":"1c910095-9506-4f90-a720-d895ba7c8235","type":"bulleted-list","children":[{"text":"Performance: no obvious re-render traps"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":148}},"e6862a58-a5e1-4228-9a66-26a30caff5fd":{"id":"e6862a58-a5e1-4228-9a66-26a30caff5fd","type":"BulletedList","value":[{"id":"25a07d57-901b-464f-9a7b-2ed8216f5899","type":"bulleted-list","children":[{"text":"Security: secrets, XSS, auth paths"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":149}},"f37bc3b5-d7b0-455c-8de5-2dd2de389de0":{"id":"f37bc3b5-d7b0-455c-8de5-2dd2de389de0","type":"Paragraph","value":[{"id":"323b0a07-6637-4878-8aae-ab69b77840d7","type":"paragraph","children":[{"text":" "}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":150}},"3941b31b-20c6-47cf-a138-94276b20b258":{"id":"3941b31b-20c6-47cf-a138-94276b20b258","type":"Paragraph","value":[{"id":"b9706bd1-56b2-4c6e-a116-d6a1b71570f4","type":"paragraph","children":[{"text":"22) Do & Don’t Quick Reference"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":151}},"1b44fba7-8672-4d09-8b0b-be794e71d4b5":{"id":"1b44fba7-8672-4d09-8b0b-be794e71d4b5","type":"Paragraph","value":[{"id":"7264e7a4-d72d-4ba9-a383-9065e6228e9e","type":"paragraph","children":[{"text":"Do","bold":true},{"text":" – Co-locate code by feature. – Validate external data. – Prefer server-state tools over hand-rolled caches. – Keep components small and pure."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":152}},"7eefca1f-e182-4192-a604-47f482646cab":{"id":"7eefca1f-e182-4192-a604-47f482646cab","type":"Paragraph","value":[{"id":"8b27944f-1371-4928-b843-9578a3bddd7e","type":"paragraph","children":[{"text":"Don’t","bold":true},{"text":" – Sprinkle "},{"text":"any"},{"text":" and disable lint rules without reason. – Create mega context providers for everything. – Mix server cache with client state stores. – Use divs for buttons/links."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":153}},"29f79c52-ffa5-4fd4-82cc-da08b0b44a9e":{"id":"29f79c52-ffa5-4fd4-82cc-da08b0b44a9e","type":"Paragraph","value":[{"id":"7005aa65-bdee-4711-b098-41ec4657378a","type":"paragraph","children":[{"text":" "}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":154}},"0e32c6be-3ed5-4408-8999-dc075b0b5e2d":{"id":"0e32c6be-3ed5-4408-8999-dc075b0b5e2d","type":"Paragraph","value":[{"id":"e4239dcb-7677-4d52-98ef-462ef66f8580","type":"paragraph","children":[{"text":"23) Starter Scripts (package.json excerpt)"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":155}},"30594a63-2a47-4f7c-b65f-ce914a40185a":{"id":"30594a63-2a47-4f7c-b65f-ce914a40185a","type":"Paragraph","value":[{"id":"6cf87f6d-2d2b-4dce-a48c-89409c82c736","type":"paragraph","children":[{"text":"{"},{"text":"\n"},{"text":" "},{"text":"  "},{"text":"\"scripts\""},{"text":":"},{"text":" "},{"text":"{"},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"\"dev\""},{"text":":"},{"text":" "},{"text":"\"vite\""},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"\"build\""},{"text":":"},{"text":" "},{"text":"\"tsc -b && vite build\""},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"\"preview\""},{"text":":"},{"text":" "},{"text":"\"vite preview\""},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"\"typecheck\""},{"text":":"},{"text":" "},{"text":"\"tsc -p tsconfig.json –noEmit\""},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"\"lint\""},{"text":":"},{"text":" "},{"text":"\"eslint . –ext .ts,.tsx\""},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"\"format\""},{"text":":"},{"text":" "},{"text":"\"prettier –write .\""},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"\"test\""},{"text":":"},{"text":" "},{"text":"\"vitest\""},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"\"test:ui\""},{"text":":"},{"text":" "},{"text":"\"vitest –ui\""},{"text":","},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"\"e2e\""},{"text":":"},{"text":" "},{"text":"\"playwright test\""},{"text":"\n"},{"text":" "},{"text":"  "},{"text":"}"},{"text":"\n"},{"text":" "},{"text":"}"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":156}},"8f66f780-5f6b-4b98-a57f-292871fc20f0":{"id":"8f66f780-5f6b-4b98-a57f-292871fc20f0","type":"Paragraph","value":[{"id":"f20cacec-348e-484b-a79d-619f15d446dc","type":"paragraph","children":[{"text":" "}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":157}},"e0273e74-f160-4f5c-a21f-d4d4458a5c70":{"id":"e0273e74-f160-4f5c-a21f-d4d4458a5c70","type":"Paragraph","value":[{"id":"b762d431-4d57-4d17-ad65-db2edc23305d","type":"paragraph","children":[{"text":"24) Adopting in Existing Repos"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":158}},"0ea192ef-dc8f-4cc9-8f84-c9c27c7225c9":{"id":"0ea192ef-dc8f-4cc9-8f84-c9c27c7225c9","type":"NumberedList","value":[{"id":"aac99d5a-aafb-4cbb-887e-adf919c13c93","type":"numbered-list","children":[{"text":"Add ESLint/Prettier configs and fix autofixable issues."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":159}},"f4a5e64a-90b7-4d23-ab1b-4da9dbdcc58b":{"id":"f4a5e64a-90b7-4d23-ab1b-4da9dbdcc58b","type":"NumberedList","value":[{"id":"353dc8b1-ea5a-4aa1-91e4-5acffe2ed78d","type":"numbered-list","children":[{"text":"Enable strict TS and address high-churn areas first."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":160}},"54632586-d4f3-4b5c-832f-7889475fc4af":{"id":"54632586-d4f3-4b5c-832f-7889475fc4af","type":"NumberedList","value":[{"id":"b6e44aaf-661b-4b0d-8a4e-ceec8c75afae","type":"numbered-list","children":[{"text":"Introduce feature folders incrementally."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":161}},"46988c4b-eb13-4cd7-abac-4a61e0a5171e":{"id":"46988c4b-eb13-4cd7-abac-4a61e0a5171e","type":"NumberedList","value":[{"id":"1cd53a4e-c8f5-437f-9a7e-16e544092d82","type":"numbered-list","children":[{"text":"Convert server state to TanStack Query in phases."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":162}},"86f0df39-924f-4185-a6e9-726d64ef85f0":{"id":"86f0df39-924f-4185-a6e9-726d64ef85f0","type":"NumberedList","value":[{"id":"8f23a7cb-9bfd-42dd-b3b0-e64e9c9ce014","type":"numbered-list","children":[{"text":"Add PR template and CI checks."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":163}},"821854c7-7e72-47b1-a806-dffa8d13f15b":{"id":"821854c7-7e72-47b1-a806-dffa8d13f15b","type":"Paragraph","value":[{"id":"ee4df426-1162-43e7-b1a7-e1235f7199b1","type":"paragraph","children":[{"text":" "}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":164}},"aaab7357-cd98-4c60-94f2-49855dd87dea":{"id":"aaab7357-cd98-4c60-94f2-49855dd87dea","type":"Paragraph","value":[{"id":"6c21a7cf-cc0b-40f0-a47d-13a6e5f8c2fa","type":"paragraph","children":[{"text":"25) Versioning & Evolution"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":165}},"f086fd59-3cd3-4abb-91ec-6304bf2419a3":{"id":"f086fd59-3cd3-4abb-91ec-6304bf2419a3","type":"BulletedList","value":[{"id":"30a496ca-0c64-4db7-9121-3768ec61fe24","type":"bulleted-list","children":[{"text":"Keep this guide in the repo ("},{"text":"/docs/coding-standards.md"},{"text":")."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":166}},"41e4d331-856b-4f9e-9127-39fbc00b2fba":{"id":"41e4d331-856b-4f9e-9127-39fbc00b2fba","type":"BulletedList","value":[{"id":"5f30738b-0dfe-4f13-8374-24a6a82c2943","type":"bulleted-list","children":[{"text":"Revisit quarterly; changes require RFC + team sign-off."}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":167}},"622d9f36-edb8-4f72-92e6-e70cd96336b3":{"id":"622d9f36-edb8-4f72-92e6-e70cd96336b3","type":"Paragraph","value":[{"id":"d4214fa3-93e1-4a67-bdaa-fa04189ed931","type":"paragraph","children":[{"text":" "}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":168}},"37a21af5-4da1-4c82-a322-5da19c6fad48":{"id":"37a21af5-4da1-4c82-a322-5da19c6fad48","type":"Paragraph","value":[{"id":"66c5d467-1dc6-4dde-b9b6-cf7444f7f280","type":"paragraph","children":[{"text":"Appendix A — Minimal Provider Setup (example)"}],"props":{"nodeType":"block"}}],"meta":{"align":"left","depth":0,"order":169}},"0de8cef4-fb68-42fb-bf94-6aaafffdc8ab":{"id":"0de8cef4-fb68-42fb-bf94-6aaafffdc8ab","type":"Paragraph","value":[{"id":"5e1fb1a4-446b-427e-8179-74726c4b8a04","type":"paragraph","children":[{"text":"import { QueryClient, QueryClientProvider } from '@tanstack/react-query';"},{"text":"\n"},{"text":" "},{"text":"import { BrowserRouter } from 'react-router-dom';"},{"text":"\n"},{"text":" "},{"text":"\n"},{"text":" "},{"text":"const client = new QueryClient();"},{"text":"\n"},{"text":" "},{"text":"\n"},{"text":" "},{"text":"export function AppProviders({ children }: { children: React.ReactNode }) {"},{"text":"\n"},{"text":" "},{"text":"  "},{"text":"return ("},{"text":"\n"},{"text":" "},{"text":"    "},{"text":"”},{“text”:”\n”},{“text”:” “},{“text”:”      “},{“text”:”{children}”},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:””},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”);”},{“text”:”\n”},{“text”:” “},{“text”:”}”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:170}},”c004cfa2-1975-4c6b-8933-414714137db5″:{“id”:”c004cfa2-1975-4c6b-8933-414714137db5″,”type”:”Paragraph”,”value”:[{“id”:”309c0e08-3b85-4497-b95b-1e6c10398834″,”type”:”paragraph”,”children”:[{“text”:”Appendix B — Zod response guard”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:171}},”deef80dd-4296-4965-bff7-078d69146f3b”:{“id”:”deef80dd-4296-4965-bff7-078d69146f3b”,”type”:”Paragraph”,”value”:[{“id”:”bc0de2f5-33bd-41d8-88f3-4368e48b51ba”,”type”:”paragraph”,”children”:[{“text”:”const”,”bold”:true},{“text”:” User “},{“text”:”=”},{“text”:” z”},{“text”:”.”},{“text”:”object”},{“text”:”({ id”},{“text”:”:”},{“text”:” z”},{“text”:”.”},{“text”:”string”},{“text”:”()”},{“text”:”,”},{“text”:” name”},{“text”:”:”},{“text”:” z”},{“text”:”.”},{“text”:”string”},{“text”:”() })”},{“text”:”;”},{“text”:”\n”},{“text”:” “},{“text”:”export type”,”bold”:true},{“text”:” User “},{“text”:”=”},{“text”:” z”},{“text”:”.”},{“text”:”infer”},{“text”:”;”},{“text”:”\n”},{“text”:” “},{“text”:”\n”},{“text”:” “},{“text”:”export”,”bold”:true},{“text”:” “},{“text”:”async”,”bold”:true},{“text”:” “},{“text”:”function”,”bold”:true},{“text”:” “},{“text”:”getUser”},{“text”:”(id”},{“text”:”:”},{“text”:” “},{“text”:”string”},{“text”:”) {“},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”const”,”bold”:true},{“text”:” data “},{“text”:”=”},{“text”:” “},{“text”:”await”,”bold”:true},{“text”:” “},{“text”:”http”},{“text”:”(“},{“text”:”`/api/users/${“},{“text”:”id”},{“text”:”}`”},{“text”:”)”},{“text”:”;”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”return”,”bold”:true},{“text”:” User”},{“text”:”.”},{“text”:”parse”},{“text”:”(data)”},{“text”:”;”},{“text”:”\n”},{“text”:” “},{“text”:”}”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:172}},”f800b37d-a4c6-4a52-9534-d60e9d0608f5″:{“id”:”f800b37d-a4c6-4a52-9534-d60e9d0608f5″,”type”:”Paragraph”,”value”:[{“id”:”c3a07ddc-b785-46d9-a264-283f113a0364″,”type”:”paragraph”,”children”:[{“text”:”Appendix C — Feature Slice Example”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:173}},”5fc867f6-58ea-480f-8878-ce7cbb0ff4a7″:{“id”:”5fc867f6-58ea-480f-8878-ce7cbb0ff4a7″,”type”:”Paragraph”,”value”:[{“id”:”b7b5a996-d84f-454b-832e-b42d41761d3b”,”type”:”paragraph”,”children”:[{“text”:”src/features/todos/”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”api/”},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”useTodos.ts”},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”useCreateTodo.ts”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”components/”},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”TodoItem.tsx”},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”TodoList.tsx”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”store/”},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”useTodoFilter.ts”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”types/”},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”todo.ts”},{“text”:”\n”},{“text”:” “},{“text”:”  “},{“text”:”hooks/”},{“text”:”\n”},{“text”:” “},{“text”:”    “},{“text”:”useVisibleTodos.ts”}],”props”:{“nodeType”:”block”}}],”meta”:{“align”:”left”,”depth”:0,”order”:174}}}

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

More posts