create-react-starter-kit 1.0.5 → 1.0.7

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 (85) hide show
  1. package/dist/cli-args.d.ts.map +1 -1
  2. package/dist/cli-args.js +2 -1
  3. package/dist/cli-args.js.map +1 -1
  4. package/dist/generator/dependencies.d.ts.map +1 -1
  5. package/dist/generator/dependencies.js +5 -0
  6. package/dist/generator/dependencies.js.map +1 -1
  7. package/dist/generator/index.d.ts.map +1 -1
  8. package/dist/generator/index.js +5 -0
  9. package/dist/generator/index.js.map +1 -1
  10. package/dist/prompts/index.d.ts.map +1 -1
  11. package/dist/prompts/index.js +8 -0
  12. package/dist/prompts/index.js.map +1 -1
  13. package/dist/templates/README.md.ejs +1 -1
  14. package/dist/templates/__when_apiLayer_axios__/src/services/api.ts.ejs +23 -0
  15. package/dist/templates/__when_apiLayer_axios__/src/services/http/client.ts.ejs +174 -0
  16. package/dist/templates/__when_apiLayer_axios__/src/services/http/errors.ts.ejs +81 -0
  17. package/dist/templates/__when_apiLayer_axios__/src/services/http/index.ts.ejs +5 -0
  18. package/dist/templates/__when_apiLayer_fetch__/src/services/api.ts.ejs +22 -0
  19. package/dist/templates/__when_apiLayer_fetch__/src/services/http/client.ts.ejs +195 -0
  20. package/dist/templates/__when_apiLayer_fetch__/src/services/http/errors.ts.ejs +81 -0
  21. package/dist/templates/__when_apiLayer_fetch__/src/services/http/index.ts.ejs +5 -0
  22. package/dist/templates/__when_buildTool_vite__/vite.config.ts.ejs +9 -1
  23. package/dist/templates/__when_buildTool_webpack__/webpack.config.js.ejs +1 -1
  24. package/dist/templates/__when_e2eTesting_cypress__/cypress.config.ts.ejs +2 -1
  25. package/dist/templates/__when_e2eTesting_playwright__/playwright.config.ts.ejs +4 -3
  26. package/dist/templates/__when_serverState_rtk-query__/src/store/postsApi.ts.ejs +28 -5
  27. package/dist/templates/__when_unitTesting_jest__/jest.config.json.ejs +8 -0
  28. package/dist/templates/__when_unitTesting_vitest__/tests/feedback.test.tsx.ejs +16 -0
  29. package/dist/templates/__when_unitTesting_vitest__/tests/posts.test.tsx.ejs +1 -3
  30. package/dist/templates/__when_unitTesting_vitest__/vitest.config.ts.ejs +31 -0
  31. package/dist/templates/docs/architecture.md.ejs +44 -25
  32. package/dist/templates/docs/best-practices.md.ejs +39 -3
  33. package/dist/templates/docs/examples/README.md.ejs +10 -10
  34. package/dist/templates/docs/examples/api.md.ejs +165 -8
  35. package/dist/templates/docs/examples/data-fetching.md.ejs +107 -6
  36. package/dist/templates/docs/examples/forms.md.ejs +66 -6
  37. package/dist/templates/docs/examples/state.md.ejs +50 -6
  38. package/dist/templates/docs/examples/styling.md.ejs +56 -8
  39. package/dist/templates/docs/examples/testing.md.ejs +63 -9
  40. package/dist/templates/docs/getting-started.md.ejs +63 -15
  41. package/dist/templates/docs/selected-stack.md.ejs +110 -8
  42. package/dist/templates/src/features/feedback/FeedbackForm.tsx.ejs +10 -0
  43. package/dist/templates/src/features/posts/PostsPanel.tsx.ejs +1 -1
  44. package/dist/templates/src/routes/PostsPage.tsx.ejs +7 -2
  45. package/dist/templates/src/types/index.ts.ejs +1 -1
  46. package/dist/templates/src/types/models.ts.ejs +18 -0
  47. package/dist/types.d.ts +1 -1
  48. package/dist/types.d.ts.map +1 -1
  49. package/package.json +1 -1
  50. package/templates/README.md.ejs +1 -1
  51. package/templates/__when_apiLayer_axios__/src/services/api.ts.ejs +23 -0
  52. package/templates/__when_apiLayer_axios__/src/services/http/client.ts.ejs +174 -0
  53. package/templates/__when_apiLayer_axios__/src/services/http/errors.ts.ejs +81 -0
  54. package/templates/__when_apiLayer_axios__/src/services/http/index.ts.ejs +5 -0
  55. package/templates/__when_apiLayer_fetch__/src/services/api.ts.ejs +22 -0
  56. package/templates/__when_apiLayer_fetch__/src/services/http/client.ts.ejs +195 -0
  57. package/templates/__when_apiLayer_fetch__/src/services/http/errors.ts.ejs +81 -0
  58. package/templates/__when_apiLayer_fetch__/src/services/http/index.ts.ejs +5 -0
  59. package/templates/__when_buildTool_vite__/vite.config.ts.ejs +9 -1
  60. package/templates/__when_buildTool_webpack__/webpack.config.js.ejs +1 -1
  61. package/templates/__when_e2eTesting_cypress__/cypress.config.ts.ejs +2 -1
  62. package/templates/__when_e2eTesting_playwright__/playwright.config.ts.ejs +4 -3
  63. package/templates/__when_serverState_rtk-query__/src/store/postsApi.ts.ejs +28 -5
  64. package/templates/__when_unitTesting_jest__/jest.config.json.ejs +8 -0
  65. package/templates/__when_unitTesting_vitest__/tests/feedback.test.tsx.ejs +16 -0
  66. package/templates/__when_unitTesting_vitest__/tests/posts.test.tsx.ejs +1 -3
  67. package/templates/__when_unitTesting_vitest__/vitest.config.ts.ejs +31 -0
  68. package/templates/docs/architecture.md.ejs +44 -25
  69. package/templates/docs/best-practices.md.ejs +39 -3
  70. package/templates/docs/examples/README.md.ejs +10 -10
  71. package/templates/docs/examples/api.md.ejs +165 -8
  72. package/templates/docs/examples/data-fetching.md.ejs +107 -6
  73. package/templates/docs/examples/forms.md.ejs +66 -6
  74. package/templates/docs/examples/state.md.ejs +50 -6
  75. package/templates/docs/examples/styling.md.ejs +56 -8
  76. package/templates/docs/examples/testing.md.ejs +63 -9
  77. package/templates/docs/getting-started.md.ejs +63 -15
  78. package/templates/docs/selected-stack.md.ejs +110 -8
  79. package/templates/src/features/feedback/FeedbackForm.tsx.ejs +10 -0
  80. package/templates/src/features/posts/PostsPanel.tsx.ejs +1 -1
  81. package/templates/src/routes/PostsPage.tsx.ejs +7 -2
  82. package/templates/src/types/index.ts.ejs +1 -1
  83. package/templates/src/types/models.ts.ejs +18 -0
  84. package/dist/templates/src/services/api.ts.ejs +0 -84
  85. package/templates/src/services/api.ts.ejs +0 -84
