@lenne.tech/cli 1.2.0 → 1.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.
Files changed (36) hide show
  1. package/build/commands/claude/install-plugin.js +339 -0
  2. package/package.json +1 -1
  3. package/build/commands/claude/install-commands.js +0 -337
  4. package/build/commands/claude/install-mcps.js +0 -258
  5. package/build/commands/claude/install-skills.js +0 -693
  6. package/build/lib/mcp-registry.js +0 -80
  7. package/build/templates/claude-commands/code-cleanup.md +0 -82
  8. package/build/templates/claude-commands/commit-message.md +0 -21
  9. package/build/templates/claude-commands/create-story.md +0 -435
  10. package/build/templates/claude-commands/mr-description-clipboard.md +0 -48
  11. package/build/templates/claude-commands/mr-description.md +0 -33
  12. package/build/templates/claude-commands/sec-review.md +0 -62
  13. package/build/templates/claude-commands/skill-optimize.md +0 -481
  14. package/build/templates/claude-commands/test-generate.md +0 -45
  15. package/build/templates/claude-skills/building-stories-with-tdd/SKILL.md +0 -265
  16. package/build/templates/claude-skills/building-stories-with-tdd/code-quality.md +0 -276
  17. package/build/templates/claude-skills/building-stories-with-tdd/database-indexes.md +0 -182
  18. package/build/templates/claude-skills/building-stories-with-tdd/examples.md +0 -1383
  19. package/build/templates/claude-skills/building-stories-with-tdd/handling-existing-tests.md +0 -197
  20. package/build/templates/claude-skills/building-stories-with-tdd/reference.md +0 -1427
  21. package/build/templates/claude-skills/building-stories-with-tdd/security-review.md +0 -307
  22. package/build/templates/claude-skills/building-stories-with-tdd/workflow.md +0 -1004
  23. package/build/templates/claude-skills/generating-nest-servers/SKILL.md +0 -303
  24. package/build/templates/claude-skills/generating-nest-servers/configuration.md +0 -285
  25. package/build/templates/claude-skills/generating-nest-servers/declare-keyword-warning.md +0 -133
  26. package/build/templates/claude-skills/generating-nest-servers/description-management.md +0 -226
  27. package/build/templates/claude-skills/generating-nest-servers/examples.md +0 -893
  28. package/build/templates/claude-skills/generating-nest-servers/framework-guide.md +0 -259
  29. package/build/templates/claude-skills/generating-nest-servers/quality-review.md +0 -864
  30. package/build/templates/claude-skills/generating-nest-servers/reference.md +0 -487
  31. package/build/templates/claude-skills/generating-nest-servers/security-rules.md +0 -371
  32. package/build/templates/claude-skills/generating-nest-servers/verification-checklist.md +0 -262
  33. package/build/templates/claude-skills/generating-nest-servers/workflow-process.md +0 -1061
  34. package/build/templates/claude-skills/using-lt-cli/SKILL.md +0 -284
  35. package/build/templates/claude-skills/using-lt-cli/examples.md +0 -546
  36. package/build/templates/claude-skills/using-lt-cli/reference.md +0 -513
