@qazuor/claude-code-config 0.4.0 → 0.6.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 (64) hide show
  1. package/README.md +395 -50
  2. package/dist/bin.cjs +3207 -165
  3. package/dist/bin.cjs.map +1 -1
  4. package/dist/bin.js +3207 -165
  5. package/dist/bin.js.map +1 -1
  6. package/dist/index.cjs +75 -58
  7. package/dist/index.cjs.map +1 -1
  8. package/dist/index.d.cts +284 -1
  9. package/dist/index.d.ts +284 -1
  10. package/dist/index.js +75 -58
  11. package/dist/index.js.map +1 -1
  12. package/package.json +24 -24
  13. package/templates/CLAUDE.md.template +60 -5
  14. package/templates/agents/README.md +58 -39
  15. package/templates/agents/_registry.json +43 -202
  16. package/templates/agents/engineering/{hono-engineer.md → api-engineer.md} +61 -70
  17. package/templates/agents/engineering/database-engineer.md +253 -0
  18. package/templates/agents/engineering/frontend-engineer.md +302 -0
  19. package/templates/docs/_registry.json +54 -0
  20. package/templates/docs/standards/code-standards.md +20 -0
  21. package/templates/docs/standards/design-standards.md +13 -0
  22. package/templates/docs/standards/documentation-standards.md +13 -0
  23. package/templates/docs/standards/performance-standards.md +524 -0
  24. package/templates/docs/standards/security-standards.md +496 -0
  25. package/templates/docs/standards/testing-standards.md +15 -0
  26. package/templates/hooks/on-notification.sh +0 -0
  27. package/templates/scripts/add-changelogs.sh +0 -0
  28. package/templates/scripts/generate-code-registry.ts +0 -0
  29. package/templates/scripts/health-check.sh +0 -0
  30. package/templates/scripts/sync-registry.sh +0 -0
  31. package/templates/scripts/telemetry-report.ts +0 -0
  32. package/templates/scripts/validate-docs.sh +0 -0
  33. package/templates/scripts/validate-registry.sh +0 -0
  34. package/templates/scripts/validate-structure.sh +0 -0
  35. package/templates/scripts/worktree-cleanup.sh +0 -0
  36. package/templates/scripts/worktree-create.sh +0 -0
  37. package/templates/skills/README.md +99 -90
  38. package/templates/skills/_registry.json +323 -16
  39. package/templates/skills/api-frameworks/express-patterns.md +411 -0
  40. package/templates/skills/api-frameworks/fastify-patterns.md +419 -0
  41. package/templates/skills/api-frameworks/hono-patterns.md +388 -0
  42. package/templates/skills/api-frameworks/nestjs-patterns.md +497 -0
  43. package/templates/skills/database/drizzle-patterns.md +449 -0
  44. package/templates/skills/database/mongoose-patterns.md +503 -0
  45. package/templates/skills/database/prisma-patterns.md +487 -0
  46. package/templates/skills/frontend-frameworks/astro-patterns.md +415 -0
  47. package/templates/skills/frontend-frameworks/nextjs-patterns.md +470 -0
  48. package/templates/skills/frontend-frameworks/react-patterns.md +516 -0
  49. package/templates/skills/frontend-frameworks/tanstack-start-patterns.md +469 -0
  50. package/templates/skills/patterns/atdd-methodology.md +364 -0
  51. package/templates/skills/patterns/bdd-methodology.md +281 -0
  52. package/templates/skills/patterns/clean-architecture.md +444 -0
  53. package/templates/skills/patterns/hexagonal-architecture.md +567 -0
  54. package/templates/skills/patterns/vertical-slice-architecture.md +502 -0
  55. package/templates/agents/engineering/astro-engineer.md +0 -293
  56. package/templates/agents/engineering/db-drizzle-engineer.md +0 -360
  57. package/templates/agents/engineering/express-engineer.md +0 -316
  58. package/templates/agents/engineering/fastify-engineer.md +0 -399
  59. package/templates/agents/engineering/mongoose-engineer.md +0 -473
  60. package/templates/agents/engineering/nestjs-engineer.md +0 -429
  61. package/templates/agents/engineering/nextjs-engineer.md +0 -451
  62. package/templates/agents/engineering/prisma-engineer.md +0 -432
  63. package/templates/agents/engineering/react-senior-dev.md +0 -394
  64. package/templates/agents/engineering/tanstack-start-engineer.md +0 -447
