@lenne.tech/cli 1.0.0 → 1.0.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/build/commands/claude/install-commands.js +332 -0
- package/build/commands/claude/install-skills.js +5 -1
- package/build/commands/server/add-property.js +22 -41
- package/build/extensions/server.js +142 -46
- package/build/templates/claude-commands/code-cleanup.md +82 -0
- package/build/templates/claude-commands/mr-description-clipboard.md +48 -0
- package/build/templates/claude-commands/mr-description.md +33 -0
- package/build/templates/claude-commands/sec-review.md +62 -0
- package/build/templates/claude-commands/skill-optimize.md +140 -0
- package/build/templates/claude-commands/test-generate.md +45 -0
- package/build/templates/claude-skills/nest-server-generator/SKILL.md +372 -1314
- package/build/templates/claude-skills/nest-server-generator/configuration.md +279 -0
- package/build/templates/claude-skills/nest-server-generator/declare-keyword-warning.md +124 -0
- package/build/templates/claude-skills/nest-server-generator/description-management.md +217 -0
- package/build/templates/claude-skills/nest-server-generator/examples.md +131 -5
- package/build/templates/claude-skills/nest-server-generator/quality-review.md +855 -0
- package/build/templates/claude-skills/nest-server-generator/reference.md +67 -13
- package/build/templates/claude-skills/nest-server-generator/security-rules.md +358 -0
- package/build/templates/claude-skills/story-tdd/SKILL.md +1173 -0
- package/build/templates/claude-skills/story-tdd/code-quality.md +266 -0
- package/build/templates/claude-skills/story-tdd/database-indexes.md +173 -0
- package/build/templates/claude-skills/story-tdd/examples.md +1332 -0
- package/build/templates/claude-skills/story-tdd/reference.md +1180 -0
- package/build/templates/claude-skills/story-tdd/security-review.md +299 -0
- package/package.json +1 -1
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: story-tdd-code-quality
|
|
3
|
+
version: 1.0.0
|
|
4
|
+
description: Code quality and refactoring guidelines for Test-Driven Development
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Code Quality & Refactoring Check
|
|
8
|
+
|
|
9
|
+
**BEFORE marking the task as complete, perform a code quality review!**
|
|
10
|
+
|
|
11
|
+
Once all tests are passing, analyze your implementation for code quality issues.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 1. Check for Code Duplication
|
|
16
|
+
|
|
17
|
+
**Identify redundant code patterns:**
|
|
18
|
+
- Repeated logic in multiple methods
|
|
19
|
+
- Similar code blocks with minor variations
|
|
20
|
+
- Duplicated validation logic
|
|
21
|
+
- Repeated data transformations
|
|
22
|
+
- Multiple similar helper functions
|
|
23
|
+
|
|
24
|
+
**Example of code duplication:**
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
// ❌ BAD: Duplicated validation logic
|
|
28
|
+
async createProduct(input: ProductInput) {
|
|
29
|
+
if (!input.name || input.name.trim().length === 0) {
|
|
30
|
+
throw new BadRequestException('Name is required');
|
|
31
|
+
}
|
|
32
|
+
if (!input.price || input.price <= 0) {
|
|
33
|
+
throw new BadRequestException('Price must be positive');
|
|
34
|
+
}
|
|
35
|
+
// ... create product
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async updateProduct(id: string, input: ProductInput) {
|
|
39
|
+
if (!input.name || input.name.trim().length === 0) {
|
|
40
|
+
throw new BadRequestException('Name is required');
|
|
41
|
+
}
|
|
42
|
+
if (!input.price || input.price <= 0) {
|
|
43
|
+
throw new BadRequestException('Price must be positive');
|
|
44
|
+
}
|
|
45
|
+
// ... update product
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// ✅ GOOD: Extracted to reusable function
|
|
49
|
+
private validateProductInput(input: ProductInput) {
|
|
50
|
+
if (!input.name || input.name.trim().length === 0) {
|
|
51
|
+
throw new BadRequestException('Name is required');
|
|
52
|
+
}
|
|
53
|
+
if (!input.price || input.price <= 0) {
|
|
54
|
+
throw new BadRequestException('Price must be positive');
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async createProduct(input: ProductInput) {
|
|
59
|
+
this.validateProductInput(input);
|
|
60
|
+
// ... create product
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async updateProduct(id: string, input: ProductInput) {
|
|
64
|
+
this.validateProductInput(input);
|
|
65
|
+
// ... update product
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 2. Extract Common Functionality
|
|
72
|
+
|
|
73
|
+
**Look for opportunities to create helper functions:**
|
|
74
|
+
- Data transformation logic
|
|
75
|
+
- Validation logic
|
|
76
|
+
- Query building
|
|
77
|
+
- Response formatting
|
|
78
|
+
- Common calculations
|
|
79
|
+
|
|
80
|
+
**Example of extracting common functionality:**
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
// ❌ BAD: Repeated price calculation logic
|
|
84
|
+
async createOrder(input: OrderInput) {
|
|
85
|
+
let totalPrice = 0;
|
|
86
|
+
for (const item of input.items) {
|
|
87
|
+
const product = await this.productService.findById(item.productId);
|
|
88
|
+
totalPrice += product.price * item.quantity;
|
|
89
|
+
}
|
|
90
|
+
// ... create order
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async estimateOrderPrice(items: OrderItem[]) {
|
|
94
|
+
let totalPrice = 0;
|
|
95
|
+
for (const item of items) {
|
|
96
|
+
const product = await this.productService.findById(item.productId);
|
|
97
|
+
totalPrice += product.price * item.quantity;
|
|
98
|
+
}
|
|
99
|
+
return totalPrice;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ✅ GOOD: Extracted to reusable helper
|
|
103
|
+
private async calculateOrderTotal(items: OrderItem[]): Promise<number> {
|
|
104
|
+
let totalPrice = 0;
|
|
105
|
+
for (const item of items) {
|
|
106
|
+
const product = await this.productService.findById(item.productId);
|
|
107
|
+
totalPrice += product.price * item.quantity;
|
|
108
|
+
}
|
|
109
|
+
return totalPrice;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async createOrder(input: OrderInput) {
|
|
113
|
+
const totalPrice = await this.calculateOrderTotal(input.items);
|
|
114
|
+
// ... create order
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async estimateOrderPrice(items: OrderItem[]) {
|
|
118
|
+
return this.calculateOrderTotal(items);
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 3. Consolidate Similar Code Paths
|
|
125
|
+
|
|
126
|
+
**Identify code paths that can be unified:**
|
|
127
|
+
- Methods with similar logic but different parameters
|
|
128
|
+
- Conditional branches that can be combined
|
|
129
|
+
- Similar error handling patterns
|
|
130
|
+
|
|
131
|
+
**Example of consolidating code paths:**
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
// ❌ BAD: Similar methods with duplicated logic
|
|
135
|
+
async findProductsByCategory(category: string) {
|
|
136
|
+
return this.find({
|
|
137
|
+
where: { category },
|
|
138
|
+
relations: ['reviews', 'supplier'],
|
|
139
|
+
order: { createdAt: 'DESC' },
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async findProductsBySupplier(supplierId: string) {
|
|
144
|
+
return this.find({
|
|
145
|
+
where: { supplierId },
|
|
146
|
+
relations: ['reviews', 'supplier'],
|
|
147
|
+
order: { createdAt: 'DESC' },
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async findProductsByPriceRange(minPrice: number, maxPrice: number) {
|
|
152
|
+
return this.find({
|
|
153
|
+
where: { price: Between(minPrice, maxPrice) },
|
|
154
|
+
relations: ['reviews', 'supplier'],
|
|
155
|
+
order: { createdAt: 'DESC' },
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// ✅ GOOD: Unified method with flexible filtering
|
|
160
|
+
async findProducts(filters: {
|
|
161
|
+
category?: string;
|
|
162
|
+
supplierId?: string;
|
|
163
|
+
priceRange?: { min: number; max: number };
|
|
164
|
+
}) {
|
|
165
|
+
const where: any = {};
|
|
166
|
+
|
|
167
|
+
if (filters.category) {
|
|
168
|
+
where.category = filters.category;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (filters.supplierId) {
|
|
172
|
+
where.supplierId = filters.supplierId;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
if (filters.priceRange) {
|
|
176
|
+
where.price = Between(filters.priceRange.min, filters.priceRange.max);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return this.find({
|
|
180
|
+
where,
|
|
181
|
+
relations: ['reviews', 'supplier'],
|
|
182
|
+
order: { createdAt: 'DESC' },
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## 4. Review for Consistency
|
|
190
|
+
|
|
191
|
+
**Ensure consistent patterns throughout your implementation:**
|
|
192
|
+
- Naming conventions match existing codebase
|
|
193
|
+
- Error handling follows project patterns
|
|
194
|
+
- Return types are consistent
|
|
195
|
+
- Similar operations use similar approaches
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## 5. Refactoring Decision Tree
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
Code duplication detected?
|
|
203
|
+
│
|
|
204
|
+
├─► Used in 2+ places?
|
|
205
|
+
│ │
|
|
206
|
+
│ ├─► YES: Extract to private method
|
|
207
|
+
│ │ │
|
|
208
|
+
│ │ └─► Used across multiple services?
|
|
209
|
+
│ │ │
|
|
210
|
+
│ │ ├─► YES: Consider utility class/function
|
|
211
|
+
│ │ └─► NO: Keep as private method
|
|
212
|
+
│ │
|
|
213
|
+
│ └─► NO: Leave as-is (don't over-engineer)
|
|
214
|
+
│
|
|
215
|
+
└─► Complex logic block?
|
|
216
|
+
│
|
|
217
|
+
├─► Hard to understand?
|
|
218
|
+
│ └─► Extract to well-named method
|
|
219
|
+
│
|
|
220
|
+
└─► Simple and clear?
|
|
221
|
+
└─► Leave as-is
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## 6. Run Tests After Refactoring
|
|
227
|
+
|
|
228
|
+
**CRITICAL: After any refactoring:**
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
npm test
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**Ensure:**
|
|
235
|
+
- ✅ All tests still pass
|
|
236
|
+
- ✅ No new failures introduced
|
|
237
|
+
- ✅ Code is more maintainable
|
|
238
|
+
- ✅ No functionality changed
|
|
239
|
+
|
|
240
|
+
---
|
|
241
|
+
|
|
242
|
+
## 7. When to Skip Refactoring
|
|
243
|
+
|
|
244
|
+
**Don't refactor if:**
|
|
245
|
+
- Code is used in only ONE place
|
|
246
|
+
- Extraction would make code harder to understand
|
|
247
|
+
- The duplication is coincidental, not conceptual
|
|
248
|
+
- Time constraints don't allow for safe refactoring
|
|
249
|
+
|
|
250
|
+
**Remember:**
|
|
251
|
+
- **Working code > Perfect code**
|
|
252
|
+
- **Refactor only if it improves maintainability**
|
|
253
|
+
- **Always run tests after refactoring**
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Quick Code Quality Checklist
|
|
258
|
+
|
|
259
|
+
Before marking complete:
|
|
260
|
+
|
|
261
|
+
- [ ] **No obvious code duplication**
|
|
262
|
+
- [ ] **Common functionality extracted to helpers**
|
|
263
|
+
- [ ] **Consistent patterns throughout**
|
|
264
|
+
- [ ] **Code follows existing patterns**
|
|
265
|
+
- [ ] **Proper error handling**
|
|
266
|
+
- [ ] **Tests still pass after refactoring**
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: story-tdd-database-indexes
|
|
3
|
+
version: 1.0.0
|
|
4
|
+
description: Database index guidelines for @UnifiedField decorator - keep indexes visible with properties
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 🔍 Database Indexes with @UnifiedField
|
|
8
|
+
|
|
9
|
+
**IMPORTANT: Always define indexes directly in the @UnifiedField decorator!**
|
|
10
|
+
|
|
11
|
+
This keeps indexes visible right where properties are defined, making them easy to spot during code reviews.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## When to Add Indexes
|
|
16
|
+
|
|
17
|
+
- ✅ Fields used in queries (find, filter, search)
|
|
18
|
+
- ✅ Foreign keys (references to other collections)
|
|
19
|
+
- ✅ Fields used in sorting operations
|
|
20
|
+
- ✅ Unique constraints (email, username, etc.)
|
|
21
|
+
- ✅ Fields frequently accessed together (compound indexes)
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Example Patterns
|
|
26
|
+
|
|
27
|
+
### Single Field Index
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
@UnifiedField({
|
|
31
|
+
description: 'User email address',
|
|
32
|
+
mongoose: { index: true, unique: true, type: String } // ✅ Simple index + unique constraint
|
|
33
|
+
})
|
|
34
|
+
email: string;
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Compound Index
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
@UnifiedField({
|
|
41
|
+
description: 'Product category',
|
|
42
|
+
mongoose: { index: true, type: String } // ✅ Part of compound index
|
|
43
|
+
})
|
|
44
|
+
category: string;
|
|
45
|
+
|
|
46
|
+
@UnifiedField({
|
|
47
|
+
description: 'Product status',
|
|
48
|
+
mongoose: { index: true, type: String } // ✅ Part of compound index
|
|
49
|
+
})
|
|
50
|
+
status: string;
|
|
51
|
+
|
|
52
|
+
// Both fields indexed individually for flexible querying
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Text Index for Search
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
@UnifiedField({
|
|
59
|
+
description: 'Product name',
|
|
60
|
+
mongoose: { type: String, text: true } // ✅ Full-text search index
|
|
61
|
+
})
|
|
62
|
+
name: string;
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Foreign Key Index
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
@UnifiedField({
|
|
69
|
+
description: 'Reference to user who created this',
|
|
70
|
+
mongoose: { index: true, type: String } // ✅ Index for JOIN operations
|
|
71
|
+
})
|
|
72
|
+
createdBy: string;
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## ⚠️ DON'T Create Indexes Separately!
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
// ❌ WRONG: Separate schema index definition
|
|
81
|
+
@Schema()
|
|
82
|
+
export class Product {
|
|
83
|
+
@UnifiedField({
|
|
84
|
+
description: 'Category',
|
|
85
|
+
mongoose: { type: String }
|
|
86
|
+
})
|
|
87
|
+
category: string;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
ProductSchema.index({ category: 1 }); // ❌ Index hidden away from property
|
|
91
|
+
|
|
92
|
+
// ✅ CORRECT: Index in decorator mongoose option
|
|
93
|
+
@Schema()
|
|
94
|
+
export class Product {
|
|
95
|
+
@UnifiedField({
|
|
96
|
+
description: 'Category',
|
|
97
|
+
mongoose: { index: true, type: String } // ✅ Immediately visible
|
|
98
|
+
})
|
|
99
|
+
category: string;
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Benefits of Decorator-Based Indexes
|
|
106
|
+
|
|
107
|
+
- ✅ Indexes visible when reviewing properties
|
|
108
|
+
- ✅ No need to search schema files
|
|
109
|
+
- ✅ Clear documentation of query patterns
|
|
110
|
+
- ✅ Easier to maintain and update
|
|
111
|
+
- ✅ Self-documenting code
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Index Verification Checklist
|
|
116
|
+
|
|
117
|
+
**Look for fields that should have indexes:**
|
|
118
|
+
- Fields used in find/filter operations
|
|
119
|
+
- Foreign keys (userId, productId, etc.)
|
|
120
|
+
- Fields used in sorting (createdAt, updatedAt, name)
|
|
121
|
+
- Unique fields (email, username, slug)
|
|
122
|
+
|
|
123
|
+
**Example check:**
|
|
124
|
+
|
|
125
|
+
```typescript
|
|
126
|
+
// Service has this query:
|
|
127
|
+
const orders = await this.orderService.find({
|
|
128
|
+
where: { customerId: userId, status: 'pending' }
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// ✅ Model should have indexes:
|
|
132
|
+
export class Order {
|
|
133
|
+
@UnifiedField({
|
|
134
|
+
description: 'Customer reference',
|
|
135
|
+
mongoose: { index: true, type: String } // ✅ Used in queries
|
|
136
|
+
})
|
|
137
|
+
customerId: string;
|
|
138
|
+
|
|
139
|
+
@UnifiedField({
|
|
140
|
+
description: 'Order status',
|
|
141
|
+
mongoose: { index: true, type: String } // ✅ Used in filtering
|
|
142
|
+
})
|
|
143
|
+
status: string;
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Red Flags - Missing Indexes
|
|
150
|
+
|
|
151
|
+
🚩 **Check for these issues:**
|
|
152
|
+
- Service queries a field but model has no index
|
|
153
|
+
- Foreign key fields without index
|
|
154
|
+
- Unique constraints not marked in decorator
|
|
155
|
+
- Fields used in sorting without index
|
|
156
|
+
|
|
157
|
+
**If indexes are missing:**
|
|
158
|
+
1. Add them to the @UnifiedField decorator immediately
|
|
159
|
+
2. Re-run tests to ensure everything still works
|
|
160
|
+
3. Document why the index is needed (query pattern)
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Quick Index Checklist
|
|
165
|
+
|
|
166
|
+
Before marking complete:
|
|
167
|
+
|
|
168
|
+
- [ ] **Fields used in find() queries have indexes**
|
|
169
|
+
- [ ] **Foreign keys (userId, productId, etc.) have indexes**
|
|
170
|
+
- [ ] **Unique fields (email, username) marked with unique: true**
|
|
171
|
+
- [ ] **Fields used in sorting have indexes**
|
|
172
|
+
- [ ] **All indexes in @UnifiedField decorator (NOT separate schema)**
|
|
173
|
+
- [ ] **Indexes match query patterns in services**
|