@@ -3,16 +3,76 @@
3
3
  **Forms:** <%= stackLabels.forms %>
4
4
  **Validation:** <%= stackLabels.validation %>
5
5
 
6
- **Live demo:** Feedback form on `/`
6
+ **Live demo:** `/feedback` `src/features/feedback/FeedbackForm.<%= jsxExt %>`
7
+ **Schemas:** `src/lib/validation.<%= ext %>`
7
8
 
8
9
  ## When to use
9
10
 
10
- Multi-field input with client-side rules and async submit.
11
+ Multi-field input with client-side rules and async submit:
11
12
 
12
- ## Best practice
13
+ - contact / feedback forms
14
+ - settings screens
15
+ - multi-step wizards (add a stepper on top of the same schema)
13
16
 
14
- Define schemas once in `src/lib/validation.<%= ext %>` and reuse across UI and API boundaries.
17
+ ## How to use in this project
15
18
 
16
- ## Snippet
19
+ 1. Define the schema once in `src/lib/validation.<%= ext %>`.
20
+ 2. Bind inputs with <%= stackLabels.forms %>.
21
+ 3. On submit, call the API layer:
22
+ <% if (serverState === 'rtk-query') { -%>
23
+ - RTK mutation: `useCreateFeedbackMutation()` → `.unwrap()`
24
+ <% } else { -%>
25
+ - `createFeedback()` from `@/services/api`
26
+ <% } -%>
27
+ 4. Show success with `role="status"` and reset the form.
17
28
 
18
- See `src/features/feedback/FeedbackForm.<%= jsxExt %>`.
29
+ <% if (forms === 'react-hook-form') { -%>
30
+ ### React Hook Form pattern
31
+
32
+ ```tsx
33
+ const {
34
+ register,
35
+ handleSubmit,
36
+ formState: { errors, isSubmitting },
37
+ } = useForm({
38
+ defaultValues,
39
+ resolver: zodResolver(feedbackSchema), // when using Zod
40
+ });
41
+
42
+ const onSubmit = handleSubmit(async (values) => {
43
+ await createFeedback(values);
44
+ });
45
+ ```
46
+ <% } else if (forms === 'formik') { -%>
47
+ ### Formik pattern
48
+
49
+ Use `<Formik>` + `<Field>` and pass a Yup schema via `validationSchema` when selected.
50
+ <% } else if (forms === 'tanstack-form') { -%>
51
+ ### TanStack Form pattern
52
+
53
+ Create the form with `useForm`, validate with your schema inside `onSubmit`, and bind each field through `form.Field`.
54
+ <% } else { -%>
55
+ ### Native form pattern
56
+
57
+ Keep values in `useState`, run the schema/validator on submit, then call the API helper.
58
+ <% } -%>
59
+
60
+ ## Best practices
61
+
62
+ - **Single source of truth for rules** — schemas in `src/lib`, not duplicated `if` checks in JSX.
63
+ - Validate **on submit** first; add on-blur validation when users need earlier feedback.
64
+ - Map API validation errors (422) back onto fields when the backend returns field paths.
65
+ - Disable the submit button while `isSubmitting` to prevent double posts.
66
+ - Keep forms accessible: real `<label>`, `aria-invalid`, and visible error text.
67
+ - Do not store form drafts in global client state unless the draft must survive across routes.
68
+
69
+ ## Testing tips
70
+
71
+ - Assert validation messages for empty submit.
72
+ - Mock the network boundary (API helper or RTK mutation) and assert the success status region.
73
+ - Prefer `userEvent` over `fireEvent` for realistic typing.
74
+
75
+ ## Related
76
+
77
+ - HTTP / RTK details: `docs/examples/api.md`
78
+ - Live UI: `/feedback`
@@ -2,16 +2,60 @@
2
2
 
