@mytechtoday/augment-extensions 1.2.2 → 1.3.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 (87) hide show
  1. package/LICENSE +22 -22
  2. package/augment-extensions/domain-rules/software-architecture/README.md +143 -143
  3. package/augment-extensions/domain-rules/software-architecture/examples/banking-layered.md +961 -961
  4. package/augment-extensions/domain-rules/software-architecture/examples/ecommerce-microservices.md +990 -990
  5. package/augment-extensions/domain-rules/software-architecture/examples/iot-eventdriven.md +882 -882
  6. package/augment-extensions/domain-rules/software-architecture/examples/monolith-to-microservices-migration.md +703 -703
  7. package/augment-extensions/domain-rules/software-architecture/examples/serverless-imageprocessing.md +957 -957
  8. package/augment-extensions/domain-rules/software-architecture/examples/trading-eventdriven.md +747 -747
  9. package/augment-extensions/domain-rules/software-architecture/module.json +119 -119
  10. package/augment-extensions/domain-rules/software-architecture/rules/challenges-solutions.md +763 -763
  11. package/augment-extensions/domain-rules/software-architecture/rules/definitions-terminology.md +409 -409
  12. package/augment-extensions/domain-rules/software-architecture/rules/design-principles.md +684 -684
  13. package/augment-extensions/domain-rules/software-architecture/rules/evaluation-testing.md +1381 -1381
  14. package/augment-extensions/domain-rules/software-architecture/rules/event-driven-architecture.md +616 -616
  15. package/augment-extensions/domain-rules/software-architecture/rules/fundamentals.md +306 -306
  16. package/augment-extensions/domain-rules/software-architecture/rules/industry-architectures.md +554 -554
  17. package/augment-extensions/domain-rules/software-architecture/rules/layered-architecture.md +776 -776
  18. package/augment-extensions/domain-rules/software-architecture/rules/microservices-architecture.md +503 -503
  19. package/augment-extensions/domain-rules/software-architecture/rules/modeling-documentation.md +1199 -1199
  20. package/augment-extensions/domain-rules/software-architecture/rules/monolithic-architecture.md +351 -351
  21. package/augment-extensions/domain-rules/software-architecture/rules/principles.md +556 -556
  22. package/augment-extensions/domain-rules/software-architecture/rules/quality-attributes.md +797 -797
  23. package/augment-extensions/domain-rules/software-architecture/rules/scalability-performance.md +1345 -1345
  24. package/augment-extensions/domain-rules/software-architecture/rules/security-architecture.md +1039 -1039
  25. package/augment-extensions/domain-rules/software-architecture/rules/serverless-architecture.md +711 -711
  26. package/augment-extensions/domain-rules/software-architecture/rules/skills-development.md +568 -568
  27. package/augment-extensions/domain-rules/software-architecture/rules/tools-methodologies.md +961 -961
  28. package/augment-extensions/visual-design/CHANGELOG.md +132 -0
  29. package/augment-extensions/visual-design/README.md +255 -0
  30. package/augment-extensions/visual-design/__tests__/README.md +119 -0
  31. package/augment-extensions/visual-design/__tests__/style-selector.test.ts +172 -0
  32. package/augment-extensions/visual-design/__tests__/vendor-styles.test.ts +214 -0
  33. package/augment-extensions/visual-design/domains/other/ai-prompt-helper.ts +157 -0
  34. package/augment-extensions/visual-design/domains/other/dotnet-application.ts +156 -0
  35. package/augment-extensions/visual-design/domains/other/linux-platform.ts +156 -0
  36. package/augment-extensions/visual-design/domains/other/mobile-application.ts +157 -0
  37. package/augment-extensions/visual-design/domains/other/motion-picture.ts +156 -0
  38. package/augment-extensions/visual-design/domains/other/os-application.ts +156 -0
  39. package/augment-extensions/visual-design/domains/other/print-campaigns.ts +158 -0
  40. package/augment-extensions/visual-design/domains/other/web-app.ts +157 -0
  41. package/augment-extensions/visual-design/domains/other/website.ts +161 -0
  42. package/augment-extensions/visual-design/domains/other/windows-platform.ts +156 -0
  43. package/augment-extensions/visual-design/domains/web-page-styles/amazon-cloudscape.ts +506 -0
  44. package/augment-extensions/visual-design/domains/web-page-styles/google-modern.ts +615 -0
  45. package/augment-extensions/visual-design/domains/web-page-styles/microsoft-fluent.ts +531 -0
  46. package/augment-extensions/visual-design/examples/README.md +97 -0
  47. package/augment-extensions/visual-design/examples/ai-prompt-generation.md +233 -0
  48. package/augment-extensions/visual-design/examples/basic-usage.md +216 -0
  49. package/augment-extensions/visual-design/examples/domain-workflows.md +257 -0
  50. package/augment-extensions/visual-design/examples/vendor-comparison.md +247 -0
  51. package/augment-extensions/visual-design/module.json +78 -0
  52. package/augment-extensions/visual-design/style-selector.ts +177 -0
  53. package/augment-extensions/visual-design/types.ts +302 -0
  54. package/augment-extensions/visual-design/visual-design-core.ts +469 -0
  55. package/augment-extensions/workflows/adr-support/README.md +227 -0
  56. package/augment-extensions/workflows/adr-support/__tests__/adr-validator.test.ts +203 -0
  57. package/augment-extensions/workflows/adr-support/adr-validator.ts +162 -0
  58. package/augment-extensions/workflows/adr-support/examples/complete-lifecycle-example.md +449 -0
  59. package/augment-extensions/workflows/adr-support/examples/integration-example.md +580 -0
  60. package/augment-extensions/workflows/adr-support/examples/superseding-example.md +436 -0
  61. package/augment-extensions/workflows/adr-support/module.json +112 -0
  62. package/augment-extensions/workflows/adr-support/rules/adr-creation.md +372 -0
  63. package/augment-extensions/workflows/adr-support/rules/beads-integration.md +443 -0
  64. package/augment-extensions/workflows/adr-support/rules/conflict-detection.md +486 -0
  65. package/augment-extensions/workflows/adr-support/rules/decision-detection.md +362 -0
  66. package/augment-extensions/workflows/adr-support/rules/lifecycle-management.md +427 -0
  67. package/augment-extensions/workflows/adr-support/rules/openspec-integration.md +465 -0
  68. package/augment-extensions/workflows/adr-support/rules/template-selection.md +405 -0
  69. package/augment-extensions/workflows/adr-support/rules/validation-rules.md +543 -0
  70. package/augment-extensions/workflows/adr-support/schemas/adr-config.json +191 -0
  71. package/augment-extensions/workflows/adr-support/schemas/adr-metadata.json +172 -0
  72. package/augment-extensions/workflows/adr-support/templates/business-case.md +235 -0
  73. package/augment-extensions/workflows/adr-support/templates/madr-elaborate.md +197 -0
  74. package/augment-extensions/workflows/adr-support/templates/madr-simple.md +68 -0
  75. package/augment-extensions/workflows/adr-support/templates/nygard.md +84 -0
  76. package/augment-extensions/writing-standards/screenplay/rules/file-organization.md +213 -213
  77. package/augment-extensions/writing-standards/screenplay/utils/__tests__/file-organization.test.ts +169 -169
  78. package/augment-extensions/writing-standards/screenplay/utils/file-organization.ts +165 -165
  79. package/cli/dist/utils/auto-sync.js +19 -19
  80. package/package.json +5 -3
  81. package/augment-extensions/workflows/openspec/README.md +0 -96
  82. package/augment-extensions/workflows/openspec/examples/complete-change-example.md +0 -244
  83. package/augment-extensions/workflows/openspec/module.json +0 -54
  84. package/augment-extensions/workflows/openspec/rules/best-practices.md +0 -272
  85. package/augment-extensions/workflows/openspec/rules/manual-setup.md +0 -231
  86. package/augment-extensions/workflows/openspec/rules/spec-format.md +0 -236
  87. package/augment-extensions/workflows/openspec/rules/workflow.md +0 -214
