返回 AiToEarn
coding-style.md
根目录 / project / aitoearn-backend / .claude / rules / coding-style.md
1 # Coding Style
2
3 ## Immutability (CRITICAL)
4
5 ALWAYS create new objects, NEVER mutate:
6
7 ```javascript
8 // WRONG: Mutation
9 function updateUser(user, name) {
10 user.name = name // MUTATION!
11 return user
12 }
13
14 // CORRECT: Immutability
15 function updateUser(user, name) {
16 return {
17 ...user,
18 name
19 }
20 }
21 ```
22
23 ## File Organization
24
25 MANY SMALL FILES > FEW LARGE FILES:
26 - High cohesion, low coupling
27 - 200-400 lines typical, 800 max
28 - Extract utilities from large components
29 - Organize by feature/domain, not by type
30
31 ## Error Handling
32
33 Business errors use `AppException + ResponseCode`, while protocol-layer errors may use standard `HttpException`. Do NOT wrap business logic with try-catch.
34
35 ```typescript
36 // WRONG: try-catch + console + throw new Error
37 try {
38 const order = await this.orderService.getById(id)
39 } catch (error) {
40 console.error('Failed:', error) // ❌ console prohibited
41 throw new Error('Order not found') // ❌ use AppException
42 }
43
44 // CORRECT: Let the framework handle exceptions
45 const order = await this.orderRepository.getById(id)
46 if (!order) {
47 throw new AppException(ResponseCode.OrderNotFound)
48 }
49 ```
50
51 Only use try-catch for infrastructure-level operations (external API calls, file I/O), and log with `this.logger.error()` instead of `console`.
52
53 ## Input Validation
54
55 ALWAYS validate user input:
56
57 ```typescript
58 import { z } from 'zod'
59
60 const schema = z.object({
61 email: z.string().email(),
62 age: z.number().int().min(0).max(150)
63 })
64
65 const validated = schema.parse(input)
66 ```
67
68 ## Logger Error Format
69
70 Error must be the first argument, message the second as a plain string:
71
72 ```typescript
73 // CORRECT
74 this.logger.error(error, `Failed to process order ${orderId}`)
75 this.logger.warn(error, `Inventory check failed for product ${productId}`)
76
77 // WRONG — error nested in object
78 this.logger.error({ path: 'xxx', message: 'yyy', error: err })
79
80 // WRONG — error interpolated into string template
81 this.logger.error(`Failed to process: ${error}`)
82
83 // WRONG — message as object
84 this.logger.error(error, { context: 'xxx' })
85 ```
86
87 Promise catch follows the same rule:
88 ```typescript
89 // CORRECT
90 promise.catch((err: Error) => this.logger.error(err, 'Failed to send notification'))
91
92 // WRONG
93 promise.catch((err: unknown) => this.logger.error({ message: 'xxx', error: err }))
94 ```
95
96 ## Code Quality Checklist
97
98 Before marking work complete:
99 - [ ] Code is readable and well-named
100 - [ ] Functions are small (<50 lines)
101 - [ ] Files are focused (<800 lines)
102 - [ ] No deep nesting (>4 levels)
103 - [ ] Proper error handling
104 - [ ] No console usage (use Logger instance)
105 - [ ] No hardcoded values
106 - [ ] No mutation (immutable patterns used)
107
107 lines MARKDOWN