@@ -1,1004 +0,0 @@
1
- ---
2
- name: story-tdd-workflow
3
- version: 1.0.0
4
- description: Complete 7-step TDD workflow with detailed implementation steps, testing guidelines, and validation process
5
- ---
6
-
7
- # Story-Based TDD Workflow - The Seven Steps
8
-
9
- ## Table of Contents
10
- - [Step 1: Story Analysis & Validation](#step-1-story-analysis--validation)
11
- - [Step 2: Create Story Test](#step-2-create-story-test)
12
- - [Step 3: Run Tests & Analyze Failures](#step-3-run-tests--analyze-failures)
13
- - [Step 3a: Fix Test Errors (if needed)](#step-3a-fix-test-errors-if-needed)
14
- - [Step 4: Implement/Extend API Code](#step-4-implementextend-api-code)
15
- - [Step 5: Validate & Iterate](#step-5-validate--iterate)
16
- - [Step 5a: Code Quality & Refactoring Check](#step-5a-code-quality--refactoring-check)
17
- - [Step 5b: Final Validation](#step-5b-final-validation)
18
-
19
- This skill follows a rigorous 7-step iterative process (with Steps 5, 5a, 5b for final validation and refactoring):
20
-
21
- ## Step 1: Story Analysis & Validation
22
-
23
- **Before writing ANY code or tests:**
24
-
25
- 1. **Read and analyze the complete user story/requirement**
26
- - Identify all functional requirements
27
- - List all acceptance criteria
28
- - Note any technical constraints
29
-
30
- 2. **🔍 VERIFY existing API structure - NEVER assume!**
31
- - **Read actual Controller files** to verify endpoints exist:
32
- - Check HTTP methods (GET, POST, PUT, DELETE)
33
- - Verify exact endpoint paths (e.g., `/api/users` vs `/users`)
34
- - Confirm request/response structures
35
- - **Read actual Resolver files** for GraphQL:
36
- - Verify mutation/query names exist
37
- - Check input types and field names
38
- - Confirm return types
39
- - **Read existing test files** to understand patterns:
40
- - How are endpoints called in practice?
41
- - What authentication is used?
42
- - What response structure is expected?
43
- - **Document what EXISTS vs what NEEDS to be created:**
44
- - Existing: `/api/products` GET, POST (verified in product.controller.ts:45)
45
- - Missing: `/api/products/:id/reviews` POST (needs implementation)
46
-
47
- 3. **Identify contradictions or ambiguities**
48
- - Look for conflicting requirements
49
- - Check for unclear specifications
50
- - Verify if requirements match existing architecture
51
- - **Verify assumed endpoints actually exist!**
52
-
53
- 4. **Ask developer for clarification IMMEDIATELY if needed**
54
- - Don't assume or guess requirements
55
- - Don't assume endpoints exist without verification
56
- - Clarify contradictions BEFORE writing tests
57
- - Get confirmation on architectural decisions
58
- - Verify security/permission requirements
59
-
60
- **⚠️ CRITICAL:** If you find ANY contradictions or ambiguities, STOP and use AskUserQuestion to clarify BEFORE proceeding to Step 2.
61
-
62
- **⚠️ CRITICAL:** If you assume an endpoint exists but didn't verify it in the code, you are doing it WRONG! Always read the actual controller/resolver files first.
63
-
64
- **Step 1 Checklist:**
65
- - [ ] Story completely read and understood
66
- - [ ] All functional requirements identified
67
- - [ ] All acceptance criteria listed
68
- - [ ] Existing API structure verified (Controllers/Resolvers read)
69
- - [ ] Documented what EXISTS vs what NEEDS creation
70
- - [ ] No contradictions or ambiguities (or clarified with developer)
71
- - [ ] Ready for Step 2
72
-
73
- ## Step 2: Create Story Test
74
-
75
- **🔍 BEFORE Creating New Tests - Check Existing Tests First!**
76
-
77
- **CRITICAL:** Before writing ANY new test, verify that the functionality isn't already tested!
78
-
79
- 1. **Search existing tests** in `tests/` directory:
80
- - Look for tests covering the same endpoints/mutations
81
- - Check if existing tests already validate the behavior
82
- - Identify tests that might need updates due to story changes
83
-
84
- 2. **If functionality is already tested:**
85
- - ✅ **DO NOT** create duplicate tests
86
- - ✅ **Extend** existing tests if new edge cases are needed
87
- - ✅ **Update** existing tests if the story changes expected behavior
88
-
89
- 3. **If story changes require modifying existing tests:**
90
- - ⚠️ **ALWAYS inform the user** about which tests will be modified and why
91
- - ⚠️ **Only modify tests** when story requirements explicitly change the expected behavior
92
- - ❌ **NEVER modify tests just because they fail** - failing tests indicate bugs in implementation!
93
-
94
- **🚨 CRITICAL RULE: Tests Protect Against Unintended Side Effects!**
95
-
96
- ```
97
- Test fails after your changes?
98
-
99
- ├─► Does the story EXPLICITLY require this behavior change?
100
- │ │
101
- │ ├─► YES (documented in story requirements):
102
- │ │ └─► ✅ Update the test AND inform the user:
103
- │ │ "Updating test X because story requires behavior Y"
104
- │ │
105
- │ └─► NO (not mentioned in story):
106
- │ └─► ❌ DO NOT modify the test!
107
- │ └─► Fix your implementation instead
108
- │ (you introduced an unintended side effect)
109
- ```
110
-
111
- **Example - WRONG approach:**
112
- ```typescript
113
- // Test fails: "expected status 200, got 401"
114
- // ❌ WRONG: Just change the expected status
115
- expect(response.status).toBe(401); // Changed from 200 to make test pass
116
- ```
117
-
118
- **Example - CORRECT approach:**
119
- ```typescript
120
- // Test fails: "expected status 200, got 401"
121
- // ✅ CORRECT: Investigate WHY it fails
122
- // → Found: Missing authentication token in new implementation
123
- // → Fix: Add proper authentication, keep test expecting 200
124
- ```
125
-
126
- **When to inform user about test changes:**
127
- - "Modifying `user-registration.story.test.ts` - story now requires email verification before login"
128
- - "Updating expected response in `product-search.test.ts` - story adds new `category` field to response"
129
- - "Adjusting test data in `order-processing.test.ts` - story changes minimum order amount from 10 to 20"
130
-
131
- **📖 For detailed guidance on handling failing tests, see: `handling-existing-tests.md`**
132
-
133
- ---
134
-
135
- **🚨 CRITICAL: ALWAYS TEST THROUGH API - NEVER DIRECT SERVICE/DB ACCESS! 🚨**
136
-
137
- **FUNDAMENTAL RULE - Read This First:**
138
-
139
- Tests MUST go through REST/GraphQL interfaces (Controller/Resolver) using TestHelper. Direct Service or Database access in test logic makes tests WORTHLESS because they bypass the actual API layer that users interact with.
140
-
141
- **✅ ALWAYS DO:**
142
- - ✅ Test via REST endpoints: `testHelper.rest('/api/users', { method: 'POST', ... })`
143
- - ✅ Test via GraphQL: `testHelper.graphQl('mutation { createUser(...) }', { ... })`
144
- - ✅ Use TestHelper for ALL functional testing
145
- - ✅ Test the complete chain: Controller/Resolver → Guards → Service → Database
146
-
147
- **❌ NEVER DO:**
148
- - ❌ Direct Service calls: `userService.create()` - bypasses authentication!
149
- - ❌ Direct DB queries in tests: `db.collection('users').findOne()` - bypasses business logic!
150
- - ❌ Service instantiation: `new UserService()` - bypasses dependency injection!
151
- - ❌ Mocking Controllers or Resolvers - defeats the purpose!
152
-
153
- **Why This Rule Is Absolute:**
154
- - **Security:** Direct Service access bypasses authentication, authorization, guards, decorators
155
- - **Reality:** Tests must verify what actual users experience through the API
156
- - **Business Logic:** Services might have additional validation that gets bypassed
157
- - **Worthless Tests:** Tests that bypass the API cannot catch real bugs
158
-
159
- **🔓 RARE Exceptions - Only for Test Setup/Cleanup (NOT for testing functionality):**
160
-
161
- Direct database access is ONLY allowed in these specific cases:
162
-
163
- **✅ Allowed in beforeAll/beforeEach/afterAll/afterEach:**
164
- - Setting user roles: `await db.collection('users').updateOne({ _id: userId }, { $set: { roles: ['admin'] } })`
165
- - Setting verified status: `await db.collection('users').updateOne({ _id: userId }, { $set: { verified: true } })`
166
- - Cleanup: `await db.collection('products').deleteMany({ createdBy: testUserId })`
167
- - Read-only verification when NO API endpoint exists: `const count = await db.collection('logs').countDocuments()`
168
-
169
- **⚠️ Ask Yourself First:**
170
- Before using direct DB/Service access, ask:
171
- 1. Can I do this via an API endpoint? → If YES, use the API!
172
- 2. Am I testing functionality? → If YES, MUST use API!
173
- 3. Is this just setup/cleanup? → Only then consider direct access
174
- 4. Am I setting roles/verified status? → Allowed exception
175
- 5. Am I reading data that has NO API endpoint? → Allowed, but prefer API
176
-
177
- **❌ Still NEVER Allowed - Even in Setup:**
178
- - ❌ Testing functionality via Services
179
- - ❌ Creating test data via Services when API exists
180
- - ❌ Verifying results via DB when API query exists
181
- - ❌ Writing to DB for anything other than roles/verified/cleanup
182
-
183
- **Example of correct usage:**
184
-
185
- ```typescript
186
- describe('User Registration Story', () => {
187
- let testHelper: TestHelper;
188
- let db: Db;
189
- let createdUserId: string;
190
-
191
- beforeAll(async () => {
192
- testHelper = new TestHelper(app);
193
- db = app.get<Connection>(getConnectionToken()).db;
194
- });
195
-
196
- afterAll(async () => {
197
- // ✅ ALLOWED: Direct DB access for cleanup
198
- if (createdUserId) {
199
- await db.collection('users').deleteOne({ _id: new ObjectId(createdUserId) });
200
- }
201
- });
202
-
203
- it('should allow new user to register with valid data', async () => {
204
- // ✅ CORRECT: Test via API
205
- const result = await testHelper.rest('/auth/signup', {
206
- method: 'POST',
207
- payload: {
208
- email: 'newuser@test.com',
209
- password: 'SecurePass123!',
210
- firstName: 'John',
211
- lastName: 'Doe'
212
- },
213
- statusCode: 201
214
- });
215
-
216
- expect(result.id).toBeDefined();
217
- expect(result.email).toBe('newuser@test.com');
218
- createdUserId = result.id;
219
-
220
- // ✅ ALLOWED: Set verified flag for subsequent tests
221
- await db.collection('users').updateOne(
222
- { _id: new ObjectId(createdUserId) },
223
- { $set: { verified: true } }
224
- );
225
- });
226
-
227
- it('should allow verified user to sign in', async () => {
228
- // ✅ CORRECT: Test via API
229
- const result = await testHelper.rest('/auth/signin', {
230
- method: 'POST',
231
- payload: {
232
- email: 'newuser@test.com',
233
- password: 'SecurePass123!'
234
- },
235
- statusCode: 201
236
- });
237
-
238
- expect(result.token).toBeDefined();
239
- expect(result.user.email).toBe('newuser@test.com');
240
-
241
- // ❌ WRONG: Don't verify via direct DB access
242
- // const dbUser = await db.collection('users').findOne({ email: 'newuser@test.com' });
243
-
244
- // ✅ CORRECT: Verify via API
245
- const profile = await testHelper.rest('/api/users/me', {
246
- method: 'GET',
247
- token: result.token,
248
- statusCode: 200
249
- });
250
- expect(profile.email).toBe('newuser@test.com');
251
- });
252
- });
253
- ```
254
-
255
- ---
256
-
257
- **🔍 BEFORE Writing Any Tests - Study the TestHelper:**
258
-
259
- **CRITICAL: Read the TestHelper source file to understand all available features!**
260
-
261
- ```
262
- node_modules/@lenne.tech/nest-server/src/test/test.helper.ts
263
- ```
264
-
265
- This file documents ALL TestHelper capabilities:
266
- - `rest()` and `graphQl()` methods with all options
267
- - File uploads via `attachments` option
268
- - Debugging with `log` and `logError` options in `TestRestOptions`
269
- - Custom headers, status code validation
270
- - Authentication token handling
271
-
272
- **Study this file BEFORE writing tests** to avoid reinventing functionality that already exists!
273
-
274
- ---
275
-
276
- **Location:** `tests/stories/` directory (create if it doesn't exist)
277
-
278
- **Directory Creation:**
279
- If the `tests/stories/` directory doesn't exist yet, create it first:
280
- ```bash
281
- mkdir -p tests/stories
282
- ```
283
-
284
- **Naming Convention:** `{feature-name}.story.test.ts`
285
- - Example: `user-registration.story.test.ts`
286
- - Example: `product-search.story.test.ts`
287
- - Example: `order-processing.story.test.ts`
288
-
289
- **📁 File Organization - Avoid Too Many Files:**
290
-
291
- **IMPORTANT:** Before creating a NEW test file, check if existing test files can be extended!
292
-
293
- Story tests typically require significant setup (TestHelper, database connections, test users, etc.), so files naturally grow larger. A typical story test file ranges from 400-800 lines, with complex features reaching 1000+ lines.
294
-
295
- **✅ PREFER extending existing files when:**
296
- - The new tests relate to the same feature/module
297
- - The existing file is not excessively large (< 1000 lines)
298
- - The tests share similar setup/teardown logic
299
- - It makes logical sense to group them together
300
-
301
- **✅ CREATE new files when:**
302
- - Testing a completely different feature/module
303
- - The existing file would exceed ~1000-1200 lines
304
- - The tests require significantly different setup
305
- - It improves clarity and maintainability
306
-
307
- **Example:**
308
- ```
309
- tests/stories/
310
- user-authentication.story.test.ts # Login, logout, password reset, session handling
311
- user-profile.story.test.ts # Profile CRUD, settings, preferences
312
- product-management.story.test.ts # Product CRUD, variants, pricing
313
- order-processing.story.test.ts # Cart, checkout, payment, fulfillment
314
- ```
315
-
316
- **Why this matters:**
317
- - Too many small files → Hard to navigate, duplicate setup code, redundant boilerplate
318
- - Too few large files → Hard to read, slow to run, merge conflicts
319
- - Balance: Group related tests, split when files grow beyond ~1000 lines
320
-
321
- **🔍 BEFORE Writing Tests - Verify Your Assumptions:**
322
-
323
- **CRITICAL: Only write tests for endpoints that you have VERIFIED exist in the code!**
324
-
325
- 1. **For REST endpoints:**
326
- ```typescript
327
- // ✅ CORRECT: Verified endpoint exists in user.controller.ts
328
- await testHelper.rest('/api/users', { method: 'POST', ... });
329
-
330
- // ❌ WRONG: Assumed endpoint without verification
331
- await testHelper.rest('/api/users/profile', { method: 'PUT', ... }); // Does this exist?
332
- ```
333
-
334
- 2. **For GraphQL mutations/queries:**
335
- ```typescript
336
- // ✅ CORRECT: Verified 'createUser' mutation exists in user.resolver.ts
337
- await testHelper.graphQl({ name: 'createUser', type: TestGraphQLType.MUTATION, ... });
338
-
339
- // ❌ WRONG: Assumed mutation without verification
340
- await testHelper.graphQl({ name: 'updateUserProfile', ... }); // Does this exist?
341
- ```
342
-
343
- 3. **Document your verification:**
344
- ```typescript
345
- // Test for user creation
346
- // Verified: POST /api/users exists in src/server/modules/user/user.controller.ts:34
347
- // Verified: Requires authentication (S_USER role)
348
- // Verified: Returns User object with id, email, firstName, lastName
349
- it('should create new user', async () => {
350
- const result = await testHelper.rest('/api/users', {
351
- method: 'POST',
352
- payload: { email: 'test@example.com', ... },
353
- token: adminToken,
354
- statusCode: 201
355
- });
356
- // ...
357
- });
358
- ```
359
-
360
- **Test Structure:**
361
-
362
- 1. **Study existing story tests** (if any exist in `tests/stories/`)
363
- - Follow established patterns and conventions
364
- - Use similar setup/teardown approaches
365
- - Match coding style and organization
366
-
367
- 2. **Study other test files** for patterns:
368
- - Check `test/**/*.test.ts` files
369
- - Understand authentication setup
370
- - Learn data creation patterns
371
- - See how API calls are made
372
-
373
- 3. **Write comprehensive story test** that includes:
374
- - Clear test description matching the story
375
- - Setup of test data and users
376
- - All acceptance criteria as test cases
377
- - Proper authentication/authorization
378
- - Validation of responses and side effects
379
- - Cleanup/teardown
380
-
381
- 4. **Ensure tests cover:**
382
- - Happy path scenarios
383
- - Edge cases
384
- - Error conditions
385
- - Security/permission checks
386
- - Data validation
387
-
388
- **Example test structure:**
389
- ```typescript
390
- describe('User Registration Story', () => {
391
- let createdUserIds: string[] = [];
392
- let createdProductIds: string[] = [];
393
-
394
- // Setup
395
- beforeAll(async () => {
396
- // Initialize test environment
397
- });
398
-
399
- afterAll(async () => {
400
- // 🧹 CLEANUP: Delete ALL test data created during tests
401
- // This prevents side effects on subsequent test runs
402
- if (createdUserIds.length > 0) {
403
- await db.collection('users').deleteMany({
404
- _id: { $in: createdUserIds.map(id => new ObjectId(id)) }
405
- });
406
- }
407
- if (createdProductIds.length > 0) {
408
- await db.collection('products').deleteMany({
409
- _id: { $in: createdProductIds.map(id => new ObjectId(id)) }
410
- });
411
- }
412
- });
413
-
414
- it('should allow new user to register with valid data', async () => {
415
- // Test implementation
416
- const user = await createUser(...);
417
- createdUserIds.push(user.id); // Track for cleanup
418
- });
419
-
420
- it('should reject registration with invalid email', async () => {
421
- // Test implementation
422
- });
423
-
424
- it('should prevent duplicate email registration', async () => {
425
- // Test implementation
426
- });
427
- });
428
- ```
429
-
430
- **🚨 CRITICAL: Test Data Management for Parallel Execution**
431
-
432
- **ALWAYS follow these rules to ensure tests can run in parallel safely!**
433
-
434
- Tests run in parallel, so improper test data management causes:
435
- - Conflicts between parallel tests (duplicate keys, race conditions)
436
- - False positives/negatives in tests
437
- - Flaky tests that pass/fail randomly
438
- - Contaminated test database
439
- - Hard-to-debug test failures
440
-
441
- **📋 GOLDEN RULES for Test Data:**
442
-
443
- 1. **Email Addresses Must End with @test.com**
444
- ```typescript
445
- // ✅ CORRECT: Will be excluded from external services (e2e.brevo.exclude)
446
- // Includes timestamp + random suffix for uniqueness even within same millisecond
447
- const testEmail = `user-${Date.now()}-${Math.random().toString(36).substring(2, 8)}@test.com`;
448
-
449
- // ⚠️ LESS SAFE: Only timestamp (collision risk if tests run in same millisecond)
450
- const testEmail = `user-${Date.now()}@test.com`;
451
-
452
- // ❌ WRONG: Won't be excluded, may trigger external emails
453
- const testEmail = 'testuser@example.com';
454
- ```
455
-
456
- **Why:** Configuration in `src/config.env.ts` uses `e2e.brevo.exclude` to filter out @test.com emails from external services. The random suffix ensures uniqueness even when multiple tests run simultaneously.
457
-
458
- 2. **NEVER Reuse Same Data Across Test Files**
459
- ```typescript
460
- // ❌ WRONG: user-story-1.test.ts and user-story-2.test.ts both use:
461
- const email = 'admin@test.com'; // ❌ Conflict when running in parallel!
462
-
463
- // ✅ CORRECT: Make data unique per test file with timestamp + random suffix
464
- const email = `admin-user-story-1-${Date.now()}-${Math.random().toString(36).substring(2, 8)}@test.com`;
465
-
466
- // ⚠️ LESS SAFE: Only timestamp
467
- const email = `admin-user-story-1-${Date.now()}@test.com`;
468
- ```
469
-
470
- **Why:** Tests run in parallel. Same email = duplicate key errors and race conditions. Random suffix prevents collisions within same millisecond.
471
-
472
- 3. **ONLY Delete What You Created in This Test File**
473
- ```typescript
474
- // ❌ WRONG: Deletes ALL test users (affects parallel tests)
475
- await db.collection('users').deleteMany({ email: /@test\.com$/ });
476
-
477
- // ✅ CORRECT: Only delete tracked entities from THIS test
478
- if (createdUserIds.length > 0) {
479
- await db.collection('users').deleteMany({
480
- _id: { $in: createdUserIds.map(id => new ObjectId(id)) }
481
- });
482
- }
483
- ```
484
-
485
- **Why:** Deleting too much breaks parallel tests that are still running.
486
-
487
- 4. **ALL Created Entities Must Be Cleaned Up**
488
- ```typescript
489
- // ✅ Track EVERY entity created
490
- let createdUserIds: string[] = [];
491
- let createdProductIds: string[] = [];
492
- let createdOrderIds: string[] = [];
493
-
494
- // ✅ Clean up ALL in afterAll
495
- afterAll(async () => {
496
- if (createdOrderIds.length > 0) {
497
- await db.collection('orders').deleteMany({
498
- _id: { $in: createdOrderIds.map(id => new ObjectId(id)) }
499
- });
500
- }
501
- // ... clean up products, users, etc.
502
- });
503
- ```
504
-
505
- **Why:** Leftover data causes side effects in future test runs.
506
-
507
- 5. **NEVER Use Fixed Port Numbers**
508
- ```typescript
509
- // ❌ WRONG: Fixed port causes conflicts in parallel tests
510
- await app.listen(3000);
511
- const response = await fetch('http://localhost:3000/api/users');
512
-
513
- // ✅ CORRECT: NestJS assigns random ports automatically
514
- await app.init(); // No port specified
515
- // Use TestHelper - it handles ports automatically
516
- const result = await testHelper.rest('/api/users', { ... });
517
- ```
518
-
519
- **Why:** Parallel tests need different ports. NestJS assigns random available ports automatically. TestHelper abstracts this away.
520
-
521
- **Cleanup Strategy:**
522
-
523
- 1. **Track all created entities:**
524
- ```typescript
525
- let createdUserIds: string[] = [];
526
- let createdProductIds: string[] = [];
527
- let createdOrderIds: string[] = [];
528
- ```
529
-
530
- 2. **Add IDs immediately after creation:**
531
- ```typescript
532
- const user = await testHelper.rest('/api/users', {
533
- method: 'POST',
534
- payload: userData,
535
- token: adminToken,
536
- });
537
- createdUserIds.push(user.id); // ✅ Track for cleanup
538
- ```
539
-
540
- 3. **Delete ALL created entities in afterAll:**
541
- ```typescript
542
- afterAll(async () => {
543
- // Clean up all test data
544
- if (createdOrderIds.length > 0) {
545
- await db.collection('orders').deleteMany({
546
- _id: { $in: createdOrderIds.map(id => new ObjectId(id)) }
547
- });
548
- }
549
- if (createdProductIds.length > 0) {
550
- await db.collection('products').deleteMany({
551
- _id: { $in: createdProductIds.map(id => new ObjectId(id)) }
552
- });
553
- }
554
- if (createdUserIds.length > 0) {
555
- await db.collection('users').deleteMany({
556
- _id: { $in: createdUserIds.map(id => new ObjectId(id)) }
557
- });
558
- }
559
-
560
- await connection.close();
561
- await app.close();
562
- });
563
- ```
564
-
565
- 4. **Clean up in correct order:**
566
- - Delete child entities first (e.g., Orders before Products)
567
- - Delete parent entities last (e.g., Users last)
568
- - Consider foreign key relationships
569
-
570
- 5. **Handle cleanup errors gracefully:**
571
- ```typescript
572
- afterAll(async () => {
573
- try {
574
- // Cleanup operations
575
- if (createdUserIds.length > 0) {
576
- await db.collection('users').deleteMany({
577
- _id: { $in: createdUserIds.map(id => new ObjectId(id)) }
578
- });
579
- }
580
- } catch (error) {
581
- console.error('Cleanup failed:', error);
582
- // Don't throw - cleanup failures shouldn't fail the test suite
583
- }
584
-
585
- await connection.close();
586
- await app.close();
587
- });
588
- ```
589
-
590
- **What to clean up:**
591
- - ✅ Users created during tests
592
- - ✅ Products/Resources created during tests
593
- - ✅ Orders/Transactions created during tests
594
- - ✅ Any relationships (comments, reviews, etc.)
595
- - ✅ Files uploaded during tests
596
- - ✅ Any other test data that persists
597
-
598
- **What NOT to clean up:**
599
- - ❌ Global test users created in `beforeAll` that are reused (clean these once at the end)
600
- - ❌ Database connections (close these separately)
601
- - ❌ The app instance (close this separately)
602
-
603
- **Step 2 Checklist:**
604
- - [ ] Test file created in tests/stories/
605
- - [ ] Endpoints verified before writing tests
606
- - [ ] ALL tests use TestHelper (rest() or graphQl())
607
- - [ ] NO direct Service or DB access in test logic
608
- - [ ] Existing test patterns studied and followed
609
- - [ ] All acceptance criteria covered
610
- - [ ] Cleanup implemented in afterAll
611
- - [ ] All test entities tracked for cleanup
612
- - [ ] Ready for Step 3
613
-
614
- ## Step 3: Run Tests & Analyze Failures
615
-
616
- **Execute all tests:**
617
- ```bash
618
- npm test
619
- ```
620
-
621
- **Or run specific story test:**
622
- ```bash
623
- npm test -- tests/stories/your-story.story.test.ts
624
- ```
625
-
626
- **Analyze results:**
627
- 1. Record which tests fail and why
628
- 2. Identify if failures are due to:
629
- - Missing implementation (expected)
630
- - Test errors/bugs (needs fixing)
631
- - Misunderstood requirements (needs clarification)
632
-
633
- **Decision point:**
634
- - If test has bugs/errors → Go to Step 3a
635
- - If API implementation is missing/incomplete → Go to Step 4
636
-
637
- **Debugging Test Failures:**
638
-
639
- If test failures are unclear, enable debugging tools:
640
- - **TestHelper:** Add `log: true, logError: true` to test options for detailed output
641
- - **Server logging:** Set `logExceptions: true` in `src/config.env.ts`
642
- - **Validation debugging:** Set `DEBUG_VALIDATION=true` environment variable
643
-
644
- See **reference.md** for detailed debugging instructions and examples.
645
-
646
- ## Step 3a: Fix Test Errors (if needed)
647
-
648
- **Only fix tests if:**
649
- - Test logic is incorrect
650
- - Test has programming errors
651
- - Test makes nonsensical demands
652
- - Test doesn't match actual requirements
653
-
654
- **Do NOT "fix" tests by:**
655
- - Removing security checks to make them pass
656
- - Lowering expectations to match incomplete implementation
657
- - Skipping test cases that should work
658
-
659
- **After fixing tests:**
660
- - Return to Step 3 (run tests again)
661
-
662
- ## Step 4: Implement/Extend API Code
663
-
664
- **Use the `nest-server-generator` skill for implementation:**
665
-
666
- 1. **Analyze what's needed:**
667
- - New modules? → Use `nest-server-generator`
668
- - New objects? → Use `nest-server-generator`
669
- - New properties? → Use `nest-server-generator`
670
- - Code modifications? → Use `nest-server-generator`
671
-
672
- 2. **🔍 Understand existing codebase first - VERIFY before using:**
673
- - **Read actual Service files** before calling methods:
674
- - Verify method names and signatures
675
- - Check required parameters and types
676
- - Confirm return types
677
- - Example: Read `user.service.ts` to verify `findById(id: string): Promise<User>` exists
678
- - **Read actual Model files** to understand data structures:
679
- - Verify field names and types
680
- - Check validation rules
681
- - Confirm relationships
682
- - **Study @lenne.tech/nest-server patterns** (in `node_modules/@lenne.tech/nest-server/src`):
683
- - Check CrudService base class for available methods (in `node_modules/@lenne.tech/nest-server/src/core/common/services/crud.service.ts`)
684
- - Check RoleEnum (in the project or `node_modules/@lenne.tech/nest-server/src/core/common/enums/role.enum.ts`)
685
- - Understand decorators: @Roles, @Restricted, @UnifiedField
686
- - Study MapAndValidatePipe for validation logic (automatically activated via CoreModule - see `node_modules/@lenne.tech/nest-server/src/core/common/pipes/map-and-validate.pipe.ts`)
687
- - **Review existing similar implementations** - don't assume, verify!
688
-
689
- **⚠️ CRITICAL:** Don't assume methods or properties exist - READ THE CODE to verify!
690
-
691
- 2a. **🚨 CRITICAL: Property Descriptions with German Comments**
692
-
693
- **When user provides German comments/descriptions for properties, you MUST preserve them correctly!**
694
-
695
- **Rule: `ENGLISH (GERMAN)` format**
696
- - German: `// Produktname` → Description: `'Product name (Produktname)'`
697
- - German: `// Straße` → Description: `'Street (Straße)'`
698
- - English: `// Product name` → Description: `'Product name'` (no translation)
699
-
700
- **Process:**
701
- 1. ✅ Extract ALL comments from user requirements (after `//`)
702
- 2. ✅ Translate German to English, keep German in parentheses
703
- 3. ✅ Fix spelling errors but preserve exact wording
704
- 4. ✅ Apply SAME description to: Model, CreateInput, UpdateInput, @ObjectType, @InputType
705
- 5. ❌ NEVER change wording (e.g., `Straße` → `Straßenname` is WRONG!)
706
- 6. ❌ NEVER skip German original in parentheses
707
-
708
- **Example from user requirements:**
709
- ```
710
- Module: Product
711
- - name: string // Produktname
712
- - price: number // Price
713
- ```
714
-
715
- **Correct implementation in ALL locations:**
716
- ```typescript
717
- // In product.model.ts:
718
- @UnifiedField({ description: 'Product name (Produktname)' })
719
- name: string;
720
-
721
- @UnifiedField({ description: 'Price' })
722
- price: number;
723
-
724
- // In product.input.ts (CreateInput, UpdateInput):
725
- @UnifiedField({ description: 'Product name (Produktname)' })
726
- name: string;
727
-
728
- @UnifiedField({ description: 'Price' })
729
- price: number;
730
- ```
731
-
732
- **See `nest-server-generator` skill → `description-management.md` for complete details.**
733
-
734
- 3. **🚨 CRITICAL: ServiceOptions when calling other Services:**
735
-
736
- **NEVER blindly pass all ServiceOptions when one Service calls another!**
737
-
738
- When implementing Service methods that call other Services, analyze which options to pass:
739
-
740
- **❌ WRONG:**
741
- ```typescript
742
- // ❌ BAD: Blindly passing all serviceOptions
743
- const product = await this.productService.findOne({ id: input.productId }, serviceOptions);
744
- ```
745
-
746
- **✅ CORRECT:**
747
- ```typescript
748
- // ✅ GOOD: Only pass what's needed (usually just currentUser)
749
- const product = await this.productService.findOne(
750
- { id: input.productId },
751
- { currentUser: serviceOptions.currentUser }
752
- );
753
-
754
- // ✅ GOOD: Only set inputType if different Input class is needed
755
- const user = await this.userService.findOne(
756
- { id: input.userId },
757
- {
758
- currentUser: serviceOptions.currentUser,
759
- inputType: UserInput // Only if specific Input class needed (e.g., UserInput, UserInputCreate)
760
- }
761
- );
762
- ```
763
-
764
- **Why this matters:**
765
- - **inputType** specifies which Input class (DTO) to use for validation (e.g., `UserInput`, `UserInputCreate`)
766
- - The inputType from outer service might be wrong for inner service
767
- - **roles** might need to be different
768
- - Other options (limit, skip, etc.) might not apply
769
- - Can cause incorrect permission checks or wrong validation
770
-
771
- **Before passing options:**
772
- - Analyze what's in serviceOptions (currentUser, inputType, roles, etc.)
773
- - Determine what the target Service actually needs
774
- - Only pass required options (usually just currentUser)
775
- - Only set inputType if a specific Input class (DTO) is needed (e.g., UserInput, UserInputCreate)
776
-
777
- 4. **Implement equivalently to existing code:**
778
- - Use TestHelper for REST oder GraphQL requests (in `node_modules/@lenne.tech/nest-server/src/test/test.helper.ts`)
779
- - Use `getStringIds()` and `getObjectIds()` from `@lenne.tech/nest-server` for ObjectId conversions
780
- - Match coding style and patterns
781
- - Use same architectural approaches
782
- - Follow established conventions
783
- - Reuse existing utilities
784
-
785
- 4a. **🔐 IMPORTANT: Guards in Controllers**
786
-
787
- **DO NOT manually add `@UseGuards(AuthGuard(AuthGuardStrategy.JWT))` - it's automatically activated by `@Roles()`!**
788
-
789
- ```typescript
790
- // ✅ CORRECT: @Roles automatically activates JWT guard
791
- @Roles(RoleEnum.ADMIN)
792
- @Get()
793
- async findAll() {
794
- return this.service.find();
795
- }
796
-
797
- // ✅ CORRECT: @Restricted also activates guards automatically
798
- @Restricted()
799
- @Post()
800
- async create(@Body() input: CreateDto) {
801
- return this.service.create(input);
802
- }
803
-
804
- // ❌ WRONG: Redundant manual guard (already included by @Roles)
805
- @UseGuards(AuthGuard(AuthGuardStrategy.JWT))
806
- @Roles(RoleEnum.ADMIN)
807
- @Get()
808
- async findAll() {
809
- return this.service.find();
810
- }
811
- ```
812
-
813
- **Why this matters:**
814
- - `@Roles()` decorator automatically applies `@UseGuards(RolesGuard)`
815
- - `RolesGuard` internally uses JWT authentication
816
- - Adding `@UseGuards(AuthGuard(...))` manually is redundant and creates duplicate guards
817
- - Existing controllers don't use manual guards - follow this pattern
818
-
819
- 5. **🔍 IMPORTANT: Database Indexes**
820
-
821
- **Always define indexes directly in the @UnifiedField decorator via mongoose option!**
822
-
823
- **Quick Guidelines:**
824
- - Fields used in queries → Add `mongoose: { index: true, type: String }`
825
- - Foreign keys → Add index
826
- - Unique fields → Add `mongoose: { index: true, unique: true, type: String }`
827
- - ⚠️ NEVER define indexes separately in schema files
828
-
829
- **📖 For detailed index patterns and examples, see: `database-indexes.md`**
830
-
831
- 6. **Prefer existing packages:**
832
- - Check if @lenne.tech/nest-server provides needed functionality
833
- - Only add new npm packages as last resort
834
- - If new package needed, verify:
835
- - High quality and well-maintained
836
- - Frequently used (npm downloads)
837
- - Active maintenance
838
- - Free license (preferably MIT)
839
- - Long-term viability
840
-
841
- ## Step 5: Validate & Iterate
842
-
843
- **Run ALL tests:**
844
- ```bash
845
- npm test
846
- ```
847
-
848
- **Check results:**
849
-
850
- ✅ **All tests pass?**
851
- - Continue to Step 5a (Code Quality Check)
852
-
853
- ❌ **Some tests still fail?**
854
- - Return to Step 3 (analyze failures)
855
- - Continue iteration
856
-
857
- ## Step 5a: Code Quality & Refactoring Check
858
-
859
- **BEFORE marking the task as complete, perform a code quality review!**
860
-
861
- Once all tests are passing, analyze your implementation for code quality issues:
862
-
863
- ### 1-3. Code Quality Review
864
-
865
- **Check for:**
866
- - Code duplication (extract to private methods if used 2+ times)
867
- - Common functionality (create helper functions)
868
- - Similar code paths (consolidate with flexible parameters)
869
- - Consistency with existing patterns
870
-
871
- **📖 For detailed refactoring patterns and examples, see: `code-quality.md`**
872
-
873
- ### 4. Review for Consistency
874
-
875
- **Ensure consistent patterns throughout your implementation:**
876
- - Naming conventions match existing codebase
877
- - Error handling follows project patterns
878
- - Return types are consistent
879
- - Similar operations use similar approaches
880
-
881
- ### 4a. Check Database Indexes
882
-
883
- **Verify that indexes are defined where needed:**
884
-
885
- **Quick check:**
886
- - Fields used in find/filter → Has index?
887
- - Foreign keys (userId, productId, etc.) → Has index?
888
- - Unique fields (email, username) → Has unique: true?
889
- - Fields used in sorting → Has index?
890
-
891
- **If indexes are missing:**
892
- - Add to @UnifiedField decorator (mongoose option)
893
- - Re-run tests
894
- - Document query pattern
895
-
896
- **📖 For detailed verification checklist, see: `database-indexes.md`**
897
-
898
- ### 4b. Security Review
899
-
900
- **🔐 CRITICAL: Perform security review before final testing!**
901
-
902
- **ALWAYS review all code changes for security vulnerabilities.**
903
-
904
- **Quick Security Check:**
905
- - [ ] @Restricted/@Roles decorators NOT removed or weakened
906
- - [ ] Ownership checks in place (users can only access own data)
907
- - [ ] All inputs validated with proper DTOs
908
- - [ ] Sensitive fields marked with hideField: true
909
- - [ ] No injection vulnerabilities
910
- - [ ] Error messages don't expose sensitive data
911
- - [ ] Authorization tests pass
912
-
913
- **Red Flags (STOP if found):**
914
- - 🚩 @Restricted decorator removed
915
- - 🚩 @Roles changed to more permissive
916
- - 🚩 Missing ownership checks
917
- - 🚩 Sensitive fields exposed
918
- - 🚩 'any' type instead of DTO
919
-
920
- **If ANY red flag found:**
921
- 1. STOP implementation
922
- 2. Fix security issue immediately
923
- 3. Re-run security checklist
924
- 4. Update tests to verify security
925
-
926
- **📖 For complete security checklist with examples, see: `security-review.md`**
927
-
928
- ### 5. Refactoring Decision Tree
929
-
930
- ```
931
- Code duplication detected?
932
-
933
- ├─► Used in 2+ places?
934
- │ │
935
- │ ├─► YES: Extract to private method
936
- │ │ │
937
- │ │ └─► Used across multiple services?
938
- │ │ │
939
- │ │ ├─► YES: Consider utility class/function
940
- │ │ └─► NO: Keep as private method
941
- │ │
942
- │ └─► NO: Leave as-is (don't over-engineer)
943
-
944
- └─► Complex logic block?
945
-
946
- ├─► Hard to understand?
947
- │ └─► Extract to well-named method
948
-
949
- └─► Simple and clear?
950
- └─► Leave as-is
951
- ```
952
-
953
- ### 6. Run Tests After Refactoring & Security Review
954
-
955
- **CRITICAL: After any refactoring, adding indexes, or security fixes:**
956
-
957
- ```bash
958
- npm test
959
- ```
960
-
961
- **Ensure:**
962
- - ✅ All tests still pass
963
- - ✅ No new failures introduced
964
- - ✅ Code is more maintainable
965
- - ✅ No functionality changed
966
- - ✅ Indexes properly applied
967
- - ✅ **Security checks still working (authorization tests pass)**
968
-
969
- ### 7. When to Skip Refactoring
970
-
971
- **Don't refactor if:**
972
- - Code is used in only ONE place
973
- - Extraction would make code harder to understand
974
- - The duplication is coincidental, not conceptual
975
- - Time constraints don't allow for safe refactoring
976
-
977
- **Remember:**
978
- - **Working code > Perfect code**
979
- - **Refactor only if it improves maintainability**
980
- - **Always run tests after refactoring**
981
- - **Always add indexes where queries are performed**
982
-
983
- ## Step 5b: Final Validation
984
-
985
- **After refactoring (or deciding not to refactor):**
986
-
987
- 1. **Run ALL tests one final time:**
988
- ```bash
989
- npm test
990
- ```
991
-
992
- 2. **Verify:**
993
- - ✅ All tests pass
994
- - ✅ Test coverage is adequate
995
- - ✅ Code follows project patterns
996
- - ✅ No obvious duplication
997
- - ✅ Clean and maintainable
998
- - ✅ **Security review completed**
999
- - ✅ **No security vulnerabilities introduced**
1000
- - ✅ **Authorization tests pass**
1001
-
1002
- 3. **Generate final report for developer**
1003
-
1004
- 4. **YOU'RE DONE!** 🎉