@mind-fold/open-flow 0.2.11 → 0.2.13
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/templates/commands/break-loop.txt +1 -1
- package/dist/templates/commands/check-cross-layer.txt +3 -3
- package/dist/templates/commands/create-command.txt +5 -5
- package/dist/templates/commands/extract-llm-docs.txt +18 -18
- package/dist/templates/commands/extract-to-rules.txt +38 -38
- package/dist/templates/commands/finish-work.txt +5 -5
- package/dist/templates/commands/generate-backend-structure.txt +27 -27
- package/dist/templates/commands/generate-frontend-structure.txt +15 -15
- package/dist/templates/commands/integrate-skill.txt +30 -30
- package/dist/templates/commands/onboard-developer.txt +257 -416
- package/dist/templates/commands/record-agent-flow.txt +4 -4
- package/dist/templates/commands/sync-from-runtime.txt +2 -2
- package/dist/templates/markdown/agent-progress-index.md.txt +9 -9
- package/dist/templates/markdown/backend-doc.md.txt +12 -12
- package/dist/templates/markdown/flow.md.txt +99 -99
- package/dist/templates/markdown/frontend-doc.md.txt +11 -11
- package/dist/templates/markdown/structure/backend/database-guidelines.md.txt +6 -6
- package/dist/templates/markdown/structure/backend/directory-structure.md.txt +28 -28
- package/dist/templates/markdown/structure/backend/index.md.txt +10 -10
- package/dist/templates/markdown/structure/backend/logging-guidelines.md.txt +4 -4
- package/dist/templates/markdown/structure/backend/quality-guidelines.md.txt +12 -12
- package/dist/templates/markdown/structure/backend/type-safety.md.txt +6 -6
- package/dist/templates/markdown/structure/flows/code-reuse-thinking-guide.md.txt +17 -17
- package/dist/templates/markdown/structure/flows/cross-layer-thinking-guide.md.txt +96 -96
- package/dist/templates/markdown/structure/flows/index.md.txt +31 -31
- package/dist/templates/markdown/structure/flows/pre-implementation-checklist.md.txt +19 -19
- package/dist/templates/markdown/structure/flows/spec-flow-template.md.txt +20 -20
- package/dist/templates/markdown/structure/frontend/component-guidelines.md.txt +12 -12
- package/dist/templates/markdown/structure/frontend/directory-structure.md.txt +61 -61
- package/dist/templates/markdown/structure/frontend/hook-guidelines.md.txt +5 -5
- package/dist/templates/markdown/structure/frontend/index.md.txt +13 -13
- package/dist/templates/markdown/structure/frontend/quality-guidelines.md.txt +21 -21
- package/dist/templates/markdown/structure/frontend/state-management.md.txt +12 -12
- package/dist/templates/markdown/structure/frontend/type-safety.md.txt +11 -11
- package/dist/templates/scripts/add-session.sh.txt +5 -5
- package/dist/templates/scripts/extract-md-headings.sh.txt +3 -3
- package/dist/templates/scripts/get-context.sh.txt +1 -1
- package/dist/templates/scripts/init-developer.sh.txt +1 -1
- package/dist/templates/scripts/update-index.sh.txt +2 -2
- package/package.json +1 -1
|
@@ -26,11 +26,11 @@ pnpm test
|
|
|
26
26
|
### Non-Null Assertions
|
|
27
27
|
|
|
28
28
|
```typescript
|
|
29
|
-
//
|
|
29
|
+
// [X] FORBIDDEN
|
|
30
30
|
const name = user!.name;
|
|
31
31
|
const data = response!.data;
|
|
32
32
|
|
|
33
|
-
//
|
|
33
|
+
// [OK] REQUIRED
|
|
34
34
|
const user = await getUser(id);
|
|
35
35
|
if (!user) {
|
|
36
36
|
throw new NotFoundError('User not found');
|
|
@@ -41,11 +41,11 @@ const name = user.name;
|
|
|
41
41
|
### Console.log
|
|
42
42
|
|
|
43
43
|
```typescript
|
|
44
|
-
//
|
|
44
|
+
// [X] FORBIDDEN
|
|
45
45
|
console.log('Debug:', data);
|
|
46
46
|
console.error('Error:', error);
|
|
47
47
|
|
|
48
|
-
//
|
|
48
|
+
// [OK] REQUIRED
|
|
49
49
|
logger.debug('processing_data', { data });
|
|
50
50
|
logger.error('operation_failed', error);
|
|
51
51
|
```
|
|
@@ -53,12 +53,12 @@ logger.error('operation_failed', error);
|
|
|
53
53
|
### Await in Loops
|
|
54
54
|
|
|
55
55
|
```typescript
|
|
56
|
-
//
|
|
56
|
+
// [X] FORBIDDEN
|
|
57
57
|
for (const id of ids) {
|
|
58
58
|
await db.select().from(users).where(eq(users.id, id));
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
//
|
|
61
|
+
// [OK] REQUIRED
|
|
62
62
|
const results = await db
|
|
63
63
|
.select()
|
|
64
64
|
.from(users)
|
|
@@ -68,11 +68,11 @@ const results = await db
|
|
|
68
68
|
### Type Assertions Without Validation
|
|
69
69
|
|
|
70
70
|
```typescript
|
|
71
|
-
//
|
|
71
|
+
// [X] FORBIDDEN
|
|
72
72
|
const data = input as UserData;
|
|
73
73
|
const config = JSON.parse(str) as Config;
|
|
74
74
|
|
|
75
|
-
//
|
|
75
|
+
// [OK] REQUIRED
|
|
76
76
|
const data = userDataSchema.parse(input);
|
|
77
77
|
const config = configSchema.parse(JSON.parse(str));
|
|
78
78
|
```
|
|
@@ -80,11 +80,11 @@ const config = configSchema.parse(JSON.parse(str));
|
|
|
80
80
|
### Any Type
|
|
81
81
|
|
|
82
82
|
```typescript
|
|
83
|
-
//
|
|
83
|
+
// [X] FORBIDDEN
|
|
84
84
|
function process(data: any) { ... }
|
|
85
85
|
const result: any = await fetch(...);
|
|
86
86
|
|
|
87
|
-
//
|
|
87
|
+
// [OK] REQUIRED
|
|
88
88
|
function process(data: unknown) {
|
|
89
89
|
const validated = schema.parse(data);
|
|
90
90
|
...
|
|
@@ -151,11 +151,11 @@ if (!user) {
|
|
|
151
151
|
### Comments
|
|
152
152
|
|
|
153
153
|
```typescript
|
|
154
|
-
//
|
|
154
|
+
// [OK] GOOD: Explain WHY, not WHAT
|
|
155
155
|
// Skip validation for internal calls to avoid performance overhead
|
|
156
156
|
const data = trustInternalData(input);
|
|
157
157
|
|
|
158
|
-
//
|
|
158
|
+
// [X] BAD: Obvious comment
|
|
159
159
|
// Get user by id
|
|
160
160
|
const user = await getUser(id);
|
|
161
161
|
```
|
|
@@ -77,7 +77,7 @@ export const userSummary = userSchema.pick({
|
|
|
77
77
|
### Problem
|
|
78
78
|
|
|
79
79
|
```typescript
|
|
80
|
-
//
|
|
80
|
+
// [X] BAD: Crashes if user is null
|
|
81
81
|
const user = await getUser(id);
|
|
82
82
|
const name = user!.name; // TypeScript trusts you, runtime doesn't
|
|
83
83
|
```
|
|
@@ -85,7 +85,7 @@ const name = user!.name; // TypeScript trusts you, runtime doesn't
|
|
|
85
85
|
### Solution: Guard with Local Variable
|
|
86
86
|
|
|
87
87
|
```typescript
|
|
88
|
-
//
|
|
88
|
+
// [OK] GOOD: Explicit null check
|
|
89
89
|
const user = await getUser(id);
|
|
90
90
|
if (!user) {
|
|
91
91
|
throw new NotFoundError('User not found');
|
|
@@ -97,7 +97,7 @@ const name = user.name; // Safe access
|
|
|
97
97
|
### Solution: Early Return
|
|
98
98
|
|
|
99
99
|
```typescript
|
|
100
|
-
//
|
|
100
|
+
// [OK] GOOD: Early return pattern
|
|
101
101
|
async function getUserName(id: string): Promise<string> {
|
|
102
102
|
const user = await getUser(id);
|
|
103
103
|
if (!user) {
|
|
@@ -178,13 +178,13 @@ if (!user) {
|
|
|
178
178
|
|
|
179
179
|
```typescript
|
|
180
180
|
// Trust external data
|
|
181
|
-
const data = externalInput as User; //
|
|
181
|
+
const data = externalInput as User; // [X]
|
|
182
182
|
|
|
183
183
|
// Use non-null assertion
|
|
184
|
-
const name = user!.name; //
|
|
184
|
+
const name = user!.name; // [X]
|
|
185
185
|
|
|
186
186
|
// Ignore parse errors
|
|
187
|
-
const data = userSchema.parse(input); //
|
|
187
|
+
const data = userSchema.parse(input); // [X] Throws on invalid
|
|
188
188
|
```
|
|
189
189
|
|
|
190
190
|
---
|
|
@@ -159,15 +159,15 @@ function Card({ title, content, badge }: CardProps) {
|
|
|
159
159
|
- [ ] Is this display value defined in multiple components?
|
|
160
160
|
- [ ] Should there be a shared config for this domain concept?
|
|
161
161
|
|
|
162
|
-
**The Problem**: Same domain concept displayed in multiple components, each with its own config. Changing one, forgetting others
|
|
162
|
+
**The Problem**: Same domain concept displayed in multiple components, each with its own config. Changing one, forgetting others -> inconsistency.
|
|
163
163
|
|
|
164
164
|
**Example - Before (bug)**:
|
|
165
165
|
```tsx
|
|
166
166
|
// TodoColumn.tsx
|
|
167
|
-
const stateConfig = { open: { label: "Open", ... } }; //
|
|
167
|
+
const stateConfig = { open: { label: "Open", ... } }; // [OK] Updated
|
|
168
168
|
|
|
169
169
|
// TodoDetailPanel.tsx (FORGOT!)
|
|
170
|
-
const stateConfig = { open: { label: "Todo", ... } }; //
|
|
170
|
+
const stateConfig = { open: { label: "Todo", ... } }; // [X] Still old
|
|
171
171
|
|
|
172
172
|
// Result: Column shows "Open", Detail panel shows "Todo"
|
|
173
173
|
```
|
|
@@ -198,7 +198,7 @@ rg "stateConfig|StateConfig|state.*label" --type tsx
|
|
|
198
198
|
- [ ] Is there already a visual distinction for this concept?
|
|
199
199
|
- [ ] Does the logic use the **same criteria** as the visual representation?
|
|
200
200
|
|
|
201
|
-
**The Problem**: Visual representation and logic use different criteria
|
|
201
|
+
**The Problem**: Visual representation and logic use different criteria -> inconsistent behavior.
|
|
202
202
|
|
|
203
203
|
**Example - Before (bug)**:
|
|
204
204
|
```typescript
|
|
@@ -265,7 +265,7 @@ import { SYNC_CONSTANTS } from "@shared/constants";
|
|
|
265
265
|
- Abstraction would be confusing
|
|
266
266
|
|
|
267
267
|
**Rule of thumb**:
|
|
268
|
-
> "Duplication is cheaper than the wrong abstraction"
|
|
268
|
+
> "Duplication is cheaper than the wrong abstraction" -- Sandi Metz
|
|
269
269
|
|
|
270
270
|
But once you see 3+ occurrences, it's time to abstract.
|
|
271
271
|
|
|
@@ -297,18 +297,18 @@ rg "open.*label|label.*open" --type tsx
|
|
|
297
297
|
|
|
298
298
|
```
|
|
299
299
|
You're about to write some code
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
300
|
+
|
|
|
301
|
+
|- Does similar code exist?
|
|
302
|
+
| |- Yes -> Can you reuse/extend it?
|
|
303
|
+
| | |- Yes -> Reuse it
|
|
304
|
+
| | \- No -> Why not? (might need abstraction)
|
|
305
|
+
| \- No -> Continue
|
|
306
|
+
|
|
|
307
|
+
|- Is this the 3rd time writing this pattern?
|
|
308
|
+
| |- Yes -> Time to abstract
|
|
309
|
+
| \- No -> OK to duplicate for now
|
|
310
|
+
|
|
|
311
|
+
\- Done
|
|
312
312
|
```
|
|
313
313
|
|
|
314
314
|
---
|
|
@@ -37,8 +37,8 @@ Before writing code, answer these questions:
|
|
|
37
37
|
**Q: How does data flow?**
|
|
38
38
|
|
|
39
39
|
```
|
|
40
|
-
[ ] Read flow: Database
|
|
41
|
-
[ ] Write flow: Component
|
|
40
|
+
[ ] Read flow: Database -> Service -> API -> Hook -> Component
|
|
41
|
+
[ ] Write flow: Component -> Hook -> API -> Service -> Database
|
|
42
42
|
[ ] Both ways (bidirectional)
|
|
43
43
|
```
|
|
44
44
|
|
|
@@ -82,92 +82,92 @@ Before writing code, answer these questions:
|
|
|
82
82
|
### Pattern A: CRUD Feature
|
|
83
83
|
|
|
84
84
|
```
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
85
|
+
+-------------------------------------------------------------+
|
|
86
|
+
| THINK THROUGH |
|
|
87
|
+
|-------------------------------------------------------------|
|
|
88
|
+
| |
|
|
89
|
+
| 1. CREATE |
|
|
90
|
+
| \- UI: What triggers creation? (button, form) |
|
|
91
|
+
| \- API: What's the input schema? |
|
|
92
|
+
| \- DB: What tables are affected? |
|
|
93
|
+
| \- Response: What does UI need back? |
|
|
94
|
+
| |
|
|
95
|
+
| 2. READ |
|
|
96
|
+
| \- List view: What fields needed? (avoid over-fetch) |
|
|
97
|
+
| \- Detail view: Lazy load heavy content? |
|
|
98
|
+
| \- Loading: Show skeleton? Empty state? |
|
|
99
|
+
| |
|
|
100
|
+
| 3. UPDATE |
|
|
101
|
+
| \- Optimistic UI? (update local before API responds) |
|
|
102
|
+
| \- Validation: Same rules as create? |
|
|
103
|
+
| \- Partial update? (PATCH vs PUT) |
|
|
104
|
+
| |
|
|
105
|
+
| 4. DELETE |
|
|
106
|
+
| \- Soft delete? (isDeleted flag) |
|
|
107
|
+
| \- Cascade? (related entities) |
|
|
108
|
+
| \- Confirmation required? |
|
|
109
|
+
| |
|
|
110
|
+
\-------------------------------------------------------------+
|
|
111
111
|
```
|
|
112
112
|
|
|
113
113
|
### Pattern B: Form Submission
|
|
114
114
|
|
|
115
115
|
```
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
116
|
+
+-------------------------------------------------------------+
|
|
117
|
+
| THINK THROUGH |
|
|
118
|
+
|-------------------------------------------------------------|
|
|
119
|
+
| |
|
|
120
|
+
| 1. INPUT |
|
|
121
|
+
| \- What fields are required vs optional? |
|
|
122
|
+
| \- What validations on each field? |
|
|
123
|
+
| \- Real-time validation or on submit? |
|
|
124
|
+
| |
|
|
125
|
+
| 2. SUBMISSION |
|
|
126
|
+
| \- Disable button while submitting? |
|
|
127
|
+
| \- Show loading indicator? |
|
|
128
|
+
| \- Prevent double submission? |
|
|
129
|
+
| |
|
|
130
|
+
| 3. SUCCESS |
|
|
131
|
+
| \- Redirect to where? |
|
|
132
|
+
| \- Show success message? |
|
|
133
|
+
| \- Invalidate which queries? |
|
|
134
|
+
| |
|
|
135
|
+
| 4. ERROR |
|
|
136
|
+
| \- Show inline errors or toast? |
|
|
137
|
+
| \- Which fields keep values? |
|
|
138
|
+
| \- How to retry? |
|
|
139
|
+
| |
|
|
140
|
+
\-------------------------------------------------------------+
|
|
141
141
|
```
|
|
142
142
|
|
|
143
143
|
### Pattern C: Data List with Filters
|
|
144
144
|
|
|
145
145
|
```
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
146
|
+
+-------------------------------------------------------------+
|
|
147
|
+
| THINK THROUGH |
|
|
148
|
+
|-------------------------------------------------------------|
|
|
149
|
+
| |
|
|
150
|
+
| 1. FILTERS |
|
|
151
|
+
| \- Which filters are available? |
|
|
152
|
+
| \- Filters in URL for shareability? |
|
|
153
|
+
| \- Server-side or client-side filtering? |
|
|
154
|
+
| |
|
|
155
|
+
| 2. PAGINATION |
|
|
156
|
+
| \- Page-based or cursor-based? |
|
|
157
|
+
| \- Total count needed? |
|
|
158
|
+
| \- Infinite scroll or explicit pages? |
|
|
159
|
+
| |
|
|
160
|
+
| 3. SORTING |
|
|
161
|
+
| \- Default sort order? |
|
|
162
|
+
| \- Multi-column sort? |
|
|
163
|
+
| \- Server-side or client-side? |
|
|
164
|
+
| |
|
|
165
|
+
| 4. LOADING |
|
|
166
|
+
| \- Skeleton for initial load? |
|
|
167
|
+
| \- Overlay for filter change? |
|
|
168
|
+
| \- Keep previous data while loading? |
|
|
169
|
+
| |
|
|
170
|
+
\-------------------------------------------------------------+
|
|
171
171
|
```
|
|
172
172
|
|
|
173
173
|
---
|
|
@@ -212,24 +212,24 @@ Before writing code, answer these questions:
|
|
|
212
212
|
|
|
213
213
|
```
|
|
214
214
|
Start: New Feature
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
215
|
+
|
|
|
216
|
+
|- Touches 3+ layers?
|
|
217
|
+
| |- Yes -> Use this thinking guide
|
|
218
|
+
| \- No -> Standard implementation
|
|
219
|
+
|
|
|
220
|
+
|- Has form submission?
|
|
221
|
+
| |- Yes -> Think through Pattern B
|
|
222
|
+
| \- No -> Skip
|
|
223
|
+
|
|
|
224
|
+
|- Has data list?
|
|
225
|
+
| |- Yes -> Think through Pattern C
|
|
226
|
+
| \- No -> Skip
|
|
227
|
+
|
|
|
228
|
+
|- Has CRUD operations?
|
|
229
|
+
| |- Yes -> Think through Pattern A
|
|
230
|
+
| \- No -> Skip
|
|
231
|
+
|
|
|
232
|
+
\- Done: Implementation checklist ready
|
|
233
233
|
```
|
|
234
234
|
|
|
235
235
|
---
|
|
@@ -18,18 +18,18 @@ Most bugs happen at **layer boundaries**, not within layers. This directory prov
|
|
|
18
18
|
|
|
19
19
|
```
|
|
20
20
|
Before writing ANY code
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
21
|
+
|
|
|
22
|
+
|- Read: Pre-Implementation Checklist
|
|
23
|
+
| \- "Will this constant be used elsewhere?"
|
|
24
|
+
| \- "Does this pattern already exist?"
|
|
25
|
+
|
|
|
26
|
+
|- If feature spans 3+ layers
|
|
27
|
+
| \- Read: Cross-Layer Thinking Guide
|
|
28
|
+
| \- Consider creating a Flow Spec
|
|
29
|
+
|
|
|
30
|
+
\- During/After implementation
|
|
31
|
+
\- Reference: Code Reuse Thinking Guide
|
|
32
|
+
\- Run: /check-cross-layer command
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
---
|
|
@@ -56,7 +56,7 @@ Before writing ANY code
|
|
|
56
56
|
|
|
57
57
|
Create a flow spec when a feature:
|
|
58
58
|
|
|
59
|
-
- [ ] Spans 3+ layers (e.g., API
|
|
59
|
+
- [ ] Spans 3+ layers (e.g., API -> Service -> Component -> Hook)
|
|
60
60
|
- [ ] Has transformation points where data format changes
|
|
61
61
|
- [ ] Has multiple consumers with different requirements
|
|
62
62
|
- [ ] Involves state that passes through multiple components
|
|
@@ -66,41 +66,41 @@ Create a flow spec when a feature:
|
|
|
66
66
|
|
|
67
67
|
## Quick Reference: Common Cross-Layer Patterns
|
|
68
68
|
|
|
69
|
-
### Pattern 1: API
|
|
69
|
+
### Pattern 1: API -> Service -> Component
|
|
70
70
|
|
|
71
71
|
```
|
|
72
72
|
API Route # Validate input, call service
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
|
|
|
74
|
+
v
|
|
75
75
|
Service Layer # Business logic, database
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
|
|
|
77
|
+
v
|
|
78
78
|
Response # Format for client
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
|
|
|
80
|
+
v
|
|
81
81
|
React Query Hook # Cache, loading states
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
|
|
|
83
|
+
v
|
|
84
84
|
Component # Render UI
|
|
85
85
|
```
|
|
86
86
|
|
|
87
87
|
**Common Mistake**: Service returns different format than hook expects.
|
|
88
88
|
|
|
89
|
-
### Pattern 2: User Action
|
|
89
|
+
### Pattern 2: User Action -> State -> API -> Refetch
|
|
90
90
|
|
|
91
91
|
```
|
|
92
92
|
User clicks button # UI Layer
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
|
|
|
94
|
+
v
|
|
95
95
|
Call mutation hook # React Query mutation
|
|
96
|
-
|
|
97
|
-
|
|
96
|
+
|
|
|
97
|
+
v
|
|
98
98
|
API Request # POST/PATCH/DELETE
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
|
|
|
100
|
+
v
|
|
101
101
|
Invalidate queries # Trigger refetch
|
|
102
|
-
|
|
103
|
-
|
|
102
|
+
|
|
|
103
|
+
v
|
|
104
104
|
UI updates # New data rendered
|
|
105
105
|
```
|
|
106
106
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
## Why This Checklist?
|
|
8
8
|
|
|
9
|
-
Most code quality issues aren't caught during implementation
|
|
9
|
+
Most code quality issues aren't caught during implementation--they're **designed in** from the start:
|
|
10
10
|
|
|
11
11
|
| Problem | Root Cause | Cost |
|
|
12
12
|
|---------|------------|------|
|
|
@@ -25,15 +25,15 @@ Most code quality issues aren't caught during implementation—they're **designe
|
|
|
25
25
|
Before adding any constant or config value:
|
|
26
26
|
|
|
27
27
|
- [ ] **Cross-layer usage?** Will this value be used in both frontend and backend?
|
|
28
|
-
- If yes
|
|
28
|
+
- If yes -> Put in shared constants file
|
|
29
29
|
- Example: Batch size used by backend sync AND frontend threshold check
|
|
30
30
|
|
|
31
31
|
- [ ] **Multiple consumers?** Will this value be used in 2+ files within the same layer?
|
|
32
|
-
- If yes
|
|
32
|
+
- If yes -> Put in a shared constants file for that layer
|
|
33
33
|
- Example: Don't define `DEBOUNCE_MS = 2000` in each hook file
|
|
34
34
|
|
|
35
35
|
- [ ] **Magic number?** Is this a hardcoded value that could change?
|
|
36
|
-
- If yes
|
|
36
|
+
- If yes -> Extract to named constant with comment explaining why
|
|
37
37
|
- Example: `BATCH_SIZE: 15 // API limit constraint`
|
|
38
38
|
|
|
39
39
|
### 2. Logic & Patterns
|
|
@@ -48,18 +48,18 @@ Before implementing any logic:
|
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
- [ ] **Will repeat?** Will this exact logic be needed in 2+ places?
|
|
51
|
-
- If yes
|
|
51
|
+
- If yes -> Create a shared hook/utility **first**, then use it
|
|
52
52
|
- Don't copy-paste and plan to refactor later
|
|
53
53
|
|
|
54
54
|
- [ ] **Callback pattern?** Does the logic need optional callbacks (onStart, onComplete, onError)?
|
|
55
|
-
- If yes
|
|
55
|
+
- If yes -> Design the abstraction with callback support from the start
|
|
56
56
|
|
|
57
57
|
### 3. Types & Interfaces
|
|
58
58
|
|
|
59
59
|
Before defining types:
|
|
60
60
|
|
|
61
61
|
- [ ] **Cross-layer type?** Is this type used across API boundary?
|
|
62
|
-
- If yes
|
|
62
|
+
- If yes -> Define in shared types location
|
|
63
63
|
- Never duplicate type definitions between frontend and backend
|
|
64
64
|
|
|
65
65
|
- [ ] **Existing type?** Does a similar type already exist?
|
|
@@ -73,7 +73,7 @@ Before creating UI components:
|
|
|
73
73
|
- Example: If items show priority icons in a specific order, sorting logic should use the same order
|
|
74
74
|
|
|
75
75
|
- [ ] **State lifecycle?** Will this component unmount during normal user flow?
|
|
76
|
-
- If yes
|
|
76
|
+
- If yes -> Consider where state should persist (parent, context, store)
|
|
77
77
|
|
|
78
78
|
---
|
|
79
79
|
|
|
@@ -81,21 +81,21 @@ Before creating UI components:
|
|
|
81
81
|
|
|
82
82
|
```
|
|
83
83
|
Adding a value/constant?
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
|-- Used in frontend AND backend? -> Shared constants
|
|
85
|
+
|-- Used in 2+ files in same layer? -> Layer-specific shared constants
|
|
86
|
+
\-- Single file only? -> Local constant is fine
|
|
87
87
|
|
|
88
88
|
Adding logic/behavior?
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
|-- Similar pattern exists? -> Extend or reuse existing
|
|
90
|
+
|-- Will be used in 2+ places? -> Create shared hook/utility first
|
|
91
|
+
\-- Single use only? -> Implement directly (but document pattern)
|
|
92
92
|
```
|
|
93
93
|
|
|
94
94
|
---
|
|
95
95
|
|
|
96
96
|
## Anti-Patterns to Avoid
|
|
97
97
|
|
|
98
|
-
###
|
|
98
|
+
### [X] Copy-Paste-Modify
|
|
99
99
|
|
|
100
100
|
```typescript
|
|
101
101
|
// DON'T: Same logic in multiple files
|
|
@@ -107,7 +107,7 @@ const triggerSync = useCallback(() => {
|
|
|
107
107
|
}, []);
|
|
108
108
|
```
|
|
109
109
|
|
|
110
|
-
###
|
|
110
|
+
### [OK] Shared Abstraction
|
|
111
111
|
|
|
112
112
|
```typescript
|
|
113
113
|
// DO: Single source of truth
|
|
@@ -119,7 +119,7 @@ export function useSyncTrigger(options) { /* logic once */ }
|
|
|
119
119
|
const triggerSync = useSyncTrigger({ workspaceId });
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
-
###
|
|
122
|
+
### [X] Local Constant Aliases
|
|
123
123
|
|
|
124
124
|
```typescript
|
|
125
125
|
// DON'T: Create local aliases for imported constants
|
|
@@ -127,7 +127,7 @@ import { CONSTANTS } from "@shared/constants";
|
|
|
127
127
|
const DEBOUNCE_MS = CONSTANTS.DEBOUNCE_MS; // Unnecessary!
|
|
128
128
|
```
|
|
129
129
|
|
|
130
|
-
###
|
|
130
|
+
### [OK] Direct Usage
|
|
131
131
|
|
|
132
132
|
```typescript
|
|
133
133
|
// DO: Use imported constants directly
|
|
@@ -171,7 +171,7 @@ setTimeout(fn, CONSTANTS.DEBOUNCE_MS);
|
|
|
171
171
|
|-------|--------|
|
|
172
172
|
| Same constant duplicated in 5+ hooks | Always ask "will this constant be used elsewhere?" before defining |
|
|
173
173
|
| Same logic copied multiple times | If logic will repeat, create abstraction **before** first use |
|
|
174
|
-
| Created local aliases for imported constants | Never create local aliases
|
|
174
|
+
| Created local aliases for imported constants | Never create local aliases--use imported constants directly |
|
|
175
175
|
|
|
176
176
|
---
|
|
177
177
|
|