@relipa/ai-flow-kit 0.2.0 → 0.2.1
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/custom/rules/java/spring-boot-rules.md +209 -0
- package/custom/rules/javascript/nestjs-examples.md +41 -0
- package/custom/rules/javascript/nestjs-rules.md +42 -0
- package/custom/rules/javascript/nodejs-express-examples.md +35 -0
- package/custom/rules/javascript/nodejs-express-rules.md +49 -0
- package/custom/rules/javascript/reactjs-examples.md +380 -0
- package/custom/rules/javascript/reactjs-rules.md +173 -0
- package/custom/rules/php/php-examples.md +161 -0
- package/custom/rules/php/php-rules.md +127 -0
- package/custom/rules/python/python-django-examples.md +34 -0
- package/custom/rules/python/python-django-rules.md +48 -0
- package/custom/rules/python/python-examples.md +32 -0
- package/custom/rules/python/python-fastapi-examples.md +30 -0
- package/custom/rules/python/python-fastapi-rules.md +35 -0
- package/custom/rules/python/python-ml-examples.md +187 -0
- package/custom/rules/python/python-ml-rules.md +121 -0
- package/custom/rules/python/python-rules.md +58 -0
- package/custom/skills/ba-skills/skill-ba-qna-template-v1.md +4 -4
- package/custom/skills/ba-skills/skill-ba-qna-v1.md +6 -0
- package/custom/skills/create-system-requirement/SKILL.md +52 -16
- package/custom/skills/create-system-requirement/system-requirement-template-v1.md +128 -0
- package/custom/skills/impact-analysis/SKILL.md +106 -106
- package/custom/skills/report-customer/SKILL.md +99 -99
- package/custom/templates/nestjs.md +5 -72
- package/custom/templates/nodejs-express.md +5 -73
- package/custom/templates/php-plain.md +5 -261
- package/custom/templates/php.md +5 -261
- package/custom/templates/python-django.md +5 -71
- package/custom/templates/python-fastapi.md +5 -54
- package/custom/templates/python-ml.md +1 -269
- package/custom/templates/python.md +5 -79
- package/custom/templates/reactjs.md +5 -492
- package/custom/templates/shared/gate-workflow.md +1 -0
- package/custom/templates/shared/ml-gate-workflow.md +1 -0
- package/custom/templates/spring-boot.md +5 -224
- package/docs/common/CHANGELOG.md +20 -10
- package/package.json +1 -1
- package/scripts/init.js +143 -40
|
@@ -1,79 +1,5 @@
|
|
|
1
|
-
# Python AI System Prompt
|
|
2
|
-
|
|
3
|
-
You are an expert Python developer. Follow these rules to produce clean, idiomatic, and maintainable Python code without a specific framework.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## Project Structure
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
project/
|
|
11
|
-
├── main.py # Entry point
|
|
12
|
-
├── src/
|
|
13
|
-
│ ├── service/ # Business logic
|
|
14
|
-
│ ├── repository/ # Data access layer
|
|
15
|
-
│ ├── model/ # Data classes / domain models
|
|
16
|
-
│ └── util/ # Pure helper functions
|
|
17
|
-
├── tests/ # Pytest suite
|
|
18
|
-
├── requirements.txt
|
|
19
|
-
└── pyproject.toml
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
---
|
|
23
|
-
|
|
24
|
-
## Python Rules
|
|
25
|
-
|
|
26
|
-
- Use **type hints** on all function signatures and return types.
|
|
27
|
-
- Follow **PEP 8** and keep functions small and single-purpose.
|
|
28
|
-
- Use **dataclasses** or **NamedTuple** for value objects; avoid plain dicts for structured data.
|
|
29
|
-
- Prefer **pathlib** over `os.path`; prefer `with` statements for file/resource handling.
|
|
30
|
-
- Raise specific exceptions — never `raise Exception("message")`.
|
|
31
|
-
|
|
32
|
-
```python
|
|
33
|
-
# ✅ Good
|
|
34
|
-
from dataclasses import dataclass
|
|
35
|
-
|
|
36
|
-
@dataclass
|
|
37
|
-
class UserRequest:
|
|
38
|
-
email: str
|
|
39
|
-
full_name: str
|
|
40
|
-
|
|
41
|
-
def create_user(request: UserRequest) -> UserResponse:
|
|
42
|
-
if not request.email:
|
|
43
|
-
raise ValueError("email is required")
|
|
44
|
-
...
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
## Testing Rules
|
|
50
|
-
|
|
51
|
-
- Use **Pytest** for all tests.
|
|
52
|
-
- Name test functions `test_<what>_<expected_outcome>`.
|
|
53
|
-
- Use `pytest.raises` to assert exceptions.
|
|
54
|
-
|
|
55
|
-
```python
|
|
56
|
-
def test_create_user_raises_when_email_is_empty():
|
|
57
|
-
with pytest.raises(ValueError, match="email is required"):
|
|
58
|
-
create_user(UserRequest(email="", full_name="Test"))
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
---
|
|
62
|
-
|
|
63
|
-
## Naming Conventions
|
|
64
|
-
|
|
65
|
-
| Element | Convention | Example |
|
|
66
|
-
|---------|-----------|---------|
|
|
67
|
-
| Module/package | snake_case | `user_service.py` |
|
|
68
|
-
| Class | PascalCase | `UserService` |
|
|
69
|
-
| Function/variable | snake_case | `find_by_id`, `user_id` |
|
|
70
|
-
| Constant | UPPER_SNAKE_CASE | `MAX_RETRY` |
|
|
71
|
-
|
|
72
|
-
---
|
|
73
|
-
|
|
74
|
-
## Common Anti-Patterns to Avoid
|
|
75
|
-
|
|
76
|
-
- ❌ Bare `except:` — always catch a specific exception type
|
|
77
|
-
- ❌ Mutable default arguments (`def f(x=[])`) — use `None` sentinel instead
|
|
78
|
-
- ❌ Global state — pass dependencies explicitly
|
|
79
|
-
- ❌ Returning `None` implicitly on error paths — raise or return a typed result
|
|
1
|
+
# Python AI System Prompt
|
|
2
|
+
|
|
3
|
+
You are an expert Python developer. Follow these rules to produce clean, idiomatic, and maintainable Python code without a specific framework.
|
|
4
|
+
|
|
5
|
+
> **Rules & code examples:** Read `.rules/python/python-rules.md` (structure, rules, naming, anti-patterns) and `.rules/python/python-examples.md` (code samples per rule area) **in full** before writing or modifying any Python code in this project.
|
|
@@ -1,492 +1,5 @@
|
|
|
1
|
-
# React.js AI System Prompt
|
|
2
|
-
|
|
3
|
-
You are an expert React.js developer. Follow these specific rules when generating or modifying code in this project.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
## Project Stack
|
|
8
|
-
|
|
9
|
-
- **React:** 18+
|
|
10
|
-
- **Language:** TypeScript
|
|
11
|
-
- **Build Tool:** Vite (prefer) or Create React App
|
|
12
|
-
- **State Management:** Zustand (local/global) or TanStack Query (server state)
|
|
13
|
-
- **Routing:** React Router v6
|
|
14
|
-
- **Styling:** Tailwind CSS + shadcn/ui (or CSS Modules if no Tailwind)
|
|
15
|
-
- **Form:** React Hook Form + Zod validation
|
|
16
|
-
- **HTTP Client:** Axios with interceptors
|
|
17
|
-
- **Testing:** Vitest + React Testing Library
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## Project Structure
|
|
22
|
-
|
|
23
|
-
```
|
|
24
|
-
src/
|
|
25
|
-
├── components/
|
|
26
|
-
│ ├── ui/ # Generic, reusable UI (Button, Input, Modal...)
|
|
27
|
-
│ └── [feature]/ # Feature-specific components
|
|
28
|
-
├── pages/ # Route-level components (thin, delegate to features)
|
|
29
|
-
├── features/ # Self-contained feature modules
|
|
30
|
-
│ └── [feature]/
|
|
31
|
-
│ ├── components/ # UI specific to this feature
|
|
32
|
-
│ ├── hooks/ # Custom hooks for this feature
|
|
33
|
-
│ ├── api.ts # API calls for this feature
|
|
34
|
-
│ ├── store.ts # Zustand slice (if needed)
|
|
35
|
-
│ ├── types.ts # TypeScript types/interfaces
|
|
36
|
-
│ └── index.ts # Public exports
|
|
37
|
-
├── hooks/ # Shared custom hooks
|
|
38
|
-
├── services/
|
|
39
|
-
│ └── api.ts # Axios instance + interceptors
|
|
40
|
-
├── store/ # Global Zustand store
|
|
41
|
-
├── types/ # Shared TypeScript types
|
|
42
|
-
├── utils/ # Pure utility functions
|
|
43
|
-
├── constants/ # App-wide constants
|
|
44
|
-
└── App.tsx
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
---
|
|
48
|
-
|
|
49
|
-
## Component Rules
|
|
50
|
-
|
|
51
|
-
### Always use Functional Components
|
|
52
|
-
|
|
53
|
-
```tsx
|
|
54
|
-
// ✅ Good
|
|
55
|
-
const UserCard = ({ user }: UserCardProps) => {
|
|
56
|
-
return <div>{user.name}</div>;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
// ❌ Bad — class component
|
|
60
|
-
class UserCard extends React.Component {}
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
### Define Props with TypeScript interface
|
|
64
|
-
|
|
65
|
-
```tsx
|
|
66
|
-
// ✅ Good
|
|
67
|
-
interface UserCardProps {
|
|
68
|
-
user: User;
|
|
69
|
-
onDelete?: (id: number) => void;
|
|
70
|
-
className?: string;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const UserCard = ({ user, onDelete, className }: UserCardProps) => {
|
|
74
|
-
// ...
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
// ❌ Bad — any, or no type
|
|
78
|
-
const UserCard = ({ user }: any) => {};
|
|
79
|
-
const UserCard = (props) => {};
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### Keep components focused and small
|
|
83
|
-
|
|
84
|
-
- One component = one responsibility
|
|
85
|
-
- If a component exceeds ~150 lines, split it
|
|
86
|
-
- Extract logic to custom hooks, keep JSX clean
|
|
87
|
-
|
|
88
|
-
```tsx
|
|
89
|
-
// ✅ Good — logic extracted to hook
|
|
90
|
-
const UserList = () => {
|
|
91
|
-
const { users, isLoading, error, deleteUser } = useUserList();
|
|
92
|
-
|
|
93
|
-
if (isLoading) return <Spinner />;
|
|
94
|
-
if (error) return <ErrorMessage message={error.message} />;
|
|
95
|
-
|
|
96
|
-
return (
|
|
97
|
-
<ul>
|
|
98
|
-
{users.map(user => (
|
|
99
|
-
<UserCard key={user.id} user={user} onDelete={deleteUser} />
|
|
100
|
-
))}
|
|
101
|
-
</ul>
|
|
102
|
-
);
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
// ❌ Bad — logic mixed into component
|
|
106
|
-
const UserList = () => {
|
|
107
|
-
const [users, setUsers] = useState([]);
|
|
108
|
-
const [loading, setLoading] = useState(true);
|
|
109
|
-
|
|
110
|
-
useEffect(() => {
|
|
111
|
-
fetch('/api/users')
|
|
112
|
-
.then(r => r.json())
|
|
113
|
-
.then(data => { setUsers(data); setLoading(false); });
|
|
114
|
-
}, []);
|
|
115
|
-
|
|
116
|
-
const handleDelete = async (id) => {
|
|
117
|
-
await fetch(`/api/users/${id}`, { method: 'DELETE' });
|
|
118
|
-
setUsers(prev => prev.filter(u => u.id !== id));
|
|
119
|
-
};
|
|
120
|
-
// ... long JSX
|
|
121
|
-
};
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
### Export convention
|
|
125
|
-
|
|
126
|
-
```tsx
|
|
127
|
-
// Named export for regular components
|
|
128
|
-
export const UserCard = ({ user }: UserCardProps) => { ... };
|
|
129
|
-
|
|
130
|
-
// Default export only for page-level components
|
|
131
|
-
export default function UserPage() { ... }
|
|
132
|
-
```
|
|
133
|
-
|
|
134
|
-
---
|
|
135
|
-
|
|
136
|
-
## Custom Hook Rules
|
|
137
|
-
|
|
138
|
-
- Prefix with `use`: `useUserList`, `useAuth`, `useModal`
|
|
139
|
-
- Extract all side effects, API calls, and complex state from components
|
|
140
|
-
- Return objects (not arrays) for multiple values — easier to destructure
|
|
141
|
-
|
|
142
|
-
```tsx
|
|
143
|
-
// ✅ Good
|
|
144
|
-
const useUserList = () => {
|
|
145
|
-
const { data: users = [], isLoading, error } = useQuery({
|
|
146
|
-
queryKey: ['users'],
|
|
147
|
-
queryFn: userApi.getAll,
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
const { mutate: deleteUser } = useMutation({
|
|
151
|
-
mutationFn: userApi.delete,
|
|
152
|
-
onSuccess: () => queryClient.invalidateQueries({ queryKey: ['users'] }),
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
return { users, isLoading, error, deleteUser };
|
|
156
|
-
};
|
|
157
|
-
|
|
158
|
-
// Usage
|
|
159
|
-
const { users, isLoading, deleteUser } = useUserList();
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
---
|
|
163
|
-
|
|
164
|
-
## State Management Rules
|
|
165
|
-
|
|
166
|
-
### Server state → TanStack Query
|
|
167
|
-
|
|
168
|
-
Use for all API data (fetching, caching, mutations):
|
|
169
|
-
|
|
170
|
-
```tsx
|
|
171
|
-
// Fetching
|
|
172
|
-
const { data, isLoading, error } = useQuery({
|
|
173
|
-
queryKey: ['users', filters], // include deps in key
|
|
174
|
-
queryFn: () => userApi.getAll(filters),
|
|
175
|
-
staleTime: 5 * 60 * 1000, // 5 minutes
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
// Mutation
|
|
179
|
-
const { mutate, isPending } = useMutation({
|
|
180
|
-
mutationFn: userApi.create,
|
|
181
|
-
onSuccess: () => {
|
|
182
|
-
queryClient.invalidateQueries({ queryKey: ['users'] });
|
|
183
|
-
toast.success('User created');
|
|
184
|
-
},
|
|
185
|
-
onError: (error) => toast.error(error.message),
|
|
186
|
-
});
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
### Client/UI state → Zustand (or useState for local)
|
|
190
|
-
|
|
191
|
-
```tsx
|
|
192
|
-
// Local state — use useState
|
|
193
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
194
|
-
|
|
195
|
-
// Shared UI state — use Zustand
|
|
196
|
-
const useAuthStore = create<AuthStore>((set) => ({
|
|
197
|
-
user: null,
|
|
198
|
-
token: null,
|
|
199
|
-
login: (user, token) => set({ user, token }),
|
|
200
|
-
logout: () => set({ user: null, token: null }),
|
|
201
|
-
}));
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
### Rules:
|
|
205
|
-
- **Never** use global state for server/API data — that's TanStack Query's job
|
|
206
|
-
- **Never** fetch in `useEffect` manually — use TanStack Query
|
|
207
|
-
- **Never** put loading/error state in Zustand — TanStack Query handles that
|
|
208
|
-
|
|
209
|
-
---
|
|
210
|
-
|
|
211
|
-
## Form Rules
|
|
212
|
-
|
|
213
|
-
Use **React Hook Form + Zod** for all forms:
|
|
214
|
-
|
|
215
|
-
```tsx
|
|
216
|
-
// 1. Define schema with Zod
|
|
217
|
-
const createUserSchema = z.object({
|
|
218
|
-
email: z.string().email('Invalid email'),
|
|
219
|
-
fullName: z.string().min(2, 'Min 2 characters').max(100),
|
|
220
|
-
password: z.string().min(8, 'Min 8 characters'),
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
type CreateUserForm = z.infer<typeof createUserSchema>;
|
|
224
|
-
|
|
225
|
-
// 2. Use in component
|
|
226
|
-
const CreateUserForm = () => {
|
|
227
|
-
const { register, handleSubmit, formState: { errors, isSubmitting } } = useForm<CreateUserForm>({
|
|
228
|
-
resolver: zodResolver(createUserSchema),
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
const onSubmit = async (data: CreateUserForm) => {
|
|
232
|
-
await createUser(data);
|
|
233
|
-
};
|
|
234
|
-
|
|
235
|
-
return (
|
|
236
|
-
<form onSubmit={handleSubmit(onSubmit)}>
|
|
237
|
-
<input {...register('email')} />
|
|
238
|
-
{errors.email && <span>{errors.email.message}</span>}
|
|
239
|
-
|
|
240
|
-
<button type="submit" disabled={isSubmitting}>
|
|
241
|
-
{isSubmitting ? 'Saving...' : 'Create'}
|
|
242
|
-
</button>
|
|
243
|
-
</form>
|
|
244
|
-
);
|
|
245
|
-
};
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
---
|
|
249
|
-
|
|
250
|
-
## API Layer Rules
|
|
251
|
-
|
|
252
|
-
One `axios` instance shared across the app with interceptors:
|
|
253
|
-
|
|
254
|
-
```tsx
|
|
255
|
-
// src/services/api.ts
|
|
256
|
-
const api = axios.create({
|
|
257
|
-
baseURL: import.meta.env.VITE_API_URL,
|
|
258
|
-
timeout: 10000,
|
|
259
|
-
headers: { 'Content-Type': 'application/json' },
|
|
260
|
-
});
|
|
261
|
-
|
|
262
|
-
// Attach token automatically
|
|
263
|
-
api.interceptors.request.use((config) => {
|
|
264
|
-
const token = useAuthStore.getState().token;
|
|
265
|
-
if (token) config.headers.Authorization = `Bearer ${token}`;
|
|
266
|
-
return config;
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
// Handle 401 globally
|
|
270
|
-
api.interceptors.response.use(
|
|
271
|
-
(response) => response,
|
|
272
|
-
(error) => {
|
|
273
|
-
if (error.response?.status === 401) {
|
|
274
|
-
useAuthStore.getState().logout();
|
|
275
|
-
window.location.href = '/login';
|
|
276
|
-
}
|
|
277
|
-
return Promise.reject(error);
|
|
278
|
-
}
|
|
279
|
-
);
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
Feature API module:
|
|
283
|
-
|
|
284
|
-
```tsx
|
|
285
|
-
// src/features/users/api.ts
|
|
286
|
-
export const userApi = {
|
|
287
|
-
getAll: (params?: UserListParams): Promise<User[]> =>
|
|
288
|
-
api.get('/users', { params }).then(r => r.data),
|
|
289
|
-
|
|
290
|
-
getById: (id: number): Promise<User> =>
|
|
291
|
-
api.get(`/users/${id}`).then(r => r.data),
|
|
292
|
-
|
|
293
|
-
create: (data: CreateUserRequest): Promise<User> =>
|
|
294
|
-
api.post('/users', data).then(r => r.data),
|
|
295
|
-
|
|
296
|
-
update: (id: number, data: UpdateUserRequest): Promise<User> =>
|
|
297
|
-
api.put(`/users/${id}`, data).then(r => r.data),
|
|
298
|
-
|
|
299
|
-
delete: (id: number): Promise<void> =>
|
|
300
|
-
api.delete(`/users/${id}`).then(r => r.data),
|
|
301
|
-
};
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
---
|
|
305
|
-
|
|
306
|
-
## TypeScript Rules
|
|
307
|
-
|
|
308
|
-
- **No `any`** — use `unknown`, proper types, or generics
|
|
309
|
-
- Define shared types in `types.ts` files
|
|
310
|
-
- Use `interface` for object shapes, `type` for unions/intersections
|
|
311
|
-
- Always type function return values for public hooks and API functions
|
|
312
|
-
|
|
313
|
-
```tsx
|
|
314
|
-
// ✅ Good
|
|
315
|
-
interface User {
|
|
316
|
-
id: number;
|
|
317
|
-
email: string;
|
|
318
|
-
fullName: string;
|
|
319
|
-
createdAt: string;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
type UserStatus = 'active' | 'inactive' | 'banned';
|
|
323
|
-
|
|
324
|
-
const getUser = async (id: number): Promise<User> => {
|
|
325
|
-
return api.get(`/users/${id}`).then(r => r.data);
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
// ❌ Bad
|
|
329
|
-
const getUser = async (id: any) => {
|
|
330
|
-
return api.get(`/users/${id}`).then((r: any) => r.data);
|
|
331
|
-
};
|
|
332
|
-
```
|
|
333
|
-
|
|
334
|
-
---
|
|
335
|
-
|
|
336
|
-
## Styling Rules (Tailwind CSS)
|
|
337
|
-
|
|
338
|
-
- Use utility classes directly — avoid custom CSS unless necessary
|
|
339
|
-
- Extract repeated class combinations into components or a `cn()` helper
|
|
340
|
-
- Use `className` prop for external style overrides
|
|
341
|
-
|
|
342
|
-
```tsx
|
|
343
|
-
// ✅ Good — cn() for conditional classes
|
|
344
|
-
import { cn } from '\@/utils/cn';
|
|
345
|
-
|
|
346
|
-
const Button = ({ variant = 'primary', disabled, className, children }: ButtonProps) => (
|
|
347
|
-
<button
|
|
348
|
-
className={cn(
|
|
349
|
-
'px-4 py-2 rounded font-medium transition-colors',
|
|
350
|
-
variant === 'primary' && 'bg-blue-600 text-white hover:bg-blue-700',
|
|
351
|
-
variant === 'outline' && 'border border-gray-300 hover:bg-gray-50',
|
|
352
|
-
disabled && 'opacity-50 cursor-not-allowed',
|
|
353
|
-
className
|
|
354
|
-
)}
|
|
355
|
-
disabled={disabled}
|
|
356
|
-
>
|
|
357
|
-
{children}
|
|
358
|
-
</button>
|
|
359
|
-
);
|
|
360
|
-
|
|
361
|
-
// ❌ Bad — inline style
|
|
362
|
-
<button style={{ backgroundColor: 'blue', padding: '8px 16px' }}>
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
---
|
|
366
|
-
|
|
367
|
-
## Performance Rules
|
|
368
|
-
|
|
369
|
-
- Use `React.memo` only when profiling shows a real problem — do not optimize prematurely
|
|
370
|
-
- Use `useMemo` / `useCallback` for expensive computations or stable references passed to children
|
|
371
|
-
- Lazy-load routes with `React.lazy` + `Suspense`
|
|
372
|
-
- Avoid anonymous functions in JSX props when passing to memoized children
|
|
373
|
-
|
|
374
|
-
```tsx
|
|
375
|
-
// Lazy routes
|
|
376
|
-
const UserPage = React.lazy(() => import('./pages/UserPage'));
|
|
377
|
-
|
|
378
|
-
<Suspense fallback={<PageSkeleton />}>
|
|
379
|
-
<UserPage />
|
|
380
|
-
</Suspense>
|
|
381
|
-
|
|
382
|
-
// useMemo for expensive computation
|
|
383
|
-
const sortedUsers = useMemo(
|
|
384
|
-
() => [...users].sort((a, b) => a.fullName.localeCompare(b.fullName)),
|
|
385
|
-
[users]
|
|
386
|
-
);
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
---
|
|
390
|
-
|
|
391
|
-
## Error Handling Rules
|
|
392
|
-
|
|
393
|
-
- Use React Error Boundary at the route level
|
|
394
|
-
- Handle API errors in TanStack Query `onError` callbacks
|
|
395
|
-
- Show user-friendly messages — never raw error objects
|
|
396
|
-
- Use toast notifications for async operation feedback
|
|
397
|
-
|
|
398
|
-
```tsx
|
|
399
|
-
// Error boundary at route level
|
|
400
|
-
<ErrorBoundary fallback={<ErrorPage />}>
|
|
401
|
-
<Routes>
|
|
402
|
-
<Route path="/users" element={<UserPage />} />
|
|
403
|
-
</Routes>
|
|
404
|
-
</ErrorBoundary>
|
|
405
|
-
|
|
406
|
-
// Async error handling
|
|
407
|
-
const { mutate } = useMutation({
|
|
408
|
-
mutationFn: userApi.create,
|
|
409
|
-
onSuccess: () => toast.success('User created successfully'),
|
|
410
|
-
onError: (error: AxiosError<ApiError>) =>
|
|
411
|
-
toast.error(error.response?.data?.message ?? 'Something went wrong'),
|
|
412
|
-
});
|
|
413
|
-
```
|
|
414
|
-
|
|
415
|
-
---
|
|
416
|
-
|
|
417
|
-
## Testing Rules
|
|
418
|
-
|
|
419
|
-
### Unit/Component tests with React Testing Library
|
|
420
|
-
|
|
421
|
-
```tsx
|
|
422
|
-
// Test behavior, not implementation
|
|
423
|
-
describe('UserCard', () => {
|
|
424
|
-
it('should display user name and email', () => {
|
|
425
|
-
const user: User = { id: 1, email: 'test\@example.com', fullName: 'Test User' };
|
|
426
|
-
render(<UserCard user={user} />);
|
|
427
|
-
|
|
428
|
-
expect(screen.getByText('Test User')).toBeInTheDocument();
|
|
429
|
-
expect(screen.getByText('test\@example.com')).toBeInTheDocument();
|
|
430
|
-
});
|
|
431
|
-
|
|
432
|
-
it('should call onDelete with user id when delete button clicked', async () => {
|
|
433
|
-
const onDelete = vi.fn();
|
|
434
|
-
const user: User = { id: 1, email: 'test\@example.com', fullName: 'Test User' };
|
|
435
|
-
|
|
436
|
-
render(<UserCard user={user} onDelete={onDelete} />);
|
|
437
|
-
await userEvent.click(screen.getByRole('button', { name: /delete/i }));
|
|
438
|
-
|
|
439
|
-
expect(onDelete).toHaveBeenCalledWith(1);
|
|
440
|
-
});
|
|
441
|
-
});
|
|
442
|
-
```
|
|
443
|
-
|
|
444
|
-
### Hook tests
|
|
445
|
-
|
|
446
|
-
```tsx
|
|
447
|
-
import { renderHook, waitFor } from '\@testing-library/react';
|
|
448
|
-
|
|
449
|
-
it('should fetch users', async () => {
|
|
450
|
-
const { result } = renderHook(() => useUserList(), { wrapper: QueryWrapper });
|
|
451
|
-
|
|
452
|
-
await waitFor(() => expect(result.current.isLoading).toBe(false));
|
|
453
|
-
|
|
454
|
-
expect(result.current.users).toHaveLength(2);
|
|
455
|
-
});
|
|
456
|
-
```
|
|
457
|
-
|
|
458
|
-
---
|
|
459
|
-
|
|
460
|
-
## Naming Conventions
|
|
461
|
-
|
|
462
|
-
| Element | Convention | Example |
|
|
463
|
-
|---------|-----------|---------|
|
|
464
|
-
| Component file | PascalCase | `UserCard.tsx` |
|
|
465
|
-
| Hook file | camelCase | `useUserList.ts` |
|
|
466
|
-
| Utility file | camelCase | `formatDate.ts` |
|
|
467
|
-
| Type/Interface | PascalCase | `User`, `CreateUserRequest` |
|
|
468
|
-
| Component | PascalCase | `UserCard`, `OrderList` |
|
|
469
|
-
| Hook | `use` + PascalCase | `useUserList`, `useAuth` |
|
|
470
|
-
| Event handler | `handle` + Action | `handleDelete`, `handleSubmit` |
|
|
471
|
-
| Boolean variable | `is/has/can` prefix | `isLoading`, `hasError`, `canEdit` |
|
|
472
|
-
| Constant | UPPER_SNAKE_CASE | `MAX_RETRY`, `API_TIMEOUT` |
|
|
473
|
-
| CSS class (custom) | kebab-case | `user-card`, `nav-item` |
|
|
474
|
-
|
|
475
|
-
---
|
|
476
|
-
|
|
477
|
-
## Common Anti-Patterns to Avoid
|
|
478
|
-
|
|
479
|
-
- ❌ Fetching in `useEffect` → use TanStack Query
|
|
480
|
-
- ❌ Using `any` type → define proper TypeScript types
|
|
481
|
-
- ❌ Storing server data in Zustand → that's TanStack Query's responsibility
|
|
482
|
-
- ❌ Class components → use functional components
|
|
483
|
-
- ❌ `index.js` everywhere → use named files for traceability
|
|
484
|
-
- ❌ Direct DOM manipulation → use React state/refs
|
|
485
|
-
- ❌ Mutating state directly → always use setter functions
|
|
486
|
-
- ❌ Large components doing everything → split into smaller focused components
|
|
487
|
-
- ❌ Prop drilling more than 2 levels → use context or Zustand
|
|
488
|
-
- ❌ Hardcoding API URLs → use `import.meta.env.VITE_API_URL`
|
|
489
|
-
|
|
490
|
-
---
|
|
491
|
-
|
|
492
|
-
When explaining changes, refer to the [React Official Documentation](https://react.dev), [TanStack Query](https://tanstack.com/query), and [React Hook Form](https://react-hook-form.com) conventions.
|
|
1
|
+
# React.js AI System Prompt
|
|
2
|
+
|
|
3
|
+
You are an expert React.js developer. Follow these specific rules when generating or modifying code in this project.
|
|
4
|
+
|
|
5
|
+
> **Rules & code examples:** Read `.rules/javascript/reactjs-rules.md` (structure, per-area rules, naming, anti-patterns) and `.rules/javascript/reactjs-examples.md` (code samples per rule area) **in full** before writing or modifying any React code in this project.
|
|
@@ -162,6 +162,7 @@ Only runs after Gate 2 has been APPROVED.
|
|
|
162
162
|
|
|
163
163
|
**INVOKE:** `superpowers:test-driven-development`
|
|
164
164
|
- **Pre-flight (bắt buộc):** chạy [Pre-flight — Đồng bộ Source & Docs](#pre-flight-bắt-buộc--đồng-bộ-source--docs-đầu-mỗi-gate) ở đầu file. Lỗi → hiển thị ⚠️ cảnh báo, không dừng gate.
|
|
165
|
+
- **Framework rules (bắt buộc, đọc trước dòng code đầu tiên):** nếu chưa đọc trong session này, đọc đầy đủ file(s) được trỏ ở dòng "> **Rules & code examples:**" đầu CLAUDE.md/AGENTS.md (`.rules/<lang>/<framework>-rules.md` + `-examples.md`). Áp dụng cho MỌI lần sửa code trong Gate này, không chỉ lần đầu.
|
|
165
166
|
- Complex feature (3+ files): `superpowers:subagent-driven-development`
|
|
166
167
|
- Write tests FIRST — run to confirm FAIL -> implement -> PASS.
|
|
167
168
|
- Bug fix EXTRA: `superpowers:systematic-debugging` + `investigate-bug` skill first.
|
|
@@ -59,6 +59,7 @@ DO NOT just check format — **understand the data and propose solutions**.
|
|
|
59
59
|
Only runs after Gate 2 has been APPROVED.
|
|
60
60
|
|
|
61
61
|
**INVOKE:** `train-model` skill
|
|
62
|
+
- **Framework rules (bắt buộc, đọc trước dòng code đầu tiên):** nếu chưa đọc trong session này, đọc đầy đủ file(s) được trỏ ở dòng "> **Rules & code examples:**" đầu CLAUDE.md/AGENTS.md (`.rules/<lang>/<framework>-rules.md` + `-examples.md`). Áp dụng cho MỌI lần sửa code trong Gate này, không chỉ lần đầu.
|
|
62
63
|
- For algorithm-optimization tickets EXTRA: `improve-algorithm` skill
|
|
63
64
|
|
|
64
65
|
**Eval-harness-first rule:** Write the metric/eval harness and establish a reproducible baseline BEFORE iterating on the model. Confirm the baseline runs and is logged — then proceed with tracked experiments.
|