@activatus/code-standards 0.0.0-stage → 3.0.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 (180) hide show
  1. package/README.md +199 -2
  2. package/docs/Guides/_category_.json +4 -0
  3. package/docs/Guides/component-library-workflow.md +182 -0
  4. package/docs/Guides/migrating.md +161 -0
  5. package/docs/Guides/setup.md +158 -0
  6. package/docs/Standards/_category_.json +4 -0
  7. package/docs/Standards/agent-skills.md +125 -0
  8. package/docs/Standards/agent-specs.md +74 -0
  9. package/docs/Standards/direnv.mdx +249 -0
  10. package/docs/Standards/documentation.md +314 -0
  11. package/docs/Standards/editorconfig.md +74 -0
  12. package/docs/Standards/eslint.md +900 -0
  13. package/docs/Standards/human-readable-names.md +274 -0
  14. package/docs/Standards/lint-errors.md +171 -0
  15. package/docs/Standards/prettier.md +106 -0
  16. package/docs/Standards/readable-code.md +570 -0
  17. package/docs/Standards/stylelint.md +193 -0
  18. package/docs/Standards/styling.md +290 -0
  19. package/docs/Standards/tech-stack.md +158 -0
  20. package/docs/Structure/_category_.json +4 -0
  21. package/docs/Structure/api-routes.md +118 -0
  22. package/docs/Structure/component-organization.md +526 -0
  23. package/docs/Structure/folder-structure.md +366 -0
  24. package/docs/Structure/import-organization.md +158 -0
  25. package/docs/Structure/naming-conventions.md +334 -0
  26. package/docs/design-system-components.md +117 -0
  27. package/docs/intro.md +44 -0
  28. package/docs/ontology.md +127 -0
  29. package/docs/templates.mdx +396 -0
  30. package/docs/version-history.md +338 -0
  31. package/package.json +60 -3
  32. package/scripts/renameSymbol.mjs +188 -0
  33. package/static/templates/.editorconfig +25 -0
  34. package/static/templates/.envrc +25 -0
  35. package/static/templates/.nvmrc +1 -0
  36. package/static/templates/AGENTS.md +163 -0
  37. package/static/templates/decision-doc.md +19 -0
  38. package/static/templates/docs/ai/agent-harness.md +17 -0
  39. package/static/templates/docs/ai/agents.md +17 -0
  40. package/static/templates/docs/ai/architecture.md +17 -0
  41. package/static/templates/docs/ai/context.md +17 -0
  42. package/static/templates/docs/ai/model-routing.md +17 -0
  43. package/static/templates/docs/ai/models.md +17 -0
  44. package/static/templates/docs/ai/retrieval.md +17 -0
  45. package/static/templates/docs/ai/tools.md +17 -0
  46. package/static/templates/docs/architecture/authentication.md +17 -0
  47. package/static/templates/docs/architecture/backend.md +17 -0
  48. package/static/templates/docs/architecture/background-jobs.md +17 -0
  49. package/static/templates/docs/architecture/backups.md +17 -0
  50. package/static/templates/docs/architecture/caching.md +17 -0
  51. package/static/templates/docs/architecture/ci-cd.md +17 -0
  52. package/static/templates/docs/architecture/disaster-recovery.md +17 -0
  53. package/static/templates/docs/architecture/environments.md +17 -0
  54. package/static/templates/docs/architecture/frontend.md +17 -0
  55. package/static/templates/docs/architecture/hosting.md +17 -0
  56. package/static/templates/docs/architecture/observability.md +17 -0
  57. package/static/templates/docs/architecture/realtime.md +17 -0
  58. package/static/templates/docs/architecture/search.md +17 -0
  59. package/static/templates/docs/architecture/services.md +17 -0
  60. package/static/templates/docs/architecture/state-management.md +17 -0
  61. package/static/templates/docs/architecture/storage.md +17 -0
  62. package/static/templates/docs/architecture/system.md +17 -0
  63. package/static/templates/docs/business/buying-trigger.md +17 -0
  64. package/static/templates/docs/business/customer-value.md +17 -0
  65. package/static/templates/docs/business/customer.md +17 -0
  66. package/static/templates/docs/business/defensibility.md +17 -0
  67. package/static/templates/docs/business/growth.md +17 -0
  68. package/static/templates/docs/business/pricing.md +17 -0
  69. package/static/templates/docs/business/revenue-model.md +17 -0
  70. package/static/templates/docs/business/unit-economics.md +17 -0
  71. package/static/templates/docs/data/analytics.md +17 -0
  72. package/static/templates/docs/data/audit.md +17 -0
  73. package/static/templates/docs/data/database.md +17 -0
  74. package/static/templates/docs/data/indexing.md +17 -0
  75. package/static/templates/docs/data/migrations.md +17 -0
  76. package/static/templates/docs/data/model.md +17 -0
  77. package/static/templates/docs/data/retention.md +17 -0
  78. package/static/templates/docs/data/schema.md +17 -0
  79. package/static/templates/docs/deployment/approval.md +17 -0
  80. package/static/templates/docs/deployment/live-verification.md +17 -0
  81. package/static/templates/docs/deployment/process.md +17 -0
  82. package/static/templates/docs/deployment/rollback.md +17 -0
  83. package/static/templates/docs/design/design-system.md +17 -0
  84. package/static/templates/docs/design/errors.md +17 -0
  85. package/static/templates/docs/design/feedback.md +17 -0
  86. package/static/templates/docs/design/interactions.md +17 -0
  87. package/static/templates/docs/design/layout.md +17 -0
  88. package/static/templates/docs/design/navigation.md +17 -0
  89. package/static/templates/docs/design/principles.md +17 -0
  90. package/static/templates/docs/design/responsive.md +17 -0
  91. package/static/templates/docs/development/branching.md +17 -0
  92. package/static/templates/docs/development/code-quality.md +17 -0
  93. package/static/templates/docs/development/coding-standards.md +21 -0
  94. package/static/templates/docs/development/commits.md +17 -0
  95. package/static/templates/docs/development/merge-strategy.md +17 -0
  96. package/static/templates/docs/development/process.md +17 -0
  97. package/static/templates/docs/development/pull-requests.md +17 -0
  98. package/static/templates/docs/experience/accessibility.md +17 -0
  99. package/static/templates/docs/experience/aha-moment.md +17 -0
  100. package/static/templates/docs/experience/anti-experience.md +17 -0
  101. package/static/templates/docs/experience/friction.md +17 -0
  102. package/static/templates/docs/experience/outcomes.md +17 -0
  103. package/static/templates/docs/experience/principles.md +17 -0
  104. package/static/templates/docs/experience/retention.md +17 -0
  105. package/static/templates/docs/experience/sharing.md +17 -0
  106. package/static/templates/docs/overview/how-it-works.md +17 -0
  107. package/static/templates/docs/overview/what-is-it.md +17 -0
  108. package/static/templates/docs/overview/writing-docs.md +16 -0
  109. package/static/templates/docs/pitch/alternatives.md +17 -0
  110. package/static/templates/docs/pitch/assumptions.md +17 -0
  111. package/static/templates/docs/pitch/audience.md +17 -0
  112. package/static/templates/docs/pitch/concept.md +17 -0
  113. package/static/templates/docs/pitch/differentiators.md +17 -0
  114. package/static/templates/docs/pitch/outcomes.md +17 -0
  115. package/static/templates/docs/pitch/problem.md +17 -0
  116. package/static/templates/docs/pitch/product-market-fit.md +17 -0
  117. package/static/templates/docs/pitch/success-criteria.md +17 -0
  118. package/static/templates/docs/pitch/validation.md +17 -0
  119. package/static/templates/docs/pitch/value-proposition.md +17 -0
  120. package/static/templates/docs/pitch/vision.md +17 -0
  121. package/static/templates/docs/scope/core.md +17 -0
  122. package/static/templates/docs/scope/exclusions.md +17 -0
  123. package/static/templates/docs/scope/future.md +17 -0
  124. package/static/templates/docs/scope/launch.md +17 -0
  125. package/static/templates/docs/scope/post-launch.md +17 -0
  126. package/static/templates/docs/scope/priorities.md +17 -0
  127. package/static/templates/docs/scope/quality-bar.md +17 -0
  128. package/static/templates/docs/security/audit.md +17 -0
  129. package/static/templates/docs/security/data-access.md +17 -0
  130. package/static/templates/docs/security/logging.md +17 -0
  131. package/static/templates/docs/security/privacy.md +17 -0
  132. package/static/templates/docs/security/secrets.md +17 -0
  133. package/static/templates/docs/security/threat-model.md +17 -0
  134. package/static/templates/docs/testing/end-to-end.md +17 -0
  135. package/static/templates/docs/testing/integration.md +17 -0
  136. package/static/templates/docs/testing/regression.md +17 -0
  137. package/static/templates/docs/testing/security.md +17 -0
  138. package/static/templates/docs/testing/strategy.md +17 -0
  139. package/static/templates/docs/testing/test-data.md +17 -0
  140. package/static/templates/docs/testing/unit.md +17 -0
  141. package/static/templates/docs/uat/checks.md +17 -0
  142. package/static/templates/docs/uat/strategy.md +17 -0
  143. package/static/templates/docs/users/permissions.md +17 -0
  144. package/static/templates/docs/users/roles.md +17 -0
  145. package/static/templates/docs/users/user-types.md +17 -0
  146. package/static/templates/docs/workflows/assignment.md +17 -0
  147. package/static/templates/docs/workflows/bugfix.md +17 -0
  148. package/static/templates/docs/workflows/dependencies.md +17 -0
  149. package/static/templates/docs/workflows/deployment.md +17 -0
  150. package/static/templates/docs/workflows/development.md +17 -0
  151. package/static/templates/docs/workflows/planning.md +17 -0
  152. package/static/templates/docs/workflows/review.md +17 -0
  153. package/static/templates/docs/workflows/uat.md +17 -0
  154. package/static/templates/docsSite/docusaurus.config.mjs +144 -0
  155. package/static/templates/docsSite/gitignore.txt +3 -0
  156. package/static/templates/docsSite/package.json.txt +42 -0
  157. package/static/templates/docsSite/pnpm-workspace.yaml +2 -0
  158. package/static/templates/docsSite/sidebars.mjs +7 -0
  159. package/static/templates/docsSite/src/css/custom.css +7 -0
  160. package/static/templates/docsSite/src/pages/index.tsx +9 -0
  161. package/static/templates/docsSite/static/images/logo.svg +4 -0
  162. package/static/templates/docsSite/tsconfig.json +7 -0
  163. package/static/templates/eslint/base/eslint.config.mjs +104 -0
  164. package/static/templates/eslint/nextjs/eslint.config.mjs +181 -0
  165. package/static/templates/eslint/react/eslint.config.mjs +173 -0
  166. package/static/templates/eslint/typescript/eslint.config.mjs +154 -0
  167. package/static/templates/globals.css +16 -0
  168. package/static/templates/husky/pre-commit +1 -0
  169. package/static/templates/next.config.mjs +21 -0
  170. package/static/templates/prettier.config.mjs +26 -0
  171. package/static/templates/skills/codeReview.md +31 -0
  172. package/static/templates/skills/format.md +18 -0
  173. package/static/templates/skills/lint.md +21 -0
  174. package/static/templates/skills/lintFix.md +24 -0
  175. package/static/templates/skills/securityAudit.md +28 -0
  176. package/static/templates/skills/test.md +24 -0
  177. package/static/templates/skills/typescript.md +28 -0
  178. package/static/templates/skills/updateLayout.md +20 -0
  179. package/static/templates/stylelint/css/stylelint.config.mjs +40 -0
  180. package/static/templates/stylelint/scss/stylelint.config.mjs +13 -0
