@node-boost/node-boost 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +196 -0
  4. package/dist/cli.js +3000 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/index.d.ts +380 -0
  7. package/dist/index.js +2708 -0
  8. package/dist/index.js.map +1 -0
  9. package/package.json +82 -0
  10. package/resources/react/architectures/component-composition/guideline.md +42 -0
  11. package/resources/react/architectures/component-composition/skill/SKILL.md +19 -0
  12. package/resources/react/architectures/custom-hooks/guideline.md +38 -0
  13. package/resources/react/architectures/custom-hooks/skill/SKILL.md +22 -0
  14. package/resources/react/architectures/data-access-layer/guideline.md +43 -0
  15. package/resources/react/architectures/data-access-layer/skill/SKILL.md +26 -0
  16. package/resources/react/architectures/error-loading-boundaries/guideline.md +36 -0
  17. package/resources/react/architectures/error-loading-boundaries/skill/SKILL.md +18 -0
  18. package/resources/react/architectures/feature-modules/guideline.md +34 -0
  19. package/resources/react/architectures/feature-modules/skill/SKILL.md +28 -0
  20. package/resources/react/architectures/feature-modules/variants/forbid.md +36 -0
  21. package/resources/react/architectures/feature-modules/variants/public-api.md +37 -0
  22. package/resources/react/architectures/modern-typescript/guideline.md +47 -0
  23. package/resources/react/architectures/modern-typescript/skill/SKILL.md +23 -0
  24. package/resources/react/architectures/secure-by-default/guideline.md +38 -0
  25. package/resources/react/architectures/secure-by-default/skill/SKILL.md +22 -0
  26. package/resources/react/architectures/server-first-components/guideline.md +34 -0
  27. package/resources/react/architectures/server-first-components/skill/SKILL.md +23 -0
  28. package/resources/react/architectures/state-management/guideline.md +34 -0
  29. package/resources/react/architectures/state-management/skill/SKILL.md +21 -0
  30. package/resources/react/architectures/styling-tailwind/guideline.md +33 -0
  31. package/resources/react/architectures/styling-tailwind/skill/SKILL.md +18 -0
  32. package/resources/react/architectures/testing-strategy/guideline.md +33 -0
  33. package/resources/react/architectures/testing-strategy/skill/SKILL.md +19 -0
  34. package/resources/react/architectures/typed-contracts/guideline.md +31 -0
  35. package/resources/react/architectures/typed-contracts/skill/SKILL.md +23 -0
  36. package/resources/react/architectures/ui-states/guideline.md +45 -0
  37. package/resources/react/architectures/ui-states/skill/SKILL.md +19 -0
  38. package/resources/react/guidelines/core.md +15 -0
  39. package/resources/react/guidelines/next/15.md +9 -0
  40. package/resources/react/guidelines/next/16.md +18 -0
  41. package/resources/react/guidelines/next/core.md +8 -0
  42. package/resources/react/guidelines/react/18.md +8 -0
  43. package/resources/react/guidelines/react/19.md +10 -0
  44. package/resources/react/guidelines/react/core.md +9 -0
  45. package/resources/react/guidelines/react-query/core.md +8 -0
  46. package/resources/react/guidelines/react-router/7.md +9 -0
  47. package/resources/react/guidelines/react-router/core.md +7 -0
  48. package/resources/react/guidelines/tailwindcss/3.md +8 -0
  49. package/resources/react/guidelines/tailwindcss/4.md +9 -0
  50. package/resources/react/guidelines/tailwindcss/core.md +8 -0
  51. package/resources/react/guidelines/testing/playwright.md +8 -0
  52. package/resources/react/guidelines/testing/vitest.md +8 -0
  53. package/resources/react/guidelines/typescript/core.md +7 -0
  54. package/resources/react/guidelines/vite/core.md +8 -0
  55. package/resources/react/guidelines/zod/3.md +8 -0
  56. package/resources/react/guidelines/zod/4.md +10 -0
  57. package/resources/react/guidelines/zod/core.md +7 -0
  58. package/resources/react/guidelines/zustand/core.md +8 -0
  59. package/resources/react/skills/next-development/SKILL.md +19 -0
  60. package/resources/react/skills/react-development/SKILL.md +18 -0
  61. package/resources/react/skills/spa-routing/SKILL.md +18 -0
  62. package/resources/react/skills/tailwindcss-development/SKILL.md +17 -0
  63. package/resources/react/skills/testing-frontend/SKILL.md +18 -0
  64. package/schema.json +216 -0