3
3
  **Library:** <%= stackLabels.stateManagement %>
4
4
 
5
- **Live demo:** Counter panel on `/`
5
+ **Live demo:** `/counter` `src/features/counter/CounterPanel.<%= jsxExt %>`
6
+ **Store wiring:** `src/store/`
6
7
 
7
8
  ## When to use
8
9
 
9
- Shared interactive state that is not fetched from an API (wizard steps, UI toggles, local counters).
10
+ Shared interactive state that is **not** fetched from an API:
10
11
 
11
- ## Best practice
12
+ - wizard steps, UI toggles, selected tabs
13
+ - ephemeral counters / filters that reset often
14
+ - cross-route UI that should survive navigation but not a full reload
12
15
 
13
- Keep stores/slices focused. Prefer feature-local state; promote to global only when multiple distant trees need it.
16
+ If the data comes from your backend, prefer **<%= stackLabels.serverState %>** instead.
14
17
 
15
- ## Snippet
18
+ ## How to use in this project
16
19
 
17
- See `src/features/counter/CounterPanel.<%= jsxExt %>` and `src/store/`.
20
+ <% if (stateManagement === 'redux') { -%>
21
+ 1. Counter slice lives in `src/store/index.<%= ext %>` (`counterSlice` + `store`).
22
+ 2. Read/write with `useSelector` / `useDispatch` from the feature panel (or add typed hooks later).
23
+
24
+ ```tsx
25
+ import { useDispatch, useSelector } from 'react-redux';
26
+ import { increment, type RootState } from '@/store';
27
+
28
+ const value = useSelector((s: RootState) => s.counter.value);
29
+ const dispatch = useDispatch();
30
+ dispatch(increment());
31
+ ```
32
+ <% } else if (stateManagement === 'zustand') { -%>
33
+ Create/consume the store from `src/store/index.<%= ext %>` with selectors so components only re-render on the slices they need.
34
+
35
+ ```tsx
36
+ import { useCounterStore } from '@/store';
37
+
38
+ const value = useCounterStore((s) => s.value);
39
+ const increment = useCounterStore((s) => s.increment);
40
+ ```
41
+ <% } else if (stateManagement === 'jotai') { -%>
42
+ Define atoms in `src/store/index.<%= ext %>` and compose them. Wrap the tree with `Provider` (already done in `providers.<%= jsxExt %>`).
43
+ <% } else if (stateManagement === 'context') { -%>
44
+ Use the provided context + reducer pattern in `src/store/context`. Keep the context value stable; expose actions through a custom hook.
45
+ <% } else { -%>
46
+ No global client-state library was selected. Prefer React local state until multiple distant trees need the same data.
47
+ <% } -%>
48
+
49
+ ## Best practices
50
+
51
+ - **Feature-local first.** Promote to global only when props drilling becomes painful across routes.
52
+ - **One concern per store/slice.** Avoid a single “appState” blob.
53
+ - **Do not mirror server entities** in client state when you already use <%= stackLabels.serverState %>.
54
+ - Prefer selectors/hooks over reading the entire store in leaf components.
55
+ - Keep side effects (HTTP, analytics) out of reducers; trigger them from thunks/listeners/components.
56
+
57
+ ## Common pitfalls
58
+
59
+ - Putting API responses into Redux/Zustand “because we might need them later”
60
+ - Updating global state on every keystroke in a form (forms belong to <%= stackLabels.forms %>)
61
+ - Forgetting to reset ephemeral UI state when leaving a flow
@@ -5,19 +5,67 @@
5
5
 
6
6
  ## When to use
7
7
 
8
- Establish design tokens early; use a component library for complex accessible primitives.
8
+ Establish design tokens early; use a component library for complex accessible primitives (dialogs, menus, focus traps).
9
9
 