@@ -0,0 +1,118 @@
1
+ ---
2
+ sidebar_position: 1
3
+ ---
4
+
5
+ # API Route Standards
6
+
7
+ Standards for organizing and naming Next.js App Router API routes.
8
+
9
+ ---
10
+
11
+ ## 🌐 Next.js App Router API Routes
12
+
13
+ API routes in Next.js 16 use the App Router with a file-based routing system.
14
+
15
+ ---
16
+
17
+ ## ✅ Folder Structure
18
+
19
+ **Use kebab-case for API route folders:**
20
+
21
+ ```text
22
+ app/api/
23
+ ├── calendar-events/
24
+ │ └── route.ts # GET, POST, PUT, DELETE
25
+ ├── webhooks/
26
+ │ ├── stripe/
27
+ │ │ └── route.ts
28
+ │ └── recall/
29
+ │ └── route.ts
30
+ └── oauth-callback/
31
+ └── google-calendar/
32
+ └── route.ts
33
+ ```
34
+
35
+ ### Organization Principles
36
+
37
+ - **Group by domain** - Related endpoints in the same folder
38
+ - **Use kebab-case** - All lowercase with hyphens
39
+ - **Nest when needed** - Sub-folders for logical grouping
40
+ - **Avoid redundancy** - Don't repeat "api" or "route" in folder names
41
+
42
+ ---
43
+
44
+ ## ✅ File Naming
45
+
46
+ **Always use `route.ts`:**
47
+
48
+ ```typescript
49
+ // ✅ Correct
50
+ app / api / users / route.ts;
51
+
52
+ // ❌ Incorrect
53
+ app / api / users.ts;
54
+ app / api / Users / route.ts;
55
+ app / api / user - management / route.ts; // avoid redundant strings
56
+ ```
57
+
58
+ ---
59
+
60
+ ## 🗂️ Route Patterns
61
+
62
+ ### Simple Routes
63
+
64
+ ```text
65
+ app/api/
66
+ ├── users/
67
+ │ └── route.ts # /api/users
68
+ ├── posts/
69
+ │ └── route.ts # /api/posts
70
+ └── comments/
71
+ └── route.ts # /api/comments
72
+ ```
73
+
74
+ ### Dynamic Routes
75
+
76
+ ```text
77
+ app/api/
78
+ ├── users/
79
+ │ └── [id]/
80
+ │ └── route.ts # /api/users/123
81
+ └── posts/
82
+ └── [slug]/
83
+ └── route.ts # /api/posts/my-post
84
+ ```
85
+
86
+ ### Nested Routes
87
+
88
+ ```text
89
+ app/api/
90
+ ├── webhooks/
91
+ │ ├── stripe/
92
+ │ │ └── route.ts # /api/webhooks/stripe
93
+ │ └── github/
94
+ │ └── route.ts # /api/webhooks/github
95
+ └── integrations/
96
+ └── calendar/
97
+ └── events/
98
+ └── route.ts # /api/integrations/calendar/events
99
+ ```
100
+
101
+ ---
102
+
103
+ ## 🔒 Security Best Practices
104
+
105
+ - **Validate input** - Use Zod schemas
106
+ - **Handle errors** - Try/catch with proper error responses
107
+ - **Rate limiting** - Implement rate limits for public endpoints
108
+ - **Authentication** - Check user permissions
109
+ - **CORS** - Configure properly for API routes
110
+ - **Environment variables** - Never log sensitive data
111
+
112
+ ---
113
+
114
+ ## 📚 Related Documentation
115
+
116
+ - [Folder Structure](/Structure/folder-structure) - Overall project structure
117
+ - [Naming Conventions](/Structure/naming-conventions) - File and folder naming
118
+ - [TypeScript](/Standards/tech-stack) - Type safety standards
@@ -0,0 +1,526 @@
1
+ ---
2
+ sidebar_position: 2
3
+ ---
4
+
5
+ # Component Organization
6
+
7
+ Each component should be self-contained with all related files in its own folder.
8
+
9
+ ## ✅ Recommended Component Structure
10
+
11
+ ```text
12
+ components/
13
+ └── button/ # camelCase folder
14
+ ├── Button.tsx # Component implementation
15
+ ├── Button.test.tsx # Unit tests
16
+ ├── Button.stories.tsx # Storybook stories
17
+ ├── utils/ # Functions used only by this component
18
+ │ ├── getButtonLabel/
19
+ │ │ ├── getButtonLabel.ts
20
+ │ │ ├── getButtonLabel.test.ts
21
+ │ │ └── index.ts
22
+ │ └── index.ts # Exports every function
23
+ ├── types.ts # Component types
24
+ └── index.ts # Public API export
25
+ ```
26
+
27
+ ## Benefits
28
+
29
+ - **Co-located related files** - Everything for one component in one place
30
+ - **Easy to move/delete** - Just drag the folder
31
+ - **Clear boundaries** - Know exactly where code lives
32
+ - **Simple to understand** - New developers can navigate quickly
33
+
34
+ ---
35
+
36
+ ## 📄 `index.ts` Pattern
37
+
38
+ The `index.ts` file defines the component's public API and makes imports cleaner.
39
+
40
+ ### Example
41
+
42
+ ```typescript
43
+ // components/button/index.ts
44
+ export { Button } from "./Button";
45
+ export type { ButtonProps } from "./types";
46
+ ```
47
+
48
+ ### Usage
49
+
50
+ ```typescript
51
+ // Clean import from component folder
52
+ import { Button } from "@/components/ui/button";
53
+
54
+ // Instead of:
55
+ import { Button } from "@/components/ui/button/Button";
56
+ ```
57
+
58
+ ## Export Guidelines
59
+
60
+ - ✅ **Export public API only** - What users of the component need
61
+ - ✅ **Re-export types** - Convenience for TypeScript users
62
+ - ✅ **Keep imports clean** - Simple, predictable import paths
63
+ - ✅ **Document public exports** - Comments for exported items
64
+
65
+ ---
66
+
67
+ ## File Breakdown
68
+
69
+ ### 📝 `Component.tsx`
70
+
71
+ The main component implementation with JSX and logic.
72
+
73
+ ```typescript
74
+ // Button.tsx
75
+ import type { ButtonProps } from './types';
76
+
77
+ export const Button = ({ children, variant, size, ...buttonProps }: ButtonProps) => {
78
+ return (
79
+ <button className={`button button-${variant}`} {...buttonProps}>
80
+ {children}
81
+ </button>
82
+ );
83
+ };
84
+ ```
85
+
86
+ ### 🧪 `Component.test.tsx`
87
+
88
+ Unit tests using Vitest & Testing Library.
89
+
90
+ ```typescript
91
+ // Button.test.tsx
92
+ import { render, screen } from '@testing-library/react';
93
+ import { describe, it, expect } from 'vitest';
94
+ import { Button } from './Button';
95
+
96
+ describe('Button', () => {
97
+ it('renders children', () => {
98
+ render(<Button>Click me</Button>);
99
+ expect(screen.getByText('Click me')).toBeInTheDocument();
100
+ });
101
+ });
102
+ ```
103
+
104
+ ### 📖 `Component.stories.tsx`
105
+
106
+ Storybook stories for documentation and visual testing.
107
+
108
+ ```typescript
109
+ // Button.stories.tsx
110
+ import type { Meta, StoryObj } from "@storybook/react";
111
+ import { Button } from "./Button";
112
+
113
+ const meta = {
114
+ title: "Components/Button",
115
+ component: Button,
116
+ } satisfies Meta<typeof Button>;
117
+
118
+ export default meta;
119
+ type StoryType = StoryObj<typeof Button>;
120
+
121
+ export const Primary: StoryType = {
122
+ args: {
123
+ children: "Primary Button",
124
+ variant: "primary",
125
+ },
126
+ };
127
+ ```
128
+
129
+ ### 📋 `types.ts`
130
+
131
+ TypeScript type definitions.
132
+
133
+ ```typescript
134
+ // types.ts
135
+ export interface ButtonProps {
136
+ children: React.ReactNode;
137
+ variant?: "primary" | "secondary" | "danger";
138
+ size?: "small" | "medium" | "large";
139
+ onClick?: () => void;
140
+ }
141
+ ```
142
+
143
+ ### 📦 `index.ts`
144
+
145
+ Public API exports - the barrel file.
146
+
147
+ ```typescript
148
+ // index.ts
149
+ export { Button } from "./Button";
150
+ export type { ButtonProps } from "./types";
151
+ ```
152
+
153
+ ---
154
+
155
+ ## 🧱 Writing a component
156
+
157
+ Every component file is laid out in the same order, so a reader always knows where to look.
158
+
159
+ | # | Section | Rule |
160
+ | --- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
161
+ | 1 | Imports | Ordered per [Import Organization](/Structure/import-organization) |
162
+ | 2 | Component | The component is the first thing in the file after the imports. Always an [arrow function](/Standards/readable-code#arrow-functions-everywhere) — [never a class](/Standards/readable-code#functions-never-classes) |
163
+ | 3 | Variable declarations | Plain values worked out from props |
164
+ | 4 | State declarations | `useState`, `useReducer`, `useRef` |
165
+ | 5 | Calculated values | Wrapped in `useMemo` |
166
+ | 6 | Nested functions | Only functions that need the component's state or props, wrapped in `useCallback` |
167
+ | 7 | Effects | `useEffect` |
168
+ | 8 | Render logic | The `return`. No inline functions |
169
+
170
+ ### Example
171
+
172
+ ```tsx title="UserListClient.tsx"
173
+ "use client";
174
+
175
+ // 1. Imports
176
+ import type { ChangeEvent } from "react";
177
+ import { useCallback, useEffect, useMemo, useState } from "react";
178
+
179
+ import type { UserListClientProps } from "./types";
180
+ import { UserListItem } from "./userListItem";
181
+ import { filterUsersByName } from "./utils";
182
+
183
+ // 2. The component is the first thing in the file
184
+ export const UserListClient = ({
185
+ users,
186
+ onUserSelect,
187
+ }: UserListClientProps) => {
188
+ // 3. Variable declarations
189
+ const totalUserCount = users.length;
190
+
191
+ // 4. State declarations
192
+ const [searchText, setSearchText] = useState("");
193
+
194
+ // 5. Calculated values, wrapped in useMemo
195
+ const visibleUsers = useMemo(
196
+ () => filterUsersByName({ users, searchText }),
197
+ [users, searchText],
198
+ );
199
+
200
+ // 6. Nested functions, wrapped in useCallback
201
+ const handleSearchTextChange = useCallback(
202
+ (event: ChangeEvent<HTMLInputElement>) => {
203
+ setSearchText(event.target.value);
204
+ },
205
+ [],
206
+ );
207
+
208
+ // 7. Effects
209
+ useEffect(() => {
210
+ document.title = `${visibleUsers.length} of ${totalUserCount} users`;
211
+ }, [visibleUsers.length, totalUserCount]);
212
+
213
+ // 8. Render logic — no inline functions
214
+ return (
215
+ <section className="bg-surface text-text">
216
+ <input value={searchText} onChange={handleSearchTextChange} />
217
+ <ul>
218
+ {visibleUsers.map((user) => (
219
+ <UserListItem
220
+ key={user.id}
221
+ user={user}
222
+ onUserSelect={onUserSelect}
223
+ />
224
+ ))}
225
+ </ul>
226
+ </section>
227
+ );
228
+ };
229
+ ```
230
+
231
+ ### Keep the UI file clean
232
+
233
+ **If a function can be written in another file, move it out of the UI file.** A function that does not need the component's state or props is not a nested function — it belongs in a [utils folder](/Structure/folder-structure#-utils).
234
+
235
+ `filterUsersByName` above only needs its arguments, so it lives in the component's `utils/` folder, in its own folder beside its test file:
236
+
237
+ ```text
238
+ userList/
239
+ ├── UserListClient.tsx
240
+ └── utils/
241
+ ├── filterUsersByName/
242
+ │ ├── filterUsersByName.ts
243
+ │ ├── filterUsersByName.test.ts
244
+ │ └── index.ts
245
+ └── index.ts
246
+ ```
247
+
248
+ ```ts title="utils/filterUsersByName/filterUsersByName.ts"
249
+ import type { UserType } from "../../types";
250
+
251
+ interface FilterUsersByNameProps {
252
+ users: UserType[];
253
+ searchText: string;
254
+ }
255
+
256
+ export const filterUsersByName = ({
257
+ users,
258
+ searchText,
259
+ }: FilterUsersByNameProps) => {
260
+ const lowerCaseSearchText = searchText.toLowerCase();
261
+
262
+ return users.filter((user) =>
263
+ user.name.toLowerCase().includes(lowerCaseSearchText),
264
+ );
265
+ };
266
+ ```
267
+
268
+ Each function folder has an `index.ts`, and so does the `utils/` folder — both are one line:
269
+
270
+ ```ts title="utils/filterUsersByName/index.ts"
271
+ export { filterUsersByName } from "./filterUsersByName";
272
+ ```
273
+
274
+ ```ts title="utils/index.ts"
275
+ export { filterUsersByName } from "./filterUsersByName";
276
+ ```
277
+
278
+ The component imports it from the folder: `import { filterUsersByName } from "./utils";`
279
+
280
+ ### No inline functions in render
281
+
282
+ Never define a function inside the JSX. Declare it above with `useCallback` and pass it by name:
283
+
284
+ ```tsx
285
+ // ✅ Good
286
+ const handleSearchTextChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
287
+ setSearchText(event.target.value);
288
+ }, []);
289
+
290
+ <input value={searchText} onChange={handleSearchTextChange} />
291
+
292
+ // ❌ Bad
293
+ <input value={searchText} onChange={(event) => setSearchText(event.target.value)} />
294
+ ```
295
+
296
+ When each item in a list needs its own handler, give the item its own component rather than writing an inline function in the loop:
297
+
298
+ ```tsx title="userListItem/UserListItem.tsx"
299
+ import { useCallback } from "react";
300
+
301
+ import type { UserType } from "../types";
302
+
303
+ interface UserListItemProps {
304
+ user: UserType;
305
+ onUserSelect?: (user: UserType) => void;
306
+ }
307
+
308
+ export const UserListItem = ({
309
+ user,
310
+ onUserSelect,
311
+ }: UserListItemProps) => {
312
+ const handleClick = useCallback(() => {
313
+ onUserSelect?.(user);
314
+ }, [onUserSelect, user]);
315
+
316
+ return (
317
+ <li>
318
+ <button onClick={handleClick}>{user.name}</button>
319
+ </li>
320
+ );
321
+ };
322
+ ```
323
+
324
+ ### Use `useMemo` and `useCallback`
325
+
326
+ - **`useMemo`** for any value calculated from props or state (filtering, sorting, totals)
327
+ - **`useCallback`** for every function passed to a child component or a JSX prop
328
+
329
+ ESLint enforces the function half of this with `react/jsx-no-bind` — see the [ESLint configuration](/Standards/eslint#reactjsx-no-bind-error).
330
+
331
+ ---
332
+
333
+ ## 🔀 Server and client components
334
+
335
+ **Server code and client code live in separate files.** The server component fetches the data and nests the client component inside it:
336
+
337
+ ```text
338
+ components/
339
+ └── userList/
340
+ ├── UserList.tsx # Server component: fetches data, renders the client component
341
+ ├── UserListClient.tsx # Client component: state, effects, event handlers
342
+ ├── utils/
343
+ ├── types.ts
344
+ └── index.ts
345
+ ```
346
+
347
+ ```tsx title="UserList.tsx"
348
+ import { getUsers } from "@/services/userService";
349
+
350
+ import { UserListClient } from "./UserListClient";
351
+
352
+ export const UserList = async () => {
353
+ const users = await getUsers();
354
+
355
+ return <UserListClient users={users} />;
356
+ };
357
+ ```
358
+
359
+ ```tsx title="UserListClient.tsx"
360
+ "use client";
361
+
362
+ import { useState } from "react";
363
+
364
+ import type { UserListClientProps } from "./types";
365
+
366
+ export const UserListClient = ({ users }: UserListClientProps) => {
367
+ const [searchText, setSearchText] = useState("");
368
+ // ...
369
+ };
370
+ ```
371
+
372
+ ### Rules
373
+
374
+ - **Server file**: data fetching, database and service calls, secrets. No `"use client"`, no hooks, no event handlers.
375
+ - **Client file**: starts with `"use client"`. State, effects and event handlers only — it receives its data as props.
376
+ - **The server component nests the client component**, never the other way round.
377
+ - **Name the client file with a `Client` suffix** (`UserListClient.tsx`) so the pair is obvious.
378
+ - **Export the server component from `index.ts`** — it is the public entry point.
379
+
380
+ ---
381
+
382
+ ## Reusable by design
383
+
384
+ Every component in `components/ui/` is built so it can be copied into another project unchanged: everything comes in through props, and it imports nothing from the project's features, services, stores or `app/` folder. Before building one, [look before you build](/Guides/component-library-workflow#1-look-before-you-build), and build it to the props in the [Design System Components](/design-system-components). See [Future-proofing](/Guides/component-library-workflow#future-proofing).
385
+
386
+ ---
387
+
388
+ ## Components from shadcn
389
+
390
+ A component added with the shadcn CLI is **our code** and follows everything on this page. Convert it when it is added: its own camelCase folder, one component per file, `types.ts`, `index.ts` and a test file. See [Adding a shadcn component](/Guides/component-library-workflow#adding-a-shadcn-component).
391
+
392
+ ---
393
+
394
+ ## Folder Naming
395
+
396
+ **Component folders use camelCase** to match the component name:
397
+
398
+ ```text
399
+ ✅ Good
400
+ components/
401
+ └── button/
402
+ ├── Button.tsx
403
+ └── index.ts
404
+
405
+ ❌ Bad
406
+ components/
407
+ └── Button/
408
+ ├── Button.tsx
409
+ └── index.ts
410
+ ```
411
+
412
+ This makes it easy to spot component folders and keeps them consistent with file naming.
413
+
414
+ ---
415
+
416
+ ## Nested Components
417
+
418
+ For components with sub-components, give each sub-component its own folder:
419
+
420
+ ```text
421
+ components/
422
+ └── card/
423
+ ├── Card.tsx
424
+ ├── Card.test.tsx
425
+ ├── cardHeader/
426
+ │ ├── CardHeader.tsx
427
+ │ ├── CardHeader.test.tsx
428
+ │ ├── types.ts
429
+ │ └── index.ts
430
+ ├── cardBody/
431
+ │ ├── CardBody.tsx
432
+ │ ├── CardBody.test.tsx
433
+ │ ├── types.ts
434
+ │ └── index.ts
435
+ ├── cardFooter/
436
+ │ ├── CardFooter.tsx
437
+ │ ├── CardFooter.test.tsx
438
+ │ ├── types.ts
439
+ │ └── index.ts
440
+ ├── types.ts
441
+ └── index.ts # Re-exports all sub-components
442
+ ```
443
+
444
+ ### `index.ts` for Nested Components
445
+
446
+ ```typescript
447
+ // Card/index.ts
448
+ export { Card } from "./Card";
449
+ export { CardHeader } from "./cardHeader";
450
+ export { CardBody } from "./cardBody";
451
+ export { CardFooter } from "./cardFooter";
452
+ export type { CardProps } from "./types";
453
+ ```
454
+
455
+ ---
456
+
457
+ ## Importing Components
458
+
459
+ ### Within the Same Folder
460
+
461
+ Inside a component's folder, import files directly. **Never import through the folder's own `index.ts`**, and never import the parent component from a sub-component — both create a [circular import](/Structure/import-organization#import-safety).
462
+
463
+ ```typescript
464
+ // card/Card.tsx — the parent imports its sub-components
465
+ import { CardBody } from "./cardBody";
466
+ import { CardHeader } from "./cardHeader";
467
+ import type { CardProps } from "./types";
468
+
469
+ // card/cardBody/CardBody.tsx — a sub-component imports types by file
470
+ import type { CardProps } from "../types";
471
+
472
+ // ❌ Bad — a sub-component importing its parent through the index
473
+ import { Card } from "..";
474
+ ```
475
+
476
+ ### From Other Components
477
+
478
+ ```typescript
479
+ // UserProfile.tsx
480
+ import { Card, CardHeader, CardBody } from "@/components/ui/card";
481
+ ```
482
+
483
+ ### Best Practices
484
+
485
+ - ✅ From **outside** a folder, import through its `index.ts` — the folder, not the file
486
+ - ✅ From **inside** a folder, import the file directly — never the folder's own `index.ts`
487
+ - ❌ Never import a parent component from one of its sub-components
488
+ - ✅ Use path aliases (`@/`) for consistency
489
+ - ❌ Avoid deep relative imports (`../../../Button`)
490
+
491
+ ---
492
+
493
+ ## When to Split Components
494
+
495
+ Consider creating separate component folders when:
496
+
497
+ 1. **Used by more than one page** → Move to the section's `components/` folder, or `components/shared/`
498
+ 2. **Complex logic** → Separate file for clarity
499
+ 3. **Multiple variants** → Sub-components in same folder
500
+ 4. **Shared styles** → Keep co-located
501
+
502
+ ### Page Components
503
+
504
+ Keep components in the page's route folder if they're only used there:
505
+
506
+ ```text
507
+ app/
508
+ └── account-settings/
509
+ ├── components/
510
+ │ └── accountForm/
511
+ │ ├── AccountForm.tsx
512
+ │ ├── AccountForm.test.tsx
513
+ │ └── index.ts
514
+ └── page.tsx
515
+ ```
516
+
517
+ See [Where components live](/Structure/folder-structure#-where-components-live) for every location.
518
+
519
+ ---
520
+
521
+ ## Resources
522
+
523
+ - [Storybook Documentation](https://storybook.js.org/docs)
524
+ - [Testing Library](https://testing-library.com/docs/react-testing-library/intro/)
525
+ - [Vitest](https://vitest.dev/)
526
+ - [Next.js Project Structure](https://nextjs.org/docs/app/building-your-application/routing/colocation)