@@ -0,0 +1,33 @@
1
+ # Testing Strategy
2
+
3
+ Shape: testing trophy. Most value sits in component/integration tests (Testing Library), a handful of e2e flows (Playwright), unit tests for pure logic.
4
+
5
+ ## Test behavior, not implementation
6
+
7
+ <code-snippet name="Query by role, act like a user" lang="tsx">
8
+ render(<InvoiceForm />)
9
+ await user.type(screen.getByLabelText(/amount/i), "120")
10
+ await user.click(screen.getByRole("button", { name: /save/i }))
11
+ expect(await screen.findByText(/invoice saved/i)).toBeInTheDocument()
12
+ </code-snippet>
13
+
14
+ - Select by role/label — it survives refactors and enforces accessible markup for free.
15
+ - No assertions on internal state, no shallow rendering, `data-testid` only when no role/label fits.
16
+
17
+ ## Mock the network, not your code
18
+
19
+ Use MSW: tests run through the real query hooks and data layer, with the API faked at the network boundary (the FE equivalent of `Http::fake()`). Never mock `useInvoices` itself — that tests a stub.
20
+
21
+ ## What to test
22
+
23
+ - User-visible behavior of features (happy path + validation).
24
+ - **Off-happy-path states**: loading, error, empty — the fallbacks nobody sees until production (pairs with ui-states).
25
+ - Complex hook logic via `renderHook`; pure functions as plain unit tests.
26
+ - Critical journeys (login, checkout) as Playwright e2e — few and stable.
27
+ - Automate a11y checks where cheap: `jest-axe`/axe-core on key screens.
28
+
29
+ ## Anti-patterns
30
+
31
+ - Chasing 100% coverage; snapshot-testing everything (brittle, diffs unread).
32
+ - Mocking modules the test is supposed to exercise.
33
+ - Next: async Server Components don't render meaningfully in jsdom — cover RSC via e2e/integration and unit-test the extracted data-layer logic instead.
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: testing-strategy
3
+ description: Write component tests with Testing Library and MSW, e2e with Playwright, and unit tests for pure logic — behavior over implementation.
4
+ ---
5
+
6
+ # Testing Strategy
7
+
8
+ ## When to use this skill
9
+
10
+ Use when adding tests for a feature, fixing a bug (write the failing test first), or reviewing test quality.
11
+
12
+ ## Procedure
13
+
14
+ 1. Default to a component test: render the feature entry, interact via `userEvent`, assert what the user sees (`getByRole`/`getByLabelText`).
15
+ 2. Fake the API with MSW handlers per scenario (success, error, empty) — never mock your own hooks or data-layer functions.
16
+ 3. Cover the four view states: happy, loading, error, empty.
17
+ 4. Pure logic (formatters, reducers, complex hooks) → unit tests / `renderHook`.
18
+ 5. Critical user journey changed? Update/add the Playwright e2e for it.
19
+ 6. Next RSC: test through e2e or extract the logic into the data layer and unit-test that.
@@ -0,0 +1,31 @@
1
+ # Typed Contracts
2
+
3
+ TypeScript types do not exist at runtime. Validate external data at the system's boundaries with zod, infer types from schemas, and trust types everywhere inside.
4
+
5
+ ## The boundaries (validate here, and only here)
6
+
7
+ 1. **API responses** — in the data layer: `invoiceListSchema.parse(await res.json())`. Exception: a generated client (orval/openapi-typescript) already carries the contract — do not double-validate.
8
+ 2. **User input** — forms (react-hook-form + zod resolver) and every Server Action (validate the payload first; a Server Action is a public endpoint).
9
+ 3. **Environment variables** — a single `env.ts` with a schema; crash at startup, not mid-request (`NB-ARCH-008`, warn, flags `process.env.X` elsewhere).
10
+ 4. **URL params** — `searchParams` are untrusted input like any query string.
11
+
12
+ <code-snippet name="Schema as single source of truth" lang="ts">
13
+ export const invoiceSchema = z.object({
14
+ id: z.string(),
15
+ amount: z.number(),
16
+ status: z.enum(["draft", "paid", "void"]),
17
+ })
18
+ export type Invoice = z.infer<typeof invoiceSchema> // type derives from schema — no duplication
19
+ </code-snippet>
20
+
21
+ ## Rules
22
+
23
+ - Never `as Invoice` on external data — a cast is a promise the runtime never checks. Parse it (`NB-ARCH-007`, warn, flags unvalidated `res.json()`/`JSON.parse` in the data layer).
24
+ - One schema per contract; derive narrower views with `.pick()`/`.omit()` instead of re-declaring.
25
+ - Form UX: validate on blur for fields, on submit for the whole form; reserve layout space for the error message so the layout does not jump.
26
+
27
+ ## Anti-patterns
28
+
29
+ - **Zod fatigue**: re-parsing the same data in every component. Validate at the boundary; inside the app the type is the truth.
30
+ - Hand-written interfaces duplicating a schema (they drift apart silently).
31
+ - Mind the zod major in this project — zod 4 changed APIs (`z.email()` top-level, reworked error customization); follow the versioned zod guideline.
@@ -0,0 +1,23 @@
1
+ ---
2
+ name: typed-contracts
3
+ description: Validate external data with zod at system boundaries (API, forms, env, URL) and derive TypeScript types from schemas.
4
+ ---
5
+
6
+ # Typed Contracts
7
+
8
+ ## When to use this skill
9
+
10
+ Use when consuming an API response, handling form input, adding an env variable, reading searchParams, or fixing `NB-ARCH-007`/`NB-ARCH-008`.
11
+
12
+ ## Procedure
13
+
14
+ 1. Define/extend the zod schema next to the data layer (`features/<x>/api/schemas.ts`); export `type X = z.infer<typeof xSchema>`.
15
+ 2. API boundary: `.parse()` (throw) or `.safeParse()` (handle) in the data-layer function. Skip when the client is generated from OpenAPI.
16
+ 3. Forms: zod resolver + validate the same schema at the start of the Server Action / mutation.
17
+ 4. Env: add the variable to `env.ts` schema; import `env` from there, never `process.env.X` inline.
18
+ 5. Never cast external data with `as` — if the shape is unknown, parse it.
19
+
20
+ ## Fixing findings
21
+
22
+ - `NB-ARCH-007`: wrap the raw `res.json()`/`JSON.parse` result in `schema.parse(...)`.
23
+ - `NB-ARCH-008`: move the `process.env.X` read into `env.ts` and import the validated value.
@@ -0,0 +1,45 @@
1
+ # UI States
2
+
3
+ Every data view has four states, not one. Design loading, error and empty explicitly — apps spend ~30% of their time off the happy path, and generated code habitually builds only the happy branch.
4
+
5
+ <code-snippet name="The four-state contract" lang="tsx">
6
+ function InvoiceList() {
7
+ const { data, isLoading, isError, refetch } = useInvoices()
8
+
9
+ if (isLoading) return <InvoiceListSkeleton />
10
+ if (isError) return <ErrorState onRetry={refetch} />
11
+ if (!data.length) return (
12
+ <EmptyState
13
+ title="No invoices yet"
14
+ description="Create your first invoice to get started."
15
+ action={<CreateInvoiceButton />}
16
+ />
17
+ )
18
+ return <InvoiceTable invoices={data} />
19
+ }
20
+ </code-snippet>
21
+
22
+ ## Empty states are a feature
23
+
24
+ - Explain **why** it's empty + give the next step (CTA). A blank screen after onboarding is the user's first impression.
25
+ - Distinguish "no data yet" (onboarding CTA) from "filters matched nothing" (show the filters + a clear-filters action — no rocket illustrations).
26
+
27
+ ## Loading: skeletons, not spinners
28
+
29
+ Skeletons mirror the coming content's shape (no layout shift). One skeleton per meaningful region — five racing spinners are worse than one calm block. In Next, `loading.tsx` is the page-level skeleton (see error-loading-boundaries); in SPAs, per-view skeleton components.
30
+
31
+ ## Optimistic UI (React 19)
32
+
33
+ For high-confidence mutations (toggle, like, add-to-list) use `useOptimistic` — instant UI, automatic rollback on error. Forms: `useActionState` handles pending/error without hand-rolled `isSubmitting`/`setError` flags. Do **not** use optimistic updates for payments or irreversible operations.
34
+
35
+ <code-snippet name="Optimistic toggle" lang="tsx">
36
+ const [optimisticDone, setOptimisticDone] = useOptimistic(todo.done)
37
+ async function toggle() {
38
+ setOptimisticDone(!optimisticDone) // instant
39
+ await toggleTodoAction(todo.id) // rollback happens automatically on error
40
+ }
41
+ </code-snippet>
42
+
43
+ ## Consistency
44
+
45
+ `EmptyState`/`ErrorState` are shared slot-based components in `components/ui/` — not ad-hoc divs per feature. Test all four states (testing-strategy).
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: ui-states
3
+ description: Build the full four-state contract (loading, error, empty, happy) for data views, with skeletons, designed empty states and React 19 optimistic updates.
4
+ ---
5
+
6
+ # UI States
7
+
8
+ ## When to use this skill
9
+
10
+ Use when building any view that renders remote data, or when adding a mutation with user-visible feedback.
11
+
12
+ ## Procedure
13
+
14
+ 1. Scaffold all four branches up front: loading (skeleton mirroring content), error (message + retry), empty (why + CTA), happy.
15
+ 2. Empty state: decide which case it is — no data yet (onboarding CTA) vs. no results for filters (keep filters visible, offer clear).
16
+ 3. Use shared `EmptyState`/`ErrorState` from `components/ui/`; extend them with slots rather than forking per feature.
17
+ 4. Mutations: high-confidence, reversible → `useOptimistic`; forms → `useActionState` for pending/error; payments/irreversible → explicit pending state, no optimism.
18
+ 5. Next App Router: page-level loading/error live in `loading.tsx`/`error.tsx`; this skill covers the *content* of those fallbacks.
19
+ 6. Add tests for the loading/error/empty branches (MSW scenarios), not just the happy path.
@@ -0,0 +1,15 @@
1
+ # Node Boost Core
2
+
3
+ Baseline for AI-assisted work in this repository. Guidelines in `.ai/guidelines/` are composed from the packages actually installed — trust them over training-data habits, which are often a major version stale.
4
+
5
+ ## Working rules
6
+
7
+ - Match the project's detected stack and versions (see the `application_info` MCP tool) before writing code; version-specific guidelines override generic knowledge.
8
+ - Follow the enabled architecture guidelines (indexed in `node-boost.md`); the `audit`/`guard` commands enforce their rules (`NB-ARCH-xxx`). Use `explain <ID>` when a finding is unclear.
9
+ - Suppressing a finding requires a reason: `// nb-disable NB-ARCH-xxx -- <why>`. Unreasoned suppressions are flagged.
10
+ - After completing changes, run `node-boost audit --changed` (or rely on the installed Stop hook) and fix findings before handing back.
11
+
12
+ ## Repository hygiene
13
+
14
+ - Do not leave dead code: unused exports, files and dependencies are context noise for both humans and agents. `knip` finds them — prefer removing over commenting out.
15
+ - Keep `node-boost.json` and generated `.ai/**` files committed; regenerate with `node-boost update` after dependency upgrades (`doctor` detects drift).
@@ -0,0 +1,9 @@
1
+ # Next.js 15
2
+
3
+ This project runs Next 15 — caching defaults changed versus 13/14. Do not generate stale idioms.
4
+
5
+ - `fetch` is **no longer cached by default**; opt in explicitly with `{ cache: "force-cache" }` or route segment config. GET route handlers and the client router cache are also uncached by default.
6
+ - `params` and `searchParams` in pages/layouts are **async** — `await` them (sync access is deprecated).
7
+ - `"use cache"` / cache components exist behind the experimental flag only — use the stable primitives (`fetch` options, `revalidateTag`, `unstable_cache`) unless the project has the flag enabled.
8
+ - React 19 is the baseline; Server Actions and form Actions are stable — use them for mutations with auth + validation.
9
+ - Partial Prerendering is experimental in 15 — structure pages with `<Suspense>` boundaries anyway (it pays off in streaming today and PPR later).
@@ -0,0 +1,18 @@
1
+ # Next.js 16
2
+
3
+ This project runs Next 16 — its caching model is **explicit**. Do not generate Next 13/14-era idioms.
4
+
5
+ - Nothing is cached by default: pages are dynamic; opt in with the `"use cache"` directive at the function/component level, as close to the data as possible (usually in the data layer).
6
+ - Control lifetimes with `cacheLife()` profiles; invalidate with `revalidateTag()`/`updateTag()` from Server Actions.
7
+ - Partial Prerendering is the default model with cache components enabled: static shell + dynamic holes defined by `<Suspense>` boundaries — structure pages accordingly (see error-loading-boundaries).
8
+ - `params` and `searchParams` in pages/layouts are **async** — `await` them.
9
+ - Do NOT write: `fetch(..., { next: { revalidate } })` as the primary caching tool, `export const revalidate`, or `unstable_cache` — these are legacy patterns superseded by `"use cache"`.
10
+ - Turbopack is the default bundler; do not add webpack-specific config unless the project already has it.
11
+
12
+ <code-snippet name="Explicit caching in the data layer" lang="ts">
13
+ export async function getInvoices() {
14
+ "use cache"
15
+ cacheLife("minutes")
16
+ return invoiceListSchema.parse(await apiClient.get("/invoices"))
17
+ }
18
+ </code-snippet>
@@ -0,0 +1,8 @@
1
+ # Next.js Core
2
+
3
+ - App Router conventions: routes are folders; `page.tsx` renders, `layout.tsx` wraps, `route.ts` handles HTTP, `loading.tsx`/`error.tsx` are boundaries. Do not mix in Pages Router idioms (`getServerSideProps`, `getStaticProps`, `_app.tsx`) unless the project actually uses `pages/`.
4
+ - Components are Server Components by default; `"use client"` only on interactive leaves (see server-first-components guideline).
5
+ - Data flows through the data layer; mutations through Server Actions with auth + validation (see data-access-layer and secure-by-default).
6
+ - Use the framework's primitives before reaching for libraries: `next/image` for images, `next/font` for fonts, `next/link` for navigation, Metadata API for `<head>`.
7
+ - Route params and `searchParams` are untrusted input — validate before use.
8
+ - Prefer `redirect()`/`notFound()` from the server over client-side workarounds.
@@ -0,0 +1,8 @@
1
+ # React 18
2
+
3
+ This project runs React 18 — React 19 APIs are NOT available. Do not generate them.
4
+
5
+ - No `use()`, no `useActionState`/`useFormStatus`/`useOptimistic`, no form `action={fn}` prop, no ref-as-prop (use `forwardRef` here).
6
+ - No React Compiler by default: memoize hot paths deliberately with `useMemo`/`useCallback`/`React.memo` — but only where profiling or obvious render pressure justifies it.
7
+ - Concurrent features available: `useTransition`/`startTransition` for non-urgent updates, `useDeferredValue` for expensive derived UI, `<Suspense>` for code-splitting and data libraries that support it.
8
+ - Optimistic UI is hand-rolled here: local state + rollback in the mutation's error handler (react-query's `onMutate`/`onError` pattern).
@@ -0,0 +1,10 @@
1
+ # React 19
2
+
3
+ This project runs React 19 — several long-standing idioms are dead. Do not generate them.
4
+
5
+ - `ref` is a regular prop: **no `forwardRef`**. `function Input({ ref, ...props })` just works.
6
+ - React Compiler (1.0, stable) memoizes automatically: **no ritual `useCallback`/`useMemo`/`React.memo`** — use them only for referential guarantees (e.g. effect deps).
7
+ - Actions are the mutation primitive: `<form action={fn}>`, `useActionState` for pending/error, `useFormStatus` inside forms, `useOptimistic` for instant feedback (see ui-states guideline).
8
+ - `use(promise)` unwraps promises in render (with Suspense); `use(Context)` replaces `useContext` and may be called conditionally.
9
+ - Metadata tags (`<title>`, `<meta>`) render from components and hoist automatically (in non-Next apps).
10
+ - `propTypes` and `defaultProps` on function components are removed — TypeScript types and default parameters instead.
@@ -0,0 +1,9 @@
1
+ # React Core
2
+
3
+ - Components are pure functions of props/state — side effects live in event handlers, the data layer, or (rarely) effects that sync with external systems.
4
+ - Compute derived data during render; do not mirror props into state or chain `useEffect` + `setState` (see custom-hooks guideline).
5
+ - Lists need stable `key`s from the data, never array indexes for dynamic lists.
6
+ - Prefer composition (children/slots) over configuration props (see component-composition guideline).
7
+ - Keep state close to where it is used; escalate deliberately (see state-management guideline).
8
+ - Semantic HTML first: `<button>`, `<a>`, `<label>` — not clickable `<div>`s.
9
+ - Follow the version-specific React guideline in this directory — React idioms shift across majors and training data lags behind.
@@ -0,0 +1,8 @@
1
+ # TanStack Query Core
2
+
3
+ - react-query owns server state — it is a cache, not a store. Never copy query results into zustand/Context (see state-management guideline).
4
+ - Components consume query hooks from the feature (`useInvoices()`), never `useQuery` inline with a raw fetch (see data-access-layer guideline).
5
+ - Query keys are structured and centralized per feature: `["invoices", filter]` — keys are the cache identity, treat them as an API.
6
+ - Mutations invalidate what they change: `useMutation` + `queryClient.invalidateQueries({ queryKey: ["invoices"] })` on success; optimistic updates via `onMutate`/`onError` rollback where UX warrants it.
7
+ - Handle all result states in the UI: `isLoading`, `isError`, empty data (see ui-states guideline).
8
+ - Configure sensible `staleTime` per data class instead of refetching everything on every focus.
@@ -0,0 +1,9 @@
1
+ # React Router 7
2
+
3
+ This project runs React Router 7 — the merged react-router package. Do not generate v5/v6-era imports or idioms.
4
+
5
+ - Import from `react-router` (v7 merged `react-router-dom` into it; check which import style this project uses and stay consistent).
6
+ - v7 spans modes: library mode (manual `<Routes>`/`createBrowserRouter`) and framework mode (file conventions, loaders/actions). **Match the project's existing mode** — do not introduce loaders/actions into a library-mode SPA that fetches via react-query.
7
+ - In library mode with react-query (typical here): data fetching stays in query hooks; the router only maps URLs to screens.
8
+ - Use `createBrowserRouter`/route objects over JSX route trees for new route configuration; type route params where the setup provides typegen.
9
+ - No `<Switch>`, no `useHistory` (v5 relics) — `<Routes>`, `useNavigate`, `useSearchParams`.
@@ -0,0 +1,7 @@
1
+ # React Router Core
2
+
3
+ - Routes are configuration, not scattered strings: keep the route tree in one module (`src/routers.tsx` / `src/routes/`), and reference paths via constants or typed helpers — no hardcoded `"/invoices/" + id` concatenation in components.
4
+ - URL is state: filters, pagination, tabs and other shareable view state belong in `searchParams`, not in a store (see state-management guideline).
5
+ - Navigation through `<Link>`/`<NavLink>`/`useNavigate` — never `window.location` for internal routes.
6
+ - Route params are untrusted input: validate/parse before use (see typed-contracts guideline).
7
+ - Lazy-load route-level components for code splitting; pair each lazy route with a skeleton fallback (see ui-states guideline).
@@ -0,0 +1,8 @@
1
+ # Tailwind CSS 3
2
+
3
+ This project runs Tailwind 3 — JS-config era. Do not generate v4 idioms.
4
+
5
+ - Configuration lives in `tailwind.config.js` (`theme.extend`, `plugins`); CSS entry uses `@tailwind base; @tailwind components; @tailwind utilities;` — NOT `@import "tailwindcss"` or `@theme` (those are v4).
6
+ - Maintain the `content` globs — a file missing from `content` means its classes are purged from the build.
7
+ - Design tokens go in `theme.extend`; reference with utilities, or `theme()` in CSS.
8
+ - PostCSS pipeline needs `tailwindcss` + `autoprefixer`.
@@ -0,0 +1,9 @@
1
+ # Tailwind CSS 4
2
+
3
+ This project runs Tailwind 4 — configuration is CSS-first. Do not generate v3 idioms.
4
+
5
+ - **No `tailwind.config.js`.** Configuration lives in CSS: `@import "tailwindcss"` plus `@theme { --color-brand: ...; }` for tokens. Do not create a JS config file.
6
+ - Theme tokens are CSS variables, usable directly (`var(--color-brand)`) and generating utilities automatically.
7
+ - No `content` array to maintain — sources are auto-detected; no PostCSS `autoprefixer`/`postcss-import` boilerplate (built in via `@tailwindcss/postcss` or the Vite plugin).
8
+ - v3 → v4 renames to respect: `shadow-sm` → `shadow-xs`, `outline-none` → `outline-hidden`, ring default width changed — check migrated class names rather than assuming v3 scales.
9
+ - Custom utilities via `@utility`, plugins via `@plugin` — in CSS, not JS.
@@ -0,0 +1,8 @@
1
+ # Tailwind CSS Core
2
+
3
+ - Utility-first in JSX; reuse through React components, not through custom CSS classes. Keep `@apply` to a rare minimum.
4
+ - Never construct class names dynamically (`text-${color}-500`) — the compiler scans sources statically; interpolated classes silently don't exist. Map conditions to full literal class strings.
5
+ - Use theme tokens for colors/spacing; arbitrary values (`w-[347px]`) are one-off exceptions with a reason.
6
+ - Visual variants via `cva` + `tailwind-merge`; conditional classes via a `cn()` helper (see styling-tailwind guideline).
7
+ - Keep class order consistent with the project's formatter (prettier-plugin-tailwindcss or Biome's sorting).
8
+ - Follow the version-specific Tailwind guideline — configuration differs fundamentally between v3 and v4.
@@ -0,0 +1,8 @@
1
+ # Playwright
2
+
3
+ - Reserve e2e for critical user journeys (login, checkout, core flows) — few, stable, high-value; everything else belongs in component tests.
4
+ - Select by role/label (`getByRole`, `getByLabel`) — same philosophy as Testing Library; avoid CSS/XPath selectors.
5
+ - Rely on web-first assertions (`await expect(locator).toBeVisible()`) — no manual `waitForTimeout` sleeps.
6
+ - Isolate state per test (fresh context/storage); seed data through APIs or fixtures, not through UI click-chains.
7
+ - Stub third-party/external services with `page.route()`; your own backend runs real in e2e when feasible.
8
+ - Use the accessibility snapshot/axe integration on key pages when cheap.
@@ -0,0 +1,8 @@
1
+ # Vitest
2
+
3
+ - Runner for unit and component tests; component tests use Testing Library + `@testing-library/jest-dom` matchers in a jsdom (or browser-mode) environment.
4
+ - Test behavior through roles/labels; mock the network with MSW, never your own hooks/modules under test (see testing-strategy guideline).
5
+ - Structure: `describe` per unit/feature, test names state observable behavior ("shows validation error when amount is empty").
6
+ - Use `vi.fn()`/`vi.spyOn` for collaborator seams; avoid `vi.mock` of internal modules — it usually signals a missing seam.
7
+ - Keep tests deterministic: fake timers for time-dependent logic (`vi.useFakeTimers`), no real network, no ordering dependence.
8
+ - Run a focused file with `vitest run <path>`; the full gate is the project's `npm test`.
@@ -0,0 +1,7 @@
1
+ # TypeScript Core
2
+
3
+ - `strict: true` is the floor; treat compiler errors as design feedback, not noise to cast away.
4
+ - No `any` and no `as` on external data — `unknown` + narrowing, or a zod parse at the boundary (see typed-contracts and modern-typescript guidelines).
5
+ - Model closed sets as discriminated unions or const objects (never `enum`); make switches exhaustive with a `never` check.
6
+ - Derive types instead of duplicating them: `z.infer`, `ReturnType`, `Pick`/`Omit`, `satisfies` for literal checking.
7
+ - Types live next to their domain (feature's `types.ts`); shared primitives (branded IDs) in `lib/`.
@@ -0,0 +1,8 @@
1
+ # Vite Core
2
+
3
+ - This is a client-rendered SPA: every component is client code, all secrets stay on the backend — the browser bundle is public.
4
+ - Env variables: only `VITE_`-prefixed values reach the client (`import.meta.env.VITE_X`) — and they are readable by every visitor. Never prefix secrets; validate env in one `env.ts` (see typed-contracts and secure-by-default guidelines).
5
+ - Use `import.meta.env` (`DEV`, `PROD`, `MODE`) — not `process.env` in app code.
6
+ - Code-split at route level with dynamic `import()`; heavy rarely-used components load lazily with a skeleton fallback.
7
+ - Static assets through imports (hashed URLs) or `public/` for verbatim files; prefer imports.
8
+ - Config in `vite.config.ts` stays lean — resolve aliases (`@/` → `src/`) should match `tsconfig.json` paths.
@@ -0,0 +1,8 @@
1
+ # Zod 3
2
+
3
+ This project runs zod 3 — do not use zod 4 APIs.
4
+
5
+ - String formats chain off strings: `z.string().email()`, `z.string().uuid()` — top-level `z.email()` does NOT exist here.
6
+ - Error customization uses `message` / `required_error` / `invalid_type_error` params and `errorMap` — the v4 unified `error` param does not exist.
7
+ - Strict/passthrough objects via `.strict()` / `.passthrough()` on `z.object`.
8
+ - `z.record(valueSchema)` accepts a single argument (string keys implied).
@@ -0,0 +1,10 @@
1
+ # Zod 4
2
+
3
+ This project runs zod 4 — several v3 idioms are gone or renamed. Do not generate v3 API.
4
+
5
+ - String formats are top-level: `z.email()`, `z.url()`, `z.uuid()` — NOT `z.string().email()` (deprecated/removed in v4).
6
+ - Error customization is unified under `error`: `z.string({ error: "Required" })`, `.min(5, { error: "Too short" })` — NOT `message`, `required_error`, `invalid_type_error`, or `errorMap`.
7
+ - `z.strictObject({...})`/`z.looseObject({...})` replace `.strict()`/`.passthrough()` styles; default objects strip unknown keys.
8
+ - Discriminated unions and recursive types are stronger — prefer `z.discriminatedUnion` for tagged payloads.
9
+ - Need a slim client bundle? `zod/mini` exists (functional API) — only introduce it if the project already uses it.
10
+ - Records: `z.record(z.string(), valueSchema)` requires the key schema explicitly.
@@ -0,0 +1,7 @@
1
+ # Zod Core
2
+
3
+ - Validate at system boundaries only: API responses (data layer), form/action input, env, URL params. Inside the app, the inferred type is the truth — no re-parsing (see typed-contracts guideline).
4
+ - One schema per contract, types derived with `z.infer`; narrower views via `.pick()`/`.omit()`/`.extend()`, not re-declared interfaces.
5
+ - `.parse()` when failure is a bug (throw), `.safeParse()` when failure is a flow (form input, external data you degrade gracefully on).
6
+ - Keep schemas next to the data layer that uses them (`features/<x>/api/schemas.ts`).
7
+ - Follow the version-specific zod guideline — the v3 → v4 API changed materially.
@@ -0,0 +1,8 @@
1
+ # Zustand Core
2
+
3
+ - The store holds **client-owned** state only: UI preferences, drafts, selections. Server data lives in react-query — writing fetched results into the store creates a second source of truth (flagged by `NB-ARCH-009`).
4
+ - Small, focused stores per concern beat one global store; colocate a feature's store inside the feature.
5
+ - Select narrowly: `useStore((s) => s.sidebarOpen)` — subscribing to the whole store re-renders on every change.
6
+ - Actions live inside the store definition (`set`/`get`), components call them — no external mutation of store state.
7
+ - Persist only what genuinely survives sessions (`persist` middleware) and version the storage schema.
8
+ - Before adding to the store, walk the ladder: `useState` → URL → Context → store (see state-management guideline).
@@ -0,0 +1,19 @@
1
+ ---
2
+ name: next-development
3
+ description: Build Next.js App Router features end-to-end — server-first pages, data layer, Server Actions, boundaries — per this project's version and conventions.
4
+ ---
5
+
6
+ # Next Development
7
+
8
+ ## When to use this skill
9
+
10
+ Use when adding or changing pages, layouts, route handlers, Server Actions, or data flow in this Next.js app.
11
+
12
+ ## Procedure
13
+
14
+ 1. Check the Next major (`application_info`) and follow the versioned guideline — caching semantics differ between 15 and 16.
15
+ 2. New route: folder in `app/`, async server `page.tsx`, data via the feature's `api/` functions; add `loading.tsx`/`error.tsx` when the page fetches (error-loading-boundaries skill).
16
+ 3. Interactivity goes into `"use client"` leaf components inside the feature (server-first-components skill).
17
+ 4. Mutations: Server Action with auth check + zod validation, then cache invalidation (`revalidateTag`/`updateTag` per version).
18
+ 5. Use framework primitives: `next/image`, `next/font`, `next/link`, Metadata API.
19
+ 6. Before handing back: `node-boost audit --changed` and fix findings.
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: react-development
3
+ description: Write React components and hooks following this project's composition, state and hooks conventions.
4
+ ---
5
+
6
+ # React Development
7
+
8
+ ## When to use this skill
9
+
10
+ Use when creating or refactoring components, hooks, or client-side state.
11
+
12
+ ## Procedure
13
+
14
+ 1. Check the React major (`application_info`) and follow the versioned guideline — 18 vs 19 idioms differ (ref-as-prop, Actions, compiler memoization).
15
+ 2. New component: start from composition (children/slots), semantic HTML, props for variants only (component-composition skill).
16
+ 3. State: classify first — server data → query hooks; URL-worthy → searchParams; local → `useState`; shared client → Context/store (state-management skill).
17
+ 4. Logic outgrowing the JSX → extract a custom hook in the feature (custom-hooks skill); avoid needless `useEffect` and ritual memoization.
18
+ 5. Cover the four UI states (ui-states skill) and add behavior tests (testing-frontend skill).
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: spa-routing
3
+ description: Add screens and navigation in this Vite + React Router SPA — central route config, URL-first state, lazy routes.
4
+ ---
5
+
6
+ # SPA Routing
7
+
8
+ ## When to use this skill
9
+
10
+ Use when adding a screen, changing navigation, or wiring view state to the URL.
11
+
12
+ ## Procedure
13
+
14
+ 1. Add the route in the central route config (`src/routers.tsx`/`src/routes/`) — never scatter path strings through components; use route constants/helpers.
15
+ 2. Lazy-load the route component (`import()`), pair with a skeleton fallback.
16
+ 3. Shareable view state (filters, page, tab) → `useSearchParams`, validated before use; do not mirror it into a store.
17
+ 4. Navigate with `<Link>`/`useNavigate`; internal redirects never touch `window.location`.
18
+ 5. The screen composes feature components (feature-modules skill); data arrives via query hooks (data-access-layer skill).
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: tailwindcss-development
3
+ description: Style with Tailwind matching this project's major version — tokens, cva variants, no dynamic class names.
4
+ ---
5
+
6
+ # Tailwind CSS Development
7
+
8
+ ## When to use this skill
9
+
10
+ Use when styling components or touching Tailwind configuration.
11
+
12
+ ## Procedure
13
+
14
+ 1. Check the Tailwind major first: v4 = CSS-first config (`@theme`, no `tailwind.config.js`); v3 = JS config + `content` globs. Follow the versioned guideline.
15
+ 2. Use theme tokens; introduce new tokens in the theme, not arbitrary values.
16
+ 3. Variants with `cva` + `tailwind-merge`; conditionals through `cn()` — never interpolate class fragments (`text-${x}-500` doesn't exist in the build).
17
+ 4. Repeated class strings → extract a `components/ui/` component instead of `@apply`.
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: testing-frontend
3
+ description: Test features with Testing Library + MSW (Vitest) and critical journeys with Playwright — behavior over implementation.
4
+ ---
5
+
6
+ # Frontend Testing
7
+
8
+ ## When to use this skill
9
+
10
+ Use when writing or fixing tests for components, hooks, or user flows.
11
+
12
+ ## Procedure
13
+
14
+ 1. Default to a component test: render the feature entry, drive it with `userEvent`, assert via `getByRole`/`getByLabelText`.
15
+ 2. Fake the network with MSW per scenario (success/error/empty); never mock the project's own hooks or data layer.
16
+ 3. Cover the four view states, not just the happy path.
17
+ 4. Pure logic → unit test; complex hooks → `renderHook`; critical journeys → Playwright (own guideline).
18
+ 5. Bug fix? Write the failing test first, then fix.