10
- ## Best practice
10
+ ## How to use in this project
11
+
12
+ | Piece | Location |
13
+ |-------|----------|
14
+ | Global styles / tokens | `src/styles/global.<%= styling === 'sass' && uiLibrary !== 'shadcn' ? 'scss' : 'css' %>` |
15
+ | Button adapter | `src/components/ui/UiButton.<%= jsxExt %>` |
16
+ | Layout chrome | `src/components/layout/` |
17
+
18
+ <% if (styling === 'tailwind') { -%>
19
+ ### Tailwind
20
+
21
+ Utility classes are available across the app. Prefer composing utilities in components over one-off CSS files unless the rule is truly global.
22
+
23
+ ```tsx
24
+ <button className="rounded-md bg-slate-900 px-3 py-2 text-white hover:bg-slate-800">
25
+ Save
26
+ </button>
27
+ ```
28
+
29
+ **Best practices**
30
+
31
+ - Extract repeated class clusters into small components (`UiButton`) instead of giant `className` strings everywhere.
32
+ - Keep design tokens (colors, spacing) consistent; avoid magic hex values in features.
33
+ <% } else if (styling === 'css-modules') { -%>
34
+ ### CSS Modules
35
+
36
+ Colocate `*.module.css` next to the component. Import the `styles` object and reference `styles.root`.
37
+ <% } else if (styling === 'styled-components') { -%>
38
+ ### Styled Components
39
+
40
+ Create styled primitives next to the component. Prefer transient props (`$active`) so DOM attributes stay clean.
41
+ <% } else { -%>
42
+ ### Sass/SCSS
43
+
44
+ Shared variables/mixins belong under `src/styles/`. Feature-specific partials can live next to the feature.
45
+ <% } -%>
11
46
 
12
47
  <% if (uiLibrary === 'shadcn') { -%>
13
- Treat shadcn-style primitives as owned source — customize freely, keep `cn()` helpers consistent.
48
+ ## shadcn/ui notes
49
+
50
+ Treat shadcn-style primitives as **owned source** — customize freely, keep `cn()` helpers consistent, and avoid patching node_modules.
14
51
  <% } else if (uiLibrary === 'none') { -%>
15
- Invest in a small set of shared primitives (`UiButton`, layout) before adding a full kit.
52
+ ## No UI kit
53
+
54
+ Invest in a small set of shared primitives (`UiButton`, layout) before adding a full kit. This keeps accessibility and spacing consistent.
16
55
  <% } else { -%>
17
- Wrap third-party components in thin adapters (`UiButton`) so swapping kits later is cheaper.
56
+ ## <%= stackLabels.uiLibrary %> notes
57
+
58
+ Wrap third-party components in thin adapters (`UiButton`) so swapping kits later is cheaper and theme overrides stay centralized (see `providers.<%= jsxExt %>`).
18
59
  <% } -%>
19
60
 
20
- ## Snippet
61
+ ## Best practices
62
+
63
+ - One visual language: spacing, type scale, and radius should feel intentional.
64
+ - Prefer composition over deep CSS specificity wars.
65
+ - Ensure focus states are visible for keyboard users.
66
+ - Keep marketing/landing flair out of app chrome unless product requires it.
67
+
68
+ ## Related
21
69
 
22
- Global styles: `src/styles/global.<%= styling === 'sass' && uiLibrary !== 'shadcn' ? 'scss' : 'css' %>`
23
- Button adapter: `src/components/ui/UiButton.<%= jsxExt %>`
70
+ - Architecture: `docs/architecture.md`
71
+ - Accessibility checklist: `docs/best-practices.md`
@@ -8,20 +8,74 @@
8
8
 
9
9
  ## When to use
10
10
 
11
- - Unit: pure logic + component behavior
12
- - E2E: critical journeys across routes
13
- - Visual: regressions in UI appearance
11
+ | Layer | Use for | Avoid using for |
12
+ |-------|---------|-----------------|
13
+ | Unit / RTL | logic, component behavior, form validation | full auth/payment journeys |
14
+ | E2E | critical user journeys across routes | asserting every CSS class |
15
+ | Visual | regressions in appearance / states | business-rule correctness |
14
16
 
15
- ## Best practice
17
+ ## How to run
16
18
 
17
- Keep e2e thin. Prefer Testing Library queries that reflect how users find elements (`getByRole`, labels).
19
+ <% if (unitTesting !== 'none') { -%>
20
+ ```bash
21
+ <%= packageManager === 'npm' ? 'npm run' : packageManager %> test
22
+ <%= packageManager === 'npm' ? 'npm run' : packageManager %> test:watch
23
+ ```
24
+ <% } -%>
25
+ <% if (e2eTesting === 'playwright') { -%>
26
+ ```bash
27
+ <%= packageManager === 'npm' ? 'npm run' : packageManager %> test:e2e:install # once
28
+ <%= packageManager === 'npm' ? 'npm run' : packageManager %> test:e2e
29
+ <%= packageManager === 'npm' ? 'npm run' : packageManager %> test:e2e:ui
30
+ ```
18
31
 
19
- ## Locations
32
+ E2E base URL: `http://127.0.0.1:<%= buildTool === 'webpack' ? 3000 : 5173 %>`
33
+ <% } else if (e2eTesting === 'cypress') { -%>
34
+ ```bash
35
+ <%= packageManager === 'npm' ? 'npm run' : packageManager %> test:e2e
36
+ ```
37
+ <% } -%>
38
+ <% if (visualTesting === 'storybook') { -%>
39
+ ```bash
40
+ <%= packageManager === 'npm' ? 'npm run' : packageManager %> storybook
41
+ ```
42
+ <% } -%>
43
+
44
+ ## Project layout
20
45
 