@@ -0,0 +1,502 @@
1
+ ---
2
+ name: vertical-slice-architecture
3
+ category: patterns
4
+ description: Vertical Slice Architecture organizing code by feature instead of technical layers
5
+ usage: Use when you want to minimize cross-cutting changes and maximize feature cohesion
6
+ input: Feature requirements, use cases, domain operations
7
+ output: Self-contained feature slices with all layers co-located by functionality
8
+ config_required:
9
+ - FEATURES_DIR: "Directory for feature slices (e.g., src/features/)"
10
+ - SHARED_DIR: "Directory for truly shared code (e.g., src/shared/)"
11
+ ---
12
+
13
+ # Vertical Slice Architecture
14
+
15
+ ## Overview
16
+
17
+ Vertical Slice Architecture, popularized by Jimmy Bogard, organizes code by feature (vertical slices) rather than technical layers (horizontal slices). Each feature contains everything it needs: handlers, validators, DTOs, and data access.
18
+
19
+ ## Configuration
20
+
21
+ | Setting | Description | Example |
22
+ |---------|-------------|---------|
23
+ | FEATURES_DIR | Feature slices location | `src/features/`, `modules/` |
24
+ | SHARED_DIR | Truly shared utilities | `src/shared/`, `common/` |
25
+ | HANDLERS_PATTERN | Handler file naming | `*.handler.ts`, `*.command.ts` |
26
+
27
+ ## Traditional Layers vs Vertical Slices
28
+
29
+ ### Traditional (Horizontal Layers)
30
+
31
+ ```
32
+ src/
33
+ ├── controllers/
34
+ │ ├── OrderController.ts # All order endpoints
35
+ │ ├── UserController.ts # All user endpoints
36
+ │ └── ProductController.ts # All product endpoints
37
+ ├── services/
38
+ │ ├── OrderService.ts # All order logic
39
+ │ ├── UserService.ts # All user logic
40
+ │ └── ProductService.ts # All product logic
41
+ ├── repositories/
42
+ │ ├── OrderRepository.ts # All order data access
43
+ │ ├── UserRepository.ts # All user data access
44
+ │ └── ProductRepository.ts # All product data access
45
+ └── models/
46
+ ├── Order.ts
47
+ ├── User.ts
48
+ └── Product.ts
49
+ ```
50
+
51
+ **Problem:** Adding a feature requires changes across multiple folders.
52
+
53
+ ### Vertical Slices
54
+
55
+ ```
56
+ src/features/
57
+ ├── orders/
58
+ │ ├── create-order/
59
+ │ │ ├── CreateOrder.handler.ts
60
+ │ │ ├── CreateOrder.validator.ts
61
+ │ │ └── CreateOrder.test.ts
62
+ │ ├── get-order/
63
+ │ │ ├── GetOrder.handler.ts
64
+ │ │ └── GetOrder.test.ts
65
+ │ └── cancel-order/
66
+ │ ├── CancelOrder.handler.ts
67
+ │ ├── CancelOrder.validator.ts
68
+ │ └── CancelOrder.test.ts
69
+ ├── users/
70
+ │ ├── register-user/
71
+ │ ├── login-user/
72
+ │ └── update-profile/
73
+ └── products/
74
+ ├── create-product/
75
+ ├── search-products/
76
+ └── update-inventory/
77
+ ```
78
+
79
+ **Benefit:** Adding a feature means adding one folder.
80
+
81
+ ## Slice Structure
82
+
83
+ ### Command/Query Pattern
84
+
85
+ ```typescript
86
+ // features/orders/create-order/CreateOrder.command.ts
87
+ export interface CreateOrderCommand {
88
+ userId: string;
89
+ items: Array<{
90
+ productId: string;
91
+ quantity: number;
92
+ }>;
93
+ shippingAddress: {
94
+ street: string;
95
+ city: string;
96
+ zipCode: string;
97
+ };
98
+ }
99
+
100
+ export interface CreateOrderResult {
101
+ orderId: string;
102
+ total: number;
103
+ estimatedDelivery: Date;
104
+ }
105
+
106
+ // features/orders/create-order/CreateOrder.handler.ts
107
+ import type { CreateOrderCommand, CreateOrderResult } from './CreateOrder.command';
108
+ import { db } from '../../../shared/database';
109
+ import { sendEmail } from '../../../shared/email';
110
+ import { calculateTotal } from './CreateOrder.utils';
111
+
112
+ export async function handleCreateOrder(
113
+ command: CreateOrderCommand
114
+ ): Promise<CreateOrderResult> {
115
+ // Validate user exists
116
+ const user = await db.user.findUnique({ where: { id: command.userId } });
117
+ if (!user) {
118
+ throw new Error('User not found');
119
+ }
120
+
121
+ // Get product prices
122
+ const products = await db.product.findMany({
123
+ where: { id: { in: command.items.map((i) => i.productId) } },
124
+ });
125
+
126
+ // Calculate total
127
+ const total = calculateTotal(command.items, products);
128
+
129
+ // Create order
130
+ const order = await db.order.create({
131
+ data: {
132
+ userId: command.userId,
133
+ items: command.items,
134
+ total,
135
+ shippingAddress: command.shippingAddress,
136
+ status: 'pending',
137
+ },
138
+ });
139
+
140
+ // Send confirmation
141
+ await sendEmail({
142
+ to: user.email,
143
+ subject: 'Order Confirmation',
144
+ body: `Your order ${order.id} has been placed.`,
145
+ });
146
+
147
+ return {
148
+ orderId: order.id,
149
+ total,
150
+ estimatedDelivery: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
151
+ };
152
+ }
153
+
154
+ // features/orders/create-order/CreateOrder.utils.ts
155
+ export function calculateTotal(
156
+ items: Array<{ productId: string; quantity: number }>,
157
+ products: Array<{ id: string; price: number }>
158
+ ): number {
159
+ return items.reduce((total, item) => {
160
+ const product = products.find((p) => p.id === item.productId);
161
+ return total + (product?.price || 0) * item.quantity;
162
+ }, 0);
163
+ }
164
+ ```
165
+
166
+ ### Validation
167
+
168
+ ```typescript
169
+ // features/orders/create-order/CreateOrder.validator.ts
170
+ import { z } from 'zod';
171
+
172
+ export const createOrderSchema = z.object({
173
+ userId: z.string().uuid(),
174
+ items: z
175
+ .array(
176
+ z.object({
177
+ productId: z.string().uuid(),
178
+ quantity: z.number().int().positive().max(100),
179
+ })
180
+ )
181
+ .min(1)
182
+ .max(50),
183
+ shippingAddress: z.object({
184
+ street: z.string().min(1).max(200),
185
+ city: z.string().min(1).max(100),
186
+ zipCode: z.string().regex(/^\d{5}(-\d{4})?$/),
187
+ }),
188
+ });
189
+
190
+ export type CreateOrderInput = z.infer<typeof createOrderSchema>;
191
+
192
+ export function validateCreateOrder(input: unknown): CreateOrderInput {
193
+ return createOrderSchema.parse(input);
194
+ }
195
+ ```
196
+
197
+ ### API Route
198
+
199
+ ```typescript
200
+ // features/orders/create-order/CreateOrder.route.ts
201
+ import type { Request, Response } from 'express';
202
+ import { handleCreateOrder } from './CreateOrder.handler';
203
+ import { validateCreateOrder } from './CreateOrder.validator';
204
+
205
+ export async function createOrderRoute(req: Request, res: Response): Promise<void> {
206
+ try {
207
+ const command = validateCreateOrder(req.body);
208
+ const result = await handleCreateOrder(command);
209
+ res.status(201).json(result);
210
+ } catch (error) {
211
+ if (error instanceof z.ZodError) {
212
+ res.status(400).json({ errors: error.errors });
213
+ return;
214
+ }
215
+ res.status(500).json({ error: 'Internal server error' });
216
+ }
217
+ }
218
+ ```
219
+
220
+ ### Tests
221
+
222
+ ```typescript
223
+ // features/orders/create-order/CreateOrder.test.ts
224
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
225
+ import { handleCreateOrder } from './CreateOrder.handler';
226
+ import { validateCreateOrder } from './CreateOrder.validator';
227
+
228
+ // Mock shared dependencies
229
+ vi.mock('../../../shared/database', () => ({
230
+ db: {
231
+ user: { findUnique: vi.fn() },
232
+ product: { findMany: vi.fn() },
233
+ order: { create: vi.fn() },
234
+ },
235
+ }));
236
+
237
+ vi.mock('../../../shared/email', () => ({
238
+ sendEmail: vi.fn(),
239
+ }));
240
+
241
+ import { db } from '../../../shared/database';
242
+ import { sendEmail } from '../../../shared/email';
243
+
244
+ describe('CreateOrder', () => {
245
+ beforeEach(() => {
246
+ vi.clearAllMocks();
247
+ });
248
+
249
+ describe('validation', () => {
250
+ it('should accept valid input', () => {
251
+ const input = {
252
+ userId: '123e4567-e89b-12d3-a456-426614174000',
253
+ items: [{ productId: '123e4567-e89b-12d3-a456-426614174001', quantity: 2 }],
254
+ shippingAddress: { street: '123 Main St', city: 'Boston', zipCode: '02101' },
255
+ };
256
+
257
+ expect(() => validateCreateOrder(input)).not.toThrow();
258
+ });
259
+
260
+ it('should reject empty items', () => {
261
+ const input = {
262
+ userId: '123e4567-e89b-12d3-a456-426614174000',
263
+ items: [],
264
+ shippingAddress: { street: '123 Main St', city: 'Boston', zipCode: '02101' },
265
+ };
266
+
267
+ expect(() => validateCreateOrder(input)).toThrow();
268
+ });
269
+ });
270
+
271
+ describe('handler', () => {
272
+ it('should create order for valid user', async () => {
273
+ // Arrange
274
+ db.user.findUnique.mockResolvedValue({ id: 'user-1', email: 'test@example.com' });
275
+ db.product.findMany.mockResolvedValue([{ id: 'prod-1', price: 10 }]);
276
+ db.order.create.mockResolvedValue({ id: 'order-1' });
277
+
278
+ // Act
279
+ const result = await handleCreateOrder({
280
+ userId: 'user-1',
281
+ items: [{ productId: 'prod-1', quantity: 2 }],
282
+ shippingAddress: { street: '123 Main', city: 'Boston', zipCode: '02101' },
283
+ });
284
+
285
+ // Assert
286
+ expect(result.orderId).toBe('order-1');
287
+ expect(result.total).toBe(20);
288
+ expect(sendEmail).toHaveBeenCalled();
289
+ });
290
+
291
+ it('should throw for non-existent user', async () => {
292
+ db.user.findUnique.mockResolvedValue(null);
293
+
294
+ await expect(
295
+ handleCreateOrder({
296
+ userId: 'invalid',
297
+ items: [{ productId: 'prod-1', quantity: 1 }],
298
+ shippingAddress: { street: '123 Main', city: 'Boston', zipCode: '02101' },
299
+ })
300
+ ).rejects.toThrow('User not found');
301
+ });
302
+ });
303
+ });
304
+ ```
305
+
306
+ ## Complete Project Structure
307
+
308
+ ```
309
+ src/
310
+ ├── features/ # All feature slices
311
+ │ ├── orders/
312
+ │ │ ├── create-order/
313
+ │ │ │ ├── CreateOrder.command.ts
314
+ │ │ │ ├── CreateOrder.handler.ts
315
+ │ │ │ ├── CreateOrder.validator.ts
316
+ │ │ │ ├── CreateOrder.route.ts
317
+ │ │ │ ├── CreateOrder.utils.ts
318
+ │ │ │ └── CreateOrder.test.ts
319
+ │ │ ├── get-order/
320
+ │ │ │ ├── GetOrder.query.ts
321
+ │ │ │ ├── GetOrder.handler.ts
322
+ │ │ │ ├── GetOrder.route.ts
323
+ │ │ │ └── GetOrder.test.ts
324
+ │ │ ├── list-orders/
325
+ │ │ ├── cancel-order/
326
+ │ │ └── index.ts # Feature barrel export
327
+ │ ├── users/
328
+ │ │ ├── register/
329
+ │ │ ├── login/
330
+ │ │ ├── update-profile/
331
+ │ │ └── index.ts
332
+ │ └── products/
333
+ │ ├── create-product/
334
+ │ ├── search-products/
335
+ │ └── index.ts
336
+ ├── shared/ # Truly shared code
337
+ │ ├── database/
338
+ │ │ ├── client.ts
339
+ │ │ └── index.ts
340
+ │ ├── email/
341
+ │ │ ├── sender.ts
342
+ │ │ └── index.ts
343
+ │ ├── auth/
344
+ │ │ ├── middleware.ts
345
+ │ │ └── index.ts
346
+ │ └── errors/
347
+ │ ├── AppError.ts
348
+ │ └── index.ts
349
+ ├── app.ts # Application setup
350
+ └── routes.ts # Route registration
351
+ ```
352
+
353
+ ## Route Registration
354
+
355
+ ```typescript
356
+ // routes.ts
357
+ import express from 'express';
358
+ import { createOrderRoute } from './features/orders/create-order/CreateOrder.route';
359
+ import { getOrderRoute } from './features/orders/get-order/GetOrder.route';
360
+ import { listOrdersRoute } from './features/orders/list-orders/ListOrders.route';
361
+ import { cancelOrderRoute } from './features/orders/cancel-order/CancelOrder.route';
362
+ import { registerRoute } from './features/users/register/Register.route';
363
+ import { loginRoute } from './features/users/login/Login.route';
364
+
365
+ const router = express.Router();
366
+
367
+ // Orders
368
+ router.post('/orders', createOrderRoute);
369
+ router.get('/orders/:id', getOrderRoute);
370
+ router.get('/orders', listOrdersRoute);
371
+ router.post('/orders/:id/cancel', cancelOrderRoute);
372
+
373
+ // Users
374
+ router.post('/users/register', registerRoute);
375
+ router.post('/users/login', loginRoute);
376
+
377
+ export default router;
378
+ ```
379
+
380
+ ## MediatR Pattern (Optional)
381
+
382
+ For larger applications, use a mediator:
383
+
384
+ ```typescript
385
+ // shared/mediator/index.ts
386
+ type Handler<TRequest, TResponse> = (request: TRequest) => Promise<TResponse>;
387
+
388
+ class Mediator {
389
+ private handlers = new Map<string, Handler<any, any>>();
390
+
391
+ register<TRequest, TResponse>(
392
+ name: string,
393
+ handler: Handler<TRequest, TResponse>
394
+ ): void {
395
+ this.handlers.set(name, handler);
396
+ }
397
+
398
+ async send<TRequest, TResponse>(
399
+ name: string,
400
+ request: TRequest
401
+ ): Promise<TResponse> {
402
+ const handler = this.handlers.get(name);
403
+ if (!handler) throw new Error(`No handler for ${name}`);
404
+ return handler(request);
405
+ }
406
+ }
407
+
408
+ export const mediator = new Mediator();
409
+
410
+ // Registration
411
+ import { handleCreateOrder } from '../features/orders/create-order/CreateOrder.handler';
412
+ mediator.register('CreateOrder', handleCreateOrder);
413
+
414
+ // Usage in route
415
+ router.post('/orders', async (req, res) => {
416
+ const result = await mediator.send('CreateOrder', req.body);
417
+ res.json(result);
418
+ });
419
+ ```
420
+
421
+ ## When to Duplicate vs Share
422
+
423
+ ### Duplicate (per slice)
424
+
425
+ - DTOs/Commands/Queries
426
+ - Validation schemas
427
+ - Slice-specific utilities
428
+ - Response mappers
429
+
430
+ ### Share (in shared/)
431
+
432
+ - Database client
433
+ - Email/notification services
434
+ - Authentication middleware
435
+ - Error handling
436
+ - Logging
437
+
438
+ ### Rule of Thumb
439
+
440
+ > "When in doubt, duplicate. If you find yourself copying the same code into a third slice, consider extracting to shared."
441
+
442
+ ## Best Practices
443
+
444
+ ### Do's
445
+
446
+ - Keep slices independent and self-contained
447
+ - Test each slice in isolation
448
+ - Use clear naming: `CreateOrder`, `GetUser`, `SearchProducts`
449
+ - Favor duplication over wrong abstraction
450
+ - Keep shared code truly generic
451
+
452
+ ### Don'ts
453
+
454
+ - Don't create "shared domain models" used by all slices
455
+ - Don't abstract too early
456
+ - Don't create service layers spanning multiple slices
457
+ - Don't share validators between slices
458
+ - Don't force slices to communicate through shared state
459
+
460
+ ## Vertical Slice vs Layered
461
+
462
+ | Aspect | Vertical Slice | Layered Architecture |
463
+ |--------|---------------|---------------------|
464
+ | Code Organization | By feature | By technical concern |
465
+ | Adding Features | One folder | Multiple folders |
466
+ | Dependencies | Slice to shared | Layer to layer |
467
+ | Coupling | Low between slices | High between layers |
468
+ | Reuse | Explicit/intentional | Often forced |
469
+ | Testing | Per slice | Per layer |
470
+
471
+ ## When to Use Vertical Slices
472
+
473
+ **Good for:**
474
+
475
+ - Feature-rich applications
476
+ - Teams working on separate features
477
+ - Rapid feature development
478
+ - Microservices preparation
479
+ - CQRS implementations
480
+
481
+ **Less suitable for:**
482
+
483
+ - Very small applications
484
+ - Heavy cross-cutting concerns
485
+ - Highly interconnected features
486
+ - Teams used to layered architecture
487
+
488
+ ## Output
489
+
490
+ **Produces:**
491
+
492
+ - Self-contained feature slices
493
+ - Minimal cross-feature dependencies
494
+ - Easy-to-test handlers
495
+ - Clear feature boundaries
496
+
497
+ **Success Criteria:**
498
+
499
+ - Adding a feature = adding one folder
500
+ - Slices don't import from other slices
501
+ - Tests run per-slice without mocking other features
502
+ - Shared code is truly generic