@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,567 @@
1
+ ---
2
+ name: hexagonal-architecture
3
+ category: patterns
4
+ description: Hexagonal Architecture (Ports and Adapters) for loosely coupled, testable applications
5
+ usage: Use when building applications that need to be independent of external systems and highly testable
6
+ input: Application requirements, domain models, external system integrations
7
+ output: Core domain with ports (interfaces) and adapters (implementations) for all external interactions
8
+ config_required:
9
+ - CORE_DIR: "Directory for core domain (e.g., src/core/)"
10
+ - PORTS_DIR: "Directory for port interfaces (e.g., src/core/ports/)"
11
+ - ADAPTERS_DIR: "Directory for adapters (e.g., src/adapters/)"
12
+ ---
13
+
14
+ # Hexagonal Architecture (Ports and Adapters)
15
+
16
+ ## Overview
17
+
18
+ Hexagonal Architecture, introduced by Alistair Cockburn, creates loosely coupled application components that can be connected to their software environment via ports and adapters. The application core is isolated from external concerns.
19
+
20
+ ## Configuration
21
+
22
+ | Setting | Description | Example |
23
+ |---------|-------------|---------|
24
+ | CORE_DIR | Core domain logic | `src/core/`, `domain/` |
25
+ | PORTS_DIR | Port interfaces | `src/core/ports/`, `ports/` |
26
+ | ADAPTERS_DIR | Adapter implementations | `src/adapters/`, `infrastructure/` |
27
+ | DRIVING_DIR | Driving (primary) adapters | `src/adapters/driving/` |
28
+ | DRIVEN_DIR | Driven (secondary) adapters | `src/adapters/driven/` |
29
+
30
+ ## The Hexagonal Model
31
+
32
+ ```
33
+ ┌─────────────────┐
34
+ │ REST API │
35
+ │ (Driving) │
36
+ └────────┬────────┘
37
+
38
+ ┌────────────────────▼────────────────────┐
39
+ │ INPUT PORT │
40
+ │ (Primary Interface) │
41
+ ├──────────────────────────────────────────┤
42
+ │ │
43
+ │ APPLICATION CORE │
44
+ │ │
45
+ │ ┌────────────────────────────┐ │
46
+ │ │ Domain Services │ │
47
+ │ │ │ │
48
+ │ │ ┌──────────────────┐ │ │
49
+ │ │ │ Domain Entities │ │ │
50
+ │ │ └──────────────────┘ │ │
51
+ │ └────────────────────────────┘ │
52
+ │ │
53
+ ├──────────────────────────────────────────┤
54
+ │ OUTPUT PORT │
55
+ │ (Secondary Interface) │
56
+ └────────────────┬─────────────────────────┘
57
+
58
+ ┌──────────────┴──────────────┐
59
+ │ │
60
+ ┌──────▼──────┐ ┌────────▼────────┐
61
+ │ Database │ │ External API │
62
+ │ (Driven) │ │ (Driven) │
63
+ └─────────────┘ └─────────────────┘
64
+ ```
65
+
66
+ ## Port Types
67
+
68
+ ### Driving Ports (Primary/Inbound)
69
+
70
+ **Purpose:** Define how the outside world can use the application.
71
+
72
+ ```typescript
73
+ // core/ports/driving/OrderService.ts
74
+ import type { Order, CreateOrderData } from '../../domain/Order';
75
+
76
+ export interface OrderService {
77
+ createOrder(data: CreateOrderData): Promise<Order>;
78
+ getOrder(id: string): Promise<Order | null>;
79
+ listUserOrders(userId: string): Promise<Order[]>;
80
+ cancelOrder(id: string): Promise<void>;
81
+ }
82
+ ```
83
+
84
+ ### Driven Ports (Secondary/Outbound)
85
+
86
+ **Purpose:** Define how the application interacts with external systems.
87
+
88
+ ```typescript
89
+ // core/ports/driven/OrderRepository.ts
90
+ import type { Order, CreateOrderData } from '../../domain/Order';
91
+
92
+ export interface OrderRepository {
93
+ save(order: Order): Promise<Order>;
94
+ findById(id: string): Promise<Order | null>;
95
+ findByUserId(userId: string): Promise<Order[]>;
96
+ delete(id: string): Promise<void>;
97
+ }
98
+
99
+ // core/ports/driven/PaymentGateway.ts
100
+ export interface PaymentGateway {
101
+ processPayment(amount: number, token: string): Promise<PaymentResult>;
102
+ refund(transactionId: string): Promise<RefundResult>;
103
+ }
104
+
105
+ // core/ports/driven/NotificationSender.ts
106
+ export interface NotificationSender {
107
+ sendEmail(to: string, subject: string, body: string): Promise<void>;
108
+ sendSMS(phone: string, message: string): Promise<void>;
109
+ }
110
+ ```
111
+
112
+ ## Adapter Types
113
+
114
+ ### Driving Adapters (Primary)
115
+
116
+ **Purpose:** Adapt external requests to port calls.
117
+
118
+ ```typescript
119
+ // adapters/driving/rest/OrderController.ts
120
+ import type { Request, Response } from 'express';
121
+ import type { OrderService } from '../../../core/ports/driving/OrderService';
122
+
123
+ export class OrderRestController {
124
+ constructor(private orderService: OrderService) {}
125
+
126
+ async create(req: Request, res: Response): Promise<void> {
127
+ const order = await this.orderService.createOrder(req.body);
128
+ res.status(201).json(order);
129
+ }
130
+
131
+ async get(req: Request, res: Response): Promise<void> {
132
+ const order = await this.orderService.getOrder(req.params.id);
133
+ if (!order) {
134
+ res.status(404).json({ error: 'Order not found' });
135
+ return;
136
+ }
137
+ res.json(order);
138
+ }
139
+ }
140
+
141
+ // adapters/driving/cli/OrderCLI.ts
142
+ import type { OrderService } from '../../../core/ports/driving/OrderService';
143
+
144
+ export class OrderCLI {
145
+ constructor(private orderService: OrderService) {}
146
+
147
+ async handleCommand(args: string[]): Promise<void> {
148
+ const [command, ...rest] = args;
149
+
150
+ switch (command) {
151
+ case 'create':
152
+ const order = await this.orderService.createOrder({
153
+ userId: rest[0],
154
+ items: JSON.parse(rest[1]),
155
+ });
156
+ console.log(`Created order: ${order.id}`);
157
+ break;
158
+ case 'get':
159
+ const found = await this.orderService.getOrder(rest[0]);
160
+ console.log(found || 'Order not found');
161
+ break;
162
+ }
163
+ }
164
+ }
165
+
166
+ // adapters/driving/graphql/OrderResolver.ts
167
+ import type { OrderService } from '../../../core/ports/driving/OrderService';
168
+
169
+ export class OrderResolver {
170
+ constructor(private orderService: OrderService) {}
171
+
172
+ async order(_: unknown, { id }: { id: string }) {
173
+ return this.orderService.getOrder(id);
174
+ }
175
+
176
+ async createOrder(_: unknown, { input }: { input: CreateOrderData }) {
177
+ return this.orderService.createOrder(input);
178
+ }
179
+ }
180
+ ```
181
+
182
+ ### Driven Adapters (Secondary)
183
+
184
+ **Purpose:** Implement ports for external systems.
185
+
186
+ ```typescript
187
+ // adapters/driven/persistence/PostgresOrderRepository.ts
188
+ import type { Order } from '../../../core/domain/Order';
189
+ import type { OrderRepository } from '../../../core/ports/driven/OrderRepository';
190
+ import { pool } from './database';
191
+
192
+ export class PostgresOrderRepository implements OrderRepository {
193
+ async save(order: Order): Promise<Order> {
194
+ const result = await pool.query(
195
+ `INSERT INTO orders (id, user_id, items, total, status, created_at)
196
+ VALUES ($1, $2, $3, $4, $5, $6)
197
+ ON CONFLICT (id) DO UPDATE SET
198
+ items = EXCLUDED.items,
199
+ total = EXCLUDED.total,
200
+ status = EXCLUDED.status
201
+ RETURNING *`,
202
+ [order.id, order.userId, order.items, order.total, order.status, order.createdAt]
203
+ );
204
+ return this.toDomain(result.rows[0]);
205
+ }
206
+
207
+ async findById(id: string): Promise<Order | null> {
208
+ const result = await pool.query('SELECT * FROM orders WHERE id = $1', [id]);
209
+ return result.rows[0] ? this.toDomain(result.rows[0]) : null;
210
+ }
211
+
212
+ async findByUserId(userId: string): Promise<Order[]> {
213
+ const result = await pool.query('SELECT * FROM orders WHERE user_id = $1', [userId]);
214
+ return result.rows.map(this.toDomain);
215
+ }
216
+
217
+ async delete(id: string): Promise<void> {
218
+ await pool.query('DELETE FROM orders WHERE id = $1', [id]);
219
+ }
220
+
221
+ private toDomain(row: any): Order {
222
+ return {
223
+ id: row.id,
224
+ userId: row.user_id,
225
+ items: row.items,
226
+ total: parseFloat(row.total),
227
+ status: row.status,
228
+ createdAt: new Date(row.created_at),
229
+ };
230
+ }
231
+ }
232
+
233
+ // adapters/driven/payment/StripePaymentGateway.ts
234
+ import type { PaymentGateway, PaymentResult } from '../../../core/ports/driven/PaymentGateway';
235
+ import Stripe from 'stripe';
236
+
237
+ export class StripePaymentGateway implements PaymentGateway {
238
+ private stripe: Stripe;
239
+
240
+ constructor(apiKey: string) {
241
+ this.stripe = new Stripe(apiKey);
242
+ }
243
+
244
+ async processPayment(amount: number, token: string): Promise<PaymentResult> {
245
+ const charge = await this.stripe.charges.create({
246
+ amount: Math.round(amount * 100),
247
+ currency: 'usd',
248
+ source: token,
249
+ });
250
+
251
+ return {
252
+ success: charge.status === 'succeeded',
253
+ transactionId: charge.id,
254
+ };
255
+ }
256
+
257
+ async refund(transactionId: string): Promise<RefundResult> {
258
+ const refund = await this.stripe.refunds.create({
259
+ charge: transactionId,
260
+ });
261
+
262
+ return {
263
+ success: refund.status === 'succeeded',
264
+ refundId: refund.id,
265
+ };
266
+ }
267
+ }
268
+
269
+ // adapters/driven/notification/SendGridNotificationSender.ts
270
+ import type { NotificationSender } from '../../../core/ports/driven/NotificationSender';
271
+ import sgMail from '@sendgrid/mail';
272
+
273
+ export class SendGridNotificationSender implements NotificationSender {
274
+ constructor(apiKey: string) {
275
+ sgMail.setApiKey(apiKey);
276
+ }
277
+
278
+ async sendEmail(to: string, subject: string, body: string): Promise<void> {
279
+ await sgMail.send({
280
+ to,
281
+ from: 'noreply@example.com',
282
+ subject,
283
+ text: body,
284
+ });
285
+ }
286
+
287
+ async sendSMS(phone: string, message: string): Promise<void> {
288
+ // Implementation with Twilio or similar
289
+ console.log(`SMS to ${phone}: ${message}`);
290
+ }
291
+ }
292
+ ```
293
+
294
+ ## Application Core
295
+
296
+ ```typescript
297
+ // core/domain/Order.ts
298
+ export interface Order {
299
+ id: string;
300
+ userId: string;
301
+ items: OrderItem[];
302
+ total: number;
303
+ status: OrderStatus;
304
+ createdAt: Date;
305
+ }
306
+
307
+ export type OrderStatus = 'pending' | 'paid' | 'shipped' | 'delivered' | 'cancelled';
308
+
309
+ export interface OrderItem {
310
+ productId: string;
311
+ quantity: number;
312
+ price: number;
313
+ }
314
+
315
+ export interface CreateOrderData {
316
+ userId: string;
317
+ items: Omit<OrderItem, 'price'>[];
318
+ }
319
+
320
+ // core/services/OrderServiceImpl.ts
321
+ import type { Order, CreateOrderData } from '../domain/Order';
322
+ import type { OrderService } from '../ports/driving/OrderService';
323
+ import type { OrderRepository } from '../ports/driven/OrderRepository';
324
+ import type { PaymentGateway } from '../ports/driven/PaymentGateway';
325
+ import type { NotificationSender } from '../ports/driven/NotificationSender';
326
+ import { v4 as uuid } from 'uuid';
327
+
328
+ export class OrderServiceImpl implements OrderService {
329
+ constructor(
330
+ private orderRepo: OrderRepository,
331
+ private paymentGateway: PaymentGateway,
332
+ private notificationSender: NotificationSender
333
+ ) {}
334
+
335
+ async createOrder(data: CreateOrderData): Promise<Order> {
336
+ // Calculate prices
337
+ const items = await this.enrichWithPrices(data.items);
338
+ const total = items.reduce((sum, item) => sum + item.price * item.quantity, 0);
339
+
340
+ const order: Order = {
341
+ id: uuid(),
342
+ userId: data.userId,
343
+ items,
344
+ total,
345
+ status: 'pending',
346
+ createdAt: new Date(),
347
+ };
348
+
349
+ const savedOrder = await this.orderRepo.save(order);
350
+
351
+ await this.notificationSender.sendEmail(
352
+ data.userId,
353
+ 'Order Created',
354
+ `Your order ${order.id} has been created.`
355
+ );
356
+
357
+ return savedOrder;
358
+ }
359
+
360
+ async getOrder(id: string): Promise<Order | null> {
361
+ return this.orderRepo.findById(id);
362
+ }
363
+
364
+ async listUserOrders(userId: string): Promise<Order[]> {
365
+ return this.orderRepo.findByUserId(userId);
366
+ }
367
+
368
+ async cancelOrder(id: string): Promise<void> {
369
+ const order = await this.orderRepo.findById(id);
370
+ if (!order) throw new Error('Order not found');
371
+ if (order.status !== 'pending') throw new Error('Cannot cancel non-pending order');
372
+
373
+ order.status = 'cancelled';
374
+ await this.orderRepo.save(order);
375
+ }
376
+
377
+ private async enrichWithPrices(items: Omit<OrderItem, 'price'>[]): Promise<OrderItem[]> {
378
+ // Fetch prices from catalog service
379
+ return items.map((item) => ({ ...item, price: 10 }));
380
+ }
381
+ }
382
+ ```
383
+
384
+ ## Project Structure
385
+
386
+ ```
387
+ src/
388
+ ├── core/ # Application Core (Hexagon)
389
+ │ ├── domain/ # Domain entities and value objects
390
+ │ │ ├── Order.ts
391
+ │ │ ├── User.ts
392
+ │ │ └── Product.ts
393
+ │ ├── ports/
394
+ │ │ ├── driving/ # Inbound ports (use cases)
395
+ │ │ │ ├── OrderService.ts
396
+ │ │ │ └── UserService.ts
397
+ │ │ └── driven/ # Outbound ports (repositories, gateways)
398
+ │ │ ├── OrderRepository.ts
399
+ │ │ ├── PaymentGateway.ts
400
+ │ │ └── NotificationSender.ts
401
+ │ └── services/ # Domain services implementing driving ports
402
+ │ ├── OrderServiceImpl.ts
403
+ │ └── UserServiceImpl.ts
404
+ └── adapters/
405
+ ├── driving/ # Primary/Inbound adapters
406
+ │ ├── rest/
407
+ │ │ ├── OrderController.ts
408
+ │ │ └── routes.ts
409
+ │ ├── graphql/
410
+ │ │ └── OrderResolver.ts
411
+ │ └── cli/
412
+ │ └── OrderCLI.ts
413
+ └── driven/ # Secondary/Outbound adapters
414
+ ├── persistence/
415
+ │ ├── PostgresOrderRepository.ts
416
+ │ └── database.ts
417
+ ├── payment/
418
+ │ └── StripePaymentGateway.ts
419
+ └── notification/
420
+ └── SendGridNotificationSender.ts
421
+ ```
422
+
423
+ ## Composition Root
424
+
425
+ ```typescript
426
+ // main.ts - Application composition
427
+ import { OrderServiceImpl } from './core/services/OrderServiceImpl';
428
+ import { PostgresOrderRepository } from './adapters/driven/persistence/PostgresOrderRepository';
429
+ import { StripePaymentGateway } from './adapters/driven/payment/StripePaymentGateway';
430
+ import { SendGridNotificationSender } from './adapters/driven/notification/SendGridNotificationSender';
431
+ import { OrderRestController } from './adapters/driving/rest/OrderController';
432
+ import express from 'express';
433
+
434
+ // Create driven adapters (outbound)
435
+ const orderRepo = new PostgresOrderRepository();
436
+ const paymentGateway = new StripePaymentGateway(process.env.STRIPE_KEY!);
437
+ const notificationSender = new SendGridNotificationSender(process.env.SENDGRID_KEY!);
438
+
439
+ // Create core service
440
+ const orderService = new OrderServiceImpl(orderRepo, paymentGateway, notificationSender);
441
+
442
+ // Create driving adapters (inbound)
443
+ const orderController = new OrderRestController(orderService);
444
+
445
+ // Wire up Express
446
+ const app = express();
447
+ app.post('/orders', (req, res) => orderController.create(req, res));
448
+ app.get('/orders/:id', (req, res) => orderController.get(req, res));
449
+
450
+ app.listen(3000);
451
+ ```
452
+
453
+ ## Testing with Test Adapters
454
+
455
+ ```typescript
456
+ // tests/core/services/OrderServiceImpl.test.ts
457
+ import { describe, it, expect, vi } from 'vitest';
458
+ import { OrderServiceImpl } from '../../../src/core/services/OrderServiceImpl';
459
+
460
+ // In-memory test adapters
461
+ class InMemoryOrderRepository {
462
+ private orders: Map<string, Order> = new Map();
463
+
464
+ async save(order: Order): Promise<Order> {
465
+ this.orders.set(order.id, order);
466
+ return order;
467
+ }
468
+
469
+ async findById(id: string): Promise<Order | null> {
470
+ return this.orders.get(id) || null;
471
+ }
472
+
473
+ async findByUserId(userId: string): Promise<Order[]> {
474
+ return Array.from(this.orders.values()).filter((o) => o.userId === userId);
475
+ }
476
+ }
477
+
478
+ class MockPaymentGateway {
479
+ processPayment = vi.fn().mockResolvedValue({ success: true, transactionId: 'tx-1' });
480
+ refund = vi.fn().mockResolvedValue({ success: true, refundId: 'ref-1' });
481
+ }
482
+
483
+ class MockNotificationSender {
484
+ sendEmail = vi.fn().mockResolvedValue(undefined);
485
+ sendSMS = vi.fn().mockResolvedValue(undefined);
486
+ }
487
+
488
+ describe('OrderServiceImpl', () => {
489
+ it('should create an order', async () => {
490
+ const orderRepo = new InMemoryOrderRepository();
491
+ const paymentGateway = new MockPaymentGateway();
492
+ const notificationSender = new MockNotificationSender();
493
+
494
+ const service = new OrderServiceImpl(orderRepo, paymentGateway, notificationSender);
495
+
496
+ const order = await service.createOrder({
497
+ userId: 'user-1',
498
+ items: [{ productId: 'prod-1', quantity: 2 }],
499
+ });
500
+
501
+ expect(order.id).toBeDefined();
502
+ expect(order.userId).toBe('user-1');
503
+ expect(notificationSender.sendEmail).toHaveBeenCalled();
504
+ });
505
+ });
506
+ ```
507
+
508
+ ## Best Practices
509
+
510
+ ### Do's
511
+
512
+ - Define ports before implementing adapters
513
+ - Keep the core domain free of framework code
514
+ - Use dependency injection for all adapters
515
+ - Create test adapters for unit testing
516
+ - Name ports after domain concepts, not technology
517
+
518
+ ### Don'ts
519
+
520
+ - Don't let the core import from adapters
521
+ - Don't put business logic in adapters
522
+ - Don't create circular dependencies
523
+ - Don't skip ports for "simple" integrations
524
+ - Don't expose adapter types in ports
525
+
526
+ ## Hexagonal vs Clean Architecture
527
+
528
+ | Aspect | Hexagonal | Clean Architecture |
529
+ |--------|-----------|-------------------|
530
+ | Focus | Ports & Adapters | Concentric layers |
531
+ | Terminology | Driving/Driven | Use Cases/Entities |
532
+ | Structure | Inside/Outside | Layers (4+) |
533
+ | Interfaces | Ports only | Multiple per layer |
534
+ | Complexity | Simpler | More structured |
535
+
536
+ ## When to Use Hexagonal
537
+
538
+ **Good for:**
539
+
540
+ - Applications with multiple entry points (REST, CLI, GraphQL)
541
+ - Integration-heavy applications
542
+ - Systems needing easy adapter swapping
543
+ - Microservices architecture
544
+ - Applications requiring high testability
545
+
546
+ **Less suitable for:**
547
+
548
+ - Simple CRUD applications
549
+ - Prototypes with unclear requirements
550
+ - Very small applications
551
+ - Teams unfamiliar with the pattern
552
+
553
+ ## Output
554
+
555
+ **Produces:**
556
+
557
+ - Core domain with clean boundaries
558
+ - Port interfaces for all external interactions
559
+ - Adapters for each technology/framework
560
+ - Highly testable application code
561
+
562
+ **Success Criteria:**
563
+
564
+ - Core has zero external dependencies
565
+ - All external interactions go through ports
566
+ - Adapters are easily swappable
567
+ - Tests use in-memory/mock adapters