21
46
  - Setup: `tests/setup.<%= ext %>` (when applicable)
22
- - Component smoke: `tests/App.test.<%= jsxExt %>`
47
+ - Unit suites: `tests/*.test.<%= jsxExt %>`
23
48
  <% if (e2eTesting === 'playwright') { -%>
24
- - E2E: `tests/e2e/home.spec.<%= ext %>`
49
+ - E2E: `tests/e2e/*.spec.<%= ext %>` (excluded from unit runner)
25
50
  <% } else if (e2eTesting === 'cypress') { -%>
26
- - E2E: `cypress/e2e/home.cy.<%= ext %>`
51
+ - E2E: `cypress/e2e/*`
52
+ <% } -%>
53
+ <% if (visualTesting === 'storybook') { -%>
54
+ - Stories: `src/**/*.stories.<%= jsxExt %>`
27
55
  <% } -%>
56
+
57
+ ## Best practices
58
+
59
+ - Query the way users do: `getByRole`, label text, placeholder — not implementation details.
60
+ - Mock at the **network/domain boundary**:
61
+ <% if (serverState === 'rtk-query') { -%>
62
+ - mock RTK hooks/endpoints for unit tests when you are not integration-testing the store
63
+ <% } else { -%>
64
+ - mock `@/services/api` helpers rather than axios/fetch internals
65
+ <% } -%>
66
+ - Keep e2e **thin**: home load, posts happy path, feedback submit.
67
+ - Do not let unit tests import Playwright specs (unit config excludes `tests/e2e`).
68
+ - For async UI, prefer `findBy*` / `waitFor` over arbitrary `sleep`.
69
+
70
+ ## Example unit test shape
71
+
72
+ ```tsx
73
+ renderWithProviders(<FeedbackForm />);
74
+ await user.click(screen.getByRole('button', { name: /Send feedback/i }));
75
+ expect(screen.getAllByText(/required|valid email/i).length).toBeGreaterThan(0);
76
+ ```
77
+
78
+ ## Related
79
+
80
+ - Strategy & CI: `docs/best-practices.md`
81
+ - Forms guide: `docs/examples/forms.md`
@@ -2,10 +2,13 @@
2
2
 
3
3
  Welcome to **<%= projectName %>**, a React starter generated by `create-react-starter-kit`.
4
4
 
5
+ This guide walks you from first install to extending the app with confidence.
6
+
5
7
  ## Prerequisites
6
8
 
7
- - Node.js 18+
8
- - <%= stackLabels.packageManager %>
9
+ - **Node.js 18+** (20 LTS recommended)
10
+ - **<%= stackLabels.packageManager %>** installed globally or via Corepack
11
+ - A modern browser for the demo UI
9
12
 
10
13
  ## Install & run
11
14
 
@@ -22,26 +25,68 @@ npm run dev
22
25
  <% } -%>
