@mind-fold/open-flow 0.1.17 → 0.2.2
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/dist/configurators/templates.d.ts.map +1 -1
- package/dist/configurators/templates.js +17 -6
- package/dist/configurators/templates.js.map +1 -1
- package/dist/configurators/workflow.d.ts.map +1 -1
- package/dist/configurators/workflow.js +82 -6
- package/dist/configurators/workflow.js.map +1 -1
- package/dist/templates/commands/break-loop.txt +107 -0
- package/dist/templates/commands/check-cross-layer.txt +153 -0
- package/dist/templates/commands/finish-work.txt +129 -0
- package/dist/templates/commands/index.d.ts +9 -5
- package/dist/templates/commands/index.d.ts.map +1 -1
- package/dist/templates/commands/index.js +16 -5
- package/dist/templates/commands/index.js.map +1 -1
- package/dist/templates/commands/init-agent.txt +100 -9
- package/dist/templates/commands/sync-from-runtime.txt +140 -0
- package/dist/templates/markdown/flow.md.txt +96 -84
- package/dist/templates/markdown/index.d.ts +21 -4
- package/dist/templates/markdown/index.d.ts.map +1 -1
- package/dist/templates/markdown/index.js +27 -4
- package/dist/templates/markdown/index.js.map +1 -1
- package/dist/templates/markdown/structure/backend/database-guidelines.md.txt +247 -0
- package/dist/templates/markdown/structure/backend/directory-structure.md.txt +153 -0
- package/dist/templates/markdown/structure/backend/error-handling.md.txt +257 -0
- package/dist/templates/markdown/structure/backend/index.md.txt +88 -0
- package/dist/templates/markdown/structure/backend/logging-guidelines.md.txt +212 -0
- package/dist/templates/markdown/structure/backend/quality-guidelines.md.txt +219 -0
- package/dist/templates/markdown/structure/backend/type-safety.md.txt +192 -0
- package/dist/templates/markdown/structure/flows/code-reuse-thinking-guide.md.txt +343 -0
- package/dist/templates/markdown/structure/flows/cross-layer-thinking-guide.md.txt +283 -0
- package/dist/templates/markdown/structure/flows/index.md.txt +133 -0
- package/dist/templates/markdown/structure/flows/pre-implementation-checklist.md.txt +182 -0
- package/dist/templates/markdown/structure/flows/spec-flow-template.md.txt +145 -0
- package/dist/templates/markdown/structure/frontend/component-guidelines.md.txt +335 -0
- package/dist/templates/markdown/structure/frontend/directory-structure.md.txt +172 -0
- package/dist/templates/markdown/structure/frontend/hook-guidelines.md.txt +287 -0
- package/dist/templates/markdown/structure/frontend/index.md.txt +91 -0
- package/dist/templates/markdown/structure/frontend/quality-guidelines.md.txt +274 -0
- package/dist/templates/markdown/structure/frontend/state-management.md.txt +293 -0
- package/dist/templates/markdown/structure/frontend/type-safety.md.txt +275 -0
- package/package.json +2 -2
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
# Component Guidelines
|
|
2
|
+
|
|
3
|
+
> Component patterns, semantic HTML, and accessibility
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Component Structure
|
|
8
|
+
|
|
9
|
+
### Basic Component
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import { type ComponentProps } from 'react';
|
|
13
|
+
import { cn } from '@/lib/utils';
|
|
14
|
+
|
|
15
|
+
interface UserCardProps {
|
|
16
|
+
user: User;
|
|
17
|
+
onClick?: () => void;
|
|
18
|
+
className?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function UserCard({ user, onClick, className }: UserCardProps) {
|
|
22
|
+
return (
|
|
23
|
+
<article
|
|
24
|
+
className={cn('rounded-lg border p-4', className)}
|
|
25
|
+
onClick={onClick}
|
|
26
|
+
>
|
|
27
|
+
<h3>{user.name}</h3>
|
|
28
|
+
<p>{user.email}</p>
|
|
29
|
+
</article>
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Component with Children
|
|
35
|
+
|
|
36
|
+
```typescript
|
|
37
|
+
interface CardProps {
|
|
38
|
+
title: string;
|
|
39
|
+
children: React.ReactNode;
|
|
40
|
+
footer?: React.ReactNode;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function Card({ title, children, footer }: CardProps) {
|
|
44
|
+
return (
|
|
45
|
+
<article className="card">
|
|
46
|
+
<header>
|
|
47
|
+
<h2>{title}</h2>
|
|
48
|
+
</header>
|
|
49
|
+
<div className="card-content">
|
|
50
|
+
{children}
|
|
51
|
+
</div>
|
|
52
|
+
{footer && (
|
|
53
|
+
<footer className="card-footer">
|
|
54
|
+
{footer}
|
|
55
|
+
</footer>
|
|
56
|
+
)}
|
|
57
|
+
</article>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
## Semantic HTML
|
|
65
|
+
|
|
66
|
+
Use proper HTML elements for their intended purpose.
|
|
67
|
+
|
|
68
|
+
### Interactive Elements
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
// ✅ GOOD: Use button for actions
|
|
72
|
+
<button onClick={handleClick}>Click me</button>
|
|
73
|
+
|
|
74
|
+
// ❌ BAD: Don't use div as button
|
|
75
|
+
<div role="button" onClick={handleClick}>Click me</div>
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Links vs Buttons
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
// Button: triggers an action
|
|
82
|
+
<button onClick={handleSubmit}>Submit</button>
|
|
83
|
+
|
|
84
|
+
// Link: navigates to a URL
|
|
85
|
+
<Link href="/about">About</Link>
|
|
86
|
+
|
|
87
|
+
// ❌ BAD: Button that looks like a link but navigates
|
|
88
|
+
<button onClick={() => router.push('/about')}>About</button>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Headings
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
// ✅ GOOD: Proper heading hierarchy
|
|
95
|
+
<article>
|
|
96
|
+
<h1>Page Title</h1>
|
|
97
|
+
<section>
|
|
98
|
+
<h2>Section Title</h2>
|
|
99
|
+
<h3>Subsection</h3>
|
|
100
|
+
</section>
|
|
101
|
+
</article>
|
|
102
|
+
|
|
103
|
+
// ❌ BAD: Skipping heading levels
|
|
104
|
+
<h1>Title</h1>
|
|
105
|
+
<h3>Subsection</h3> // Missing h2
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Lists
|
|
109
|
+
|
|
110
|
+
```typescript
|
|
111
|
+
// ✅ GOOD: Use list elements for lists
|
|
112
|
+
<ul>
|
|
113
|
+
{items.map(item => (
|
|
114
|
+
<li key={item.id}>{item.name}</li>
|
|
115
|
+
))}
|
|
116
|
+
</ul>
|
|
117
|
+
|
|
118
|
+
// ❌ BAD: Divs for list
|
|
119
|
+
<div>
|
|
120
|
+
{items.map(item => (
|
|
121
|
+
<div key={item.id}>{item.name}</div>
|
|
122
|
+
))}
|
|
123
|
+
</div>
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Image Optimization
|
|
129
|
+
|
|
130
|
+
### Next.js Image Component
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
import Image from 'next/image';
|
|
134
|
+
|
|
135
|
+
// ✅ GOOD: Use Next.js Image
|
|
136
|
+
<Image
|
|
137
|
+
src="/avatar.png"
|
|
138
|
+
alt="User avatar"
|
|
139
|
+
width={100}
|
|
140
|
+
height={100}
|
|
141
|
+
/>
|
|
142
|
+
|
|
143
|
+
// ❌ BAD: Native img tag
|
|
144
|
+
<img src="/avatar.png" alt="User avatar" />
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### External Images
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
// next.config.js - configure allowed domains
|
|
151
|
+
module.exports = {
|
|
152
|
+
images: {
|
|
153
|
+
remotePatterns: [
|
|
154
|
+
{ protocol: 'https', hostname: '*.example.com' },
|
|
155
|
+
],
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// Component
|
|
160
|
+
<Image
|
|
161
|
+
src="https://cdn.example.com/avatar.png"
|
|
162
|
+
alt="Avatar"
|
|
163
|
+
width={100}
|
|
164
|
+
height={100}
|
|
165
|
+
/>
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Accessibility
|
|
171
|
+
|
|
172
|
+
### Labels for Inputs
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
// ✅ GOOD: Associated label
|
|
176
|
+
<label htmlFor="email">Email</label>
|
|
177
|
+
<input id="email" type="email" />
|
|
178
|
+
|
|
179
|
+
// ✅ GOOD: Implicit label
|
|
180
|
+
<label>
|
|
181
|
+
Email
|
|
182
|
+
<input type="email" />
|
|
183
|
+
</label>
|
|
184
|
+
|
|
185
|
+
// ❌ BAD: No label
|
|
186
|
+
<input type="email" placeholder="Email" />
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### ARIA Attributes
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
// Loading state
|
|
193
|
+
<button disabled={isLoading} aria-busy={isLoading}>
|
|
194
|
+
{isLoading ? 'Loading...' : 'Submit'}
|
|
195
|
+
</button>
|
|
196
|
+
|
|
197
|
+
// Error state
|
|
198
|
+
<input
|
|
199
|
+
aria-invalid={!!error}
|
|
200
|
+
aria-describedby={error ? 'email-error' : undefined}
|
|
201
|
+
/>
|
|
202
|
+
{error && <span id="email-error">{error}</span>}
|
|
203
|
+
|
|
204
|
+
// Modal dialog
|
|
205
|
+
<dialog aria-modal="true" aria-labelledby="dialog-title">
|
|
206
|
+
<h2 id="dialog-title">Confirm Action</h2>
|
|
207
|
+
</dialog>
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
### Keyboard Navigation
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
// Handle keyboard events for custom interactive elements
|
|
214
|
+
function Dropdown({ items }: { items: Item[] }) {
|
|
215
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
216
|
+
|
|
217
|
+
const handleKeyDown = (e: KeyboardEvent) => {
|
|
218
|
+
switch (e.key) {
|
|
219
|
+
case 'ArrowDown':
|
|
220
|
+
setActiveIndex(i => Math.min(i + 1, items.length - 1));
|
|
221
|
+
break;
|
|
222
|
+
case 'ArrowUp':
|
|
223
|
+
setActiveIndex(i => Math.max(i - 1, 0));
|
|
224
|
+
break;
|
|
225
|
+
case 'Enter':
|
|
226
|
+
selectItem(items[activeIndex]);
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
return (
|
|
232
|
+
<ul role="listbox" onKeyDown={handleKeyDown}>
|
|
233
|
+
{items.map((item, index) => (
|
|
234
|
+
<li
|
|
235
|
+
key={item.id}
|
|
236
|
+
role="option"
|
|
237
|
+
aria-selected={index === activeIndex}
|
|
238
|
+
>
|
|
239
|
+
{item.name}
|
|
240
|
+
</li>
|
|
241
|
+
))}
|
|
242
|
+
</ul>
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
## Component Patterns
|
|
250
|
+
|
|
251
|
+
### Compound Components
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
// Card.tsx
|
|
255
|
+
const CardContext = createContext<{ variant: string } | null>(null);
|
|
256
|
+
|
|
257
|
+
function Card({ children, variant = 'default' }) {
|
|
258
|
+
return (
|
|
259
|
+
<CardContext.Provider value={{ variant }}>
|
|
260
|
+
<article className={cn('card', variant)}>
|
|
261
|
+
{children}
|
|
262
|
+
</article>
|
|
263
|
+
</CardContext.Provider>
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
Card.Header = function CardHeader({ children }) {
|
|
268
|
+
return <header className="card-header">{children}</header>;
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
Card.Body = function CardBody({ children }) {
|
|
272
|
+
return <div className="card-body">{children}</div>;
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
Card.Footer = function CardFooter({ children }) {
|
|
276
|
+
return <footer className="card-footer">{children}</footer>;
|
|
277
|
+
};
|
|
278
|
+
|
|
279
|
+
// Usage
|
|
280
|
+
<Card variant="elevated">
|
|
281
|
+
<Card.Header>Title</Card.Header>
|
|
282
|
+
<Card.Body>Content</Card.Body>
|
|
283
|
+
<Card.Footer>Actions</Card.Footer>
|
|
284
|
+
</Card>
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Controlled vs Uncontrolled
|
|
288
|
+
|
|
289
|
+
```typescript
|
|
290
|
+
interface InputProps {
|
|
291
|
+
value?: string; // Controlled
|
|
292
|
+
defaultValue?: string; // Uncontrolled
|
|
293
|
+
onChange?: (value: string) => void;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function Input({ value, defaultValue, onChange }: InputProps) {
|
|
297
|
+
const [internalValue, setInternalValue] = useState(defaultValue ?? '');
|
|
298
|
+
|
|
299
|
+
const isControlled = value !== undefined;
|
|
300
|
+
const currentValue = isControlled ? value : internalValue;
|
|
301
|
+
|
|
302
|
+
const handleChange = (e: ChangeEvent<HTMLInputElement>) => {
|
|
303
|
+
if (!isControlled) {
|
|
304
|
+
setInternalValue(e.target.value);
|
|
305
|
+
}
|
|
306
|
+
onChange?.(e.target.value);
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
return <input value={currentValue} onChange={handleChange} />;
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Best Practices
|
|
316
|
+
|
|
317
|
+
### DO
|
|
318
|
+
|
|
319
|
+
- Use semantic HTML elements
|
|
320
|
+
- Include alt text for images
|
|
321
|
+
- Associate labels with inputs
|
|
322
|
+
- Handle loading and error states
|
|
323
|
+
- Use TypeScript for props
|
|
324
|
+
|
|
325
|
+
### DON'T
|
|
326
|
+
|
|
327
|
+
- Use divs for everything
|
|
328
|
+
- Use onClick on non-interactive elements
|
|
329
|
+
- Forget keyboard accessibility
|
|
330
|
+
- Skip heading levels
|
|
331
|
+
- Use native img in Next.js
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
**Language**: All documentation must be written in **English**.
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Directory Structure
|
|
2
|
+
|
|
3
|
+
> Module organization and file layout for frontend development
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Standard Layout
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
src/
|
|
11
|
+
├── app/ # Next.js App Router (if using Next.js)
|
|
12
|
+
│ ├── (marketing)/ # Marketing pages group
|
|
13
|
+
│ ├── (app)/ # Application pages group
|
|
14
|
+
│ └── api/ # API routes
|
|
15
|
+
│
|
|
16
|
+
├── components/ # Shared components
|
|
17
|
+
│ ├── ui/ # Base UI components (Button, Input, etc.)
|
|
18
|
+
│ └── common/ # Composite components (Header, Footer, etc.)
|
|
19
|
+
│
|
|
20
|
+
├── modules/ # Feature modules
|
|
21
|
+
│ └── {feature}/
|
|
22
|
+
│ ├── components/ # Feature-specific components
|
|
23
|
+
│ ├── hooks/ # Feature-specific hooks
|
|
24
|
+
│ ├── context/ # Feature-specific context
|
|
25
|
+
│ ├── lib/ # Feature-specific utilities
|
|
26
|
+
│ └── types.ts # Feature types
|
|
27
|
+
│
|
|
28
|
+
├── hooks/ # Shared hooks
|
|
29
|
+
│ ├── use-debounce.ts
|
|
30
|
+
│ └── use-local-storage.ts
|
|
31
|
+
│
|
|
32
|
+
├── lib/ # Shared utilities
|
|
33
|
+
│ ├── api-client.ts # API client setup
|
|
34
|
+
│ ├── utils.ts # Helper functions
|
|
35
|
+
│ └── constants.ts # Global constants
|
|
36
|
+
│
|
|
37
|
+
├── types/ # Shared type definitions
|
|
38
|
+
│ └── index.ts
|
|
39
|
+
│
|
|
40
|
+
└── styles/ # Global styles
|
|
41
|
+
└── globals.css
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Feature Module Structure
|
|
47
|
+
|
|
48
|
+
Each feature module is self-contained:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
modules/users/
|
|
52
|
+
├── components/
|
|
53
|
+
│ ├── user-card.tsx # Display component
|
|
54
|
+
│ ├── user-form.tsx # Form component
|
|
55
|
+
│ └── user-list.tsx # List component
|
|
56
|
+
│
|
|
57
|
+
├── hooks/
|
|
58
|
+
│ ├── use-user.ts # Single user query
|
|
59
|
+
│ ├── use-users.ts # Users list query
|
|
60
|
+
│ └── use-update-user.ts # Update mutation
|
|
61
|
+
│
|
|
62
|
+
├── context/
|
|
63
|
+
│ └── user-context.tsx # Feature-level state
|
|
64
|
+
│
|
|
65
|
+
├── lib/
|
|
66
|
+
│ └── user-utils.ts # Feature-specific helpers
|
|
67
|
+
│
|
|
68
|
+
└── types.ts # Feature types (if not from API)
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Component Organization
|
|
74
|
+
|
|
75
|
+
### UI Components (Primitives)
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
components/ui/
|
|
79
|
+
├── button.tsx # Base button
|
|
80
|
+
├── input.tsx # Base input
|
|
81
|
+
├── select.tsx # Base select
|
|
82
|
+
├── dialog.tsx # Modal dialog
|
|
83
|
+
├── dropdown-menu.tsx # Dropdown menu
|
|
84
|
+
└── index.ts # Barrel export
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Common Components (Composites)
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
components/common/
|
|
91
|
+
├── header.tsx # App header
|
|
92
|
+
├── sidebar.tsx # Navigation sidebar
|
|
93
|
+
├── page-layout.tsx # Page wrapper
|
|
94
|
+
├── error-boundary.tsx # Error boundary
|
|
95
|
+
└── loading-spinner.tsx # Loading state
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Naming Conventions
|
|
101
|
+
|
|
102
|
+
| Type | Convention | Example |
|
|
103
|
+
|------|------------|---------|
|
|
104
|
+
| Files | kebab-case | `user-card.tsx` |
|
|
105
|
+
| Components | PascalCase | `UserCard` |
|
|
106
|
+
| Hooks | camelCase with `use` prefix | `useUser` |
|
|
107
|
+
| Types | PascalCase | `UserData` |
|
|
108
|
+
| Constants | SCREAMING_SNAKE | `MAX_FILE_SIZE` |
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Import Order
|
|
113
|
+
|
|
114
|
+
Organize imports in this order:
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// 1. React and framework imports
|
|
118
|
+
import { useState, useEffect } from 'react';
|
|
119
|
+
import { useRouter } from 'next/navigation';
|
|
120
|
+
|
|
121
|
+
// 2. Third-party libraries
|
|
122
|
+
import { useQuery } from '@tanstack/react-query';
|
|
123
|
+
import { z } from 'zod';
|
|
124
|
+
|
|
125
|
+
// 3. Internal aliases (@/)
|
|
126
|
+
import { Button } from '@/components/ui/button';
|
|
127
|
+
import { useAuth } from '@/hooks/use-auth';
|
|
128
|
+
|
|
129
|
+
// 4. Relative imports (same module)
|
|
130
|
+
import { UserCard } from './user-card';
|
|
131
|
+
import type { UserFormData } from './types';
|
|
132
|
+
|
|
133
|
+
// 5. Styles
|
|
134
|
+
import styles from './user-list.module.css';
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Best Practices
|
|
140
|
+
|
|
141
|
+
### DO
|
|
142
|
+
|
|
143
|
+
- Keep feature modules self-contained
|
|
144
|
+
- Use barrel exports (`index.ts`) for clean imports
|
|
145
|
+
- Co-locate related files (component + hook + types)
|
|
146
|
+
- Prefix hook files with `use-`
|
|
147
|
+
|
|
148
|
+
### DON'T
|
|
149
|
+
|
|
150
|
+
- Create deeply nested directories (max 3 levels)
|
|
151
|
+
- Put feature-specific code in shared directories
|
|
152
|
+
- Use generic names (`utils.ts`) in feature modules
|
|
153
|
+
- Mix different features in one module
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Module Boundaries
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
✅ ALLOWED:
|
|
161
|
+
- modules/users/ imports from components/ui/
|
|
162
|
+
- modules/users/ imports from hooks/
|
|
163
|
+
- modules/users/ imports from lib/
|
|
164
|
+
|
|
165
|
+
❌ NOT ALLOWED:
|
|
166
|
+
- modules/users/ imports from modules/orders/
|
|
167
|
+
(Use shared hooks or lift to common location)
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
**Language**: All documentation must be written in **English**.
|