@champpaba/claude-agent-kit 2.7.0 → 2.8.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 (44) hide show
  1. package/.claude/CLAUDE.md +49 -0
  2. package/.claude/commands/csetup.md +364 -38
  3. package/.claude/commands/cview.md +364 -364
  4. package/.claude/contexts/design/accessibility.md +611 -611
  5. package/.claude/contexts/design/layout.md +400 -400
  6. package/.claude/contexts/design/responsive.md +551 -551
  7. package/.claude/contexts/design/shadows.md +522 -522
  8. package/.claude/contexts/design/typography.md +465 -465
  9. package/.claude/contexts/domain/README.md +164 -164
  10. package/.claude/contexts/patterns/agent-coordination.md +388 -388
  11. package/.claude/contexts/patterns/development-principles.md +513 -513
  12. package/.claude/contexts/patterns/error-handling.md +478 -478
  13. package/.claude/contexts/patterns/logging.md +424 -424
  14. package/.claude/contexts/patterns/tdd-classification.md +516 -516
  15. package/.claude/contexts/patterns/testing.md +413 -413
  16. package/.claude/lib/tdd-classifier.md +345 -345
  17. package/.claude/lib/validation-gates.md +484 -484
  18. package/.claude/settings.local.json +42 -42
  19. package/.claude/templates/context-template.md +45 -45
  20. package/.claude/templates/flags-template.json +42 -42
  21. package/.claude/templates/phases-sections/accessibility-test.md +17 -17
  22. package/.claude/templates/phases-sections/api-design.md +37 -37
  23. package/.claude/templates/phases-sections/backend-tests.md +16 -16
  24. package/.claude/templates/phases-sections/backend.md +37 -37
  25. package/.claude/templates/phases-sections/business-logic-validation.md +16 -16
  26. package/.claude/templates/phases-sections/component-tests.md +17 -17
  27. package/.claude/templates/phases-sections/contract-backend.md +16 -16
  28. package/.claude/templates/phases-sections/contract-frontend.md +16 -16
  29. package/.claude/templates/phases-sections/database.md +35 -35
  30. package/.claude/templates/phases-sections/e2e-tests.md +16 -16
  31. package/.claude/templates/phases-sections/fix-implementation.md +17 -17
  32. package/.claude/templates/phases-sections/frontend-integration.md +18 -18
  33. package/.claude/templates/phases-sections/manual-flow-test.md +15 -15
  34. package/.claude/templates/phases-sections/manual-ux-test.md +16 -16
  35. package/.claude/templates/phases-sections/refactor-implementation.md +17 -17
  36. package/.claude/templates/phases-sections/refactor.md +16 -16
  37. package/.claude/templates/phases-sections/regression-tests.md +15 -15
  38. package/.claude/templates/phases-sections/responsive-test.md +16 -16
  39. package/.claude/templates/phases-sections/script-implementation.md +43 -43
  40. package/.claude/templates/phases-sections/test-coverage.md +16 -16
  41. package/.claude/templates/phases-sections/user-approval.md +14 -14
  42. package/LICENSE +21 -21
  43. package/README.md +25 -0
  44. package/package.json +8 -4
