red64-cli 0.1.0 → 0.3.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.
- package/README.md +1 -2
- package/dist/cli/parseArgs.d.ts.map +1 -1
- package/dist/cli/parseArgs.js +5 -0
- package/dist/cli/parseArgs.js.map +1 -1
- package/dist/components/init/CompleteStep.d.ts.map +1 -1
- package/dist/components/init/CompleteStep.js +2 -2
- package/dist/components/init/CompleteStep.js.map +1 -1
- package/dist/components/init/TestCheckStep.d.ts +16 -0
- package/dist/components/init/TestCheckStep.d.ts.map +1 -0
- package/dist/components/init/TestCheckStep.js +120 -0
- package/dist/components/init/TestCheckStep.js.map +1 -0
- package/dist/components/init/index.d.ts +1 -0
- package/dist/components/init/index.d.ts.map +1 -1
- package/dist/components/init/index.js +1 -0
- package/dist/components/init/index.js.map +1 -1
- package/dist/components/init/types.d.ts +9 -0
- package/dist/components/init/types.d.ts.map +1 -1
- package/dist/components/screens/InitScreen.d.ts.map +1 -1
- package/dist/components/screens/InitScreen.js +69 -6
- package/dist/components/screens/InitScreen.js.map +1 -1
- package/dist/components/screens/ListScreen.d.ts.map +1 -1
- package/dist/components/screens/ListScreen.js +28 -3
- package/dist/components/screens/ListScreen.js.map +1 -1
- package/dist/components/screens/StartScreen.d.ts.map +1 -1
- package/dist/components/screens/StartScreen.js +212 -13
- package/dist/components/screens/StartScreen.js.map +1 -1
- package/dist/components/ui/ArtifactsSidebar.d.ts +19 -0
- package/dist/components/ui/ArtifactsSidebar.d.ts.map +1 -0
- package/dist/components/ui/ArtifactsSidebar.js +51 -0
- package/dist/components/ui/ArtifactsSidebar.js.map +1 -0
- package/dist/components/ui/FeatureSidebar.d.ts.map +1 -1
- package/dist/components/ui/FeatureSidebar.js +1 -1
- package/dist/components/ui/FeatureSidebar.js.map +1 -1
- package/dist/components/ui/index.d.ts +1 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +1 -0
- package/dist/components/ui/index.js.map +1 -1
- package/dist/services/ClaudeErrorDetector.js +3 -3
- package/dist/services/ClaudeErrorDetector.js.map +1 -1
- package/dist/services/ConfigService.d.ts +1 -0
- package/dist/services/ConfigService.d.ts.map +1 -1
- package/dist/services/ConfigService.js.map +1 -1
- package/dist/services/ProjectDetector.d.ts +28 -0
- package/dist/services/ProjectDetector.d.ts.map +1 -0
- package/dist/services/ProjectDetector.js +236 -0
- package/dist/services/ProjectDetector.js.map +1 -0
- package/dist/services/TestRunner.d.ts +46 -0
- package/dist/services/TestRunner.d.ts.map +1 -0
- package/dist/services/TestRunner.js +85 -0
- package/dist/services/TestRunner.js.map +1 -0
- package/dist/services/index.d.ts +2 -0
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +2 -0
- package/dist/services/index.js.map +1 -1
- package/dist/types/index.d.ts +13 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js.map +1 -1
- package/framework/.red64/settings/templates/specs/gap-analysis.md +163 -0
- package/framework/agents/claude/.claude/agents/red64/spec-impl.md +131 -2
- package/framework/agents/claude/.claude/agents/red64/validate-gap.md +13 -7
- package/framework/agents/claude/.claude/commands/red64/spec-impl.md +24 -0
- package/framework/agents/claude/.claude/commands/red64/validate-gap.md +4 -0
- package/framework/agents/codex/.codex/agents/red64/spec-impl.md +131 -2
- package/framework/agents/codex/.codex/agents/red64/validate-gap.md +13 -7
- package/framework/agents/codex/.codex/commands/red64/spec-impl.md +24 -0
- package/framework/agents/codex/.codex/commands/red64/validate-gap.md +4 -0
- package/framework/stacks/generic/feedback.md +80 -0
- package/framework/stacks/nextjs/accessibility.md +437 -0
- package/framework/stacks/nextjs/api.md +431 -0
- package/framework/stacks/nextjs/coding-style.md +282 -0
- package/framework/stacks/nextjs/commenting.md +226 -0
- package/framework/stacks/nextjs/components.md +411 -0
- package/framework/stacks/nextjs/conventions.md +333 -0
- package/framework/stacks/nextjs/css.md +310 -0
- package/framework/stacks/nextjs/error-handling.md +442 -0
- package/framework/stacks/nextjs/feedback.md +124 -0
- package/framework/stacks/nextjs/migrations.md +332 -0
- package/framework/stacks/nextjs/models.md +362 -0
- package/framework/stacks/nextjs/queries.md +410 -0
- package/framework/stacks/nextjs/responsive.md +338 -0
- package/framework/stacks/nextjs/tech-stack.md +177 -0
- package/framework/stacks/nextjs/test-writing.md +475 -0
- package/framework/stacks/nextjs/validation.md +467 -0
- package/framework/stacks/python/api.md +468 -0
- package/framework/stacks/python/authentication.md +342 -0
- package/framework/stacks/python/code-quality.md +283 -0
- package/framework/stacks/python/code-refactoring.md +315 -0
- package/framework/stacks/python/coding-style.md +462 -0
- package/framework/stacks/python/conventions.md +399 -0
- package/framework/stacks/python/error-handling.md +512 -0
- package/framework/stacks/python/feedback.md +92 -0
- package/framework/stacks/python/implement-ai-llm.md +468 -0
- package/framework/stacks/python/migrations.md +388 -0
- package/framework/stacks/python/models.md +399 -0
- package/framework/stacks/python/python.md +232 -0
- package/framework/stacks/python/queries.md +451 -0
- package/framework/stacks/python/structure.md +245 -58
- package/framework/stacks/python/tech.md +92 -35
- package/framework/stacks/python/testing.md +380 -0
- package/framework/stacks/python/validation.md +471 -0
- package/framework/stacks/rails/authentication.md +176 -0
- package/framework/stacks/rails/code-quality.md +287 -0
- package/framework/stacks/rails/code-refactoring.md +299 -0
- package/framework/stacks/rails/feedback.md +130 -0
- package/framework/stacks/rails/implement-ai-llm-with-rubyllm.md +342 -0
- package/framework/stacks/rails/rails.md +301 -0
- package/framework/stacks/rails/rails8-best-practices.md +498 -0
- package/framework/stacks/rails/rails8-css.md +573 -0
- package/framework/stacks/rails/structure.md +140 -0
- package/framework/stacks/rails/tech.md +108 -0
- package/framework/stacks/react/code-quality.md +521 -0
- package/framework/stacks/react/components.md +625 -0
- package/framework/stacks/react/data-fetching.md +586 -0
- package/framework/stacks/react/feedback.md +110 -0
- package/framework/stacks/react/forms.md +694 -0
- package/framework/stacks/react/performance.md +640 -0
- package/framework/stacks/react/product.md +22 -9
- package/framework/stacks/react/state-management.md +472 -0
- package/framework/stacks/react/structure.md +351 -44
- package/framework/stacks/react/tech.md +219 -30
- package/framework/stacks/react/testing.md +690 -0
- package/package.json +1 -1
- package/framework/stacks/node/product.md +0 -27
- package/framework/stacks/node/structure.md +0 -82
- package/framework/stacks/node/tech.md +0 -63
|
@@ -4,73 +4,380 @@
|
|
|
4
4
|
|
|
5
5
|
## Organization Philosophy
|
|
6
6
|
|
|
7
|
-
Feature-first organization with shared components and utilities. Each feature is self-contained with its own components, hooks, and
|
|
7
|
+
Feature-first organization with shared components and utilities. Each feature is self-contained with its own components, hooks, types, and API calls. Shared code lives in dedicated directories at the root level.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Directory Structure
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
src/
|
|
15
|
+
├── app/ # Application shell
|
|
16
|
+
│ ├── App.tsx # Root component, providers
|
|
17
|
+
│ ├── routes.tsx # Route definitions
|
|
18
|
+
│ └── providers/ # Context providers (QueryClient, etc.)
|
|
19
|
+
├── components/ # Shared UI components
|
|
20
|
+
│ ├── ui/ # Primitive components (Button, Input, Modal)
|
|
21
|
+
│ └── layout/ # Layout components (Header, Sidebar, Footer)
|
|
22
|
+
├── features/ # Feature modules (self-contained)
|
|
23
|
+
│ ├── auth/
|
|
24
|
+
│ ├── dashboard/
|
|
25
|
+
│ └── users/
|
|
26
|
+
├── hooks/ # Shared custom hooks
|
|
27
|
+
├── lib/ # Third-party library configurations
|
|
28
|
+
├── services/ # API client, external integrations
|
|
29
|
+
├── stores/ # Global state (Zustand stores)
|
|
30
|
+
├── types/ # Shared TypeScript types
|
|
31
|
+
└── utils/ # Pure utility functions
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
8
35
|
|
|
9
36
|
## Directory Patterns
|
|
10
37
|
|
|
11
|
-
###
|
|
12
|
-
**
|
|
13
|
-
|
|
14
|
-
|
|
38
|
+
### `/src/app/` - Application Shell
|
|
39
|
+
**Purpose**: Application entry point, routing, and global providers
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
// app/App.tsx
|
|
43
|
+
import { QueryClientProvider } from '@tanstack/react-query';
|
|
44
|
+
import { RouterProvider } from 'react-router-dom';
|
|
45
|
+
import { queryClient } from '@/lib/query-client';
|
|
46
|
+
import { router } from './routes';
|
|
47
|
+
|
|
48
|
+
export function App() {
|
|
49
|
+
return (
|
|
50
|
+
<QueryClientProvider client={queryClient}>
|
|
51
|
+
<RouterProvider router={router} />
|
|
52
|
+
</QueryClientProvider>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
### `/src/components/` - Shared Components
|
|
60
|
+
**Purpose**: Reusable UI components used across multiple features
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
components/
|
|
64
|
+
├── ui/
|
|
65
|
+
│ ├── Button/
|
|
66
|
+
│ │ ├── Button.tsx
|
|
67
|
+
│ │ ├── Button.test.tsx
|
|
68
|
+
│ │ └── index.ts
|
|
69
|
+
│ ├── Input/
|
|
70
|
+
│ ├── Modal/
|
|
71
|
+
│ └── index.ts # Barrel export
|
|
72
|
+
└── layout/
|
|
73
|
+
├── Header.tsx
|
|
74
|
+
├── Sidebar.tsx
|
|
75
|
+
└── PageLayout.tsx
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
**Rules**:
|
|
79
|
+
- Components must be generic and reusable
|
|
80
|
+
- No business logic; accept data via props
|
|
81
|
+
- Include unit tests for interactive components
|
|
82
|
+
- Export via barrel files for clean imports
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
### `/src/features/` - Feature Modules
|
|
87
|
+
**Purpose**: Self-contained feature code with its own components, hooks, API, and types
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
features/
|
|
91
|
+
└── users/
|
|
92
|
+
├── components/ # Feature-specific components
|
|
93
|
+
│ ├── UserList.tsx
|
|
94
|
+
│ ├── UserCard.tsx
|
|
95
|
+
│ └── UserForm.tsx
|
|
96
|
+
├── hooks/ # Feature-specific hooks
|
|
97
|
+
│ ├── useUsers.ts
|
|
98
|
+
│ └── useUserMutations.ts
|
|
99
|
+
├── api/ # Feature API calls
|
|
100
|
+
│ └── users.api.ts
|
|
101
|
+
├── types/ # Feature types
|
|
102
|
+
│ └── user.types.ts
|
|
103
|
+
├── utils/ # Feature utilities
|
|
104
|
+
│ └── user.utils.ts
|
|
105
|
+
└── index.ts # Public API (barrel export)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Feature Module Rules**:
|
|
109
|
+
- Features are isolated; do not import from other features
|
|
110
|
+
- Shared code goes in root-level directories
|
|
111
|
+
- Export only the public API via `index.ts`
|
|
112
|
+
- Feature components can import from `@/components/ui`
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// features/users/index.ts - Public API
|
|
116
|
+
export { UserList } from './components/UserList';
|
|
117
|
+
export { useUsers, useUser } from './hooks/useUsers';
|
|
118
|
+
export type { User, CreateUserInput } from './types/user.types';
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
### `/src/hooks/` - Shared Hooks
|
|
124
|
+
**Purpose**: Custom React hooks used across multiple features
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
hooks/
|
|
128
|
+
├── useDebounce.ts
|
|
129
|
+
├── useLocalStorage.ts
|
|
130
|
+
├── useMediaQuery.ts
|
|
131
|
+
├── useOnClickOutside.ts
|
|
132
|
+
└── index.ts
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Naming**: Always prefix with `use` (e.g., `useDebounce.ts`)
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
// hooks/useDebounce.ts
|
|
139
|
+
import { useState, useEffect } from 'react';
|
|
140
|
+
|
|
141
|
+
export function useDebounce<T>(value: T, delay: number): T {
|
|
142
|
+
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
143
|
+
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
const timer = setTimeout(() => setDebouncedValue(value), delay);
|
|
146
|
+
return () => clearTimeout(timer);
|
|
147
|
+
}, [value, delay]);
|
|
148
|
+
|
|
149
|
+
return debouncedValue;
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
### `/src/services/` - API & External Services
|
|
156
|
+
**Purpose**: HTTP client setup, API configurations, external integrations
|
|
157
|
+
|
|
158
|
+
```
|
|
159
|
+
services/
|
|
160
|
+
├── api.ts # Base API client configuration
|
|
161
|
+
├── auth.service.ts # Auth-specific API calls (if not in feature)
|
|
162
|
+
└── storage.service.ts # LocalStorage/SessionStorage wrapper
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
// services/api.ts
|
|
167
|
+
import ky from 'ky';
|
|
168
|
+
import { useAuthStore } from '@/stores/auth.store';
|
|
169
|
+
|
|
170
|
+
export const api = ky.create({
|
|
171
|
+
prefixUrl: import.meta.env.VITE_API_URL,
|
|
172
|
+
hooks: {
|
|
173
|
+
beforeRequest: [
|
|
174
|
+
(request) => {
|
|
175
|
+
const token = useAuthStore.getState().token;
|
|
176
|
+
if (token) {
|
|
177
|
+
request.headers.set('Authorization', `Bearer ${token}`);
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
},
|
|
182
|
+
});
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
### `/src/stores/` - Global State
|
|
188
|
+
**Purpose**: Zustand stores for client-side state
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
stores/
|
|
192
|
+
├── auth.store.ts
|
|
193
|
+
├── ui.store.ts # UI state (sidebar open, theme, etc.)
|
|
194
|
+
└── index.ts
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// stores/auth.store.ts
|
|
199
|
+
import { create } from 'zustand';
|
|
200
|
+
import { persist } from 'zustand/middleware';
|
|
15
201
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
202
|
+
interface AuthState {
|
|
203
|
+
token: string | null;
|
|
204
|
+
user: User | null;
|
|
205
|
+
setAuth: (token: string, user: User) => void;
|
|
206
|
+
clearAuth: () => void;
|
|
207
|
+
}
|
|
20
208
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
209
|
+
export const useAuthStore = create<AuthState>()(
|
|
210
|
+
persist(
|
|
211
|
+
(set) => ({
|
|
212
|
+
token: null,
|
|
213
|
+
user: null,
|
|
214
|
+
setAuth: (token, user) => set({ token, user }),
|
|
215
|
+
clearAuth: () => set({ token: null, user: null }),
|
|
216
|
+
}),
|
|
217
|
+
{ name: 'auth-storage' }
|
|
218
|
+
)
|
|
219
|
+
);
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
25
223
|
|
|
26
|
-
###
|
|
27
|
-
**
|
|
28
|
-
**Purpose**: API calls and external integrations
|
|
29
|
-
**Example**: api.ts, auth.service.ts
|
|
224
|
+
### `/src/types/` - Shared Types
|
|
225
|
+
**Purpose**: TypeScript interfaces and types used across features
|
|
30
226
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
227
|
+
```
|
|
228
|
+
types/
|
|
229
|
+
├── api.types.ts # API response shapes
|
|
230
|
+
├── common.types.ts # Utility types
|
|
231
|
+
└── index.ts
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
// types/api.types.ts
|
|
236
|
+
export interface PaginatedResponse<T> {
|
|
237
|
+
items: T[];
|
|
238
|
+
total: number;
|
|
239
|
+
page: number;
|
|
240
|
+
perPage: number;
|
|
241
|
+
hasNext: boolean;
|
|
242
|
+
}
|
|
35
243
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
244
|
+
export interface ApiError {
|
|
245
|
+
code: string;
|
|
246
|
+
message: string;
|
|
247
|
+
details?: Record<string, string[]>;
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
### `/src/utils/` - Utility Functions
|
|
254
|
+
**Purpose**: Pure utility functions with no React dependencies
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
utils/
|
|
258
|
+
├── formatters.ts # Date, number, currency formatting
|
|
259
|
+
├── validators.ts # Validation helpers
|
|
260
|
+
├── cn.ts # className utility (clsx + tailwind-merge)
|
|
261
|
+
└── index.ts
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
// utils/cn.ts
|
|
266
|
+
import { clsx, type ClassValue } from 'clsx';
|
|
267
|
+
import { twMerge } from 'tailwind-merge';
|
|
268
|
+
|
|
269
|
+
export function cn(...inputs: ClassValue[]): string {
|
|
270
|
+
return twMerge(clsx(inputs));
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
### `/src/lib/` - Library Configurations
|
|
277
|
+
**Purpose**: Configuration for third-party libraries
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
lib/
|
|
281
|
+
├── query-client.ts # TanStack Query client setup
|
|
282
|
+
├── zod-schemas.ts # Shared Zod schemas
|
|
283
|
+
└── dayjs.ts # dayjs with plugins
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
40
287
|
|
|
41
288
|
## Naming Conventions
|
|
42
289
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
290
|
+
| Type | Convention | Example |
|
|
291
|
+
|------|------------|---------|
|
|
292
|
+
| **Components** | PascalCase | `UserProfile.tsx`, `Button.tsx` |
|
|
293
|
+
| **Hooks** | camelCase with `use` prefix | `useAuth.ts`, `useDebounce.ts` |
|
|
294
|
+
| **Utilities** | camelCase | `formatters.ts`, `validators.ts` |
|
|
295
|
+
| **Types** | PascalCase | `User`, `ApiResponse` |
|
|
296
|
+
| **Stores** | camelCase with `.store` suffix | `auth.store.ts` |
|
|
297
|
+
| **API files** | camelCase with `.api` suffix | `users.api.ts` |
|
|
298
|
+
| **Test files** | Same as source with `.test` | `Button.test.tsx` |
|
|
299
|
+
| **Constants** | SCREAMING_SNAKE_CASE | `API_BASE_URL` |
|
|
300
|
+
|
|
301
|
+
---
|
|
47
302
|
|
|
48
303
|
## Import Organization
|
|
49
304
|
|
|
50
305
|
```typescript
|
|
51
|
-
// 1. React
|
|
52
|
-
import
|
|
53
|
-
|
|
306
|
+
// 1. React imports
|
|
307
|
+
import { useState, useEffect, type ReactNode } from 'react';
|
|
308
|
+
|
|
309
|
+
// 2. Third-party libraries
|
|
310
|
+
import { useQuery } from '@tanstack/react-query';
|
|
311
|
+
import { useForm } from 'react-hook-form';
|
|
54
312
|
|
|
55
|
-
//
|
|
56
|
-
import { Button } from '@/components/
|
|
313
|
+
// 3. Absolute imports (internal)
|
|
314
|
+
import { Button } from '@/components/ui';
|
|
57
315
|
import { useAuth } from '@/hooks/useAuth';
|
|
316
|
+
import { api } from '@/services/api';
|
|
317
|
+
import type { User } from '@/types';
|
|
58
318
|
|
|
59
|
-
//
|
|
319
|
+
// 4. Relative imports (same feature)
|
|
60
320
|
import { UserCard } from './UserCard';
|
|
61
|
-
import type {
|
|
321
|
+
import type { UserListProps } from './types';
|
|
322
|
+
|
|
323
|
+
// 5. Styles (if CSS modules)
|
|
324
|
+
import styles from './UserList.module.css';
|
|
62
325
|
```
|
|
63
326
|
|
|
64
|
-
**Path Aliases
|
|
65
|
-
-
|
|
66
|
-
|
|
327
|
+
**Path Aliases** (configured in `tsconfig.json` and `vite.config.ts`):
|
|
328
|
+
- `@/` → `src/`
|
|
329
|
+
|
|
330
|
+
---
|
|
67
331
|
|
|
68
332
|
## Code Organization Principles
|
|
69
333
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
334
|
+
### Colocation
|
|
335
|
+
Keep related code together. A feature's components, hooks, types, and API calls live in the same directory.
|
|
336
|
+
|
|
337
|
+
### Single Responsibility
|
|
338
|
+
Each file has one primary purpose. A component file contains one component. A hook file contains one hook.
|
|
339
|
+
|
|
340
|
+
### Barrel Exports
|
|
341
|
+
Use `index.ts` for clean imports, but only export the public API.
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
// features/users/index.ts
|
|
345
|
+
export { UserList } from './components/UserList';
|
|
346
|
+
export { UserForm } from './components/UserForm';
|
|
347
|
+
export { useUsers } from './hooks/useUsers';
|
|
348
|
+
// Don't export internal components like UserCard
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### Dependency Direction
|
|
352
|
+
- Features import from shared (`@/components`, `@/hooks`, `@/utils`)
|
|
353
|
+
- Features do NOT import from other features
|
|
354
|
+
- Shared code does NOT import from features
|
|
74
355
|
|
|
75
356
|
---
|
|
76
|
-
|
|
357
|
+
|
|
358
|
+
## Test File Organization
|
|
359
|
+
|
|
360
|
+
```
|
|
361
|
+
src/
|
|
362
|
+
├── features/
|
|
363
|
+
│ └── users/
|
|
364
|
+
│ ├── components/
|
|
365
|
+
│ │ ├── UserList.tsx
|
|
366
|
+
│ │ └── UserList.test.tsx # Co-located with component
|
|
367
|
+
│ └── hooks/
|
|
368
|
+
│ ├── useUsers.ts
|
|
369
|
+
│ └── useUsers.test.ts
|
|
370
|
+
└── utils/
|
|
371
|
+
├── formatters.ts
|
|
372
|
+
└── formatters.test.ts
|
|
373
|
+
|
|
374
|
+
tests/ # E2E tests at root level
|
|
375
|
+
├── e2e/
|
|
376
|
+
│ ├── auth.spec.ts
|
|
377
|
+
│ └── users.spec.ts
|
|
378
|
+
└── setup.ts
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
_Document patterns, not file trees. New files following patterns should not require updates to this document._
|