@activatus/code-standards 0.0.0-stage → 2.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 (183) hide show
  1. package/README.md +200 -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 +144 -0
  5. package/docs/Guides/setup.md +130 -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 +89 -0
  9. package/docs/Standards/branch-naming.md +66 -0
  10. package/docs/Standards/conventional-commits.md +189 -0
  11. package/docs/Standards/direnv.mdx +249 -0
  12. package/docs/Standards/documentation.md +311 -0
  13. package/docs/Standards/editorconfig.md +72 -0
  14. package/docs/Standards/eslint.md +709 -0
  15. package/docs/Standards/human-readable-names.md +234 -0
  16. package/docs/Standards/lint-errors.md +139 -0
  17. package/docs/Standards/prettier.md +97 -0
  18. package/docs/Standards/readable-code.md +540 -0
  19. package/docs/Standards/stylelint.md +178 -0
  20. package/docs/Standards/styling.md +284 -0
  21. package/docs/Standards/tech-stack.md +156 -0
  22. package/docs/Structure/_category_.json +4 -0
  23. package/docs/Structure/api-routes.md +118 -0
  24. package/docs/Structure/component-organization.md +519 -0
  25. package/docs/Structure/folder-structure.md +353 -0
  26. package/docs/Structure/import-organization.md +158 -0
  27. package/docs/Structure/naming-conventions.md +336 -0
  28. package/docs/design-system-components.md +117 -0
  29. package/docs/intro.md +46 -0
  30. package/docs/ontology.md +132 -0
  31. package/docs/templates.mdx +419 -0
  32. package/docs/version-history.md +211 -0
  33. package/package.json +56 -3
  34. package/static/templates/.commitlintrc.json +3 -0
  35. package/static/templates/.editorconfig +28 -0
  36. package/static/templates/.envrc +25 -0
  37. package/static/templates/.nvmrc +1 -0
  38. package/static/templates/AGENTS.md +160 -0
  39. package/static/templates/decision-doc.md +19 -0
  40. package/static/templates/docs/ai/agent-harness.md +17 -0
  41. package/static/templates/docs/ai/agents.md +17 -0
  42. package/static/templates/docs/ai/architecture.md +17 -0
  43. package/static/templates/docs/ai/context.md +17 -0
  44. package/static/templates/docs/ai/model-routing.md +17 -0
  45. package/static/templates/docs/ai/models.md +17 -0
  46. package/static/templates/docs/ai/retrieval.md +17 -0
  47. package/static/templates/docs/ai/tools.md +17 -0
  48. package/static/templates/docs/architecture/authentication.md +17 -0
  49. package/static/templates/docs/architecture/backend.md +17 -0
  50. package/static/templates/docs/architecture/background-jobs.md +17 -0
  51. package/static/templates/docs/architecture/backups.md +17 -0
  52. package/static/templates/docs/architecture/caching.md +17 -0
  53. package/static/templates/docs/architecture/ci-cd.md +17 -0
  54. package/static/templates/docs/architecture/disaster-recovery.md +17 -0
  55. package/static/templates/docs/architecture/environments.md +17 -0
  56. package/static/templates/docs/architecture/frontend.md +17 -0
  57. package/static/templates/docs/architecture/hosting.md +17 -0
  58. package/static/templates/docs/architecture/observability.md +17 -0
  59. package/static/templates/docs/architecture/realtime.md +17 -0
  60. package/static/templates/docs/architecture/search.md +17 -0
  61. package/static/templates/docs/architecture/services.md +17 -0
  62. package/static/templates/docs/architecture/state-management.md +17 -0
  63. package/static/templates/docs/architecture/storage.md +17 -0
  64. package/static/templates/docs/architecture/system.md +17 -0
  65. package/static/templates/docs/business/buying-trigger.md +17 -0
  66. package/static/templates/docs/business/customer-value.md +17 -0
  67. package/static/templates/docs/business/customer.md +17 -0
  68. package/static/templates/docs/business/defensibility.md +17 -0
  69. package/static/templates/docs/business/growth.md +17 -0
  70. package/static/templates/docs/business/pricing.md +17 -0
  71. package/static/templates/docs/business/revenue-model.md +17 -0
  72. package/static/templates/docs/business/unit-economics.md +17 -0
  73. package/static/templates/docs/data/analytics.md +17 -0
  74. package/static/templates/docs/data/audit.md +17 -0
  75. package/static/templates/docs/data/database.md +17 -0
  76. package/static/templates/docs/data/indexing.md +17 -0
  77. package/static/templates/docs/data/migrations.md +17 -0
  78. package/static/templates/docs/data/model.md +17 -0
  79. package/static/templates/docs/data/retention.md +17 -0
  80. package/static/templates/docs/data/schema.md +17 -0
  81. package/static/templates/docs/deployment/approval.md +17 -0
  82. package/static/templates/docs/deployment/live-verification.md +17 -0
  83. package/static/templates/docs/deployment/process.md +17 -0
  84. package/static/templates/docs/deployment/rollback.md +17 -0
  85. package/static/templates/docs/design/design-system.md +17 -0
  86. package/static/templates/docs/design/errors.md +17 -0
  87. package/static/templates/docs/design/feedback.md +17 -0
  88. package/static/templates/docs/design/interactions.md +17 -0
  89. package/static/templates/docs/design/layout.md +17 -0
  90. package/static/templates/docs/design/navigation.md +17 -0
  91. package/static/templates/docs/design/principles.md +17 -0
  92. package/static/templates/docs/design/responsive.md +17 -0
  93. package/static/templates/docs/development/branching.md +17 -0
  94. package/static/templates/docs/development/code-quality.md +17 -0
  95. package/static/templates/docs/development/coding-standards.md +17 -0
  96. package/static/templates/docs/development/commits.md +17 -0
  97. package/static/templates/docs/development/merge-strategy.md +17 -0
  98. package/static/templates/docs/development/process.md +17 -0
  99. package/static/templates/docs/development/pull-requests.md +17 -0
  100. package/static/templates/docs/experience/accessibility.md +17 -0
  101. package/static/templates/docs/experience/aha-moment.md +17 -0
  102. package/static/templates/docs/experience/anti-experience.md +17 -0
  103. package/static/templates/docs/experience/friction.md +17 -0
  104. package/static/templates/docs/experience/outcomes.md +17 -0
  105. package/static/templates/docs/experience/principles.md +17 -0
  106. package/static/templates/docs/experience/retention.md +17 -0
  107. package/static/templates/docs/experience/sharing.md +17 -0
  108. package/static/templates/docs/overview/how-it-works.md +17 -0
  109. package/static/templates/docs/overview/what-is-it.md +17 -0
  110. package/static/templates/docs/overview/writing-docs.md +16 -0
  111. package/static/templates/docs/pitch/alternatives.md +17 -0
  112. package/static/templates/docs/pitch/assumptions.md +17 -0
  113. package/static/templates/docs/pitch/audience.md +17 -0
  114. package/static/templates/docs/pitch/concept.md +17 -0
  115. package/static/templates/docs/pitch/differentiators.md +17 -0
  116. package/static/templates/docs/pitch/outcomes.md +17 -0
  117. package/static/templates/docs/pitch/problem.md +17 -0
  118. package/static/templates/docs/pitch/product-market-fit.md +17 -0
  119. package/static/templates/docs/pitch/success-criteria.md +17 -0
  120. package/static/templates/docs/pitch/validation.md +17 -0
  121. package/static/templates/docs/pitch/value-proposition.md +17 -0
  122. package/static/templates/docs/pitch/vision.md +17 -0
  123. package/static/templates/docs/scope/core.md +17 -0
  124. package/static/templates/docs/scope/exclusions.md +17 -0
  125. package/static/templates/docs/scope/future.md +17 -0
  126. package/static/templates/docs/scope/launch.md +17 -0
  127. package/static/templates/docs/scope/post-launch.md +17 -0
  128. package/static/templates/docs/scope/priorities.md +17 -0
  129. package/static/templates/docs/scope/quality-bar.md +17 -0
  130. package/static/templates/docs/security/audit.md +17 -0
  131. package/static/templates/docs/security/data-access.md +17 -0
  132. package/static/templates/docs/security/logging.md +17 -0
  133. package/static/templates/docs/security/privacy.md +17 -0
  134. package/static/templates/docs/security/secrets.md +17 -0
  135. package/static/templates/docs/security/threat-model.md +17 -0
  136. package/static/templates/docs/testing/end-to-end.md +17 -0
  137. package/static/templates/docs/testing/integration.md +17 -0
  138. package/static/templates/docs/testing/regression.md +17 -0
  139. package/static/templates/docs/testing/security.md +17 -0
  140. package/static/templates/docs/testing/strategy.md +17 -0
  141. package/static/templates/docs/testing/test-data.md +17 -0
  142. package/static/templates/docs/testing/unit.md +17 -0
  143. package/static/templates/docs/uat/checks.md +17 -0
  144. package/static/templates/docs/uat/strategy.md +17 -0
  145. package/static/templates/docs/users/permissions.md +17 -0
  146. package/static/templates/docs/users/roles.md +17 -0
  147. package/static/templates/docs/users/user-types.md +17 -0
  148. package/static/templates/docs/workflows/assignment.md +17 -0
  149. package/static/templates/docs/workflows/bugfix.md +17 -0
  150. package/static/templates/docs/workflows/dependencies.md +17 -0
  151. package/static/templates/docs/workflows/deployment.md +17 -0
  152. package/static/templates/docs/workflows/development.md +17 -0
  153. package/static/templates/docs/workflows/planning.md +17 -0
  154. package/static/templates/docs/workflows/review.md +17 -0
  155. package/static/templates/docs/workflows/uat.md +17 -0
  156. package/static/templates/docsSite/docusaurus.config.ts +119 -0
  157. package/static/templates/docsSite/gitignore.txt +3 -0
  158. package/static/templates/docsSite/package.json.txt +42 -0
  159. package/static/templates/docsSite/pnpm-workspace.yaml +2 -0
  160. package/static/templates/docsSite/sidebars.ts +8 -0
  161. package/static/templates/docsSite/src/css/custom.css +1 -0
  162. package/static/templates/docsSite/src/pages/index.tsx +9 -0
  163. package/static/templates/docsSite/static/images/logo.svg +4 -0
  164. package/static/templates/docsSite/tsconfig.json +7 -0
  165. package/static/templates/eslint/base/eslint.config.mjs +79 -0
  166. package/static/templates/eslint/nextjs/eslint.config.mjs +137 -0
  167. package/static/templates/eslint/react/eslint.config.mjs +138 -0
  168. package/static/templates/eslint/typescript/eslint.config.mjs +126 -0
  169. package/static/templates/globals.css +16 -0
  170. package/static/templates/husky/commit-msg +1 -0
  171. package/static/templates/husky/pre-commit +1 -0
  172. package/static/templates/next.config.mjs +18 -0
  173. package/static/templates/prettier.config.js +17 -0
  174. package/static/templates/skills/codeReview.md +31 -0
  175. package/static/templates/skills/format.md +18 -0
  176. package/static/templates/skills/lint.md +21 -0
  177. package/static/templates/skills/lintFix.md +24 -0
  178. package/static/templates/skills/securityAudit.md +28 -0
  179. package/static/templates/skills/test.md +24 -0
  180. package/static/templates/skills/typescript.md +28 -0
  181. package/static/templates/skills/updateLayout.md +20 -0
  182. package/static/templates/stylelint/css/stylelint.config.mjs +28 -0
  183. package/static/templates/stylelint/scss/stylelint.config.mjs +10 -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,519 @@
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 key={user.id} user={user} onUserSelect={onUserSelect} />
220
+ ))}
221
+ </ul>
222
+ </section>
223
+ );
224
+ };
225
+ ```
226
+
227
+ ### Keep the UI file clean
228
+
229
+ **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).
230
+
231
+ `filterUsersByName` above only needs its arguments, so it lives in the component's `utils/` folder, in its own folder beside its test file:
232
+
233
+ ```text
234
+ userList/
235
+ ├── UserListClient.tsx
236
+ └── utils/
237
+ ├── filterUsersByName/
238
+ │ ├── filterUsersByName.ts
239
+ │ ├── filterUsersByName.test.ts
240
+ │ └── index.ts
241
+ └── index.ts
242
+ ```
243
+
244
+ ```ts title="utils/filterUsersByName/filterUsersByName.ts"
245
+ import type { UserType } from "../../types";
246
+
247
+ interface FilterUsersByNameProps {
248
+ users: UserType[];
249
+ searchText: string;
250
+ }
251
+
252
+ export const filterUsersByName = ({
253
+ users,
254
+ searchText,
255
+ }: FilterUsersByNameProps) => {
256
+ const lowerCaseSearchText = searchText.toLowerCase();
257
+
258
+ return users.filter((user) =>
259
+ user.name.toLowerCase().includes(lowerCaseSearchText),
260
+ );
261
+ };
262
+ ```
263
+
264
+ Each function folder has an `index.ts`, and so does the `utils/` folder — both are one line:
265
+
266
+ ```ts title="utils/filterUsersByName/index.ts"
267
+ export { filterUsersByName } from "./filterUsersByName";
268
+ ```
269
+
270
+ ```ts title="utils/index.ts"
271
+ export { filterUsersByName } from "./filterUsersByName";
272
+ ```
273
+
274
+ The component imports it from the folder: `import { filterUsersByName } from "./utils";`
275
+
276
+ ### No inline functions in render
277
+
278
+ Never define a function inside the JSX. Declare it above with `useCallback` and pass it by name:
279
+
280
+ ```tsx
281
+ // ✅ Good
282
+ const handleSearchTextChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
283
+ setSearchText(event.target.value);
284
+ }, []);
285
+
286
+ <input value={searchText} onChange={handleSearchTextChange} />
287
+
288
+ // ❌ Bad
289
+ <input value={searchText} onChange={(event) => setSearchText(event.target.value)} />
290
+ ```
291
+
292
+ 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:
293
+
294
+ ```tsx title="userListItem/UserListItem.tsx"
295
+ import { useCallback } from "react";
296
+
297
+ import type { UserType } from "../types";
298
+
299
+ interface UserListItemProps {
300
+ user: UserType;
301
+ onUserSelect?: (user: UserType) => void;
302
+ }
303
+
304
+ export const UserListItem = ({ user, onUserSelect }: UserListItemProps) => {
305
+ const handleClick = useCallback(() => {
306
+ onUserSelect?.(user);
307
+ }, [onUserSelect, user]);
308
+
309
+ return (
310
+ <li>
311
+ <button onClick={handleClick}>{user.name}</button>
312
+ </li>
313
+ );
314
+ };
315
+ ```
316
+
317
+ ### Use `useMemo` and `useCallback`
318
+
319
+ - **`useMemo`** for any value calculated from props or state (filtering, sorting, totals)
320
+ - **`useCallback`** for every function passed to a child component or a JSX prop
321
+
322
+ ESLint enforces the function half of this with `react/jsx-no-bind` — see the [ESLint configuration](/Standards/eslint#reactjsx-no-bind-error).
323
+
324
+ ---
325
+
326
+ ## 🔀 Server and client components
327
+
328
+ **Server code and client code live in separate files.** The server component fetches the data and nests the client component inside it:
329
+
330
+ ```text
331
+ components/
332
+ └── userList/
333
+ ├── UserList.tsx # Server component: fetches data, renders the client component
334
+ ├── UserListClient.tsx # Client component: state, effects, event handlers
335
+ ├── utils/
336
+ ├── types.ts
337
+ └── index.ts
338
+ ```
339
+
340
+ ```tsx title="UserList.tsx"
341
+ import { getUsers } from "@/services/userService";
342
+
343
+ import { UserListClient } from "./UserListClient";
344
+
345
+ export const UserList = async () => {
346
+ const users = await getUsers();
347
+
348
+ return <UserListClient users={users} />;
349
+ };
350
+ ```
351
+
352
+ ```tsx title="UserListClient.tsx"
353
+ "use client";
354
+
355
+ import { useState } from "react";
356
+
357
+ import type { UserListClientProps } from "./types";
358
+
359
+ export const UserListClient = ({ users }: UserListClientProps) => {
360
+ const [searchText, setSearchText] = useState("");
361
+ // ...
362
+ };
363
+ ```
364
+
365
+ ### Rules
366
+
367
+ - **Server file**: data fetching, database and service calls, secrets. No `"use client"`, no hooks, no event handlers.
368
+ - **Client file**: starts with `"use client"`. State, effects and event handlers only — it receives its data as props.
369
+ - **The server component nests the client component**, never the other way round.
370
+ - **Name the client file with a `Client` suffix** (`UserListClient.tsx`) so the pair is obvious.
371
+ - **Export the server component from `index.ts`** — it is the public entry point.
372
+
373
+ ---
374
+
375
+ ## Reusable by design
376
+
377
+ 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).
378
+
379
+ ---
380
+
381
+ ## Components from shadcn
382
+
383
+ 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).
384
+
385
+ ---
386
+
387
+ ## Folder Naming
388
+
389
+ **Component folders use camelCase** to match the component name:
390
+
391
+ ```text
392
+ ✅ Good
393
+ components/
394
+ └── button/
395
+ ├── Button.tsx
396
+ └── index.ts
397
+
398
+ ❌ Bad
399
+ components/
400
+ └── Button/
401
+ ├── Button.tsx
402
+ └── index.ts
403
+ ```
404
+
405
+ This makes it easy to spot component folders and keeps them consistent with file naming.
406
+
407
+ ---
408
+
409
+ ## Nested Components
410
+
411
+ For components with sub-components, give each sub-component its own folder:
412
+
413
+ ```text
414
+ components/
415
+ └── card/
416
+ ├── Card.tsx
417
+ ├── Card.test.tsx
418
+ ├── cardHeader/
419
+ │ ├── CardHeader.tsx
420
+ │ ├── CardHeader.test.tsx
421
+ │ ├── types.ts
422
+ │ └── index.ts
423
+ ├── cardBody/
424
+ │ ├── CardBody.tsx
425
+ │ ├── CardBody.test.tsx
426
+ │ ├── types.ts
427
+ │ └── index.ts
428
+ ├── cardFooter/
429
+ │ ├── CardFooter.tsx
430
+ │ ├── CardFooter.test.tsx
431
+ │ ├── types.ts
432
+ │ └── index.ts
433
+ ├── types.ts
434
+ └── index.ts # Re-exports all sub-components
435
+ ```
436
+
437
+ ### `index.ts` for Nested Components
438
+
439
+ ```typescript
440
+ // Card/index.ts
441
+ export { Card } from "./Card";
442
+ export { CardHeader } from "./cardHeader";
443
+ export { CardBody } from "./cardBody";
444
+ export { CardFooter } from "./cardFooter";
445
+ export type { CardProps } from "./types";
446
+ ```
447
+
448
+ ---
449
+
450
+ ## Importing Components
451
+
452
+ ### Within the Same Folder
453
+
454
+ 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).
455
+
456
+ ```typescript
457
+ // card/Card.tsx — the parent imports its sub-components
458
+ import { CardBody } from "./cardBody";
459
+ import { CardHeader } from "./cardHeader";
460
+ import type { CardProps } from "./types";
461
+
462
+ // card/cardBody/CardBody.tsx — a sub-component imports types by file
463
+ import type { CardProps } from "../types";
464
+
465
+ // ❌ Bad — a sub-component importing its parent through the index
466
+ import { Card } from "..";
467
+ ```
468
+
469
+ ### From Other Components
470
+
471
+ ```typescript
472
+ // UserProfile.tsx
473
+ import { Card, CardHeader, CardBody } from "@/components/ui/card";
474
+ ```
475
+
476
+ ### Best Practices
477
+
478
+ - ✅ From **outside** a folder, import through its `index.ts` — the folder, not the file
479
+ - ✅ From **inside** a folder, import the file directly — never the folder's own `index.ts`
480
+ - ❌ Never import a parent component from one of its sub-components
481
+ - ✅ Use path aliases (`@/`) for consistency
482
+ - ❌ Avoid deep relative imports (`../../../Button`)
483
+
484
+ ---
485
+
486
+ ## When to Split Components
487
+
488
+ Consider creating separate component folders when:
489
+
490
+ 1. **Used by more than one page** → Move to the section's `components/` folder, or `components/shared/`
491
+ 2. **Complex logic** → Separate file for clarity
492
+ 3. **Multiple variants** → Sub-components in same folder
493
+ 4. **Shared styles** → Keep co-located
494
+
495
+ ### Page Components
496
+
497
+ Keep components in the page's route folder if they're only used there:
498
+
499
+ ```text
500
+ app/
501
+ └── account-settings/
502
+ ├── components/
503
+ │ └── accountForm/
504
+ │ ├── AccountForm.tsx
505
+ │ ├── AccountForm.test.tsx
506
+ │ └── index.ts
507
+ └── page.tsx
508
+ ```
509
+
510
+ See [Where components live](/Structure/folder-structure#-where-components-live) for every location.
511
+
512
+ ---
513
+
514
+ ## Resources
515
+
516
+ - [Storybook Documentation](https://storybook.js.org/docs)
517
+ - [Testing Library](https://testing-library.com/docs/react-testing-library/intro/)
518
+ - [Vitest](https://vitest.dev/)
519
+ - [Next.js Project Structure](https://nextjs.org/docs/app/building-your-application/routing/colocation)