@@ -1,616 +1,616 @@
1
- # Event-Driven Architecture
2
-
3
- ## Overview
4
-
5
- This document covers event-driven architecture patterns, message queues, event sourcing, and best practices for building reactive, loosely-coupled systems.
6
-
7
- ---
8
-
9
- ## Knowledge
10
-
11
- ### What is Event-Driven Architecture?
12
-
13
- **Definition**
14
- - Architecture where components communicate through events
15
- - Events represent state changes or significant occurrences
16
- - Producers emit events without knowing consumers
17
- - Consumers react to events independently
18
- - Asynchronous, loosely-coupled communication
19
-
20
- **Core Concepts**
21
-
22
- **Event**
23
- - Immutable record of something that happened
24
- - Contains: event type, timestamp, payload
25
- - Examples: OrderPlaced, UserRegistered, PaymentProcessed
26
-
27
- **Event Producer**
28
- - Component that detects and publishes events
29
- - Doesn't know who consumes events
30
- - Fire-and-forget pattern
31
-
32
- **Event Consumer**
33
- - Component that subscribes to and processes events
34
- - Can have multiple consumers per event
35
- - Processes events independently
36
-
37
- **Event Channel**
38
- - Medium for transmitting events
39
- - Examples: message queue, event stream, event bus
40
-
41
- ### Event Types
42
-
43
- **Domain Events**
44
- - Business-significant occurrences
45
- - Examples: OrderPlaced, CustomerRegistered
46
- - Trigger business workflows
47
-
48
- **Integration Events**
49
- - Cross-system communication
50
- - Examples: OrderShipped (from warehouse system)
51
- - Enable system integration
52
-
53
- **System Events**
54
- - Technical occurrences
55
- - Examples: ServiceStarted, CacheCleared
56
- - Support operations and monitoring
57
-
58
- ### When to Use Event-Driven Architecture
59
-
60
- **Good Fit**
61
- - Complex workflows with multiple steps
62
- - Need for loose coupling
63
- - Asynchronous processing requirements
64
- - Real-time data processing
65
- - Microservices communication
66
- - Integration with external systems
67
-
68
- **Poor Fit**
69
- - Simple CRUD applications
70
- - Strong consistency requirements
71
- - Synchronous request-response needed
72
- - Simple linear workflows
73
- - Limited scalability needs
74
-
75
- ---
76
-
77
- ## Skills
78
-
79
- ### Message Queue Patterns
80
-
81
- **Point-to-Point (Queue)**
82
- ```
83
- Producer → Queue → Consumer
84
- ```
85
- - One message, one consumer
86
- - Message removed after consumption
87
- - Load balancing across consumers
88
- - Use for: task distribution, work queues
89
-
90
- **Publish-Subscribe (Topic)**
91
- ```
92
- Producer → Topic → [Consumer A, Consumer B, Consumer C]
93
- ```
94
- - One message, multiple consumers
95
- - Each subscriber gets copy
96
- - Broadcast pattern
97
- - Use for: notifications, event broadcasting
98
-
99
- **Request-Reply**
100
- ```
101
- Client → Request Queue → Server
102
- Client ← Reply Queue ← Server
103
- ```
104
- - Asynchronous request-response
105
- - Correlation ID links request/reply
106
- - Use for: async RPC, long-running operations
107
-
108
- ### Event Streaming
109
-
110
- **Event Stream Characteristics**
111
- - Ordered sequence of events
112
- - Events persisted (not deleted after consumption)
113
- - Multiple consumers can read independently
114
- - Replay capability
115
- - Examples: Apache Kafka, AWS Kinesis
116
-
117
- **Stream Processing**
118
- - Real-time event processing
119
- - Stateful computations
120
- - Windowing and aggregation
121
- - Complex event processing
122
-
123
- **Kafka Example**
124
- ```
125
- Topic: orders
126
- ├── Partition 0: [Event1, Event2, Event3]
127
- ├── Partition 1: [Event4, Event5, Event6]
128
- └── Partition 2: [Event7, Event8, Event9]
129
-
130
- Consumer Group A: [Consumer1, Consumer2]
131
- Consumer Group B: [Consumer3]
132
- ```
133
-
134
- ### Event Sourcing
135
-
136
- **Concept**
137
- - Store events, not current state
138
- - State is derived from event history
139
- - Complete audit trail
140
- - Time travel (replay to any point)
141
-
142
- **Event Store**
143
- - Append-only log of events
144
- - Events are immutable
145
- - Optimized for writes
146
- - Examples: EventStore, Kafka, custom DB
147
-
148
- **Event Sourcing Pattern**
149
- ```
150
- Command → Aggregate → Events → Event Store
151
-
152
- Event Handler → Read Model
153
- ```
154
-
155
- **Aggregate Example**
156
- ```java
157
- public class Order {
158
- private String id;
159
- private OrderStatus status;
160
- private List<OrderItem> items;
161
- private List<DomainEvent> uncommittedEvents = new ArrayList<>();
162
-
163
- // Command handler
164
- public void placeOrder(List<OrderItem> items) {
165
- // Validate
166
- if (items.isEmpty()) {
167
- throw new IllegalArgumentException("Order must have items");
168
- }
169
-
170
- // Apply event
171
- apply(new OrderPlacedEvent(this.id, items, Instant.now()));
172
- }
173
-
174
- // Event handler
175
- private void apply(OrderPlacedEvent event) {
176
- this.items = event.getItems();
177
- this.status = OrderStatus.PLACED;
178
- uncommittedEvents.add(event);
179
- }
180
-
181
- // Reconstitute from events
182
- public static Order fromEvents(List<DomainEvent> events) {
183
- Order order = new Order();
184
- events.forEach(order::apply);
185
- return order;
186
- }
187
- }
188
- ```
189
-
190
- ### CQRS (Command Query Responsibility Segregation)
191
-
192
- **Concept**
193
- - Separate read and write models
194
- - Commands: change state
195
- - Queries: read state
196
- - Often combined with event sourcing
197
-
198
- **Architecture**
199
- ```
200
- Command → Write Model → Events → Event Store
201
-
202
- Event Handler
203
-
204
- Query ← Read Model ← Projection ← Events
205
- ```
206
-
207
- **Benefits**
208
- - Optimize read and write independently
209
- - Scale read and write separately
210
- - Different data models for different needs
211
- - Simplified queries
212
-
213
- ---
214
-
215
- ## Examples
216
-
217
- ### Order Processing with Events
218
-
219
- **Event Definitions**
220
- ```java
221
- // Base event
222
- public abstract class DomainEvent {
223
- private final String eventId;
224
- private final Instant timestamp;
225
-
226
- protected DomainEvent() {
227
- this.eventId = UUID.randomUUID().toString();
228
- this.timestamp = Instant.now();
229
- }
230
- }
231
-
232
- // Order events
233
- public class OrderPlacedEvent extends DomainEvent {
234
- private final String orderId;
235
- private final String customerId;
236
- private final List<OrderItem> items;
237
- private final BigDecimal total;
238
- }
239
-
240
- public class OrderPaidEvent extends DomainEvent {
241
- private final String orderId;
242
- private final String paymentId;
243
- private final BigDecimal amount;
244
- }
245
-
246
- public class OrderShippedEvent extends DomainEvent {
247
- private final String orderId;
248
- private final String trackingNumber;
249
- private final Instant shippedAt;
250
- }
251
- ```
252
-
253
- **Event Publisher**
254
- ```java
255
- @Service
256
- public class OrderService {
257
- private final OrderRepository orderRepository;
258
- private final EventPublisher eventPublisher;
259
-
260
- @Transactional
261
- public Order placeOrder(PlaceOrderCommand command) {
262
- // Create order
263
- Order order = new Order(command.getCustomerId());
264
- order.addItems(command.getItems());
265
-
266
- // Save order
267
- order = orderRepository.save(order);
268
-
269
- // Publish event
270
- OrderPlacedEvent event = new OrderPlacedEvent(
271
- order.getId(),
272
- order.getCustomerId(),
273
- order.getItems(),
274
- order.getTotal()
275
- );
276
-
277
- eventPublisher.publish("orders", event);
278
-
279
- return order;
280
- }
281
- }
282
-
283
- @Component
284
- public class KafkaEventPublisher implements EventPublisher {
285
- private final KafkaTemplate<String, DomainEvent> kafkaTemplate;
286
-
287
- @Override
288
- public void publish(String topic, DomainEvent event) {
289
- kafkaTemplate.send(topic, event.getEventId(), event);
290
- }
291
- }
292
- ```
293
-
294
- **Event Consumers**
295
- ```java
296
- // Inventory Service - Reserve items
297
- @Component
298
- public class InventoryEventHandler {
299
- private final InventoryService inventoryService;
300
-
301
- @KafkaListener(topics = "orders", groupId = "inventory-service")
302
- public void handleOrderPlaced(OrderPlacedEvent event) {
303
- inventoryService.reserveItems(
304
- event.getOrderId(),
305
- event.getItems()
306
- );
307
- }
308
- }
309
-
310
- // Notification Service - Send confirmation
311
- @Component
312
- public class NotificationEventHandler {
313
- private final EmailService emailService;
314
-
315
- @KafkaListener(topics = "orders", groupId = "notification-service")
316
- public void handleOrderPlaced(OrderPlacedEvent event) {
317
- emailService.sendOrderConfirmation(
318
- event.getCustomerId(),
319
- event.getOrderId()
320
- );
321
- }
322
- }
323
-
324
- // Analytics Service - Track metrics
325
- @Component
326
- public class AnalyticsEventHandler {
327
- private final AnalyticsService analyticsService;
328
-
329
- @KafkaListener(topics = "orders", groupId = "analytics-service")
330
- public void handleOrderPlaced(OrderPlacedEvent event) {
331
- analyticsService.recordOrderPlaced(
332
- event.getOrderId(),
333
- event.getTotal(),
334
- event.getTimestamp()
335
- );
336
- }
337
- }
338
- ```
339
-
340
- ### Event Sourcing Implementation
341
-
342
- **Event Store**
343
- ```java
344
- @Repository
345
- public class EventStore {
346
- private final JdbcTemplate jdbcTemplate;
347
-
348
- public void saveEvents(String aggregateId, List<DomainEvent> events) {
349
- String sql = """
350
- INSERT INTO events (aggregate_id, event_type, event_data, version, timestamp)
351
- VALUES (?, ?, ?::jsonb, ?, ?)
352
- """;
353
-
354
- for (DomainEvent event : events) {
355
- jdbcTemplate.update(
356
- sql,
357
- aggregateId,
358
- event.getClass().getSimpleName(),
359
- toJson(event),
360
- event.getVersion(),
361
- event.getTimestamp()
362
- );
363
- }
364
- }
365
-
366
- public List<DomainEvent> getEvents(String aggregateId) {
367
- String sql = """
368
- SELECT event_type, event_data
369
- FROM events
370
- WHERE aggregate_id = ?
371
- ORDER BY version ASC
372
- """;
373
-
374
- return jdbcTemplate.query(sql, (rs, rowNum) -> {
375
- String eventType = rs.getString("event_type");
376
- String eventData = rs.getString("event_data");
377
- return fromJson(eventType, eventData);
378
- }, aggregateId);
379
- }
380
- }
381
- ```
382
-
383
- **Aggregate with Event Sourcing**
384
- ```java
385
- public class Order {
386
- private String id;
387
- private String customerId;
388
- private List<OrderItem> items = new ArrayList<>();
389
- private OrderStatus status;
390
- private int version = 0;
391
- private List<DomainEvent> uncommittedEvents = new ArrayList<>();
392
-
393
- // Command: Place order
394
- public void placeOrder(String customerId, List<OrderItem> items) {
395
- if (this.status != null) {
396
- throw new IllegalStateException("Order already placed");
397
- }
398
-
399
- apply(new OrderPlacedEvent(this.id, customerId, items));
400
- }
401
-
402
- // Command: Pay for order
403
- public void pay(String paymentId, BigDecimal amount) {
404
- if (this.status != OrderStatus.PLACED) {
405
- throw new IllegalStateException("Order not in PLACED status");
406
- }
407
-
408
- apply(new OrderPaidEvent(this.id, paymentId, amount));
409
- }
410
-
411
- // Event handlers
412
- private void apply(OrderPlacedEvent event) {
413
- this.customerId = event.getCustomerId();
414
- this.items = new ArrayList<>(event.getItems());
415
- this.status = OrderStatus.PLACED;
416
- this.version++;
417
- uncommittedEvents.add(event);
418
- }
419
-
420
- private void apply(OrderPaidEvent event) {
421
- this.status = OrderStatus.PAID;
422
- this.version++;
423
- uncommittedEvents.add(event);
424
- }
425
-
426
- // Reconstitute from events
427
- public static Order fromEvents(String id, List<DomainEvent> events) {
428
- Order order = new Order();
429
- order.id = id;
430
-
431
- for (DomainEvent event : events) {
432
- if (event instanceof OrderPlacedEvent e) {
433
- order.apply(e);
434
- } else if (event instanceof OrderPaidEvent e) {
435
- order.apply(e);
436
- }
437
- }
438
-
439
- order.uncommittedEvents.clear();
440
- return order;
441
- }
442
-
443
- public List<DomainEvent> getUncommittedEvents() {
444
- return new ArrayList<>(uncommittedEvents);
445
- }
446
-
447
- public void markEventsAsCommitted() {
448
- uncommittedEvents.clear();
449
- }
450
- }
451
- ```
452
-
453
- ### Saga Pattern for Distributed Transactions
454
-
455
- **Choreography-Based Saga**
456
- ```java
457
- // Order Service
458
- @Component
459
- public class OrderSagaHandler {
460
- private final OrderRepository orderRepository;
461
- private final EventPublisher eventPublisher;
462
-
463
- @KafkaListener(topics = "payments")
464
- public void handlePaymentProcessed(PaymentProcessedEvent event) {
465
- Order order = orderRepository.findById(event.getOrderId());
466
- order.markAsPaid();
467
- orderRepository.save(order);
468
-
469
- // Trigger next step
470
- eventPublisher.publish("shipments",
471
- new ShipOrderEvent(order.getId())
472
- );
473
- }
474
-
475
- @KafkaListener(topics = "payments")
476
- public void handlePaymentFailed(PaymentFailedEvent event) {
477
- Order order = orderRepository.findById(event.getOrderId());
478
- order.cancel();
479
- orderRepository.save(order);
480
-
481
- // Compensate: Release inventory
482
- eventPublisher.publish("inventory",
483
- new ReleaseInventoryEvent(order.getId())
484
- );
485
- }
486
- }
487
- ```
488
-
489
- ---
490
-
491
- ## Understanding
492
-
493
- ### Advantages of Event-Driven Architecture
494
-
495
- **Loose Coupling**
496
- - Producers don't know consumers
497
- - Add/remove consumers without affecting producers
498
- - Independent evolution
499
- - Easier testing
500
-
501
- **Scalability**
502
- - Asynchronous processing
503
- - Load leveling with queues
504
- - Independent scaling of consumers
505
- - Parallel processing
506
-
507
- **Resilience**
508
- - Failure isolation
509
- - Retry mechanisms
510
- - Dead letter queues
511
- - Graceful degradation
512
-
513
- **Flexibility**
514
- - Easy to add new features (new consumers)
515
- - Support multiple workflows
516
- - Real-time and batch processing
517
- - Event replay for recovery
518
-
519
- **Auditability**
520
- - Complete event history
521
- - Audit trail
522
- - Debugging and troubleshooting
523
- - Compliance and reporting
524
-
525
- ### Challenges and Disadvantages
526
-
527
- **Complexity**
528
- - Distributed system challenges
529
- - Eventual consistency
530
- - Event ordering issues
531
- - Debugging difficulties
532
-
533
- **Event Schema Evolution**
534
- - Backward compatibility needed
535
- - Versioning strategy required
536
- - Consumer updates coordination
537
- - Schema registry management
538
-
539
- **Duplicate Events**
540
- - At-least-once delivery
541
- - Idempotent consumers required
542
- - Deduplication logic
543
- - Event ID tracking
544
-
545
- **Event Ordering**
546
- - No global ordering (distributed systems)
547
- - Partition-level ordering only
548
- - Out-of-order events
549
- - Causality tracking needed
550
-
551
- **Operational Overhead**
552
- - Message broker management
553
- - Monitoring and alerting
554
- - Dead letter queue handling
555
- - Event store maintenance
556
-
557
- ### Best Practices
558
-
559
- **Event Design**
560
- - Events are immutable
561
- - Include all necessary data (avoid lookups)
562
- - Use meaningful event names (past tense)
563
- - Version events from the start
564
- - Include correlation IDs
565
-
566
- **Consumer Design**
567
- - Idempotent event handlers
568
- - Handle duplicate events
569
- - Use dead letter queues
570
- - Implement retry with backoff
571
- - Monitor consumer lag
572
-
573
- **Error Handling**
574
- - Retry transient failures
575
- - Dead letter queue for poison messages
576
- - Compensating transactions
577
- - Circuit breakers
578
- - Alerting and monitoring
579
-
580
- **Event Store**
581
- - Append-only design
582
- - Partition by aggregate ID
583
- - Snapshot for performance
584
- - Archive old events
585
- - Backup and recovery
586
-
587
- **Monitoring**
588
- - Event throughput
589
- - Consumer lag
590
- - Processing time
591
- - Error rates
592
- - Dead letter queue size
593
-
594
- ---
595
-
596
- ## References
597
-
598
- - **Books**
599
- - "Designing Event-Driven Systems" by Ben Stopford
600
- - "Enterprise Integration Patterns" by Gregor Hohpe
601
- - "Implementing Domain-Driven Design" by Vaughn Vernon
602
-
603
- - **Patterns**
604
- - Event Sourcing Pattern
605
- - CQRS Pattern
606
- - Saga Pattern
607
- - Outbox Pattern
608
- - Event Notification Pattern
609
-
610
- - **Technologies**
611
- - Message Brokers: Apache Kafka, RabbitMQ, AWS SNS/SQS
612
- - Event Stores: EventStore, Axon Server
613
- - Stream Processing: Apache Flink, Kafka Streams
614
- - Schema Registry: Confluent Schema Registry, AWS Glue
615
-
616
-
1
+ # Event-Driven Architecture
2
+
3
+ ## Overview
4
+
5
+ This document covers event-driven architecture patterns, message queues, event sourcing, and best practices for building reactive, loosely-coupled systems.
6
+
7
+ ---
8
+
9
+ ## Knowledge
10
+
11
+ ### What is Event-Driven Architecture?
12
+
13
+ **Definition**
14
+ - Architecture where components communicate through events
15
+ - Events represent state changes or significant occurrences
16
+ - Producers emit events without knowing consumers
17
+ - Consumers react to events independently
18
+ - Asynchronous, loosely-coupled communication
19
+
20
+ **Core Concepts**
21
+
22
+ **Event**
23
+ - Immutable record of something that happened
24
+ - Contains: event type, timestamp, payload
25
+ - Examples: OrderPlaced, UserRegistered, PaymentProcessed
26
+
27
+ **Event Producer**
28
+ - Component that detects and publishes events
29
+ - Doesn't know who consumes events
30
+ - Fire-and-forget pattern
31
+
32
+ **Event Consumer**
33
+ - Component that subscribes to and processes events
34
+ - Can have multiple consumers per event
35
+ - Processes events independently
36
+
37
+ **Event Channel**
38
+ - Medium for transmitting events
39
+ - Examples: message queue, event stream, event bus
40
+
41
+ ### Event Types
42
+
43
+ **Domain Events**
44
+ - Business-significant occurrences
45
+ - Examples: OrderPlaced, CustomerRegistered
46
+ - Trigger business workflows
47
+
48
+ **Integration Events**
49
+ - Cross-system communication
50
+ - Examples: OrderShipped (from warehouse system)
51
+ - Enable system integration
52
+
53
+ **System Events**
54
+ - Technical occurrences
55
+ - Examples: ServiceStarted, CacheCleared
56
+ - Support operations and monitoring
57
+
58
+ ### When to Use Event-Driven Architecture
59
+
60
+ **Good Fit**
61
+ - Complex workflows with multiple steps
62
+ - Need for loose coupling
63
+ - Asynchronous processing requirements
64
+ - Real-time data processing
65
+ - Microservices communication
66
+ - Integration with external systems
67
+
68
+ **Poor Fit**
69
+ - Simple CRUD applications
70
+ - Strong consistency requirements
71
+ - Synchronous request-response needed
72
+ - Simple linear workflows
73
+ - Limited scalability needs
74
+
75
+ ---
76
+
77
+ ## Skills
78
+
79
+ ### Message Queue Patterns
80
+
81
+ **Point-to-Point (Queue)**
82
+ ```
83
+ Producer → Queue → Consumer
84
+ ```
85
+ - One message, one consumer
86
+ - Message removed after consumption
87
+ - Load balancing across consumers
88
+ - Use for: task distribution, work queues
89
+
90
+ **Publish-Subscribe (Topic)**
91
+ ```
92
+ Producer → Topic → [Consumer A, Consumer B, Consumer C]
93
+ ```
94
+ - One message, multiple consumers
95
+ - Each subscriber gets copy
96
+ - Broadcast pattern
97
+ - Use for: notifications, event broadcasting
98
+
99
+ **Request-Reply**
100
+ ```
101
+ Client → Request Queue → Server
102
+ Client ← Reply Queue ← Server
103
+ ```
104
+ - Asynchronous request-response
105
+ - Correlation ID links request/reply
106
+ - Use for: async RPC, long-running operations
107
+
108
+ ### Event Streaming
109
+
110
+ **Event Stream Characteristics**
111
+ - Ordered sequence of events
112
+ - Events persisted (not deleted after consumption)
113
+ - Multiple consumers can read independently
114
+ - Replay capability
115
+ - Examples: Apache Kafka, AWS Kinesis
116
+
117
+ **Stream Processing**
118
+ - Real-time event processing
119
+ - Stateful computations
120
+ - Windowing and aggregation
121
+ - Complex event processing
122
+
123
+ **Kafka Example**
124
+ ```
125
+ Topic: orders
126
+ ├── Partition 0: [Event1, Event2, Event3]
127
+ ├── Partition 1: [Event4, Event5, Event6]
128
+ └── Partition 2: [Event7, Event8, Event9]
129
+
130
+ Consumer Group A: [Consumer1, Consumer2]
131
+ Consumer Group B: [Consumer3]
132
+ ```
133
+
134
+ ### Event Sourcing
135
+
136
+ **Concept**
137
+ - Store events, not current state
138
+ - State is derived from event history
139
+ - Complete audit trail
140
+ - Time travel (replay to any point)
141
+
142
+ **Event Store**
143
+ - Append-only log of events
144
+ - Events are immutable
145
+ - Optimized for writes
146
+ - Examples: EventStore, Kafka, custom DB
147
+
148
+ **Event Sourcing Pattern**
149
+ ```
150
+ Command → Aggregate → Events → Event Store
151
+
152
+ Event Handler → Read Model
153
+ ```
154
+
155
+ **Aggregate Example**
156
+ ```java
157
+ public class Order {
158
+ private String id;
159
+ private OrderStatus status;
160
+ private List<OrderItem> items;
161
+ private List<DomainEvent> uncommittedEvents = new ArrayList<>();
162
+
163
+ // Command handler
164
+ public void placeOrder(List<OrderItem> items) {
165
+ // Validate
166
+ if (items.isEmpty()) {
167
+ throw new IllegalArgumentException("Order must have items");
168
+ }
169
+
170
+ // Apply event
171
+ apply(new OrderPlacedEvent(this.id, items, Instant.now()));
172
+ }
173
+
174
+ // Event handler
175
+ private void apply(OrderPlacedEvent event) {
176
+ this.items = event.getItems();
177
+ this.status = OrderStatus.PLACED;
178
+ uncommittedEvents.add(event);
179
+ }
180
+
181
+ // Reconstitute from events
182
+ public static Order fromEvents(List<DomainEvent> events) {
183
+ Order order = new Order();
184
+ events.forEach(order::apply);
185
+ return order;
186
+ }
187
+ }
188
+ ```
189
+
190
+ ### CQRS (Command Query Responsibility Segregation)
191
+
192
+ **Concept**
193
+ - Separate read and write models
194
+ - Commands: change state
195
+ - Queries: read state
196
+ - Often combined with event sourcing
197
+
198
+ **Architecture**
199
+ ```
200
+ Command → Write Model → Events → Event Store
201
+
202
+ Event Handler
203
+
204
+ Query ← Read Model ← Projection ← Events
205
+ ```
206
+
207
+ **Benefits**
208
+ - Optimize read and write independently
209
+ - Scale read and write separately
210
+ - Different data models for different needs
211
+ - Simplified queries
212
+
213
+ ---
214
+
215
+ ## Examples
216
+
217
+ ### Order Processing with Events
218
+
219
+ **Event Definitions**
220
+ ```java
221
+ // Base event
222
+ public abstract class DomainEvent {
223
+ private final String eventId;
224
+ private final Instant timestamp;
225
+
226
+ protected DomainEvent() {
227
+ this.eventId = UUID.randomUUID().toString();
228
+ this.timestamp = Instant.now();
229
+ }
230
+ }
231
+
232
+ // Order events
233
+ public class OrderPlacedEvent extends DomainEvent {
234
+ private final String orderId;
235
+ private final String customerId;
236
+ private final List<OrderItem> items;
237
+ private final BigDecimal total;
238
+ }
239
+
240
+ public class OrderPaidEvent extends DomainEvent {
241
+ private final String orderId;
242
+ private final String paymentId;
243
+ private final BigDecimal amount;
244
+ }
245
+
246
+ public class OrderShippedEvent extends DomainEvent {
247
+ private final String orderId;
248
+ private final String trackingNumber;
249
+ private final Instant shippedAt;
250
+ }
251
+ ```
252
+
253
+ **Event Publisher**
254
+ ```java
255
+ @Service
256
+ public class OrderService {
257
+ private final OrderRepository orderRepository;
258
+ private final EventPublisher eventPublisher;
259
+
260
+ @Transactional
261
+ public Order placeOrder(PlaceOrderCommand command) {
262
+ // Create order
263
+ Order order = new Order(command.getCustomerId());
264
+ order.addItems(command.getItems());
265
+
266
+ // Save order
267
+ order = orderRepository.save(order);
268
+
269
+ // Publish event
270
+ OrderPlacedEvent event = new OrderPlacedEvent(
271
+ order.getId(),
272
+ order.getCustomerId(),
273
+ order.getItems(),
274
+ order.getTotal()
275
+ );
276
+
277
+ eventPublisher.publish("orders", event);
278
+
279
+ return order;
280
+ }
281
+ }
282
+
283
+ @Component
284
+ public class KafkaEventPublisher implements EventPublisher {
285
+ private final KafkaTemplate<String, DomainEvent> kafkaTemplate;
286
+
287
+ @Override
288
+ public void publish(String topic, DomainEvent event) {
289
+ kafkaTemplate.send(topic, event.getEventId(), event);
290
+ }
291
+ }
292
+ ```
293
+
294
+ **Event Consumers**
295
+ ```java
296
+ // Inventory Service - Reserve items
297
+ @Component
298
+ public class InventoryEventHandler {
299
+ private final InventoryService inventoryService;
300
+
301
+ @KafkaListener(topics = "orders", groupId = "inventory-service")
302
+ public void handleOrderPlaced(OrderPlacedEvent event) {
303
+ inventoryService.reserveItems(
304
+ event.getOrderId(),
305
+ event.getItems()
306
+ );
307
+ }
308
+ }
309
+
310
+ // Notification Service - Send confirmation
311
+ @Component
312
+ public class NotificationEventHandler {
313
+ private final EmailService emailService;
314
+
315
+ @KafkaListener(topics = "orders", groupId = "notification-service")
316
+ public void handleOrderPlaced(OrderPlacedEvent event) {
317
+ emailService.sendOrderConfirmation(
318
+ event.getCustomerId(),
319
+ event.getOrderId()
320
+ );
321
+ }
322
+ }
323
+
324
+ // Analytics Service - Track metrics
325
+ @Component
326
+ public class AnalyticsEventHandler {
327
+ private final AnalyticsService analyticsService;
328
+
329
+ @KafkaListener(topics = "orders", groupId = "analytics-service")
330
+ public void handleOrderPlaced(OrderPlacedEvent event) {
331
+ analyticsService.recordOrderPlaced(
332
+ event.getOrderId(),
333
+ event.getTotal(),
334
+ event.getTimestamp()
335
+ );
336
+ }
337
+ }
338
+ ```
339
+
340
+ ### Event Sourcing Implementation
341
+
342
+ **Event Store**
343
+ ```java
344
+ @Repository
345
+ public class EventStore {
346
+ private final JdbcTemplate jdbcTemplate;
347
+
348
+ public void saveEvents(String aggregateId, List<DomainEvent> events) {
349
+ String sql = """
350
+ INSERT INTO events (aggregate_id, event_type, event_data, version, timestamp)
351
+ VALUES (?, ?, ?::jsonb, ?, ?)
352
+ """;
353
+
354
+ for (DomainEvent event : events) {
355
+ jdbcTemplate.update(
356
+ sql,
357
+ aggregateId,
358
+ event.getClass().getSimpleName(),
359
+ toJson(event),
360
+ event.getVersion(),
361
+ event.getTimestamp()
362
+ );
363
+ }
364
+ }
365
+
366
+ public List<DomainEvent> getEvents(String aggregateId) {
367
+ String sql = """
368
+ SELECT event_type, event_data
369
+ FROM events
370
+ WHERE aggregate_id = ?
371
+ ORDER BY version ASC
372
+ """;
373
+
374
+ return jdbcTemplate.query(sql, (rs, rowNum) -> {
375
+ String eventType = rs.getString("event_type");
376
+ String eventData = rs.getString("event_data");
377
+ return fromJson(eventType, eventData);
378
+ }, aggregateId);
379
+ }
380
+ }
381
+ ```
382
+
383
+ **Aggregate with Event Sourcing**
384
+ ```java
385
+ public class Order {
386
+ private String id;
387
+ private String customerId;
388
+ private List<OrderItem> items = new ArrayList<>();
389
+ private OrderStatus status;
390
+ private int version = 0;
391
+ private List<DomainEvent> uncommittedEvents = new ArrayList<>();
392
+
393
+ // Command: Place order
394
+ public void placeOrder(String customerId, List<OrderItem> items) {
395
+ if (this.status != null) {
396
+ throw new IllegalStateException("Order already placed");
397
+ }
398
+
399
+ apply(new OrderPlacedEvent(this.id, customerId, items));
400
+ }
401
+
402
+ // Command: Pay for order
403
+ public void pay(String paymentId, BigDecimal amount) {
404
+ if (this.status != OrderStatus.PLACED) {
405
+ throw new IllegalStateException("Order not in PLACED status");
406
+ }
407
+
408
+ apply(new OrderPaidEvent(this.id, paymentId, amount));
409
+ }
410
+
411
+ // Event handlers
412
+ private void apply(OrderPlacedEvent event) {
413
+ this.customerId = event.getCustomerId();
414
+ this.items = new ArrayList<>(event.getItems());
415
+ this.status = OrderStatus.PLACED;
416
+ this.version++;
417
+ uncommittedEvents.add(event);
418
+ }
419
+
420
+ private void apply(OrderPaidEvent event) {
421
+ this.status = OrderStatus.PAID;
422
+ this.version++;
423
+ uncommittedEvents.add(event);
424
+ }
425
+
426
+ // Reconstitute from events
427
+ public static Order fromEvents(String id, List<DomainEvent> events) {
428
+ Order order = new Order();
429
+ order.id = id;
430
+
431
+ for (DomainEvent event : events) {
432
+ if (event instanceof OrderPlacedEvent e) {
433
+ order.apply(e);
434
+ } else if (event instanceof OrderPaidEvent e) {
435
+ order.apply(e);
436
+ }
437
+ }
438
+
439
+ order.uncommittedEvents.clear();
440
+ return order;
441
+ }
442
+
443
+ public List<DomainEvent> getUncommittedEvents() {
444
+ return new ArrayList<>(uncommittedEvents);
445
+ }
446
+
447
+ public void markEventsAsCommitted() {
448
+ uncommittedEvents.clear();
449
+ }
450
+ }
451
+ ```
452
+
453
+ ### Saga Pattern for Distributed Transactions
454
+
455
+ **Choreography-Based Saga**
456
+ ```java
457
+ // Order Service
458
+ @Component
459
+ public class OrderSagaHandler {
460
+ private final OrderRepository orderRepository;
461
+ private final EventPublisher eventPublisher;
462
+
463
+ @KafkaListener(topics = "payments")
464
+ public void handlePaymentProcessed(PaymentProcessedEvent event) {
465
+ Order order = orderRepository.findById(event.getOrderId());
466
+ order.markAsPaid();
467
+ orderRepository.save(order);
468
+
469
+ // Trigger next step
470
+ eventPublisher.publish("shipments",
471
+ new ShipOrderEvent(order.getId())
472
+ );
473
+ }
474
+
475
+ @KafkaListener(topics = "payments")
476
+ public void handlePaymentFailed(PaymentFailedEvent event) {
477
+ Order order = orderRepository.findById(event.getOrderId());
478
+ order.cancel();
479
+ orderRepository.save(order);
480
+
481
+ // Compensate: Release inventory
482
+ eventPublisher.publish("inventory",
483
+ new ReleaseInventoryEvent(order.getId())
484
+ );
485
+ }
486
+ }
487
+ ```
488
+
489
+ ---
490
+
491
+ ## Understanding
492
+
493
+ ### Advantages of Event-Driven Architecture
494
+
495
+ **Loose Coupling**
496
+ - Producers don't know consumers
497
+ - Add/remove consumers without affecting producers
498
+ - Independent evolution
499
+ - Easier testing
500
+
501
+ **Scalability**
502
+ - Asynchronous processing
503
+ - Load leveling with queues
504
+ - Independent scaling of consumers
505
+ - Parallel processing
506
+
507
+ **Resilience**
508
+ - Failure isolation
509
+ - Retry mechanisms
510
+ - Dead letter queues
511
+ - Graceful degradation
512
+
513
+ **Flexibility**
514
+ - Easy to add new features (new consumers)
515
+ - Support multiple workflows
516
+ - Real-time and batch processing
517
+ - Event replay for recovery
518
+
519
+ **Auditability**
520
+ - Complete event history
521
+ - Audit trail
522
+ - Debugging and troubleshooting
523
+ - Compliance and reporting
524
+
525
+ ### Challenges and Disadvantages
526
+
527
+ **Complexity**
528
+ - Distributed system challenges
529
+ - Eventual consistency
530
+ - Event ordering issues
531
+ - Debugging difficulties
532
+
533
+ **Event Schema Evolution**
534
+ - Backward compatibility needed
535
+ - Versioning strategy required
536
+ - Consumer updates coordination
537
+ - Schema registry management
538
+
539
+ **Duplicate Events**
540
+ - At-least-once delivery
541
+ - Idempotent consumers required
542
+ - Deduplication logic
543
+ - Event ID tracking
544
+
545
+ **Event Ordering**
546
+ - No global ordering (distributed systems)
547
+ - Partition-level ordering only
548
+ - Out-of-order events
549
+ - Causality tracking needed
550
+
551
+ **Operational Overhead**
552
+ - Message broker management
553
+ - Monitoring and alerting
554
+ - Dead letter queue handling
555
+ - Event store maintenance
556
+
557
+ ### Best Practices
558
+
559
+ **Event Design**
560
+ - Events are immutable
561
+ - Include all necessary data (avoid lookups)
562
+ - Use meaningful event names (past tense)
563
+ - Version events from the start
564
+ - Include correlation IDs
565
+
566
+ **Consumer Design**
567
+ - Idempotent event handlers
568
+ - Handle duplicate events
569
+ - Use dead letter queues
570
+ - Implement retry with backoff
571
+ - Monitor consumer lag
572
+
573
+ **Error Handling**
574
+ - Retry transient failures
575
+ - Dead letter queue for poison messages
576
+ - Compensating transactions
577
+ - Circuit breakers
578
+ - Alerting and monitoring
579
+
580
+ **Event Store**
581
+ - Append-only design
582
+ - Partition by aggregate ID
583
+ - Snapshot for performance
584
+ - Archive old events
585
+ - Backup and recovery
586
+
587
+ **Monitoring**
588
+ - Event throughput
589
+ - Consumer lag
590
+ - Processing time
591
+ - Error rates
592
+ - Dead letter queue size
593
+
594
+ ---
595
+
596
+ ## References
597
+
598
+ - **Books**
599
+ - "Designing Event-Driven Systems" by Ben Stopford
600
+ - "Enterprise Integration Patterns" by Gregor Hohpe
601
+ - "Implementing Domain-Driven Design" by Vaughn Vernon
602
+
603
+ - **Patterns**
604
+ - Event Sourcing Pattern
605
+ - CQRS Pattern
606
+ - Saga Pattern
607
+ - Outbox Pattern
608
+ - Event Notification Pattern
609
+
610
+ - **Technologies**
611
+ - Message Brokers: Apache Kafka, RabbitMQ, AWS SNS/SQS
612
+ - Event Stores: EventStore, Axon Server
613
+ - Stream Processing: Apache Flink, Kafka Streams
614
+ - Schema Registry: Confluent Schema Registry, AWS Glue
615
+
616
+