@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.
Files changed (25) hide show
  1. package/build/commands/claude/install-commands.js +332 -0
  2. package/build/commands/claude/install-skills.js +5 -1
  3. package/build/commands/server/add-property.js +22 -41
  4. package/build/extensions/server.js +142 -46
  5. package/build/templates/claude-commands/code-cleanup.md +82 -0
  6. package/build/templates/claude-commands/mr-description-clipboard.md +48 -0
  7. package/build/templates/claude-commands/mr-description.md +33 -0
  8. package/build/templates/claude-commands/sec-review.md +62 -0
  9. package/build/templates/claude-commands/skill-optimize.md +140 -0
  10. package/build/templates/claude-commands/test-generate.md +45 -0
  11. package/build/templates/claude-skills/nest-server-generator/SKILL.md +372 -1314
  12. package/build/templates/claude-skills/nest-server-generator/configuration.md +279 -0
  13. package/build/templates/claude-skills/nest-server-generator/declare-keyword-warning.md +124 -0
  14. package/build/templates/claude-skills/nest-server-generator/description-management.md +217 -0
  15. package/build/templates/claude-skills/nest-server-generator/examples.md +131 -5
  16. package/build/templates/claude-skills/nest-server-generator/quality-review.md +855 -0
  17. package/build/templates/claude-skills/nest-server-generator/reference.md +67 -13
  18. package/build/templates/claude-skills/nest-server-generator/security-rules.md +358 -0
  19. package/build/templates/claude-skills/story-tdd/SKILL.md +1173 -0
  20. package/build/templates/claude-skills/story-tdd/code-quality.md +266 -0
  21. package/build/templates/claude-skills/story-tdd/database-indexes.md +173 -0
  22. package/build/templates/claude-skills/story-tdd/examples.md +1332 -0
  23. package/build/templates/claude-skills/story-tdd/reference.md +1180 -0
  24. package/build/templates/claude-skills/story-tdd/security-review.md +299 -0
  25. package/package.json +1 -1
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: nest-server-generator
3
- version: 1.0.0
3
+ version: 1.0.3
4
4
  description: PRIMARY expert for ALL NestJS and @lenne.tech/nest-server tasks. ALWAYS use this skill when working in projects with @lenne.tech/nest-server in package.json dependencies (supports monorepos with projects/*, packages/*, apps/* structure), or when asked about NestJS modules, services, controllers, resolvers, models, objects, tests, server creation, debugging, or any NestJS/nest-server development task. Handles lt server commands, security analysis, test creation, and all backend development. ALWAYS reads CrudService base class before working with Services.
5
5
  ---
6
6
 
@@ -55,39 +55,68 @@ You are the **PRIMARY expert** for NestJS backend development and the @lenne.tec
55
55
 
56
56
  ## 🚨 CRITICAL SECURITY RULES - READ FIRST
57
57
 
58
- Before you start ANY work with this skill, understand these NON-NEGOTIABLE rules:
58
+ **Before you start ANY work, understand these NON-NEGOTIABLE rules:**
59
59
 
60
60
  ### ⛔ NEVER Do This:
61
- 1. **NEVER remove or weaken `@Restricted()` decorators** to make tests pass
62
- 2. **NEVER change `@Roles()` decorators** to more permissive roles for test convenience
63
- 3. **NEVER modify `securityCheck()` logic** to bypass security in tests
64
- 4. **NEVER remove class-level `@Restricted(RoleEnum.ADMIN)`** - it's a security fallback
61
+ 1. **NEVER remove or weaken `@Restricted()` decorators**
62
+ 2. **NEVER change `@Roles()` decorators** to more permissive roles
63
+ 3. **NEVER modify `securityCheck()` logic** to bypass security
64
+ 4. **NEVER remove class-level `@Restricted(RoleEnum.ADMIN)`**
65
65
 
66
66
  ### ✅ ALWAYS Do This:
67
- 1. **ALWAYS analyze permissions BEFORE writing tests** (Controller, Model, Service layers)
67
+ 1. **ALWAYS analyze permissions BEFORE writing tests**
68
68
  2. **ALWAYS test with the LEAST privileged user** who is authorized
69
- 3. **ALWAYS create appropriate test users** for each permission level
70
- 4. **ALWAYS adapt tests to security requirements**, never the other way around
71
- 5. **ALWAYS ask developer for approval** before changing ANY security decorator
72
- 6. **ALWAYS aim for maximum test coverage** (80-100% depending on criticality)
69
+ 3. **ALWAYS adapt tests to security requirements**, never vice versa
70
+ 4. **ALWAYS ask developer for approval** before changing ANY security decorator
71
+
72
+ **📖 For complete security rules, testing guidelines, and examples, see: `security-rules.md`**
73
+
74
+ ## 🚨 CRITICAL: NEVER USE `declare` KEYWORD FOR PROPERTIES
75
+
76
+ **⚠️ DO NOT use the `declare` keyword when defining properties in classes!**
77
+
78
+ ### Quick Rule
73
79
 
74
- ### 🔑 Permission Hierarchy (Specific Overrides General):
75
80
  ```typescript
76
- @Restricted(RoleEnum.ADMIN) // FALLBACK: DO NOT REMOVE
77
- export class ProductController {
78
- @Roles(RoleEnum.S_USER) // ← SPECIFIC: This method is more open
79
- async createProduct() { } // ← S_USER can access (specific wins)
81
+ // WRONG
82
+ export class ProductCreateInput extends ProductInput {
83
+ declare name: string; // Decorator won't work!
84
+ }
80
85
 
81
- async secretMethod() { } // ADMIN only (fallback applies)
86
+ // CORRECT
87
+ export class ProductCreateInput extends ProductInput {
88
+ @UnifiedField({ description: 'Product name' })
89
+ name: string; // Decorator works properly
82
90
  }
83
91
  ```
84
92
 
85
- **Why class-level `@Restricted(ADMIN)` MUST stay:**
86
- - If someone forgets `@Roles()` on a new method → it's secure by default
87
- - Shows the class is security-sensitive
88
- - Fail-safe protection
93
+ **Why**: `declare` prevents decorators from being applied, breaking the decorator system.
94
+
95
+ **📖 For detailed explanation and correct patterns, see: `declare-keyword-warning.md`**
96
+
97
+ ## 🚨 CRITICAL: DESCRIPTION MANAGEMENT
98
+
99
+ **⚠️ COMMON MISTAKE:** Descriptions are often applied inconsistently. You MUST follow this process for EVERY component.
89
100
 
90
- **See "CRITICAL: Security & Test Coverage Rules" section for complete details.**
101
+ ### 3-Step Process
102
+
103
+ **1. Extract descriptions** from user's `// comments`
104
+
105
+ **2. Format correctly:**
106
+ - English input → `'Product name'`
107
+ - German input → `'Product name (Produktname)'`
108
+ - **⚠️ Fix typos ONLY, NEVER change wording!**
109
+
110
+ **3. Apply EVERYWHERE:**
111
+ - Model file
112
+ - Create Input file
113
+ - Update Input file
114
+ - Object files (if SubObject)
115
+ - Class-level @ObjectType() decorators
116
+
117
+ **📖 For detailed formatting rules, examples, and verification checklist, see: `description-management.md`**
118
+
119
+ ---
91
120
 
92
121
  ## Core Responsibilities
93
122
 
@@ -190,38 +219,22 @@ export class ProductService extends CrudService<Product> {
190
219
 
191
220
  ## Configuration File (lt.config.json)
192
221
 
193
- The lenne.tech CLI supports project-level configuration via `lt.config.json` files. This allows you to set default values for commands, eliminating the need for repeated CLI parameters or interactive prompts.
222
+ The lenne.tech CLI supports project-level configuration via `lt.config.json` files to set default values for commands.
194
223
 
195
- ### File Location and Hierarchy
224
+ **📖 For complete configuration guide including structure, options, and examples, see: `configuration.md`**
196
225
 
197
- - **Location**: Place `lt.config.json` in your project root or any parent directory
198
- - **Hierarchy**: The CLI searches from the current directory up to the root, merging configurations
199
- - **Priority** (lowest to highest):
200
- 1. Default values (hardcoded in CLI)
201
- 2. Config from parent directories (higher up = lower priority)
202
- 3. Config from current directory
203
- 4. CLI parameters (`--flag value`)
204
- 5. Interactive user input
205
-
206
- ### Configuration Structure
226
+ **Quick reference:**
227
+ - **Location**: Project root or parent directories
228
+ - **Priority**: CLI parameters > Interactive input > Config file > Defaults
229
+ - **Key option**: `commands.server.module.controller` - Sets default controller type ("Rest" | "GraphQL" | "Both" | "auto")
207
230
 
231
+ **Example config:**
208
232
  ```json
209
233
  {
210
- "meta": {
211
- "version": "1.0.0",
212
- "name": "My Project",
213
- "description": "Optional project description"
214
- },
215
234
  "commands": {
216
235
  "server": {
217
236
  "module": {
218
- "controller": "Both",
219
- "skipLint": false
220
- },
221
- "object": {
222
- "skipLint": false
223
- },
224
- "addProp": {
237
+ "controller": "Rest",
225
238
  "skipLint": false
226
239
  }
227
240
  }
@@ -229,238 +242,8 @@ The lenne.tech CLI supports project-level configuration via `lt.config.json` fil
229
242
  }
230
243
  ```
231
244
 
232
- ### Available Configuration Options
233
-
234
- **Server Module Configuration (`commands.server.module`)**:
235
- - `controller`: Default controller type (`"Rest"` | `"GraphQL"` | `"Both"` | `"auto"`)
236
- - `skipLint`: Skip lint prompt after module creation (boolean)
237
-
238
- **Server Object Configuration (`commands.server.object`)**:
239
- - `skipLint`: Skip lint prompt after object creation (boolean)
240
-
241
- **Server AddProp Configuration (`commands.server.addProp`)**:
242
- - `skipLint`: Skip lint prompt after adding property (boolean)
243
-
244
- ### Using Configuration in Commands
245
-
246
- **Example 1: Configure controller type globally**
247
- ```json
248
- {
249
- "commands": {
250
- "server": {
251
- "module": {
252
- "controller": "Rest"
253
- }
254
- }
255
- }
256
- }
257
- ```
258
-
259
- Now all `lt server module` commands will default to REST controllers:
260
- ```bash
261
- # Uses "Rest" from config (no prompt)
262
- lt server module --name Product --prop-name-0 name --prop-type-0 string
263
- ```
264
-
265
- **Example 2: Override config with CLI parameter**
266
- ```bash
267
- # Ignores config, uses GraphQL
268
- lt server module --name Product --controller GraphQL
269
- ```
270
-
271
- **Example 3: Auto-detect from config**
272
- ```json
273
- {
274
- "commands": {
275
- "server": {
276
- "module": {
277
- "controller": "auto"
278
- }
279
- }
280
- }
281
- }
282
- ```
283
-
284
- Now the CLI will auto-detect controller type from existing modules without prompting.
285
-
286
- ### Managing Configuration
287
-
288
- **Initialize configuration**:
289
- ```bash
290
- lt config init
291
- ```
292
-
293
- **Show current configuration** (merged from all hierarchy levels):
294
- ```bash
295
- lt config show
296
- ```
297
-
298
- **Get help**:
299
- ```bash
300
- lt config help
301
- ```
302
-
303
- ### When to Use Configuration
304
-
305
- **✅ Use configuration when:**
306
- - Creating multiple modules with the same controller type
307
- - Working in a team with agreed-upon conventions
308
- - Automating module generation in CI/CD
309
- - You want to skip repetitive prompts
310
-
311
- **❌ Don't use configuration when:**
312
- - Creating a single module with specific requirements
313
- - Each module needs a different controller type
314
- - You're just testing or experimenting
315
-
316
- ### Best Practices
317
-
318
- 1. **Project Root**: Place `lt.config.json` in your project root
319
- 2. **Version Control**: Commit the config file to share with your team
320
- 3. **Documentation**: Add a README note explaining the config choices
321
- 4. **Override When Needed**: Use CLI parameters to override for special cases
322
-
323
- ### 🎯 IMPORTANT: Configuration After Server Creation
324
-
325
- **CRITICAL WORKFLOW**: After creating a new server with `lt server create`, you **MUST** initialize the configuration file to set project conventions.
326
-
327
- #### Automatic Post-Creation Setup
328
-
329
- When you create a new NestJS server, immediately follow these steps:
330
-
331
- 1. **Navigate to the API directory**:
332
- ```bash
333
- cd projects/api
334
- ```
335
-
336
- 2. **Create the configuration file manually**:
337
- ```bash
338
- # Create lt.config.json with controller preference
339
- ```
340
-
341
- 3. **Ask the developer for their preference** (if not already specified):
342
- ```
343
- What controller type do you prefer for new modules in this project?
344
- 1. Rest - REST controllers only
345
- 2. GraphQL - GraphQL resolvers only
346
- 3. Both - Both REST and GraphQL
347
- 4. auto - Auto-detect from existing modules
348
- ```
349
-
350
- 4. **Write the configuration** based on the answer:
351
- ```json
352
- {
353
- "meta": {
354
- "version": "1.0.0"
355
- },
356
- "commands": {
357
- "server": {
358
- "module": {
359
- "controller": "Rest"
360
- }
361
- }
362
- }
363
- }
364
- ```
365
-
366
- #### Why This Is Important
367
-
368
- - ✅ **Consistency**: All modules will follow the same pattern
369
- - ✅ **No Prompts**: Developers won't be asked for controller type repeatedly
370
- - ✅ **Team Alignment**: Everyone uses the same conventions
371
- - ✅ **Automation**: Scripts and CI/CD can create modules without interaction
372
-
373
- #### Example Workflow
374
-
375
- ```bash
376
- # User creates new server
377
- lt server create --name MyAPI
378
-
379
- # You (Claude) navigate to API directory
380
- cd projects/api
381
-
382
- # You ask the user
383
- "I've created the server. What controller type would you like to use for modules?"
384
- "1. Rest (REST only)"
385
- "2. GraphQL (GraphQL only)"
386
- "3. Both (REST + GraphQL)"
387
- "4. auto (Auto-detect)"
388
-
389
- # User answers: "Rest"
390
-
391
- # You create lt.config.json
392
- {
393
- "meta": {
394
- "version": "1.0.0"
395
- },
396
- "commands": {
397
- "server": {
398
- "module": {
399
- "controller": "Rest"
400
- }
401
- }
402
- }
403
- }
404
-
405
- # Confirm to user
406
- "✅ Configuration saved! All new modules will default to REST controllers."
407
- "You can change this anytime by editing lt.config.json or running 'lt config init'."
408
- ```
409
-
410
- #### Configuration Options Explained
411
-
412
- **"Rest"**:
413
- - ✅ Creates REST controllers (`@Controller()`)
414
- - ❌ No GraphQL resolvers
415
- - ❌ No PubSub integration
416
- - **Best for**: Traditional REST APIs, microservices
417
-
418
- **"GraphQL"**:
419
- - ❌ No REST controllers
420
- - ✅ Creates GraphQL resolvers (`@Resolver()`)
421
- - ✅ Includes PubSub for subscriptions
422
- - **Best for**: GraphQL-first APIs, real-time apps
423
-
424
- **"Both"**:
425
- - ✅ Creates REST controllers
426
- - ✅ Creates GraphQL resolvers
427
- - ✅ Includes PubSub
428
- - **Best for**: Hybrid APIs, gradual migration
429
-
430
- **"auto"**:
431
- - 🤖 Analyzes existing modules
432
- - 🤖 Detects pattern automatically
433
- - 🤖 No user prompt
434
- - **Best for**: Following existing conventions
435
-
436
- #### When NOT to Create Config
437
-
438
- Skip config creation if:
439
- - ❌ User is just testing/experimenting
440
- - ❌ User explicitly says "no configuration"
441
- - ❌ Project already has lt.config.json
442
-
443
- ### Integration with Commands
444
-
445
- When generating code, **ALWAYS check for configuration**:
446
- 1. Load config via `lt config show` or check for `lt.config.json`
447
- 2. Use configured values in command construction
448
- 3. Only pass CLI parameters when overriding config
449
-
450
- **Example: Generating module with config**
451
- ```bash
452
- # Check if config exists and what controller type is configured
453
- # If config has "controller": "Rest", use it
454
- lt server module --name Product --prop-name-0 name --prop-type-0 string
455
-
456
- # If config has "controller": "auto", let CLI detect
457
- lt server module --name Order --prop-name-0 total --prop-type-0 number
458
-
459
- # Override config when needed
460
- lt server module --name User --controller Both
461
- ```
462
-
463
- ## Command Syntax Reference
245
+ **Initialize config**: `lt config init`
246
+ **Show current config**: `lt config show`
464
247
 
465
248
  ### lt server module
466
249
  Creates a complete NestJS module with model, service, controller/resolver, and DTOs.
@@ -876,29 +659,177 @@ export class BuyerProfile extends Profile { ... }
876
659
 
877
660
  ### Phase 5: Description Management
878
661
 
879
- **Rule**: All descriptions follow format: `"ENGLISH_DESCRIPTION (DEUTSCHE_BESCHREIBUNG)"`
662
+ **⚠️ CRITICAL PHASE - Refer to "CRITICAL: DESCRIPTION MANAGEMENT" section at the top of this document!**
663
+
664
+ This phase is often done incorrectly. Follow these steps EXACTLY:
665
+
666
+ #### Step 5.1: Extract Descriptions from User Input
667
+
668
+ **BEFORE applying any descriptions, review the original specification:**
669
+
670
+ Go back to the user's original specification and extract ALL comments that appear after `//`:
671
+
672
+ ```
673
+ Module: Product
674
+ - name: string // Product name
675
+ - price: number // Produktpreis
676
+ - description?: string // Produktbeschreibung
677
+ - stock: number // Current inventory
678
+
679
+ SubObject: Address
680
+ - street: string // Straße
681
+ - city: string // City name
682
+ - zipCode: string // Postleitzahl
683
+ ```
684
+
685
+ **Create a mapping**:
686
+ ```
687
+ Product.name → "Product name" (English)
688
+ Product.price → "Produktpreis" (German)
689
+ Product.description → "Produktbeschreibung" (German)
690
+ Product.stock → "Current inventory" (English)
691
+ Address.street → "Straße" (German)
692
+ Address.city → "City name" (English)
693
+ Address.zipCode → "Postleitzahl" (German)
694
+ ```
695
+
696
+ #### Step 5.2: Format Descriptions
697
+
698
+ **Rule**: `"ENGLISH_DESCRIPTION (DEUTSCHE_BESCHREIBUNG)"`
880
699
 
881
- **Process for each property**:
700
+ Apply formatting rules:
882
701
 
883
702
  1. **If comment is in English**:
884
703
  ```
885
- // Street name
704
+ // Product name
886
705
  ```
887
- → Use as: `description: 'Street name'`
706
+ → Use as: `description: 'Product name'`
707
+
708
+ Fix typos if needed:
709
+ ```
710
+ // Prodcut name (typo)
711
+ ```
712
+ → Use as: `description: 'Product name'` (typo corrected)
888
713
 
889
714
  2. **If comment is in German**:
715
+ ```
716
+ // Produktpreis
717
+ ```
718
+ → Translate and add original: `description: 'Product price (Produktpreis)'`
719
+
890
720
  ```
891
721
  // Straße
892
722
  ```
893
723
  → Translate and add original: `description: 'Street (Straße)'`
894
724
 
895
- 3. **If no comment**:
896
- → Create meaningful description: `description: 'User email address'`
725
+ Fix typos in original:
726
+ ```
727
+ // Postleizahl (typo: missing 't')
728
+ ```
729
+ → Translate and add corrected: `description: 'Postal code (Postleitzahl)'`
730
+
731
+ 3. **If no comment provided**:
732
+ → Create meaningful English description: `description: 'User email address'`
733
+
734
+ **⚠️ CRITICAL - Preserve Original Wording**:
735
+
736
+ - ✅ **DO:** Fix spelling/typos only
737
+ - ❌ **DON'T:** Rephrase, expand, or improve wording
738
+ - ❌ **DON'T:** Change terms (they may be predefined/referenced by external systems)
739
+
740
+ **Examples**:
741
+ ```
742
+ ✅ CORRECT:
743
+ // Straße → 'Street (Straße)' (preserve word)
744
+ // Produkt → 'Product (Produkt)' (don't add "name")
745
+ // Status → 'Status (Status)' (same in both languages)
746
+
747
+ ❌ WRONG:
748
+ // Straße → 'Street name (Straßenname)' (changed word!)
749
+ // Produkt → 'Product name (Produktname)' (added word!)
750
+ // Status → 'Current status (Aktueller Status)' (added word!)
751
+ ```
752
+
753
+ #### Step 5.3: Apply Descriptions EVERYWHERE
754
+
755
+ **🚨 MOST IMPORTANT: Apply SAME description to ALL files!**
756
+
757
+ For **EVERY property in EVERY Module**:
758
+
759
+ 1. Open `<module>.model.ts` → Add description to property
760
+ 2. Open `inputs/<module>-create.input.ts` → Add SAME description to property
761
+ 3. Open `inputs/<module>.input.ts` → Add SAME description to property
762
+
763
+ For **EVERY property in EVERY SubObject**:
764
+
765
+ 1. Open `objects/<object>/<object>.object.ts` → Add description to property
766
+ 2. Open `objects/<object>/<object>-create.input.ts` → Add SAME description to property
767
+ 3. Open `objects/<object>/<object>.input.ts` → Add SAME description to property
768
+
769
+ **Example for Module "Product" with property "price"**:
770
+
771
+ ```typescript
772
+ // File: src/server/modules/product/product.model.ts
773
+ @UnifiedField({ description: 'Product price (Produktpreis)' })
774
+ price: number;
775
+
776
+ // File: src/server/modules/product/inputs/product-create.input.ts
777
+ @UnifiedField({ description: 'Product price (Produktpreis)' })
778
+ price: number;
779
+
780
+ // File: src/server/modules/product/inputs/product.input.ts
781
+ @UnifiedField({ description: 'Product price (Produktpreis)' })
782
+ price?: number;
783
+ ```
784
+
785
+ **Example for SubObject "Address" with property "street"**:
786
+
787
+ ```typescript
788
+ // File: src/server/common/objects/address/address.object.ts
789
+ @UnifiedField({ description: 'Street (Straße)' })
790
+ street: string;
791
+
792
+ // File: src/server/common/objects/address/address-create.input.ts
793
+ @UnifiedField({ description: 'Street (Straße)' })
794
+ street: string;
795
+
796
+ // File: src/server/common/objects/address/address.input.ts
797
+ @UnifiedField({ description: 'Street (Straße)' })
798
+ street?: string;
799
+ ```
800
+
801
+ #### Step 5.4: Add Class-Level Descriptions
802
+
803
+ Also add descriptions to the `@ObjectType()` and `@InputType()` decorators:
804
+
805
+ ```typescript
806
+ @ObjectType({ description: 'Product entity (Produkt-Entität)' })
807
+ export class Product extends CoreModel { ... }
808
+
809
+ @InputType({ description: 'Product creation data (Produkt-Erstellungsdaten)' })
810
+ export class ProductCreateInput { ... }
811
+
812
+ @InputType({ description: 'Product update data (Produkt-Aktualisierungsdaten)' })
813
+ export class ProductInput { ... }
814
+ ```
815
+
816
+ #### Step 5.5: Verify Consistency
817
+
818
+ After applying all descriptions, verify:
819
+
820
+ - [ ] All user-provided comments extracted and processed
821
+ - [ ] All German descriptions translated to format: `ENGLISH (DEUTSCH)`
822
+ - [ ] All English descriptions kept as-is
823
+ - [ ] Module Model has descriptions on all properties
824
+ - [ ] Module CreateInput has SAME descriptions on all properties
825
+ - [ ] Module UpdateInput has SAME descriptions on all properties
826
+ - [ ] SubObject has descriptions on all properties
827
+ - [ ] SubObject CreateInput has SAME descriptions on all properties
828
+ - [ ] SubObject UpdateInput has SAME descriptions on all properties
829
+ - [ ] Class-level decorators have descriptions
830
+ - [ ] NO inconsistencies (same property, different descriptions)
897
831
 
898
- 4. **Apply same description to**:
899
- - Model property
900
- - Input property (both create and update)
901
- - Output property
832
+ **If ANY checkbox is unchecked, STOP and fix before continuing to Phase 6!**
902
833
 
903
834
  ### Phase 6: Enum File Creation
904
835
 
@@ -920,6 +851,99 @@ export enum StatusEnum {
920
851
 
921
852
  ### Phase 7: API Test Creation
922
853
 
854
+ **⚠️ CRITICAL: Test Type Requirement**
855
+
856
+ **ONLY create API tests using TestHelper - NEVER create direct Service tests!**
857
+
858
+ - ✅ **DO:** Create tests that call REST endpoints or GraphQL queries/mutations using `TestHelper`
859
+ - ✅ **DO:** Test through the API layer (Controller/Resolver → Service → Database)
860
+ - ❌ **DON'T:** Create tests that directly instantiate or call Service methods
861
+ - ❌ **DON'T:** Create unit tests for Services (e.g., `user.service.spec.ts`)
862
+ - ❌ **DON'T:** Mock dependencies or bypass the API layer
863
+
864
+ **Why API tests only?**
865
+ - API tests validate the complete security model (decorators, guards, permissions)
866
+ - Direct Service tests bypass authentication and authorization checks
867
+ - TestHelper provides all necessary tools for comprehensive API testing
868
+
869
+ **Exception: Direct database/service access for test setup/cleanup ONLY**
870
+
871
+ Direct database or service access is ONLY allowed for:
872
+
873
+ - ✅ **Test Setup (beforeAll/beforeEach)**:
874
+ - Setting user roles in database: `await db.collection('users').updateOne({ _id: userId }, { $set: { roles: ['admin'] } })`
875
+ - Setting verified flag: `await db.collection('users').updateOne({ _id: userId }, { $set: { verified: true } })`
876
+ - Creating prerequisite test data that can't be created via API
877
+
878
+ - ✅ **Test Cleanup (afterAll/afterEach)**:
879
+ - Deleting test objects: `await db.collection('products').deleteMany({ createdBy: testUserId })`
880
+ - Cleaning up test data: `await db.collection('users').deleteOne({ email: 'test@example.com' })`
881
+
882
+ - ❌ **NEVER for testing functionality**:
883
+ - Don't call `userService.create()` to test user creation - use API endpoint!
884
+ - Don't call `productService.update()` to test updates - use API endpoint!
885
+ - Don't access database to verify results - query via API instead!
886
+
887
+ **Example of correct usage:**
888
+
889
+ ```typescript
890
+ describe('Product Tests', () => {
891
+ let adminToken: string;
892
+ let userId: string;
893
+
894
+ beforeAll(async () => {
895
+ // ✅ ALLOWED: Direct DB access for setup
896
+ const user = await testHelper.rest('/auth/signup', {
897
+ method: 'POST',
898
+ payload: { email: 'admin@test.com', password: 'password' }
899
+ });
900
+ userId = user.id;
901
+
902
+ // ✅ ALLOWED: Direct DB manipulation for test setup
903
+ await db.collection('users').updateOne(
904
+ { _id: new ObjectId(userId) },
905
+ { $set: { roles: ['admin'], verified: true } }
906
+ );
907
+
908
+ // Get token via API
909
+ const auth = await testHelper.rest('/auth/signin', {
910
+ method: 'POST',
911
+ payload: { email: 'admin@test.com', password: 'password' }
912
+ });
913
+ adminToken = auth.token;
914
+ });
915
+
916
+ it('should create product', async () => {
917
+ // ✅ CORRECT: Test via API
918
+ const result = await testHelper.rest('/api/products', {
919
+ method: 'POST',
920
+ payload: { name: 'Test Product' },
921
+ token: adminToken
922
+ });
923
+
924
+ expect(result.name).toBe('Test Product');
925
+
926
+ // ❌ WRONG: Don't verify via DB
927
+ // const dbProduct = await db.collection('products').findOne({ _id: result.id });
928
+
929
+ // ✅ CORRECT: Verify via API
930
+ const fetched = await testHelper.rest(`/api/products/${result.id}`, {
931
+ method: 'GET',
932
+ token: adminToken
933
+ });
934
+ expect(fetched.name).toBe('Test Product');
935
+ });
936
+
937
+ afterAll(async () => {
938
+ // ✅ ALLOWED: Direct DB access for cleanup
939
+ await db.collection('products').deleteMany({ createdBy: userId });
940
+ await db.collection('users').deleteOne({ _id: new ObjectId(userId) });
941
+ });
942
+ });
943
+ ```
944
+
945
+ ---
946
+
923
947
  **⚠️ CRITICAL: Test Creation Process**
924
948
 
925
949
  Creating API tests is NOT just about testing functionality - it's about **validating the security model**. You MUST follow this exact process:
@@ -1594,7 +1618,20 @@ After generation, verify:
1594
1618
  - [ ] All Objects created
1595
1619
  - [ ] All Modules created
1596
1620
  - [ ] All properties in alphabetical order
1597
- - [ ] All descriptions follow format: "ENGLISH (DEUTSCH)"
1621
+ - [ ] **DESCRIPTIONS (Critical - check thoroughly):**
1622
+ - [ ] All user-provided comments (after `//`) extracted from specification
1623
+ - [ ] All German descriptions translated to format: `ENGLISH (DEUTSCH)`
1624
+ - [ ] All English descriptions kept as-is (spelling corrected)
1625
+ - [ ] ALL Module Models have descriptions on all properties
1626
+ - [ ] ALL Module CreateInputs have SAME descriptions
1627
+ - [ ] ALL Module UpdateInputs have SAME descriptions
1628
+ - [ ] ALL SubObjects have descriptions on all properties
1629
+ - [ ] ALL SubObject CreateInputs have SAME descriptions
1630
+ - [ ] ALL SubObject UpdateInputs have SAME descriptions
1631
+ - [ ] ALL `@ObjectType()` decorators have descriptions
1632
+ - [ ] ALL `@InputType()` decorators have descriptions
1633
+ - [ ] NO inconsistencies (same property, different descriptions in different files)
1634
+ - [ ] NO German-only descriptions (must be translated)
1598
1635
  - [ ] Inheritance properly implemented
1599
1636
  - [ ] Required fields correctly set in CreateInputs
1600
1637
  - [ ] Enum files created in `src/server/common/enums/`
@@ -1747,1036 +1784,57 @@ import { User } from '../../user/user.model';
1747
1784
 
1748
1785
  ## ⚠️ CRITICAL: Security & Test Coverage Rules
1749
1786
 
1750
- ### Rule 1: NEVER Weaken Security for Test Convenience
1751
-
1752
- **❌ ABSOLUTELY FORBIDDEN:**
1753
- ```typescript
1754
- // BEFORE (secure):
1755
- @Restricted(RoleEnum.ADMIN)
1756
- export class ProductController {
1757
- @Roles(RoleEnum.S_USER)
1758
- async createProduct() { ... }
1759
- }
1760
-
1761
- // AFTER (FORBIDDEN - security weakened!):
1762
- // @Restricted(RoleEnum.ADMIN) ← NEVER remove this!
1763
- export class ProductController {
1764
- @Roles(RoleEnum.S_USER)
1765
- async createProduct() { ... }
1766
- }
1767
- ```
1768
-
1769
- **🚨 CRITICAL RULE:**
1770
- - **NEVER remove or weaken `@Restricted()` decorators** on Controllers, Resolvers, Models, or Objects
1771
- - **NEVER change `@Roles()` decorators** to more permissive roles just to make tests pass
1772
- - **NEVER modify `securityCheck()` logic** to bypass security for testing
1773
-
1774
- **If tests fail due to permissions:**
1775
- 1. ✅ **CORRECT**: Adjust the test to use the appropriate user/token
1776
- 2. ✅ **CORRECT**: Create test users with the required roles
1777
- 3. ❌ **WRONG**: Weaken security to make tests pass
1778
-
1779
- **Any security changes MUST:**
1780
- - Be discussed with the developer FIRST
1781
- - Have a solid business justification
1782
- - Be explicitly approved by the developer
1783
- - Be documented with the reason
1784
-
1785
- ### Rule 2: Understanding Permission Hierarchy
1786
-
1787
- **⭐ Key Concept: Specific Overrides General**
1788
-
1789
- The `@Restricted()` decorator on a class acts as a **security fallback** - if a method/property doesn't specify permissions, it inherits the class-level restriction. This is a **security-by-default** pattern.
1790
-
1791
- **Example - Controller/Resolver:**
1792
- ```typescript
1793
- @Restricted(RoleEnum.ADMIN) // ← FALLBACK: Protects everything by default
1794
- export class ProductController {
1795
-
1796
- @Roles(RoleEnum.S_EVERYONE) // ← SPECIFIC: This method is MORE open
1797
- async getPublicProducts() {
1798
- // Anyone can access this
1799
- }
1800
-
1801
- @Roles(RoleEnum.S_USER) // ← SPECIFIC: This method is MORE open
1802
- async getMyProducts() {
1803
- // Any signed-in user can access this
1804
- }
1805
-
1806
- async adminOnlyMethod() { // ← NO DECORATOR: Falls back to @Restricted(ADMIN)
1807
- // Only admins can access this
1808
- }
1809
- }
1810
- ```
1811
-
1812
- **Why `@Restricted(RoleEnum.ADMIN)` MUST stay:**
1813
- - **Fail-safe**: If someone forgets `@Roles()` on a new method, it's protected by default
1814
- - **Security**: Without it, a method without `@Roles()` would be open to everyone
1815
- - **Intent**: Shows the class is security-sensitive
1816
-
1817
- **Example - Model/Object:**
1818
- ```typescript
1819
- @Restricted(RoleEnum.ADMIN) // ← FALLBACK: Protects all properties by default
1820
- export class Product extends CoreModel {
1821
-
1822
- @Restricted(RoleEnum.S_EVERYONE) // ← SPECIFIC: This field is MORE open
1823
- name: string;
1824
-
1825
- @Restricted(RoleEnum.S_USER) // ← SPECIFIC: This field is MORE open
1826
- description: string;
1827
-
1828
- secretInternalNotes: string; // ← NO DECORATOR: Falls back to ADMIN only
1829
-
1830
- securityCheck(user: User) {
1831
- // Controls who can see the entire object
1832
- if (user?.hasRole(RoleEnum.ADMIN)) return this;
1833
- if (this.isPublic) return this;
1834
- return undefined;
1835
- }
1836
- }
1837
- ```
1838
-
1839
- ### Rule 3: Test Coverage Strategy
1787
+ **This section provides detailed rules for security and testing. It's duplicated at the beginning of this file for visibility.**
1840
1788
 
1841
- **🎯 Goal: Maximum Coverage WITHOUT Compromising Security**
1842
-
1843
- **Approach:**
1844
- 1. **Analyze permissions thoroughly** (as described in Phase 7)
1845
- 2. **Create appropriate test users** for each permission level:
1846
- ```typescript
1847
- const adminUser = await testHelper.createUser({ roles: [RoleEnum.ADMIN] });
1848
- const regularUser = await testHelper.createUser({ roles: [RoleEnum.S_USER] });
1849
- const creatorUser = await testHelper.createUser({ roles: [RoleEnum.S_USER] });
1850
- ```
1851
- 3. **Test with the LEAST privileged user** who should have access
1852
- 4. **Also test with UNAUTHORIZED users** to verify security
1853
- 5. **Document why certain operations require certain roles**
1854
-
1855
- **Coverage Priorities:**
1856
- 1. **100% coverage** for all security-critical code (securityCheck, guards)
1857
- 2. **100% coverage** for all endpoints (both success and failure cases)
1858
- 3. **100% coverage** for all permission combinations
1859
- 4. **90%+ coverage** for business logic
1860
- 5. **Complete coverage** of error paths and edge cases
1861
-
1862
- **Testing Strategy:**
1863
- ```typescript
1864
- describe('ProductController', () => {
1865
- describe('createProduct', () => {
1866
- // Test with minimum required privilege
1867
- it('should create product as S_USER', async () => {
1868
- // ✅ Tests with least privileged user who should succeed
1869
- });
1789
+ **📖 For the complete content with all rules, examples, and testing strategies, see: `security-rules.md`**
1870
1790
 
1871
- // Test security failure
1872
- it('should FAIL to create product without auth', async () => {
1873
- // Verifies security works
1874
- });
1875
- });
1791
+ **Quick reminder - Core rules:**
1792
+ 1. **NEVER weaken @Restricted or @Roles decorators** to make tests pass
1793
+ 2. **NEVER modify securityCheck() logic** to bypass security
1794
+ 3. **ALWAYS test with least privileged user** who is authorized
1795
+ 4. **ALWAYS create appropriate test users** for each permission level
1796
+ 5. **ALWAYS ask developer** before changing ANY security decorator
1797
+ 6. **Aim for 80-100% test coverage** without compromising security
1876
1798
 
1877
- describe('adminOnlyMethod', () => {
1878
- it('should execute as admin', async () => {
1879
- // Uses admin token (required for this method)
1880
- });
1799
+ **Testing approach:**
1800
+ - Analyze permissions first
1801
+ - Create test users for each role
1802
+ - Test happy path with appropriate user
1803
+ - Test security failures (403 responses)
1804
+ - Document why certain roles are required
1881
1805
 
1882
- it('should FAIL for regular user', async () => {
1883
- // ✅ Verifies fallback to @Restricted(ADMIN) works
1884
- });
1806
+ ## Phase 8: Pre-Report Quality Review
1885
1807
 
1886
- it('should FAIL without auth', async () => {
1887
- // ✅ Verifies security
1888
- });
1889
- });
1890
- });
1891
- ```
1892
-
1893
- ### Rule 4: When Security Changes Are Necessary
1894
-
1895
- **If you genuinely believe a security restriction is too strict:**
1896
-
1897
- 1. **STOP** - Do NOT make the change
1898
- 2. **Analyze** - Why is the restriction failing the test?
1899
- 3. **Document** - Prepare a clear explanation:
1900
- - What restriction exists?
1901
- - Why does it block the test?
1902
- - What business case requires opening it?
1903
- - What security risks does opening it introduce?
1904
- - What mitigation strategies exist?
1905
- 4. **Ask the developer**:
1906
- ```
1907
- "I've analyzed the permissions for [Method/Property] and found:
1908
- - Current restriction: @Restricted(RoleEnum.ADMIN)
1909
- - Test requirement: S_USER needs access to [do X]
1910
- - Business justification: [explain why]
1911
- - Security impact: [explain risks]
1912
- - Mitigation: [how to minimize risk]
1913
-
1914
- Should I:
1915
- A) Keep security as-is and adjust the test
1916
- B) Change to @Restricted(RoleEnum.S_USER) with your approval
1917
- C) Something else?"
1918
- ```
1919
- 5. **Wait for explicit approval** before changing ANY security decorator
1920
- 6. **Document the decision** in code comments:
1921
- ```typescript
1922
- // Changed from ADMIN to S_USER on 2024-01-15
1923
- // Reason: Users need to create their own products
1924
- // Approved by: [Developer Name]
1925
- @Restricted(RoleEnum.S_USER)
1926
- ```
1927
-
1928
- **Remember:**
1929
- - Security is NOT negotiable for test convenience
1930
- - Tests must adapt to security requirements, not vice versa
1931
- - When in doubt, keep it secure and ask
1932
-
1933
- ## Phase 8: Pre-Report Quality Review
1934
-
1935
- **CRITICAL**: Before creating the final report, you MUST perform a comprehensive quality review:
1936
-
1937
- ### Step 1: Identify All Changes
1938
-
1939
- Use git to identify all created and modified files:
1940
-
1941
- ```bash
1942
- git status --short
1943
- git diff --name-only
1944
- ```
1945
-
1946
- For each file, review:
1947
- - All newly created files
1948
- - All modified files
1949
- - File structure and organization
1950
-
1951
- ### Step 2: Test Management
1952
-
1953
- **CRITICAL**: Ensure tests are created/updated for all changes:
1954
-
1955
- #### Step 2.1: Analyze Existing Tests FIRST
1956
-
1957
- **BEFORE creating or modifying ANY tests, you MUST thoroughly analyze existing tests**:
1958
-
1959
- 1. **Identify all existing test files**:
1960
- ```bash
1961
- # List all test directories and files
1962
- ls -la tests/
1963
- ls -la tests/modules/
1964
- find tests -name "*.e2e-spec.ts" -type f
1965
- ```
1966
-
1967
- 2. **Read multiple existing test files completely**:
1968
- ```bash
1969
- # Read at least 2-3 different module tests to understand patterns
1970
- cat tests/modules/user.e2e-spec.ts
1971
- cat tests/modules/<another-module>.e2e-spec.ts
1972
-
1973
- # Also check the common and project test files
1974
- cat tests/common.e2e-spec.ts
1975
- cat tests/project.e2e-spec.ts
1976
- ```
1977
-
1978
- 3. **CRITICAL: Understand the TestHelper thoroughly**:
1979
-
1980
- **Before creating any tests, you MUST understand the TestHelper from @lenne.tech/nest-server**:
1981
-
1982
- ```bash
1983
- # Read the TestHelper source code to understand its capabilities
1984
- cat node_modules/@lenne.tech/nest-server/src/test/test.helper.ts
1985
- ```
1986
-
1987
- **Analyze the TestHelper to understand**:
1988
- - **Available methods**: What methods does TestHelper provide?
1989
- - **Configuration options**: How can TestHelper be configured?
1990
- - **GraphQL support**: How to use `graphQl()` method? What parameters does it accept?
1991
- - **REST support**: How to use `rest()` method? What parameters does it accept?
1992
- - **Authentication**: How does TestHelper handle tokens and authentication?
1993
- - **Request building**: How are requests constructed? What options are available?
1994
- - **Response handling**: How are responses processed? What format is returned?
1995
- - **Error handling**: How does TestHelper handle errors and failures?
1996
- - **Helper utilities**: What additional utilities are available?
1997
-
1998
- **Document your findings**:
1999
- ```typescript
2000
- // Example: Understanding TestHelper.graphQl()
2001
- // Method signature: graphQl(options: GraphQLOptions, config?: RequestConfig)
2002
- // GraphQLOptions: { name, type (QUERY/MUTATION), arguments, fields }
2003
- // RequestConfig: { token, statusCode, headers }
2004
- // Returns: Parsed response data or error
2005
-
2006
- // Example: Understanding TestHelper.rest()
2007
- // Method signature: rest(method: HttpMethod, path: string, options?: RestOptions)
2008
- // HttpMethod: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
2009
- // RestOptions: { body, token, statusCode, headers }
2010
- // Returns: Response data or error
2011
- ```
2012
-
2013
- **Common TestHelper patterns to understand**:
2014
- - How to execute GraphQL queries/mutations with `graphQl()`
2015
- - How to execute REST requests with `rest()`
2016
- - How to pass authentication tokens (same for both methods)
2017
- - How to handle expected errors (statusCode parameter)
2018
- - How to work with response data
2019
- - How to structure test data
2020
- - When to use GraphQL vs REST methods
2021
-
2022
- **Only after fully understanding TestHelper, proceed to next step.**
2023
-
2024
- 4. **Understand the testing approach used**:
2025
- - Which test framework? (Jest, Mocha, etc.)
2026
- - Which testing utilities? (@lenne.tech/nest-server testHelper, custom helpers)
2027
- - How is the test app initialized? (beforeAll setup)
2028
- - How are test users/auth handled?
2029
- - How is test data created and cleaned up?
2030
- - What assertion library? (expect, should, etc.)
2031
- - Are there custom matchers?
2032
-
2033
- 5. **Document the patterns you observe**:
2034
- - **Import patterns**: Which modules are imported? In what order?
2035
- - **Setup patterns**: How is beforeAll/beforeEach structured?
2036
- - **Auth patterns**: How do tests authenticate? Token handling?
2037
- - **Test structure**: Describe blocks organization? Test naming conventions?
2038
- - **CRUD patterns**: How are create/read/update/delete tested?
2039
- - **Assertion patterns**: What assertions are used? How detailed?
2040
- - **Cleanup patterns**: How is afterAll/afterEach structured?
2041
- - **Error testing**: How are failures/validations tested?
2042
-
2043
- 6. **Verify existing tests run successfully**:
2044
- ```bash
2045
- # Run existing tests to ensure they pass
2046
- npm run test:e2e
2047
-
2048
- # If any fail, understand why before proceeding
2049
- # Your new/modified tests MUST NOT break existing tests
2050
- ```
2051
-
2052
- 7. **Create a mental checklist**:
2053
- - [ ] I have read and understand the TestHelper source code
2054
- - [ ] I understand TestHelper methods and configuration
2055
- - [ ] I understand how to use graphQl() method (GraphQL queries/mutations)
2056
- - [ ] I understand how to use rest() method (REST endpoints)
2057
- - [ ] I understand when to use graphQl() vs rest()
2058
- - [ ] I understand TestHelper authentication and error handling
2059
- - [ ] I understand which test helpers/utilities are used
2060
- - [ ] I understand the authentication/authorization pattern
2061
- - [ ] I understand the test data lifecycle (create/cleanup)
2062
- - [ ] I understand the assertion patterns
2063
- - [ ] I understand the error testing approach
2064
- - [ ] All existing tests pass before I make changes
2065
-
2066
- **Only after completing this analysis, proceed to create or modify tests.**
2067
-
2068
- #### Step 2.1.1: Understanding Permissions and User Rights in Tests
2069
-
2070
- **CRITICAL**: Before creating tests, you MUST understand the 3-layer permission system:
2071
-
2072
- **Important Definitions**:
2073
-
2074
- - **Admin User**: A user whose `roles` array contains `'admin'`
2075
- ```typescript
2076
- // Example admin user
2077
- {
2078
- id: '123',
2079
- email: 'admin@test.com',
2080
- roles: ['admin', 'user'] // ← Contains 'admin'
2081
- }
2082
- ```
2083
-
2084
- - **Creator**: The user who created an object, identified by matching IDs
2085
- ```typescript
2086
- // User who created the object
2087
- const user = { id: 'user-123', email: 'creator@test.com' };
2088
-
2089
- // Object created by this user
2090
- const product = {
2091
- id: 'product-456',
2092
- name: 'Test Product',
2093
- createdBy: 'user-123' // ← Matches user.id → This user is the CREATOR
2094
- };
2095
-
2096
- // Different user (NOT the creator)
2097
- const otherUser = { id: 'user-789', email: 'other@test.com' };
2098
- // otherUser.id !== product.createdBy → NOT the creator!
2099
- ```
2100
-
2101
- **The Three Permission Layers**:
2102
-
2103
- 1. **Controller/Resolver Layer** (`@Roles()` decorator):
2104
- - Controls WHO can call the endpoint
2105
- - Example: `@Roles(RoleEnum.ADMIN)` → Only admins can call this endpoint
2106
- - Example: `@Roles(RoleEnum.S_USER)` → All signed-in users can call
2107
-
2108
- 2. **Service Layer** (`serviceOptions.roles` parameter):
2109
- - Controls what permissions are checked during service processing
2110
- - Example: Update/Delete often require `[RoleEnum.ADMIN, RoleEnum.S_CREATOR]`
2111
- - The creator can update/delete their own items
2112
-
2113
- 3. **Model Layer** (`securityCheck()` method):
2114
- - Controls WHAT data is returned to the user
2115
- - Standard implementation:
2116
- ```typescript
2117
- securityCheck(user: User, force?: boolean) {
2118
- // Admins see everything (user.roles contains 'admin')
2119
- if (force || user?.hasRole(RoleEnum.ADMIN)) {
2120
- return this;
2121
- }
2122
- // Only creator can see their own data (user.id === this.createdBy)
2123
- if (!equalIds(user, this.createdBy)) {
2124
- return undefined; // Non-creator gets nothing!
2125
- }
2126
- return this;
2127
- }
2128
- ```
2129
- - **Key checks**:
2130
- - `user?.hasRole(RoleEnum.ADMIN)` → Returns `true` if `user.roles.includes('admin')`
2131
- - `equalIds(user, this.createdBy)` → Returns `true` if `user.id === this.createdBy`
2132
-
2133
- **Default Permission Behavior**:
2134
- - **Create**: Usually accessible to signed-in users (`RoleEnum.S_USER`)
2135
- - **Read/List**: Usually accessible to signed-in users, but securityCheck filters results
2136
- - **Update**: Only ADMIN or CREATOR (via `serviceOptions.roles` check)
2137
- - **Delete**: Only ADMIN or CREATOR (via `serviceOptions.roles` check)
2138
-
2139
- **Analyzing Permissions Before Creating Tests**:
2140
-
2141
- Before writing tests, check these 3 locations:
2142
-
2143
- 1. **Check Controller/Resolver decorators**:
2144
- ```typescript
2145
- // In product.resolver.ts
2146
- @Roles(RoleEnum.ADMIN) // ← WHO can call this?
2147
- @Query(() => Product)
2148
- async getProduct(@Args('id') id: string) { ... }
2149
-
2150
- @Roles(RoleEnum.S_USER) // ← All signed-in users
2151
- @Mutation(() => Product)
2152
- async createProduct(@Args('input') input: ProductCreateInput) { ... }
2153
- ```
2154
-
2155
- 2. **Check Model/Object `@Restricted` decorators**:
2156
- ```typescript
2157
- // In product.model.ts
2158
- @Restricted(RoleEnum.ADMIN) // ← Model-level restriction
2159
- export class Product extends CoreModel {
2160
-
2161
- @Restricted(RoleEnum.ADMIN) // ← Property-level restriction
2162
- @UnifiedField()
2163
- internalNotes?: string;
2164
- }
2165
- ```
2166
-
2167
- 3. **Check Model `securityCheck()` logic**:
2168
- ```typescript
2169
- // In product.model.ts
2170
- securityCheck(user: User, force?: boolean) {
2171
- // Admin check: user.roles contains 'admin'
2172
- if (force || user?.hasRole(RoleEnum.ADMIN)) {
2173
- return this; // Admin sees all
2174
- }
2175
-
2176
- // Custom logic: Allow public products for everyone
2177
- if (this.isPublic) {
2178
- return this;
2179
- }
2180
-
2181
- // Creator check: user.id === this.createdBy
2182
- if (!equalIds(user, this.createdBy)) {
2183
- return undefined; // Non-creator gets nothing
2184
- }
2185
- return this; // Creator sees their own product
2186
- }
2187
- ```
2188
-
2189
- **Creating Appropriate Test Users**:
2190
-
2191
- Based on permission analysis, create appropriate test users:
2192
-
2193
- ```typescript
2194
- describe('Product Module', () => {
2195
- let testHelper: TestHelper;
2196
- let adminToken: string;
2197
- let userToken: string;
2198
- let otherUserToken: string;
2199
- let createdProductId: string;
2200
-
2201
- beforeAll(async () => {
2202
- testHelper = new TestHelper(app);
2203
-
2204
- // Admin user (user.roles contains 'admin')
2205
- const adminAuth = await testHelper.graphQl({
2206
- name: 'signIn',
2207
- type: TestGraphQLType.MUTATION,
2208
- arguments: { email: 'admin@test.com', password: 'admin' },
2209
- fields: ['token', 'user { id email roles }']
2210
- });
2211
- adminToken = adminAuth.token;
2212
- // adminAuth.user.roles = ['admin', 'user'] ← Contains 'admin'
2213
-
2214
- // Regular user (will be the creator of test objects)
2215
- const userAuth = await testHelper.graphQl({
2216
- name: 'signIn',
2217
- type: TestGraphQLType.MUTATION,
2218
- arguments: { email: 'user@test.com', password: 'user' },
2219
- fields: ['token', 'user { id email roles }']
2220
- });
2221
- userToken = userAuth.token;
2222
- // When this user creates an object → object.createdBy = userAuth.user.id
2223
-
2224
- // Another regular user (will NOT be the creator)
2225
- const otherUserAuth = await testHelper.graphQl({
2226
- name: 'signIn',
2227
- type: TestGraphQLType.MUTATION,
2228
- arguments: { email: 'other@test.com', password: 'other' },
2229
- fields: ['token', 'user { id email roles }']
2230
- });
2231
- otherUserToken = otherUserAuth.token;
2232
- // otherUserAuth.user.id !== object.createdBy → NOT the creator
2233
- });
2234
- });
2235
- ```
2236
-
2237
- **Test Structure Based on Permissions**:
2238
-
2239
- ```typescript
2240
- describe('Product Module', () => {
2241
- // ... setup with adminToken, userToken, otherUserToken
2242
-
2243
- describe('Create Product', () => {
2244
- it('should create product as regular user', async () => {
2245
- const result = await testHelper.graphQl({
2246
- name: 'createProduct',
2247
- type: TestGraphQLType.MUTATION,
2248
- arguments: { input: { name: 'Test Product', price: 99.99 } },
2249
- fields: ['id', 'name', 'createdBy { id }']
2250
- }, { token: userToken }); // ← Created by userToken
2251
-
2252
- expect(result.name).toBe('Test Product');
2253
- // result.createdBy.id now equals userAuth.user.id
2254
- // → userToken is the CREATOR of this product
2255
- createdProductId = result.id;
2256
- });
2257
- });
2258
-
2259
- describe('Update Product', () => {
2260
- it('should update product as creator', async () => {
2261
- const result = await testHelper.graphQl({
2262
- name: 'updateProduct',
2263
- type: TestGraphQLType.MUTATION,
2264
- arguments: {
2265
- id: createdProductId,
2266
- input: { price: 89.99 }
2267
- },
2268
- fields: ['id', 'price']
2269
- }, { token: userToken }); // ← Creator: userAuth.user.id === product.createdBy
2270
-
2271
- expect(result.price).toBe(89.99);
2272
- });
2273
-
2274
- it('should update product as admin', async () => {
2275
- const result = await testHelper.graphQl({
2276
- name: 'updateProduct',
2277
- type: TestGraphQLType.MUTATION,
2278
- arguments: {
2279
- id: createdProductId,
2280
- input: { price: 79.99 }
2281
- },
2282
- fields: ['id', 'price']
2283
- }, { token: adminToken }); // ← Admin: adminAuth.user.roles contains 'admin'
2284
-
2285
- expect(result.price).toBe(79.99);
2286
- });
2287
-
2288
- it('should fail to update product as non-creator', async () => {
2289
- const result = await testHelper.graphQl({
2290
- name: 'updateProduct',
2291
- type: TestGraphQLType.MUTATION,
2292
- arguments: {
2293
- id: createdProductId,
2294
- input: { price: 69.99 }
2295
- },
2296
- fields: ['id']
2297
- }, { token: otherUserToken, statusCode: 403 }); // ← Not creator: otherUserAuth.user.id !== product.createdBy
2298
-
2299
- expect(result.errors).toBeDefined();
2300
- });
2301
- });
2302
-
2303
- describe('Delete Product', () => {
2304
- it('should delete product as creator', async () => {
2305
- // First create a new product to delete
2306
- const created = await testHelper.graphQl({
2307
- name: 'createProduct',
2308
- type: TestGraphQLType.MUTATION,
2309
- arguments: { input: { name: 'To Delete', price: 50 } },
2310
- fields: ['id']
2311
- }, { token: userToken });
2312
-
2313
- // Delete as creator
2314
- const result = await testHelper.graphQl({
2315
- name: 'deleteProduct',
2316
- type: TestGraphQLType.MUTATION,
2317
- arguments: { id: created.id },
2318
- fields: ['id']
2319
- }, { token: userToken }); // ← Creator: userAuth.user.id === created.createdBy
2320
-
2321
- expect(result.id).toBe(created.id);
2322
- });
2323
-
2324
- it('should fail to delete product as non-creator', async () => {
2325
- const result = await testHelper.graphQl({
2326
- name: 'deleteProduct',
2327
- type: TestGraphQLType.MUTATION,
2328
- arguments: { id: createdProductId },
2329
- fields: ['id']
2330
- }, { token: otherUserToken, statusCode: 403 }); // ← Not creator: otherUserAuth.user.id !== product.createdBy
2331
-
2332
- expect(result.errors).toBeDefined();
2333
- });
2334
-
2335
- it('should delete any product as admin', async () => {
2336
- const result = await testHelper.graphQl({
2337
- name: 'deleteProduct',
2338
- type: TestGraphQLType.MUTATION,
2339
- arguments: { id: createdProductId },
2340
- fields: ['id']
2341
- }, { token: adminToken }); // ← Admin: adminAuth.user.roles contains 'admin'
2342
-
2343
- expect(result.id).toBe(createdProductId);
2344
- });
2345
- });
2346
- });
2347
- ```
2348
-
2349
- **Permission Testing Checklist**:
2350
-
2351
- Before creating tests, verify:
2352
-
2353
- - [ ] I have checked the `@Roles()` decorators in controllers/resolvers
2354
- - [ ] I have checked the `@Restricted()` decorators in models/objects
2355
- - [ ] I have reviewed the `securityCheck()` logic in models
2356
- - [ ] I understand who can CREATE items (usually S_USER)
2357
- - [ ] I understand who can READ items (S_USER + securityCheck filtering)
2358
- - [ ] I understand who can UPDATE items (usually ADMIN + S_CREATOR)
2359
- - [ ] I understand who can DELETE items (usually ADMIN + S_CREATOR)
2360
- - [ ] I have created appropriate test users (admin, creator, non-creator)
2361
- - [ ] My tests use the CREATOR token (user.id === object.createdBy) for update/delete operations
2362
- - [ ] My tests verify that non-creators (user.id !== object.createdBy) CANNOT update/delete
2363
- - [ ] My tests verify that admins (user.roles contains 'admin') CAN update/delete everything
2364
-
2365
- **Common Permission Test Patterns**:
2366
-
2367
- 1. **Test with creator** (user.id === object.createdBy) → Should succeed
2368
- 2. **Test with admin** (user.roles contains 'admin') → Should succeed
2369
- 3. **Test with other user** (user.id !== object.createdBy) → Should fail (403)
2370
-
2371
- **Only after understanding permissions, proceed to create tests.**
2372
-
2373
- #### Step 2.2: For Newly Created Modules
2374
-
2375
- **CRITICAL: Follow the correct test folder structure**:
2376
-
2377
- The project uses a specific test organization:
2378
-
2379
- 1. **Module tests** (for modules in `src/server/modules/`):
2380
- ```
2381
- tests/modules/<module-name>.e2e-spec.ts
2382
- ```
2383
- - Each module gets its own test file directly in `tests/modules/`
2384
- - Examples: `tests/modules/user.e2e-spec.ts`, `tests/modules/book.e2e-spec.ts`
2385
-
2386
- 2. **Common tests** (for common functionality in `src/server/common/`):
2387
- ```
2388
- tests/common.e2e-spec.ts
2389
- ```
2390
- - All common functionality (enums, objects, helpers) tested here
2391
- - Single file for all common-related tests
2392
-
2393
- 3. **Project tests** (for everything else - root level, config, etc.):
2394
- ```
2395
- tests/project.e2e-spec.ts
2396
- ```
2397
- - General project-level tests
2398
- - Configuration tests
2399
- - Integration tests
2400
-
2401
- **Determine correct test location**:
2402
-
2403
- ```bash
2404
- # BEFORE creating a test, ask yourself:
2405
- # - Is this a module in src/server/modules/? → tests/modules/<name>.e2e-spec.ts
2406
- # - Is this common functionality? → Add to tests/common.e2e-spec.ts
2407
- # - Is this project-level? → Add to tests/project.e2e-spec.ts
2408
-
2409
- # Check existing test structure to confirm:
2410
- ls -la tests/
2411
- ls tests/modules/
2412
- ```
2413
-
2414
- **Create new test files** for modules following the patterns you identified:
2415
-
2416
- ```bash
2417
- # For a new module (e.g., Book)
2418
- tests/modules/book.e2e-spec.ts
2419
- ```
2420
-
2421
- **IMPORTANT**: Your new test file MUST:
2422
- 1. **Match the exact structure** of existing test files
2423
- 2. **Use the same imports** as existing tests
2424
- 3. **Follow the same setup/cleanup pattern** (beforeAll, afterAll)
2425
- 4. **Use the same test helpers/utilities** you observed
2426
- 5. **Follow the same authentication pattern**
2427
- 6. **Use the same assertion style**
2428
- 7. **Follow the same naming conventions** for describe/it blocks
2429
-
2430
- **Each new test file must include**:
2431
- 1. All CRUD operations (create, find all, find by ID, update, delete)
2432
- 2. Authorization tests (unauthorized should fail, authorized should succeed)
2433
- 3. Required field validation (missing required fields should fail)
2434
- 4. Proper test data setup and cleanup (beforeAll, afterAll)
2435
- 5. Tests for any custom methods or relationships
2436
-
2437
- **Ensure all prerequisites are met by analyzing existing tests**:
2438
-
2439
- Before writing test code, identify ALL prerequisites from existing test files:
2440
-
2441
- ```bash
2442
- # Read an existing module test to understand prerequisites
2443
- cat tests/modules/user.e2e-spec.ts
2444
- ```
2445
-
2446
- **Common prerequisites to check**:
2447
- 1. **Test data dependencies**:
2448
- - Does the module reference other modules? (e.g., Book → User for borrowedBy)
2449
- - Do you need to create related test data first?
2450
- - Example: To test Book with borrowedBy: User, create test User first
2451
-
2452
- 2. **Authentication requirements**:
2453
- - What roles/permissions are needed?
2454
- - Do test users need to be created with specific roles?
2455
- - Example: Admin user for create operations, regular user for read operations
2456
-
2457
- 3. **Database setup**:
2458
- - Are there database constraints or required collections?
2459
- - Do embedded objects or enums need to exist?
2460
-
2461
- 4. **Configuration**:
2462
- - Are environment variables or config values needed?
2463
- - Example: JWT secrets, database connections
2464
-
2465
- **Pattern from existing tests**:
2466
- ```typescript
2467
- // Example structure you should follow:
2468
- beforeAll(async () => {
2469
- // 1. Initialize test app/module
2470
- // 2. Set up database connection
2471
- // 3. Create prerequisite test data (users, roles, etc.)
2472
- // 4. Authenticate and get tokens
2473
- });
2474
-
2475
- describe('Module Tests', () => {
2476
- // Tests here
2477
- });
2478
-
2479
- afterAll(async () => {
2480
- // 1. Delete created test data (in reverse order)
2481
- // 2. Clean up connections
2482
- // 3. Close app
2483
- });
2484
- ```
2485
-
2486
- **CRITICAL**: Look at how existing tests handle prerequisites and replicate the exact same approach.
2487
-
2488
- #### Step 2.3: For Modified Existing Modules
2489
-
2490
- **Update existing test files** when you modify modules:
2491
-
2492
- 1. **FIRST: Read the existing test file completely**:
2493
- ```bash
2494
- # Find and read the test file for the module you modified
2495
- find tests -name "*<module-name>*.e2e-spec.ts"
2496
- cat tests/modules/<module-name>.e2e-spec.ts
2497
- ```
2498
-
2499
- 2. **Understand what the existing tests cover**:
2500
- - Which operations are tested?
2501
- - Which properties are validated?
2502
- - What edge cases are covered?
2503
- - How is test data structured?
2504
-
2505
- 3. **Run existing tests to ensure they pass BEFORE your changes**:
2506
- ```bash
2507
- npm run test:e2e
2508
- ```
2509
-
2510
- 4. **Review and update tests**:
2511
- - **Added properties**: Add tests verifying new properties work correctly
2512
- - **Changed validation**: Update tests to reflect new validation rules
2513
- - **Added relationships**: Add tests for new references/embedded objects
2514
- - **Changed required fields**: Update CreateInput tests accordingly
2515
- - **Removed properties**: Remove related test assertions
2516
-
2517
- 5. **Verify test coverage**:
2518
- - All new properties are tested
2519
- - Changed behavior is verified
2520
- - Edge cases are covered
2521
- - Authorization still works correctly
2522
-
2523
- 6. **Run tests again to ensure your changes don't break anything**:
2524
- ```bash
2525
- npm run test:e2e
2526
- ```
2527
-
2528
- ### Step 3: Compare with Existing Code
2529
-
2530
- **Compare generated code with existing project code**:
2531
-
2532
- 1. **Read existing similar modules** to understand project patterns:
2533
- ```bash
2534
- # Example: If you created a User module, check existing modules
2535
- ls src/server/modules/
2536
- ```
2537
-
2538
- 2. **Check for consistency**:
2539
- - Code style (indentation, spacing, formatting)
2540
- - Import ordering and organization
2541
- - Naming conventions (camelCase, PascalCase, kebab-case)
2542
- - File structure and directory organization
2543
- - Comment style and documentation
2544
- - Decorator usage (@Field, @Prop, etc.)
2545
- - Error handling patterns
2546
- - Validation patterns
2547
-
2548
- 3. **Review property ordering**:
2549
- - Verify alphabetical order in models
2550
- - Verify alphabetical order in inputs
2551
- - Verify alphabetical order in outputs
2552
- - Check decorator consistency
2553
-
2554
- ### Step 4: Critical Analysis
2555
-
2556
- **Analyze each file critically**:
2557
-
2558
- 1. **Style consistency**:
2559
- - Does the code match the project's existing style?
2560
- - Are imports grouped and ordered correctly?
2561
- - Is indentation consistent with the project?
2562
- - Are naming conventions followed?
2563
-
2564
- 2. **Structural consistency**:
2565
- - Are decorators in the same order as existing code?
2566
- - Is the file structure identical to existing modules?
2567
- - Are descriptions formatted the same way?
2568
- - Are relationships implemented consistently?
2569
-
2570
- 3. **Code quality**:
2571
- - Are there any redundant imports?
2572
- - Are there any missing imports?
2573
- - Are descriptions meaningful and complete?
2574
- - Are TypeScript types correctly used?
2575
-
2576
- 4. **Best practices**:
2577
- - Are required fields properly marked?
2578
- - Are nullable fields correctly configured?
2579
- - Are references properly typed?
2580
- - Are arrays correctly configured?
2581
-
2582
- ### Step 5: Automated Optimizations
2583
-
2584
- **Apply automatic improvements**:
2585
-
2586
- 1. **Fix import ordering**:
2587
- - External imports first (alphabetically)
2588
- - @lenne.tech/nest-server imports next
2589
- - Local imports last (alphabetically by path depth)
2590
-
2591
- 2. **Fix property ordering**:
2592
- - Reorder all properties alphabetically in models
2593
- - Reorder all properties alphabetically in inputs
2594
- - Reorder all properties alphabetically in outputs
2595
-
2596
- 3. **Fix formatting**:
2597
- - Ensure consistent indentation
2598
- - Remove extra blank lines
2599
- - Add missing blank lines between sections
2600
-
2601
- 4. **Fix descriptions**:
2602
- - Ensure all follow "ENGLISH (DEUTSCH)" format
2603
- - Add missing descriptions
2604
- - Improve unclear descriptions
2605
-
2606
- 5. **Fix common patterns**:
2607
- - Standardize decorator usage
2608
- - Standardize validation patterns
2609
- - Standardize error handling
2610
-
2611
- ### Step 6: Pre-Report Testing
2612
-
2613
- **MANDATORY**: Run all tests before reporting:
2614
-
2615
- ```bash
2616
- # Run TypeScript compilation
2617
- npm run build
2618
-
2619
- # Run linting
2620
- npm run lint
2621
-
2622
- # Run all tests
2623
- npm run test:e2e
2624
-
2625
- # If any fail, fix issues and repeat
2626
- ```
2627
-
2628
- **If tests fail**:
2629
- 1. Analyze the error
2630
- 2. Fix the issue
2631
- 3. Re-run tests
2632
- 4. Repeat until all tests pass
2633
-
2634
- #### Debugging Failed Tests - Important Guidelines
2635
-
2636
- **When tests fail, use systematic debugging with console.log statements:**
2637
-
2638
- 1. **Add debug messages in Controllers/Resolvers**:
2639
- ```typescript
2640
- // In controller/resolver - BEFORE service call
2641
- console.log('🔵 [Controller] createProduct - Input:', input);
2642
- console.log('🔵 [Controller] createProduct - User:', serviceOptions?.user);
2643
-
2644
- const result = await this.productService.create(input, serviceOptions);
2645
-
2646
- // AFTER service call
2647
- console.log('🔵 [Controller] createProduct - Result:', result);
2648
- ```
2649
-
2650
- 2. **Add debug messages in Services**:
2651
- ```typescript
2652
- // In service method
2653
- console.log('🟢 [Service] create - Input:', input);
2654
- console.log('🟢 [Service] create - ServiceOptions:', serviceOptions);
2655
-
2656
- const created = await super.create(input, serviceOptions);
2657
-
2658
- console.log('🟢 [Service] create - Created:', created);
2659
- ```
2660
-
2661
- 3. **Understand the permissions system**:
2662
- - **Controllers/Resolvers**: `@Roles()` decorator controls WHO can call the endpoint
2663
- - **Services**: `serviceOptions.roles` controls what the service checks during processing
2664
- - **Models**: `securityCheck()` method determines what data is returned to the user
2665
-
2666
- 4. **Default permission behavior**:
2667
- - Only **Admin users** (user.roles contains 'admin') OR the **creator** (user.id === object.createdBy) of an element can access it
2668
- - This is enforced in the `securityCheck()` method in models:
2669
- ```typescript
2670
- securityCheck(user: User, force?: boolean) {
2671
- // Admin: user.roles contains 'admin'
2672
- if (force || user?.hasRole(RoleEnum.ADMIN)) {
2673
- return this; // Admin sees everything
2674
- }
2675
- // Creator: user.id === this.createdBy
2676
- if (!equalIds(user, this.createdBy)) {
2677
- return undefined; // Non-creator (user.id !== this.createdBy) gets nothing
2678
- }
2679
- return this; // Creator sees their own data
2680
- }
2681
- ```
2682
-
2683
- 5. **Debugging strategy for permission issues**:
2684
-
2685
- **Step 1**: Run failing test with Admin user first
2686
- ```typescript
2687
- // In test setup
2688
- const adminToken = await testHelper.signIn('admin@test.com', 'admin-password');
2689
-
2690
- // Use admin token in test
2691
- const result = await testHelper.graphQl({...}, { token: adminToken });
2692
- ```
2693
-
2694
- **Step 2**: Analyze results
2695
- - ✅ **Works with Admin, fails with normal user** → Permission issue (check Roles, securityCheck)
2696
- - ❌ **Fails with Admin too** → Different issue (check logic, data, validation)
2697
-
2698
- 6. **Common permission issues and solutions**:
2699
-
2700
- | Problem | Cause | Solution |
2701
- |---------|-------|----------|
2702
- | 401/403 on endpoint | `@Roles()` too restrictive | Adjust decorator in controller/resolver |
2703
- | Empty result despite data existing | `securityCheck()` returns undefined | Modify securityCheck logic or use Admin |
2704
- | Service throws permission error | `serviceOptions.roles` check fails | Pass correct roles in serviceOptions |
2705
-
2706
- 7. **Remove debug messages after fixing**:
2707
- ```bash
2708
- # After tests pass, remove all console.log statements
2709
- # Search for debug patterns
2710
- grep -r "console.log" src/server/modules/your-module/
2711
-
2712
- # Remove them manually or with sed
2713
- # Then verify tests still pass
2714
- npm run test:e2e
2715
- ```
2716
-
2717
- **Debugging workflow example**:
2718
- ```typescript
2719
- // 1. Test fails - add debugging
2720
- @Mutation(() => Product)
2721
- async createProduct(@Args('input') input: ProductCreateInput, @GraphQLServiceOptions() opts) {
2722
- console.log('🔵 START createProduct', { input, user: opts?.user?.email });
2723
-
2724
- const result = await this.productService.create(input, opts);
2725
-
2726
- console.log('🔵 END createProduct', { result: result?.id });
2727
- return result;
2728
- }
2729
-
2730
- // In service
2731
- async create(input: ProductCreateInput, serviceOptions?: ServiceOptions) {
2732
- console.log('🟢 Service create', { input, user: serviceOptions?.user?.email });
2733
-
2734
- const created = await super.create(input, serviceOptions);
2735
-
2736
- console.log('🟢 Service created', { id: created?.id, createdBy: created?.createdBy });
2737
- return created;
2738
- }
2739
-
2740
- // 2. Run test - observe output:
2741
- // 🔵 START createProduct { input: {...}, user: 'test@test.com' }
2742
- // 🟢 Service create { input: {...}, user: 'test@test.com' }
2743
- // 🟢 Service created { id: '123', createdBy: '456' }
2744
- // 🔵 END createProduct { result: undefined } ← AHA! Result is undefined!
2745
-
2746
- // 3. Check model securityCheck() - likely returns undefined for non-creator (user.id !== object.createdBy)
2747
- // 4. Fix: Either use Admin user (user.roles contains 'admin') or adjust securityCheck logic
2748
- // 5. Test passes → Remove console.log statements
2749
- // 6. Verify tests still pass
2750
- ```
2751
-
2752
- **Do not proceed to final report if**:
2753
- - TypeScript compilation fails
2754
- - Linting fails
2755
- - Any tests fail
2756
- - Console shows errors or warnings
2757
-
2758
- ### Step 7: Final Verification
2759
-
2760
- Before reporting, verify:
2761
-
2762
- - [ ] All files compared with existing code
2763
- - [ ] Code style matches project patterns
2764
- - [ ] All imports properly ordered
2765
- - [ ] All properties in alphabetical order
2766
- - [ ] All descriptions follow format
2767
- - [ ] **TestHelper source code read and understood**
2768
- - [ ] **TestHelper methods and configuration understood**
2769
- - [ ] **Existing tests analyzed BEFORE creating/modifying tests**
2770
- - [ ] **Existing tests passed BEFORE making changes**
2771
- - [ ] **Tests in correct location (tests/modules/<name>.e2e-spec.ts, tests/common.e2e-spec.ts, or tests/project.e2e-spec.ts)**
2772
- - [ ] **New test files created for all new modules**
2773
- - [ ] **Existing test files updated for all modified modules**
2774
- - [ ] **All prerequisites identified and handled (test data dependencies, auth, etc.)**
2775
- - [ ] **All new/modified tests follow exact patterns from existing tests**
2776
- - [ ] TypeScript compiles without errors
2777
- - [ ] Linter passes without warnings
2778
- - [ ] **All tests pass AFTER changes**
2779
- - [ ] No console errors or warnings
1808
+ **CRITICAL**: Before creating the final report, you MUST perform a comprehensive quality review.
1809
+
1810
+ **📖 For the complete quality review process with all steps, checklists, and examples, see: `quality-review.md`**
1811
+
1812
+ **Quick overview - 7 steps:**
1813
+
1814
+ 1. **Identify All Changes**: Use git to identify all created/modified files
1815
+ 2. **Test Management**:
1816
+ - Analyze existing tests FIRST (understand TestHelper, patterns, permissions)
1817
+ - Create new test files for newly created modules (in `tests/modules/`)
1818
+ - Update existing test files for modified modules
1819
+ - Follow exact patterns from existing tests
1820
+ 3. **Compare with Existing Code**: Check consistency (style, structure, naming)
1821
+ 4. **Critical Analysis**: Verify style, structure, code quality, best practices
1822
+ 5. **Automated Optimizations**: Fix import ordering, property ordering, formatting, descriptions
1823
+ 6. **Pre-Report Testing**: Run build, lint, and all tests (must all pass!)
1824
+ 7. **Final Verification**: Complete checklist before proceeding to Final Report
1825
+
1826
+ **Critical reminders:**
1827
+ - [ ] **TestHelper thoroughly understood** (read source code, understand graphQl() and rest() methods)
1828
+ - [ ] **Existing tests analyzed** BEFORE creating new tests
1829
+ - [ ] **Permission system understood** (3 layers: Controller @Roles, Service options, Model securityCheck)
1830
+ - [ ] **Tests in correct location** (tests/modules/, tests/common.e2e-spec.ts, or tests/project.e2e-spec.ts)
1831
+ - [ ] **All tests pass** before reporting
1832
+
1833
+ **Permission testing approach:**
1834
+ - Admin users: `user.roles.includes('admin')`
1835
+ - Creators: `user.id === object.createdBy`
1836
+ - Always test with appropriate user (creator for update/delete, admin for everything)
1837
+ - Test security failures (403 responses)
2780
1838
 
2781
1839
  **Only after ALL checks pass, proceed to Final Report.**
2782
1840