@@ -1,513 +1,513 @@
1
- # Development Principles
2
-
3
- **Core Philosophy:** Build software that is simple, maintainable, observable, and resilient.
4
-
5
- ---
6
-
7
- ## KISS (Keep It Simple, Stupid)
8
-
9
- Simplicity should be a key goal in design. Choose straightforward solutions over complex ones.
10
-
11
- ### Examples
12
-
13
- **❌ Complex:**
14
- ```typescript
15
- // Over-engineered abstraction
16
- class UserRepositoryFactory {
17
- createRepository(type: 'sql' | 'nosql') {
18
- return type === 'sql'
19
- ? new SQLUserRepository(new DatabaseConnection())
20
- : new NoSQLUserRepository(new MongoConnection())
21
- }
22
- }
23
- ```
24
-
25
- **✅ Simple:**
26
- ```typescript
27
- // Direct, readable
28
- import { prisma } from '@/lib/db'
29
-
30
- export async function getUser(id: string) {
31
- return prisma.user.findUnique({ where: { id } })
32
- }
33
- ```
34
-
35
- ---
36
-
37
- ## YAGNI (You Aren't Gonna Need It)
38
-
39
- Avoid building functionality on speculation. Implement features only when needed.
40
-
41
- ### When to Apply
42
-
43
- **❌ Don't Build:**
44
- - "We might need this someday"
45
- - Premature optimization
46
- - Unused abstractions
47
- - Speculative features
48
-
49
- **✅ Build Only:**
50
- - Features with clear requirements
51
- - Immediate user needs
52
- - Proven performance bottlenecks
53
-
54
- ### Example
55
-
56
- ```typescript
57
- // ❌ YAGNI Violation - Building for future maybe-needs
58
- interface User {
59
- id: string
60
- email: string
61
- name: string
62
- preferences?: UserPreferences // Not needed yet
63
- settings?: UserSettings // Not needed yet
64
- metadata?: Record<string, unknown> // "Just in case"
65
- }
66
-
67
- // ✅ YAGNI Compliant - Build what you need now
68
- interface User {
69
- id: string
70
- email: string
71
- name: string
72
- }
73
- // Add fields when requirements are clear
74
- ```
75
-
76
- ---
77
-
78
- ## SOLID Principles
79
-
80
- ### 1. Single Responsibility Principle (SRP)
81
-
82
- Each module/class/function should have ONE reason to change.
83
-
84
- **❌ Violates SRP:**
85
- ```typescript
86
- class UserService {
87
- createUser(data: UserData) { /* ... */ }
88
- sendWelcomeEmail(user: User) { /* ... */ }
89
- logActivity(action: string) { /* ... */ }
90
- validateEmail(email: string) { /* ... */ }
91
- }
92
- ```
93
-
94
- **✅ Follows SRP:**
95
- ```typescript
96
- // lib/services/user-service.ts
97
- class UserService {
98
- createUser(data: UserData) { /* ... */ }
99
- }
100
-
101
- // lib/services/email-service.ts
102
- class EmailService {
103
- sendWelcomeEmail(user: User) { /* ... */ }
104
- }
105
-
106
- // lib/logger.ts
107
- export const logger = { /* ... */ }
108
-
109
- // lib/validators.ts
110
- export function validateEmail(email: string) { /* ... */ }
111
- ```
112
-
113
- ---
114
-
115
- ### 2. Open/Closed Principle (OCP)
116
-
117
- Software entities should be **open for extension** but **closed for modification**.
118
-
119
- **❌ Violates OCP:**
120
- ```typescript
121
- function calculateDiscount(user: User, order: Order) {
122
- if (user.type === 'regular') {
123
- return order.total * 0.05
124
- } else if (user.type === 'premium') {
125
- return order.total * 0.10
126
- } else if (user.type === 'vip') {
127
- return order.total * 0.20
128
- }
129
- // Adding new user types requires modifying this function
130
- }
131
- ```
132
-
133
- **✅ Follows OCP:**
134
- ```typescript
135
- interface DiscountStrategy {
136
- calculate(order: Order): number
137
- }
138
-
139
- class RegularDiscount implements DiscountStrategy {
140
- calculate(order: Order) { return order.total * 0.05 }
141
- }
142
-
143
- class PremiumDiscount implements DiscountStrategy {
144
- calculate(order: Order) { return order.total * 0.10 }
145
- }
146
-
147
- class VIPDiscount implements DiscountStrategy {
148
- calculate(order: Order) { return order.total * 0.20 }
149
- }
150
-
151
- // Adding new discount types = create new class (no modification needed)
152
- function calculateDiscount(strategy: DiscountStrategy, order: Order) {
153
- return strategy.calculate(order)
154
- }
155
- ```
156
-
157
- ---
158
-
159
- ### 3. Liskov Substitution Principle (LSP)
160
-
161
- Subtypes must be substitutable for their base types without altering correctness.
162
-
163
- **❌ Violates LSP:**
164
- ```typescript
165
- class Bird {
166
- fly() { console.log('Flying') }
167
- }
168
-
169
- class Penguin extends Bird {
170
- fly() { throw new Error('Penguins cannot fly') } // Breaks substitution
171
- }
172
- ```
173
-
174
- **✅ Follows LSP:**
175
- ```typescript
176
- interface Bird {
177
- move(): void
178
- }
179
-
180
- class FlyingBird implements Bird {
181
- move() { console.log('Flying') }
182
- }
183
-
184
- class Penguin implements Bird {
185
- move() { console.log('Swimming') }
186
- }
187
- ```
188
-
189
- ---
190
-
191
- ### 4. Interface Segregation Principle (ISP)
192
-
193
- Clients should not depend on interfaces they don't use.
194
-
195
- **❌ Violates ISP:**
196
- ```typescript
197
- interface Worker {
198
- work(): void
199
- eat(): void
200
- sleep(): void
201
- }
202
-
203
- class Robot implements Worker {
204
- work() { /* ... */ }
205
- eat() { throw new Error('Robots do not eat') } // Forced to implement
206
- sleep() { throw new Error('Robots do not sleep') } // Forced to implement
207
- }
208
- ```
209
-
210
- **✅ Follows ISP:**
211
- ```typescript
212
- interface Workable {
213
- work(): void
214
- }
215
-
216
- interface Eatable {
217
- eat(): void
218
- }
219
-
220
- interface Sleepable {
221
- sleep(): void
222
- }
223
-
224
- class Human implements Workable, Eatable, Sleepable {
225
- work() { /* ... */ }
226
- eat() { /* ... */ }
227
- sleep() { /* ... */ }
228
- }
229
-
230
- class Robot implements Workable {
231
- work() { /* ... */ }
232
- }
233
- ```
234
-
235
- ---
236
-
237
- ### 5. Dependency Inversion Principle (DIP)
238
-
239
- High-level modules should not depend on low-level modules. Both should depend on abstractions.
240
-
241
- **❌ Violates DIP:**
242
- ```typescript
243
- class MySQLDatabase {
244
- query(sql: string) { /* ... */ }
245
- }
246
-
247
- class UserService {
248
- private db = new MySQLDatabase() // Direct dependency on low-level module
249
-
250
- getUser(id: string) {
251
- return this.db.query(`SELECT * FROM users WHERE id = ${id}`)
252
- }
253
- }
254
- ```
255
-
256
- **✅ Follows DIP:**
257
- ```typescript
258
- interface Database {
259
- query(sql: string): Promise<unknown>
260
- }
261
-
262
- class MySQLDatabase implements Database {
263
- query(sql: string) { /* ... */ }
264
- }
265
-
266
- class PostgreSQLDatabase implements Database {
267
- query(sql: string) { /* ... */ }
268
- }
269
-
270
- class UserService {
271
- constructor(private db: Database) {} // Depends on abstraction
272
-
273
- getUser(id: string) {
274
- return this.db.query(`SELECT * FROM users WHERE id = ${id}`)
275
- }
276
- }
277
-
278
- // Usage
279
- const userService = new UserService(new MySQLDatabase())
280
- // Easy to swap: new UserService(new PostgreSQLDatabase())
281
- ```
282
-
283
- ---
284
-
285
- ## Fail Fast
286
-
287
- Detect errors early and raise exceptions immediately when issues occur.
288
-
289
- ### When to Fail Fast
290
-
291
- **✅ Fail immediately on:**
292
- - Invalid input
293
- - Missing required configuration
294
- - Broken dependencies
295
- - Database connection failures
296
- - Authentication failures
297
-
298
- **❌ Don't fail fast on:**
299
- - Transient network errors (retry instead)
300
- - User input errors (validate gracefully)
301
- - Optional features
302
-
303
- ### Examples
304
-
305
- **❌ Silent Failure:**
306
- ```typescript
307
- function divide(a: number, b: number) {
308
- if (b === 0) {
309
- return 0 // Silent failure - wrong!
310
- }
311
- return a / b
312
- }
313
- ```
314
-
315
- **✅ Fail Fast:**
316
- ```typescript
317
- function divide(a: number, b: number) {
318
- if (b === 0) {
319
- throw new Error('Division by zero') // Immediate failure
320
- }
321
- return a / b
322
- }
323
- ```
324
-
325
- **✅ Fail Fast with Validation:**
326
- ```typescript
327
- import { z } from 'zod'
328
-
329
- const userSchema = z.object({
330
- email: z.string().email(),
331
- age: z.number().min(18)
332
- })
333
-
334
- export async function createUser(data: unknown) {
335
- // Fail fast if data is invalid
336
- const validated = userSchema.parse(data) // Throws on invalid input
337
-
338
- // Continue with valid data
339
- return prisma.user.create({ data: validated })
340
- }
341
- ```
342
-
343
- ---
344
-
345
- ## Observability First
346
-
347
- Every significant action must be observable through logging.
348
-
349
- **Critical Rule:** If an action happens without logs, it's invisible in production.
350
-
351
- ### What to Log
352
-
353
- | Event Type | Log Level |
354
- |------------|-----------|
355
- | API Route Entry/Exit | INFO |
356
- | Database Operations | INFO |
357
- | External API Calls | INFO |
358
- | User Actions | INFO |
359
- | Errors & Exceptions | ERROR |
360
- | State Changes | DEBUG |
361
-
362
- **See `patterns/logging.md` for complete patterns.**
363
-
364
- ---
365
-
366
- ## DRY (Don't Repeat Yourself)
367
-
368
- Every piece of knowledge should have a single, authoritative representation.
369
-
370
- **❌ Violates DRY:**
371
- ```typescript
372
- // File 1
373
- const MAX_FILE_SIZE = 5 * 1024 * 1024 // 5MB
374
-
375
- // File 2
376
- const MAX_FILE_SIZE = 5 * 1024 * 1024 // 5MB (duplicate!)
377
-
378
- // File 3
379
- if (file.size > 5 * 1024 * 1024) { /* ... */ } // Hardcoded (duplicate!)
380
- ```
381
-
382
- **✅ Follows DRY:**
383
- ```typescript
384
- // lib/constants.ts
385
- export const MAX_FILE_SIZE = 5 * 1024 * 1024 // Single source of truth
386
-
387
- // File 1
388
- import { MAX_FILE_SIZE } from '@/lib/constants'
389
-
390
- // File 2
391
- import { MAX_FILE_SIZE } from '@/lib/constants'
392
-
393
- // File 3
394
- import { MAX_FILE_SIZE } from '@/lib/constants'
395
- if (file.size > MAX_FILE_SIZE) { /* ... */ }
396
- ```
397
-
398
- ---
399
-
400
- ## Separation of Concerns
401
-
402
- Different concerns should be handled by different modules.
403
-
404
- **Example: Next.js API Route**
405
-
406
- **❌ Mixed Concerns:**
407
- ```typescript
408
- export async function POST(request: NextRequest) {
409
- const body = await request.json()
410
-
411
- // Validation mixed with business logic
412
- if (!body.email || !body.email.includes('@')) {
413
- return NextResponse.json({ error: 'Invalid email' }, { status: 400 })
414
- }
415
-
416
- // Database logic mixed with API logic
417
- const user = await prisma.user.create({
418
- data: { email: body.email, name: body.name }
419
- })
420
-
421
- // Email sending mixed with everything else
422
- await fetch('https://api.sendgrid.com/send', {
423
- method: 'POST',
424
- body: JSON.stringify({ to: user.email, subject: 'Welcome' })
425
- })
426
-
427
- return NextResponse.json(user)
428
- }
429
- ```
430
-
431
- **✅ Separated Concerns:**
432
- ```typescript
433
- // app/api/users/route.ts (API Layer)
434
- export async function POST(request: NextRequest) {
435
- const body = await request.json()
436
- const validated = validateUserInput(body) // Validation layer
437
- const user = await userService.createUser(validated) // Business layer
438
- await emailService.sendWelcome(user) // Email layer
439
- return NextResponse.json(user)
440
- }
441
-
442
- // lib/validators/user.ts (Validation Layer)
443
- export function validateUserInput(data: unknown) {
444
- return userSchema.parse(data)
445
- }
446
-
447
- // lib/services/user-service.ts (Business Layer)
448
- export const userService = {
449
- async createUser(data: ValidatedUserData) {
450
- return prisma.user.create({ data })
451
- }
452
- }
453
-
454
- // lib/services/email-service.ts (Email Layer)
455
- export const emailService = {
456
- async sendWelcome(user: User) {
457
- await sendEmail({ to: user.email, subject: 'Welcome' })
458
- }
459
- }
460
- ```
461
-
462
- ---
463
-
464
- ## Principle of Least Surprise
465
-
466
- Code should behave in a way that minimizes surprise for other developers.
467
-
468
- **❌ Surprising:**
469
- ```typescript
470
- // Function name suggests it only reads, but it also writes
471
- function getUser(id: string) {
472
- const user = db.findUser(id)
473
- db.updateLastAccessed(id) // Surprise! Side effect!
474
- return user
475
- }
476
- ```
477
-
478
- **✅ Expected:**
479
- ```typescript
480
- // Clear function names, no surprises
481
- function getUser(id: string) {
482
- return db.findUser(id)
483
- }
484
-
485
- function getUserAndUpdateAccess(id: string) {
486
- const user = db.findUser(id)
487
- db.updateLastAccessed(id) // Expected from function name
488
- return user
489
- }
490
- ```
491
-
492
- ---
493
-
494
- ## Quick Reference
495
-
496
- | Principle | Summary |
497
- |-----------|---------|
498
- | **KISS** | Choose simple solutions over complex ones |
499
- | **YAGNI** | Build only what you need now |
500
- | **SRP** | One responsibility per module |
501
- | **OCP** | Open for extension, closed for modification |
502
- | **LSP** | Subtypes must be substitutable |
503
- | **ISP** | Don't force clients to depend on unused methods |
504
- | **DIP** | Depend on abstractions, not concretions |
505
- | **Fail Fast** | Detect and raise errors immediately |
506
- | **Observability** | Log everything that matters |
507
- | **DRY** | Single source of truth for all knowledge |
508
- | **Separation** | Different concerns in different modules |
509
- | **Least Surprise** | Code should behave as expected |
510
-
511
- ---
512
-
513
- **💡 Remember:** Good principles lead to maintainable code!
1
+ # Development Principles
2
+
3
+ **Core Philosophy:** Build software that is simple, maintainable, observable, and resilient.
4
+
5
+ ---
6
+
7
+ ## KISS (Keep It Simple, Stupid)
8
+
9
+ Simplicity should be a key goal in design. Choose straightforward solutions over complex ones.
10
+
11
+ ### Examples
12
+
13
+ **❌ Complex:**
14
+ ```typescript
15
+ // Over-engineered abstraction
16
+ class UserRepositoryFactory {
17
+ createRepository(type: 'sql' | 'nosql') {
18
+ return type === 'sql'
19
+ ? new SQLUserRepository(new DatabaseConnection())
20
+ : new NoSQLUserRepository(new MongoConnection())
21
+ }
22
+ }
23
+ ```
24
+
25
+ **✅ Simple:**
26
+ ```typescript
27
+ // Direct, readable
28
+ import { prisma } from '@/lib/db'
29
+
30
+ export async function getUser(id: string) {
31
+ return prisma.user.findUnique({ where: { id } })
32
+ }
33
+ ```
34
+
35
+ ---
36
+
37
+ ## YAGNI (You Aren't Gonna Need It)
38
+
39
+ Avoid building functionality on speculation. Implement features only when needed.
40
+
41
+ ### When to Apply
42
+
43
+ **❌ Don't Build:**
44
+ - "We might need this someday"
45
+ - Premature optimization
46
+ - Unused abstractions
47
+ - Speculative features
48
+
49
+ **✅ Build Only:**
50
+ - Features with clear requirements
51
+ - Immediate user needs
52
+ - Proven performance bottlenecks
53
+
54
+ ### Example
55
+
56
+ ```typescript
57
+ // ❌ YAGNI Violation - Building for future maybe-needs
58
+ interface User {
59
+ id: string
60
+ email: string
61
+ name: string
62
+ preferences?: UserPreferences // Not needed yet
63
+ settings?: UserSettings // Not needed yet
64
+ metadata?: Record<string, unknown> // "Just in case"
65
+ }
66
+
67
+ // ✅ YAGNI Compliant - Build what you need now
68
+ interface User {
69
+ id: string
70
+ email: string
71
+ name: string
72
+ }
73
+ // Add fields when requirements are clear
74
+ ```
75
+
76
+ ---
77
+
78
+ ## SOLID Principles
79
+
80
+ ### 1. Single Responsibility Principle (SRP)
81
+
82
+ Each module/class/function should have ONE reason to change.
83
+
84
+ **❌ Violates SRP:**
85
+ ```typescript
86
+ class UserService {
87
+ createUser(data: UserData) { /* ... */ }
88
+ sendWelcomeEmail(user: User) { /* ... */ }
89
+ logActivity(action: string) { /* ... */ }
90
+ validateEmail(email: string) { /* ... */ }
91
+ }
92
+ ```
93
+
94
+ **✅ Follows SRP:**
95
+ ```typescript
96
+ // lib/services/user-service.ts
97
+ class UserService {
98
+ createUser(data: UserData) { /* ... */ }
99
+ }
100
+
101
+ // lib/services/email-service.ts
102
+ class EmailService {
103
+ sendWelcomeEmail(user: User) { /* ... */ }
104
+ }
105
+
106
+ // lib/logger.ts
107
+ export const logger = { /* ... */ }
108
+
109
+ // lib/validators.ts
110
+ export function validateEmail(email: string) { /* ... */ }
111
+ ```
112
+
113
+ ---
114
+
115
+ ### 2. Open/Closed Principle (OCP)
116
+
117
+ Software entities should be **open for extension** but **closed for modification**.
118
+
119
+ **❌ Violates OCP:**
120
+ ```typescript
121
+ function calculateDiscount(user: User, order: Order) {
122
+ if (user.type === 'regular') {
123
+ return order.total * 0.05
124
+ } else if (user.type === 'premium') {
125
+ return order.total * 0.10
126
+ } else if (user.type === 'vip') {
127
+ return order.total * 0.20
128
+ }
129
+ // Adding new user types requires modifying this function
130
+ }
131
+ ```
132
+
133
+ **✅ Follows OCP:**
134
+ ```typescript
135
+ interface DiscountStrategy {
136
+ calculate(order: Order): number
137
+ }
138
+
139
+ class RegularDiscount implements DiscountStrategy {
140
+ calculate(order: Order) { return order.total * 0.05 }
141
+ }
142
+
143
+ class PremiumDiscount implements DiscountStrategy {
144
+ calculate(order: Order) { return order.total * 0.10 }
145
+ }
146
+
147
+ class VIPDiscount implements DiscountStrategy {
148
+ calculate(order: Order) { return order.total * 0.20 }
149
+ }
150
+
151
+ // Adding new discount types = create new class (no modification needed)
152
+ function calculateDiscount(strategy: DiscountStrategy, order: Order) {
153
+ return strategy.calculate(order)
154
+ }
155
+ ```
156
+
157
+ ---
158
+
159
+ ### 3. Liskov Substitution Principle (LSP)
160
+
161
+ Subtypes must be substitutable for their base types without altering correctness.
162
+
163
+ **❌ Violates LSP:**
164
+ ```typescript
165
+ class Bird {
166
+ fly() { console.log('Flying') }
167
+ }
168
+
169
+ class Penguin extends Bird {
170
+ fly() { throw new Error('Penguins cannot fly') } // Breaks substitution
171
+ }
172
+ ```
173
+
174
+ **✅ Follows LSP:**
175
+ ```typescript
176
+ interface Bird {
177
+ move(): void
178
+ }
179
+
180
+ class FlyingBird implements Bird {
181
+ move() { console.log('Flying') }
182
+ }
183
+
184
+ class Penguin implements Bird {
185
+ move() { console.log('Swimming') }
186
+ }
187
+ ```
188
+
189
+ ---
190
+
191
+ ### 4. Interface Segregation Principle (ISP)
192
+
193
+ Clients should not depend on interfaces they don't use.
194
+
195
+ **❌ Violates ISP:**
196
+ ```typescript
197
+ interface Worker {
198
+ work(): void
199
+ eat(): void
200
+ sleep(): void
201
+ }
202
+
203
+ class Robot implements Worker {
204
+ work() { /* ... */ }
205
+ eat() { throw new Error('Robots do not eat') } // Forced to implement
206
+ sleep() { throw new Error('Robots do not sleep') } // Forced to implement
207
+ }
208
+ ```
209
+
210
+ **✅ Follows ISP:**
211
+ ```typescript
212
+ interface Workable {
213
+ work(): void
214
+ }
215
+
216
+ interface Eatable {
217
+ eat(): void
218
+ }
219
+
220
+ interface Sleepable {
221
+ sleep(): void
222
+ }
223
+
224
+ class Human implements Workable, Eatable, Sleepable {
225
+ work() { /* ... */ }
226
+ eat() { /* ... */ }
227
+ sleep() { /* ... */ }
228
+ }
229
+
230
+ class Robot implements Workable {
231
+ work() { /* ... */ }
232
+ }
233
+ ```
234
+
235
+ ---
236
+
237
+ ### 5. Dependency Inversion Principle (DIP)
238
+
239
+ High-level modules should not depend on low-level modules. Both should depend on abstractions.
240
+
241
+ **❌ Violates DIP:**
242
+ ```typescript
243
+ class MySQLDatabase {
244
+ query(sql: string) { /* ... */ }
245
+ }
246
+
247
+ class UserService {
248
+ private db = new MySQLDatabase() // Direct dependency on low-level module
249
+
250
+ getUser(id: string) {
251
+ return this.db.query(`SELECT * FROM users WHERE id = ${id}`)
252
+ }
253
+ }
254
+ ```
255
+
256
+ **✅ Follows DIP:**
257
+ ```typescript
258
+ interface Database {
259
+ query(sql: string): Promise<unknown>
260
+ }
261
+
262
+ class MySQLDatabase implements Database {
263
+ query(sql: string) { /* ... */ }
264
+ }
265
+
266
+ class PostgreSQLDatabase implements Database {
267
+ query(sql: string) { /* ... */ }
268
+ }
269
+
270
+ class UserService {
271
+ constructor(private db: Database) {} // Depends on abstraction
272
+
273
+ getUser(id: string) {
274
+ return this.db.query(`SELECT * FROM users WHERE id = ${id}`)
275
+ }
276
+ }
277
+
278
+ // Usage
279
+ const userService = new UserService(new MySQLDatabase())
280
+ // Easy to swap: new UserService(new PostgreSQLDatabase())
281
+ ```
282
+
283
+ ---
284
+
285
+ ## Fail Fast
286
+
287
+ Detect errors early and raise exceptions immediately when issues occur.
288
+
289
+ ### When to Fail Fast
290
+
291
+ **✅ Fail immediately on:**
292
+ - Invalid input
293
+ - Missing required configuration
294
+ - Broken dependencies
295
+ - Database connection failures
296
+ - Authentication failures
297
+
298
+ **❌ Don't fail fast on:**
299
+ - Transient network errors (retry instead)
300
+ - User input errors (validate gracefully)
301
+ - Optional features
302
+
303
+ ### Examples
304
+
305
+ **❌ Silent Failure:**
306
+ ```typescript
307
+ function divide(a: number, b: number) {
308
+ if (b === 0) {
309
+ return 0 // Silent failure - wrong!
310
+ }
311
+ return a / b
312
+ }
313
+ ```
314
+
315
+ **✅ Fail Fast:**
316
+ ```typescript
317
+ function divide(a: number, b: number) {
318
+ if (b === 0) {
319
+ throw new Error('Division by zero') // Immediate failure
320
+ }
321
+ return a / b
322
+ }
323
+ ```
324
+
325
+ **✅ Fail Fast with Validation:**
326
+ ```typescript
327
+ import { z } from 'zod'
328
+
329
+ const userSchema = z.object({
330
+ email: z.string().email(),
331
+ age: z.number().min(18)
332
+ })
333
+
334
+ export async function createUser(data: unknown) {
335
+ // Fail fast if data is invalid
336
+ const validated = userSchema.parse(data) // Throws on invalid input
337
+
338
+ // Continue with valid data
339
+ return prisma.user.create({ data: validated })
340
+ }
341
+ ```
342
+
343
+ ---
344
+
345
+ ## Observability First
346
+
347
+ Every significant action must be observable through logging.
348
+
349
+ **Critical Rule:** If an action happens without logs, it's invisible in production.
350
+
351
+ ### What to Log
352
+
353
+ | Event Type | Log Level |
354
+ |------------|-----------|
355
+ | API Route Entry/Exit | INFO |
356
+ | Database Operations | INFO |
357
+ | External API Calls | INFO |
358
+ | User Actions | INFO |
359
+ | Errors & Exceptions | ERROR |
360
+ | State Changes | DEBUG |
361
+
362
+ **See `patterns/logging.md` for complete patterns.**
363
+
364
+ ---
365
+
366
+ ## DRY (Don't Repeat Yourself)
367
+
368
+ Every piece of knowledge should have a single, authoritative representation.
369
+
370
+ **❌ Violates DRY:**
371
+ ```typescript
372
+ // File 1
373
+ const MAX_FILE_SIZE = 5 * 1024 * 1024 // 5MB
374
+
375
+ // File 2
376
+ const MAX_FILE_SIZE = 5 * 1024 * 1024 // 5MB (duplicate!)
377
+
378
+ // File 3
379
+ if (file.size > 5 * 1024 * 1024) { /* ... */ } // Hardcoded (duplicate!)
380
+ ```
381
+
382
+ **✅ Follows DRY:**
383
+ ```typescript
384
+ // lib/constants.ts
385
+ export const MAX_FILE_SIZE = 5 * 1024 * 1024 // Single source of truth
386
+
387
+ // File 1
388
+ import { MAX_FILE_SIZE } from '@/lib/constants'
389
+
390
+ // File 2
391
+ import { MAX_FILE_SIZE } from '@/lib/constants'
392
+
393
+ // File 3
394
+ import { MAX_FILE_SIZE } from '@/lib/constants'
395
+ if (file.size > MAX_FILE_SIZE) { /* ... */ }
396
+ ```
397
+
398
+ ---
399
+
400
+ ## Separation of Concerns
401
+
402
+ Different concerns should be handled by different modules.
403
+
404
+ **Example: Next.js API Route**
405
+
406
+ **❌ Mixed Concerns:**
407
+ ```typescript
408
+ export async function POST(request: NextRequest) {
409
+ const body = await request.json()
410
+
411
+ // Validation mixed with business logic
412
+ if (!body.email || !body.email.includes('@')) {
413
+ return NextResponse.json({ error: 'Invalid email' }, { status: 400 })
414
+ }
415
+
416
+ // Database logic mixed with API logic
417
+ const user = await prisma.user.create({
418
+ data: { email: body.email, name: body.name }
419
+ })
420
+
421
+ // Email sending mixed with everything else
422
+ await fetch('https://api.sendgrid.com/send', {
423
+ method: 'POST',
424
+ body: JSON.stringify({ to: user.email, subject: 'Welcome' })
425
+ })
426
+
427
+ return NextResponse.json(user)
428
+ }
429
+ ```
430
+
431
+ **✅ Separated Concerns:**
432
+ ```typescript
433
+ // app/api/users/route.ts (API Layer)
434
+ export async function POST(request: NextRequest) {
435
+ const body = await request.json()
436
+ const validated = validateUserInput(body) // Validation layer
437
+ const user = await userService.createUser(validated) // Business layer
438
+ await emailService.sendWelcome(user) // Email layer
439
+ return NextResponse.json(user)
440
+ }
441
+
442
+ // lib/validators/user.ts (Validation Layer)
443
+ export function validateUserInput(data: unknown) {
444
+ return userSchema.parse(data)
445
+ }
446
+
447
+ // lib/services/user-service.ts (Business Layer)
448
+ export const userService = {
449
+ async createUser(data: ValidatedUserData) {
450
+ return prisma.user.create({ data })
451
+ }
452
+ }
453
+
454
+ // lib/services/email-service.ts (Email Layer)
455
+ export const emailService = {
456
+ async sendWelcome(user: User) {
457
+ await sendEmail({ to: user.email, subject: 'Welcome' })
458
+ }
459
+ }
460
+ ```
461
+
462
+ ---
463
+
464
+ ## Principle of Least Surprise
465
+
466
+ Code should behave in a way that minimizes surprise for other developers.
467
+
468
+ **❌ Surprising:**
469
+ ```typescript
470
+ // Function name suggests it only reads, but it also writes
471
+ function getUser(id: string) {
472
+ const user = db.findUser(id)
473
+ db.updateLastAccessed(id) // Surprise! Side effect!
474
+ return user
475
+ }
476
+ ```
477
+
478
+ **✅ Expected:**
479
+ ```typescript
480
+ // Clear function names, no surprises
481
+ function getUser(id: string) {
482
+ return db.findUser(id)
483
+ }
484
+
485
+ function getUserAndUpdateAccess(id: string) {
486
+ const user = db.findUser(id)
487
+ db.updateLastAccessed(id) // Expected from function name
488
+ return user
489
+ }
490
+ ```
491
+
492
+ ---
493
+
494
+ ## Quick Reference
495
+
496
+ | Principle | Summary |
497
+ |-----------|---------|
498
+ | **KISS** | Choose simple solutions over complex ones |
499
+ | **YAGNI** | Build only what you need now |
500
+ | **SRP** | One responsibility per module |
501
+ | **OCP** | Open for extension, closed for modification |
502
+ | **LSP** | Subtypes must be substitutable |
503
+ | **ISP** | Don't force clients to depend on unused methods |
504
+ | **DIP** | Depend on abstractions, not concretions |
505
+ | **Fail Fast** | Detect and raise errors immediately |
506
+ | **Observability** | Log everything that matters |
507
+ | **DRY** | Single source of truth for all knowledge |
508
+ | **Separation** | Different concerns in different modules |
509
+ | **Least Surprise** | Code should behave as expected |
510
+
511
+ ---
512
+
513
+ **💡 Remember:** Good principles lead to maintainable code!