23
26
  ```
24
27
 
28
+ Dev server URL (default): **http://localhost:<%= buildTool === 'webpack' ? 3000 : 5173 %>**
29
+
30
+ Useful scripts:
31
+
32
+ | Script | Purpose |
33
+ |--------|---------|
34
+ | `dev` | Local development server |
35
+ | `build` | Production bundle |
36
+ | `preview` | Serve the production build locally |
37
+ <% if (unitTesting !== 'none') { -%>
38
+ | `test` / `test:watch` | Unit tests |
39
+ <% } -%>
40
+ <% if (e2eTesting !== 'none') { -%>
41
+ | `test:e2e` | End-to-end tests |
42
+ <% } -%>
43
+ <% if (visualTesting === 'storybook') { -%>
44
+ | `storybook` | Component explorer |
45
+ <% } -%>
46
+ | `lint` / `format` | Code quality |
47
+
25
48
  ## Environment variables
26
49
 
27
- Copy `.env.example` → `.env` and fill values. Restart the dev server after changes.
50
+ 1. Copy `.env.example` → `.env`
51
+ 2. Fill values for your environment
52
+ 3. Restart `dev` after changes
28
53
 
29
- Only variables prefixed for your bundler (e.g. `VITE_`) are exposed to the browser. Keep secrets on the server.
54
+ Only client-safe variables (typically `VITE_*`) are exposed to the browser. Never put private API keys in front-end env vars.
55
+
56
+ | Variable | Purpose |
57
+ |----------|---------|
58
+ | `VITE_API_BASE_URL` | REST API base URL (defaults to JSONPlaceholder for demos) |
59
+ <% if (errorTracking === 'sentry') { -%>
60
+ | `VITE_SENTRY_DSN` | Sentry DSN |
61
+ <% } else if (errorTracking === 'bugsnag') { -%>
62
+ | `VITE_BUGSNAG_API_KEY` | Bugsnag API key |
63
+ <% } else if (errorTracking === 'logrocket') { -%>
64
+ | `VITE_LOGROCKET_APP_ID` | LogRocket app id |
65
+ <% } else if (errorTracking === 'datadog') { -%>
66
+ | `VITE_DATADOG_APPLICATION_ID` / `VITE_DATADOG_CLIENT_TOKEN` | Datadog RUM |
67
+ <% } -%>
30
68
 
31
69
  ## What to explore first
32
70
 
33
- 1. Open `/` demo panels for state, data fetching, and forms.
34
- 2. Open `/about` orientation for the folder layout.
35
- 3. Read `docs/selected-stack.md` why each library is present.
36
- 4. Skim `docs/examples/` focused usage notes per concern.
71
+ 1. **`/`**stack badges and orientation
72
+ 2. **`/counter`**client state (<%= stackLabels.stateManagement %>)
73
+ 3. **`/posts`**server state (<%= stackLabels.serverState %>)
74
+ 4. **`/feedback`**forms + validation (<%= stackLabels.forms %> / <%= stackLabels.validation %>)
75
+ 5. **`docs/selected-stack.md`** — why each library was chosen
76
+ 6. **`docs/examples/`** — deep usage guides with copy-paste patterns
37
77
 
38
- ## Extending the app
78
+ ## Extending the app (recommended flow)
39
79
 
40
- - Add a domain under `src/features/<name>/`.
41
- - Register routes in `src/App.<%= jsxExt %>`.
42
- - Put shared UI in `src/components/`.
43
- - Put HTTP clients in `src/services/`.
44
- - Import with `@/` (maps to `src/`), e.g. `import { env } from '@/config/env'`.
80
+ 1. Create a feature folder: `src/features/<domain>/`
81
+ 2. Add UI, hooks, and domain types next to that feature
82
+ 3. Register a route in `src/App.<%= jsxExt %>`
83
+ 4. Put shared primitives in `src/components/`
84
+ <% if (apiLayer === 'none') { -%>
85
+ 5. Add RTK Query endpoints in `src/store/` (or a feature-local `*Api` slice)
86
+ <% } else { -%>
87
+ 5. Add HTTP helpers in `src/services/api.<%= ext %>` (and keep transport details in `src/services/http/`)
88
+ <% } -%>
89
+ 6. Import with `@/` — e.g. `import { env } from '@/config/env'`
45
90
 
46
91
  ## Testing
47
92
 
@@ -51,5 +96,8 @@ Only variables prefixed for your bundler (e.g. `VITE_`) are exposed to the brows
51
96
  <% if (e2eTesting !== 'none') { -%>
52
97
  - E2E: `<%= packageManager === 'npm' ? 'npm run' : packageManager %> test:e2e`
53
98
  <% } -%>
99
+ <% if (visualTesting === 'storybook') { -%>
100
+ - Storybook: `<%= packageManager === 'npm' ? 'npm run' : packageManager %> storybook`
101
+ <% } -%>
54
102
 
55
- See `docs/best-practices.md` for CI and production notes.
103
+ See `docs/best-practices.md` and `docs/examples/testing.md` for strategy and CI notes.
@@ -1,44 +1,146 @@
1
1
  # Selected stack
2
2
 
3
- This document explains each choice made when generating **<%= projectName %>**.
3
+ This document explains each choice made when generating **<%= projectName %>**, how to use it day-to-day, and the practices that keep the codebase maintainable.
4
4
 
5
5
  ## Build — <%= stackLabels.buildTool %>
6
6
 
7
- Fast local feedback and a production bundle. Prefer keeping config minimal; add plugins only when needed.
7
+ <% if (buildTool === 'vite') { -%>
8
+ Vite gives fast HMR and a Rollup-based production build. Config lives in `vite.config.<%= ext %>`.
8
9
 
9
- **Best practice:** lock Node and package manager versions in CI for reproducible builds.
10
+ **Day-to-day:** `<%= packageManager === 'npm' ? 'npm run' : packageManager %> dev` → http://localhost:5173
11
+ <% } else if (buildTool === 'webpack') { -%>
12
+ Webpack is configured in `webpack.config.js` with Babel (or TS pipeline), HtmlWebpackPlugin, and a dev server.
13
+
14
+ **Day-to-day:** `<%= packageManager === 'npm' ? 'npm run' : packageManager %> dev` → http://localhost:3000
15
+ <% } else { -%>
16
+ Your bundler is wired with scripts in `package.json`. Prefer keeping config minimal; add plugins only when needed.
17
+ <% } -%>
18
+
19
+ **Best practices**
20
+
21
+ - Lock Node and package manager versions in CI.
22
+ - Treat `build` as the source of truth for production issues (not only `dev`).
23
+ - Keep path aliases (`@/`) in sync between TS config and the bundler.
10
24
 
11
25
  ## Language — <%= stackLabels.language %>
12
26
 
13
27
  <% if (isTypeScript) { -%>
14
- TypeScript catches contract mistakes early. Keep `strict` on; avoid `any` except at true boundaries.
28
+ TypeScript catches contract mistakes early. Keep `strict` on; avoid `any` except at true boundaries (third-party quirks, gradual migrations).
29
+
30
+ **Pattern:** model API payloads in `src/types/models.<%= ext %>`, not inline in components.
15
31
  <% } else { -%>
16
- JavaScript keeps the barrier low. Consider migrating hot modules to TypeScript as the app grows.
32
+ JavaScript keeps the barrier low. Prefer JSDoc for public helpers, and consider migrating hot modules to TypeScript as the app grows.
17
33
  <% } -%>
18
34
 
19
35
  ## Routing — <%= stackLabels.router %>
20
36
 
21
37
  Client-side navigation with nested layouts. Keep route modules thin; push data loading into features.
22
38
 
39
+ **Best practices**
40
+
41
+ - Colocate route-level UI under `src/routes/`.
42
+ - Avoid fetching in layout components unless every child needs the data.
43
+ - Use loading/error UI at the feature boundary.
44
+
23
45
  ## Client state — <%= stackLabels.stateManagement %>
24
46
 
25
47
  Use for UI state (modals, wizards, ephemeral counters). Do **not** mirror server entities here if you have a server-state library.
26
48
 
49
+ **Live demo:** `/counter` → `src/features/counter/`
50
+
51
+ **Best practices**
52
+
53
+ - Feature-local state first; promote to global only when multiple distant trees need it.
54
+ - Keep stores/slices focused on one domain.
55
+ - Prefer selectors/hooks over reading the whole store in components.
56
+
27
57
  ## Server state — <%= stackLabels.serverState %>
28
58
 
29
- Caches remote data, handles loading/error, and deduplicates requests. Example: posts panel on the home page.
59
+ Caches remote data, handles loading/error, and deduplicates requests.
60
+
61
+ **Live demo:** `/posts` → `src/features/posts/PostsPanel.<%= jsxExt %>`
62
+
63
+ <% if (serverState === 'rtk-query') { -%>
64
+ **How to use**
65
+
66
+ 1. Define endpoints in `src/store/postsApi.<%= ext %>` (or a new `*Api` slice).
67
+ 2. Export hooks (`useGetPostsQuery`, `useCreateFeedbackMutation`).
68
+ 3. Call hooks from features — no manual `useEffect` fetching.
69
+
70
+ **Best practices**
71
+
72
+ - Use `tagTypes` + `providesTags` / `invalidatesTags` for cache coherence.
73
+ - Put auth headers in `prepareHeaders`, not in every endpoint.
74
+ - Prefer mutations for writes; invalidate related query tags after success.
75
+ <% } else if (serverState === 'tanstack-query') { -%>
76
+ **How to use**
77
+
78
+ ```tsx
79
+ const { data, isLoading, error, refetch } = useQuery({
80
+ queryKey: ['posts'],
81
+ queryFn: ({ signal }) => fetchPosts(signal),
82
+ });
83
+ ```
84
+
85
+ **Best practices**
86
+
87
+ - Stable, hierarchical query keys: `['posts']`, `['posts', id]`.
88
+ - Pass `signal` into your HTTP helpers so navigations cancel in-flight work.
89
+ - Keep `queryFn` thin — call domain API helpers, not raw HTTP.
90
+ <% } else if (serverState === 'swr') { -%>
91
+ **How to use**
92
+
93
+ SWR is configured in `providers.<%= jsxExt %>` with a shared `fetcher`. Components call `useSWR(key)`.
94
+
95
+ **Best practices**
96
+
97
+ - Keys should be URLs or stable resource identifiers.
98
+ - Use `mutate` for local revalidation after writes.
99
+ <% } else { -%>
100
+ No dedicated server-state library was selected. Prefer adding one before the app grows past a few screens.
101
+ <% } -%>
30
102
 
31
103
  ## Forms — <%= stackLabels.forms %> / Validation — <%= stackLabels.validation %>
32
104
 
33
105
  Schemas define the contract; the form library binds inputs. Share schemas with API payloads when possible.
34
106
 
107
+ **Live demo:** `/feedback` → `src/features/feedback/FeedbackForm.<%= jsxExt %>`
108
+ **Schemas:** `src/lib/validation.<%= ext %>`
109
+
110
+ **Best practices**
111
+
112
+ - Validate on submit (and optionally on blur) — avoid blocking every keystroke unless UX requires it.
113
+ - Keep error messages user-facing; log technical details separately.
114
+ - Reuse the same schema on the server if you own both sides.
115
+
35
116
  ## Styling — <%= stackLabels.styling %> / UI — <%= stackLabels.uiLibrary %>
36
117
 
37
118
  Tokens and primitives establish visual consistency. Prefer composition over one-off CSS.
38
119
 
120
+ **Best practices**
121
+
122
+ - Wrap third-party primitives in thin adapters (`UiButton`) so swapping kits later is cheaper.
123
+ - Keep global tokens in `src/styles/`; keep feature-specific styles close to the feature.
124
+
39
125
  ## API — <%= stackLabels.apiLayer %>
40
126
 
41
- Centralize base URL, headers, and error logging in `src/services/api.<%= ext %>`.
127
+ <% if (apiLayer === 'none') { -%>
128
+ HTTP is owned by **RTK Query** (`fetchBaseQuery`). There is intentionally **no** separate Axios/Fetch client in this project.
129
+
130
+ See `docs/examples/data-fetching.md` and `src/store/postsApi.<%= ext %>`.
131
+ <% } else if (apiLayer === 'axios') { -%>
132
+ Axios is configured under `src/services/http/` with:
133
+
134
+ - request interceptors (auth token, request IDs)
135
+ - response interceptors (normalized `ApiError`, 401 event)
136
+ - domain helpers in `src/services/api.<%= ext %>`
137
+
138
+ See `docs/examples/api.md` for patterns and examples.
139
+ <% } else { -%>
140
+ A shared Fetch wrapper lives under `src/services/http/` with timeout, auth headers, request IDs, and normalized `ApiError`s. Domain helpers sit in `src/services/api.<%= ext %>`.
141
+
142
+ See `docs/examples/api.md` for patterns and examples.
143
+ <% } -%>
42
144
 
43
145
  ## Quality gates
44
146
 
@@ -52,4 +154,4 @@ Centralize base URL, headers, and error logging in `src/services/api.<%= ext %>`
52
154
  | Git hooks | Husky + lint-staged + commitlint |
53
155
  | Structure | Feature-based + `@/` aliases |
54
156
 
55
- See `docs/examples/` for focused usage notes.
157
+ See `docs/examples/` for focused usage notes with deeper examples.
@@ -32,7 +32,11 @@ import { validateFeedback<% if (isTypeScript) { %>, type FeedbackValues<% } %> }
32
32
  import { feedbackSchema<% if (isTypeScript) { %>, type FeedbackValues<% } %> } from '@/lib/validation';
33
33
  <% } -%>
34
34
  <% } -%>
35
+ <% if (serverState === 'rtk-query') { -%>
36
+ import { useCreateFeedbackMutation } from '@/store/postsApi';
37
+ <% } else { -%>
35
38
  import { createFeedback } from '@/services/api';
39
+ <% } -%>
36
40
  import { UiButton } from '@/components/ui/UiButton';
37
41
 
38
42
  const defaults<% if (isTypeScript) { %>: FeedbackValues<% } %> = {
@@ -43,6 +47,12 @@ const defaults<% if (isTypeScript) { %>: FeedbackValues<% } %> = {
43
47
 
44
48
  export function FeedbackForm() {
45
49
  const [status, setStatus] = useState<% if (isTypeScript) { %><string | null><% } %>(null);
50
+ <% if (serverState === 'rtk-query') { -%>
51
+ const [createFeedbackMutation] = useCreateFeedbackMutation();
52
+ const createFeedback = async (values<% if (isTypeScript) { %>: FeedbackValues<% } %>) => {
53
+ await createFeedbackMutation(values).unwrap();
54
+ };
55
+ <% } -%>
46
56
 
47
57
  <% if (forms === 'react-hook-form') { -%>
48
58
  const {
@@ -14,7 +14,7 @@ export function PostsPanel() {
14
14
  <% if (serverState === 'tanstack-query') { -%>
15
15
  const { data, isLoading, error, refetch, isFetching } = useQuery({
16
16
  queryKey: ['posts'],
17
- queryFn: fetchPosts,
17
+ queryFn: ({ signal }) => fetchPosts(signal),
18
18
  });
19
19
  <% } else if (serverState === 'swr') { -%>
20
20
  const { data, error, isLoading, isValidating, mutate } = useSWR('/posts?_limit=5');
@@ -7,8 +7,13 @@ export function PostsPage() {
7
7
  <p className="eyebrow">Server state</p>
8
8
  <h1>Posts</h1>
9
9
  <p className="lede">
10
- Fetches sample posts via <strong><%= stackLabels.serverState === 'None' ? stackLabels.apiLayer : stackLabels.serverState %></strong>{' '}
11
- and <strong><%= stackLabels.apiLayer %></strong>.
10
+ Fetches sample posts via <strong><%= stackLabels.serverState === 'None' ? stackLabels.apiLayer : stackLabels.serverState %></strong>
11
+ <% if (apiLayer !== 'none' && serverState !== 'rtk-query') { -%>
12
+ {' '}and <strong><%= stackLabels.apiLayer %></strong>
13
+ <% } else if (serverState === 'rtk-query') { -%>
14
+ {' '}(HTTP via <code>fetchBaseQuery</code>)
15
+ <% } -%>
16
+ .
12
17
  </p>
13
18
  </header>
14
19
  <PostsPanel />
@@ -1,6 +1,6 @@
1
1
  <% if (isTypeScript) { -%>
2
2
  /** Shared domain types used across features. */
3
- export type { Post } from '@/services/api';
3
+ export type { Post, FeedbackPayload } from './models';
4
4
  <% } else { -%>
5
5
  // Shared types live here when you migrate hot paths to TypeScript.
6
6
  export {};
@@ -0,0 +1,18 @@
1
+ <% if (isTypeScript) { -%>
2
+ /** Shared domain models used by features and the HTTP / RTK layers. */
3
+ export interface Post {
4
+ userId: number;
5
+ id: number;
6
+ title: string;
7
+ body: string;
8
+ }
9
+
10
+ export interface FeedbackPayload {
11
+ name: string;
12
+ email: string;
13
+ message: string;
14
+ }
15
+ <% } else { -%>
16
+ // Shared domain models live here when you migrate hot paths to TypeScript.
17
+ export {};
18
+ <% } -%>