eva4j 1.0.17 → 1.0.18

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 (134) hide show
  1. package/AGENTS.md +2 -0
  2. package/DOMAIN_YAML_GUIDE.md +3 -1
  3. package/QUICK_REFERENCE.md +8 -4
  4. package/bin/eva4j.js +70 -2
  5. package/config/defaults.json +1 -0
  6. package/docs/CAMUNDA_DMN_GUIDE.md +1380 -0
  7. package/docs/KAFKA_PRODUCTION_CONFIG.md +441 -0
  8. package/docs/RABBITMQ_PRODUCTION_CONFIG.md +227 -0
  9. package/docs/commands/ADD_RABBITMQ_CLIENT.md +192 -0
  10. package/docs/commands/EVALUATE_SYSTEM.md +272 -8
  11. package/docs/commands/GENERATE_RABBITMQ_EVENT.md +341 -0
  12. package/docs/commands/GENERATE_RABBITMQ_LISTENER.md +595 -0
  13. package/docs/commands/GENERATE_TEMPORAL_FLOW.md +52 -12
  14. package/docs/commands/INDEX.md +27 -3
  15. package/docs/prototype/TEMPORAL_COMMUNICATION_PATTERNS.md +731 -0
  16. package/docs/prototype/TEMPORAL_DESIGN_METHODOLOGY.md +740 -0
  17. package/docs/prototype/system/RISKS.md +277 -0
  18. package/docs/prototype/system/customers.yaml +133 -0
  19. package/docs/prototype/system/inventory.yaml +109 -0
  20. package/docs/prototype/system/notifications.yaml +131 -0
  21. package/docs/prototype/system/orders.yaml +241 -0
  22. package/docs/prototype/system/payments.yaml +256 -0
  23. package/docs/prototype/system/products.yaml +168 -0
  24. package/docs/prototype/system/system.yaml +269 -0
  25. package/examples/domain-endpoints-multi-aggregate.yaml +140 -0
  26. package/examples/domain-read-models.yaml +2 -2
  27. package/examples/system/customer.yaml +89 -0
  28. package/examples/system/orders.yaml +119 -0
  29. package/examples/system/product.yaml +27 -0
  30. package/examples/system/system.yaml +80 -0
  31. package/package.json +1 -1
  32. package/src/agents/design-gap-analyst-temporal.agent.md +452 -0
  33. package/src/agents/design-gap-analyst.agent.md +383 -0
  34. package/src/agents/design-reviewer-temporal.agent.md +412 -0
  35. package/src/agents/design-reviewer.agent.md +31 -5
  36. package/src/agents/implement-use-cases.prompt.md +179 -0
  37. package/src/agents/ux-gap-analyst.agent.md +412 -0
  38. package/src/commands/add-rabbitmq-client.js +261 -0
  39. package/src/commands/add-temporal-client.js +22 -2
  40. package/src/commands/build.js +267 -11
  41. package/src/commands/evaluate-system.js +700 -13
  42. package/src/commands/generate-entities.js +308 -16
  43. package/src/commands/generate-rabbitmq-event.js +665 -0
  44. package/src/commands/generate-rabbitmq-listener.js +205 -0
  45. package/src/commands/generate-temporal-activity.js +968 -34
  46. package/src/commands/generate-temporal-flow.js +95 -38
  47. package/src/commands/generate-temporal-system.js +708 -0
  48. package/src/skills/build-system-yaml/SKILL.md +222 -2
  49. package/src/skills/build-system-yaml/references/domain-yaml-spec.md +50 -4
  50. package/src/skills/build-system-yaml/references/module-spec.md +57 -8
  51. package/src/skills/build-temporal-system/SKILL.md +752 -0
  52. package/src/skills/build-temporal-system/references/temporal-communication-patterns.md +167 -0
  53. package/src/skills/build-temporal-system/references/temporal-domain-yaml-spec.md +449 -0
  54. package/src/skills/build-temporal-system/references/temporal-module-spec.md +353 -0
  55. package/src/skills/build-temporal-system/references/temporal-system-yaml-spec.md +326 -0
  56. package/src/skills/implement-use-case/SKILL.md +350 -0
  57. package/src/skills/implement-use-case/references/use-case-patterns.md +980 -0
  58. package/src/skills/requirements-elicitation/SKILL.md +228 -0
  59. package/src/skills/requirements-elicitation/references/interview-framework.md +260 -0
  60. package/src/skills/requirements-elicitation/references/output-templates.md +368 -0
  61. package/src/utils/bounded-context-diagram.js +844 -0
  62. package/src/utils/domain-validator.js +266 -4
  63. package/src/utils/naming.js +10 -0
  64. package/src/utils/system-validator.js +169 -11
  65. package/src/utils/system-yaml-parser.js +318 -0
  66. package/src/utils/temporal-validator.js +497 -0
  67. package/src/utils/yaml-to-entity.js +10 -7
  68. package/templates/aggregate/DomainEventHandler.java.ejs +116 -22
  69. package/templates/aggregate/JpaAggregateRoot.java.ejs +2 -2
  70. package/templates/aggregate/JpaEntity.java.ejs +2 -2
  71. package/templates/base/docker/rabbitmq-services.yaml.ejs +12 -0
  72. package/templates/base/resources/parameters/develop/kafka.yaml.ejs +5 -0
  73. package/templates/base/resources/parameters/develop/rabbitmq.yaml.ejs +15 -0
  74. package/templates/base/resources/parameters/develop/temporal.yaml.ejs +0 -3
  75. package/templates/base/resources/parameters/local/kafka.yaml.ejs +5 -0
  76. package/templates/base/resources/parameters/local/rabbitmq.yaml.ejs +15 -0
  77. package/templates/base/resources/parameters/local/temporal.yaml.ejs +0 -3
  78. package/templates/base/resources/parameters/production/kafka.yaml.ejs +39 -8
  79. package/templates/base/resources/parameters/production/rabbitmq.yaml.ejs +32 -0
  80. package/templates/base/resources/parameters/production/temporal.yaml.ejs +0 -3
  81. package/templates/base/resources/parameters/test/kafka.yaml.ejs +12 -6
  82. package/templates/base/resources/parameters/test/rabbitmq.yaml.ejs +15 -0
  83. package/templates/base/resources/parameters/test/temporal.yaml.ejs +0 -3
  84. package/templates/base/root/AGENTS.md.ejs +1 -1
  85. package/templates/crud/EndpointsController.java.ejs +1 -1
  86. package/templates/crud/ScaffoldCommand.java.ejs +5 -2
  87. package/templates/crud/ScaffoldCommandHandler.java.ejs +3 -1
  88. package/templates/crud/ScaffoldQuery.java.ejs +5 -2
  89. package/templates/crud/ScaffoldQueryHandler.java.ejs +3 -1
  90. package/templates/crud/SubEntityRemoveCommand.java.ejs +1 -1
  91. package/templates/evaluate/report.html.ejs +1447 -90
  92. package/templates/kafka-event/KafkaConfigBean.java.ejs +1 -1
  93. package/templates/kafka-event/KafkaMessageBroker.java.ejs +3 -3
  94. package/templates/ports/PortAclMapper.java.ejs +35 -0
  95. package/templates/ports/PortFeignAdapter.java.ejs +7 -22
  96. package/templates/ports/PortFeignClient.java.ejs +4 -0
  97. package/templates/ports/PortResponseDto.java.ejs +1 -1
  98. package/templates/rabbitmq-event/RabbitConfigBean.java.ejs +33 -0
  99. package/templates/rabbitmq-event/RabbitConfigExchange.java.ejs +12 -0
  100. package/templates/rabbitmq-event/RabbitMessageBroker.java.ejs +35 -0
  101. package/templates/rabbitmq-event/RabbitMessageBrokerMethod.java.ejs +9 -0
  102. package/templates/rabbitmq-listener/RabbitConfigConsumerBean.java.ejs +33 -0
  103. package/templates/rabbitmq-listener/RabbitConfigConsumerExchange.java.ejs +12 -0
  104. package/templates/rabbitmq-listener/RabbitListenerClass.java.ejs +82 -0
  105. package/templates/rabbitmq-listener/RabbitListenerSimple.java.ejs +56 -0
  106. package/templates/read-model/ReadModelJpa.java.ejs +1 -1
  107. package/templates/read-model/ReadModelJpaRepository.java.ejs +2 -0
  108. package/templates/read-model/ReadModelRabbitListener.java.ejs +71 -0
  109. package/templates/read-model/ReadModelRepositoryImpl.java.ejs +9 -5
  110. package/templates/read-model/ReadModelSyncHandler.java.ejs +2 -0
  111. package/templates/shared/configurations/kafkaConfig/KafkaConfig.java.ejs +18 -4
  112. package/templates/shared/configurations/rabbitmqConfig/RabbitMQConfig.java.ejs +100 -0
  113. package/templates/shared/configurations/temporalConfig/TemporalConfig.java.ejs +2 -64
  114. package/templates/shared/configurations/temporalConfig/TemporalWorkerFactoryLifecycle.java.ejs +41 -0
  115. package/templates/temporal-activity/ActivityImpl.java.ejs +68 -2
  116. package/templates/temporal-activity/ActivityInput.java.ejs +14 -0
  117. package/templates/temporal-activity/ActivityInterface.java.ejs +7 -1
  118. package/templates/temporal-activity/ActivityOutput.java.ejs +14 -0
  119. package/templates/temporal-activity/NestedType.java.ejs +12 -0
  120. package/templates/temporal-activity/SharedActivityInput.java.ejs +14 -0
  121. package/templates/temporal-activity/SharedActivityInterface.java.ejs +15 -0
  122. package/templates/temporal-activity/SharedActivityOutput.java.ejs +14 -0
  123. package/templates/temporal-activity/SharedNestedType.java.ejs +12 -0
  124. package/templates/temporal-flow/ModuleHeavyActivity.java.ejs +6 -0
  125. package/templates/temporal-flow/ModuleLightActivity.java.ejs +6 -0
  126. package/templates/temporal-flow/ModuleTemporalWorkerConfig.java.ejs +58 -0
  127. package/templates/temporal-flow/WorkFlowImpl.java.ejs +172 -12
  128. package/templates/temporal-flow/WorkFlowInput.java.ejs +11 -0
  129. package/templates/temporal-flow/WorkFlowInterface.java.ejs +5 -4
  130. package/templates/temporal-flow/WorkFlowService.java.ejs +42 -12
  131. package/COMMAND_EVALUATION.md +0 -911
  132. package/test-c2010.js +0 -49
  133. package/test-update-compat.js +0 -109
  134. package/test-update-lifecycle.js +0 -121
@@ -0,0 +1,341 @@
1
+ # Command `generate rabbitmq-event` (alias: `g rabbitmq-event`)
2
+
3
+ ## Description
4
+
5
+ Generates the infrastructure for publishing a domain event to a RabbitMQ exchange, enabling asynchronous event-driven communication between modules or microservices using topic exchanges, routing keys, and dead-letter queues.
6
+
7
+ ## Purpose
8
+
9
+ Implement event publishing without coupling the sender to the consumer. The generated `MessageBroker` port keeps the domain free of RabbitMQ dependencies, while the adapter handles the actual publishing using `EventEnvelope` for correlation tracking. Each event gets its own exchange, queue, routing key, and DLQ configuration.
10
+
11
+ ## Syntax
12
+
13
+ ```bash
14
+ eva generate rabbitmq-event <module> [event-name]
15
+ eva g rabbitmq-event <module> [event-name] # Short alias
16
+ ```
17
+
18
+ ### Parameters
19
+
20
+ | Parameter | Required | Description |
21
+ |-----------|----------|-------------|
22
+ | `module` | Yes | Module that owns and publishes the event (e.g., `user`, `order`) |
23
+ | `event-name` | No | Event name in kebab-case — prompted if omitted; `IntegrationEvent` suffix is added automatically |
24
+
25
+ > **Interactive prompts (when event-name is omitted):**
26
+ > - If `domain.yaml` exists with declared events, a **multi-select list** is shown (including an "All events" option and a "Custom name" fallback).
27
+ > - If no `domain.yaml`, a free-text prompt asks for the event name.
28
+
29
+ **Note:** Running the command multiple times on the same module safely **appends** a new method to the existing `MessageBroker.java` without overwriting it.
30
+
31
+ ## Prerequisites
32
+
33
+ RabbitMQ client must be installed in the project:
34
+
35
+ ```bash
36
+ eva add rabbitmq-client
37
+ ```
38
+
39
+ ## Examples
40
+
41
+ ### Example 1: User created event
42
+
43
+ ```bash
44
+ eva g rabbitmq-event user user-created
45
+ ```
46
+
47
+ Generates:
48
+ - `user/application/events/UserCreatedIntegrationEvent.java`
49
+ - `user/application/ports/MessageBroker.java` (created or appended)
50
+ - `user/infrastructure/adapters/rabbitmqMessageBroker/UserRabbitMessageBroker.java`
51
+ - `shared/configurations/rabbitmqConfig/RabbitMQConfig.java` (exchange + queue + binding beans added)
52
+ - Adds exchange, queue, and routing-key entries to `parameters/*/rabbitmq.yaml`
53
+
54
+ ### Example 2: Order placed event
55
+
56
+ ```bash
57
+ eva g rabbitmq-event order order-placed
58
+ ```
59
+
60
+ ### Example 3: Multiple events in the same module
61
+
62
+ ```bash
63
+ eva g rabbitmq-event user user-created # Creates MessageBroker with publishUserCreatedIntegrationEvent
64
+ eva g rabbitmq-event user user-updated # Appends publishUserUpdatedIntegrationEvent to MessageBroker
65
+ eva g rabbitmq-event user user-deleted # Appends publishUserDeletedIntegrationEvent to MessageBroker
66
+ ```
67
+
68
+ Each run adds a new method without overwriting existing ones.
69
+
70
+ ### Example 4: Batch mode from domain.yaml
71
+
72
+ ```bash
73
+ eva g rabbitmq-event order
74
+ # Interactive multi-select:
75
+ # ★ All events
76
+ # ──────────────
77
+ # ◻ OrderPlaced (from Order aggregate)
78
+ # ◻ OrderConfirmed (from Order aggregate)
79
+ # ◻ OrderCancelled (from Order aggregate)
80
+ # ──────────────
81
+ # ◻ Custom name (free text)...
82
+ ```
83
+
84
+ Select "All events" to generate all declared domain events at once.
85
+
86
+ ## Generated Code Structure
87
+
88
+ ```
89
+ <module>/
90
+ ├── application/
91
+ │ ├── events/
92
+ │ │ └── UserCreatedIntegrationEvent.java # Java record (event data)
93
+ │ └── ports/
94
+ │ └── MessageBroker.java # Port interface (append-safe)
95
+
96
+ └── infrastructure/
97
+ └── adapters/
98
+ └── rabbitmqMessageBroker/
99
+ └── UserRabbitMessageBroker.java # RabbitMQ adapter
100
+
101
+ shared/
102
+ └── infrastructure/
103
+ └── configurations/
104
+ └── rabbitmqConfig/
105
+ └── RabbitMQConfig.java # Exchange + Queue + Binding beans
106
+ ```
107
+
108
+ ## Generated Files
109
+
110
+ ### 1. Integration Event (Application Layer)
111
+
112
+ **UserCreatedIntegrationEvent.java** (`application/events/`):
113
+ ```java
114
+ package com.example.project.user.application.events;
115
+
116
+ public record UserCreatedIntegrationEvent(
117
+ // TODO: Add your event fields here
118
+ // Example:
119
+ // Long id,
120
+ // String name,
121
+ // LocalDateTime createdAt
122
+ ) {
123
+ }
124
+ ```
125
+
126
+ > Events are pure Java records — immutable, no Lombok, no framework annotations.
127
+
128
+ ### 2. MessageBroker Port (Application Layer)
129
+
130
+ **MessageBroker.java** (`application/ports/`):
131
+ ```java
132
+ package com.example.project.user.application.ports;
133
+
134
+ import com.example.project.user.application.events.UserCreatedIntegrationEvent;
135
+
136
+ public interface MessageBroker {
137
+
138
+ void publishUserCreatedIntegrationEvent(UserCreatedIntegrationEvent event);
139
+ }
140
+ ```
141
+
142
+ > If `MessageBroker.java` already exists (from a previous run), the new `publishXxx` method is **appended** to the interface rather than overwriting it.
143
+
144
+ ### 3. RabbitMQ Adapter (Infrastructure)
145
+
146
+ **UserRabbitMessageBroker.java** (`infrastructure/adapters/rabbitmqMessageBroker/`):
147
+ ```java
148
+ package com.example.project.user.infrastructure.adapters.rabbitmqMessageBroker;
149
+
150
+ import com.example.project.user.application.events.UserCreatedIntegrationEvent;
151
+ import com.example.project.user.application.ports.MessageBroker;
152
+ import com.example.project.shared.infrastructure.eventEnvelope.EventEnvelope;
153
+ import org.springframework.amqp.rabbit.core.RabbitTemplate;
154
+ import org.springframework.beans.factory.annotation.Value;
155
+ import org.springframework.stereotype.Component;
156
+ import org.slf4j.MDC;
157
+
158
+ @Component("userRabbitMessageBroker")
159
+ public class UserRabbitMessageBroker implements MessageBroker {
160
+
161
+ @Value("${exchanges.user}")
162
+ private String exchange;
163
+
164
+ @Value("${routing-keys.user-created}")
165
+ private String userCreatedRoutingKey;
166
+
167
+ private final RabbitTemplate rabbitTemplate;
168
+
169
+ public UserRabbitMessageBroker(RabbitTemplate rabbitTemplate) {
170
+ this.rabbitTemplate = rabbitTemplate;
171
+ }
172
+
173
+ @Override
174
+ public void publishUserCreatedIntegrationEvent(UserCreatedIntegrationEvent event) {
175
+ EventEnvelope<UserCreatedIntegrationEvent> envelope = EventEnvelope.of(
176
+ userCreatedRoutingKey,
177
+ event,
178
+ MDC.get("correlationId")
179
+ );
180
+ rabbitTemplate.convertAndSend(exchange, userCreatedRoutingKey, envelope);
181
+ }
182
+ }
183
+ ```
184
+
185
+ > `EventEnvelope.of(routingKey, payload, correlationId)` wraps the event with routing metadata and the current MDC correlation ID for distributed tracing.
186
+
187
+ ### 4. RabbitMQConfig Beans (Shared)
188
+
189
+ For each event, the command adds exchange, queue, binding, and DLQ beans to `RabbitMQConfig.java`:
190
+
191
+ ```java
192
+ // ── Exchange (once per module) ──────────────────────────
193
+
194
+ @Value("${exchanges.user}")
195
+ private String userExchangeName;
196
+
197
+ @Bean
198
+ public TopicExchange userExchange() {
199
+ return new TopicExchange(userExchangeName, true, false);
200
+ }
201
+
202
+ @Bean
203
+ public TopicExchange userDlxExchange() {
204
+ return new TopicExchange(userExchangeName + ".dlx", true, false);
205
+ }
206
+
207
+ // ── Queue + Binding (per event) ─────────────────────────
208
+
209
+ @Value("${queues.user-created}")
210
+ private String userCreatedTopicQueueName;
211
+
212
+ @Value("${routing-keys.user-created}")
213
+ private String userCreatedTopicRoutingKeyValue;
214
+
215
+ @Bean
216
+ public Queue userCreatedTopicQueue() {
217
+ return QueueBuilder.durable(userCreatedTopicQueueName)
218
+ .withArgument("x-dead-letter-exchange", userExchangeName + ".dlx")
219
+ .build();
220
+ }
221
+
222
+ @Bean
223
+ public Binding userCreatedTopicBinding() {
224
+ return BindingBuilder
225
+ .bind(userCreatedTopicQueue())
226
+ .to(userExchange())
227
+ .with(userCreatedTopicRoutingKeyValue);
228
+ }
229
+
230
+ @Bean
231
+ public Queue userCreatedTopicDlq() {
232
+ return QueueBuilder.durable(userCreatedTopicQueueName + ".dlq").build();
233
+ }
234
+
235
+ @Bean
236
+ public Binding userCreatedTopicDlqBinding() {
237
+ return BindingBuilder
238
+ .bind(userCreatedTopicDlq())
239
+ .to(userDlxExchange())
240
+ .with(userCreatedTopicRoutingKeyValue);
241
+ }
242
+ ```
243
+
244
+ ## Configuration Added
245
+
246
+ ```yaml
247
+ # parameters/local/rabbitmq.yaml
248
+ exchanges:
249
+ user: user.events
250
+
251
+ queues:
252
+ user-created: user.user-created
253
+
254
+ routing-keys:
255
+ user-created: user.created
256
+ ```
257
+
258
+ The same entries are added to every environment (`local`, `develop`, `test`, `production`).
259
+
260
+ ### RabbitMQ Topology
261
+
262
+ Each event generates the following topology:
263
+
264
+ ```
265
+ Producer → [user.events exchange] → routing key: user.created → [user.user-created queue]
266
+ ↓ (on failure)
267
+ [user.events.dlx exchange] → routing key: user.created → [user.user-created.dlq queue]
268
+ ```
269
+
270
+ ## Usage in a Command Handler
271
+
272
+ Inject `MessageBroker` (the port, not the RabbitMQ class) and call the publish method:
273
+
274
+ ```java
275
+ @ApplicationComponent
276
+ public class CreateUserCommandHandler {
277
+
278
+ private final UserRepository userRepository;
279
+ private final MessageBroker messageBroker;
280
+
281
+ public CreateUserCommandHandler(UserRepository userRepository, MessageBroker messageBroker) {
282
+ this.userRepository = userRepository;
283
+ this.messageBroker = messageBroker;
284
+ }
285
+
286
+ public void handle(CreateUserCommand command) {
287
+ User user = new User(command.name(), command.email());
288
+ userRepository.save(user);
289
+
290
+ messageBroker.publishUserCreatedIntegrationEvent(
291
+ new UserCreatedIntegrationEvent(/* fill fields */)
292
+ );
293
+ }
294
+ }
295
+ ```
296
+
297
+ ## DomainEventHandler Wiring
298
+
299
+ When the module has domain events (from `domain.yaml`), the command also wires the `DomainEventHandler` to publish integration events after transaction commit:
300
+
301
+ ```java
302
+ @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
303
+ public void onUserCreated(UserCreated event) {
304
+ messageBroker.publishUserCreatedIntegrationEvent(
305
+ new UserCreatedIntegrationEvent(event.getUserId(), event.getCreatedAt())
306
+ );
307
+ }
308
+ ```
309
+
310
+ ## Bean Naming
311
+
312
+ The adapter is registered with an explicit bean name to avoid conflicts when multiple modules have a `MessageBroker`:
313
+
314
+ | Module | Bean name |
315
+ |--------|-----------|
316
+ | `user` | `userRabbitMessageBroker` |
317
+ | `order` | `orderRabbitMessageBroker` |
318
+ | `product` | `productRabbitMessageBroker` |
319
+
320
+ Spring resolves the correct adapter for each module via constructor injection by type + qualifier if needed.
321
+
322
+ ## Comparison with Kafka Events
323
+
324
+ | Aspect | Kafka | RabbitMQ |
325
+ |--------|-------|----------|
326
+ | Adapter class | `{Module}KafkaMessageBroker` | `{Module}RabbitMessageBroker` |
327
+ | Adapter directory | `kafkaMessageBroker/` | `rabbitmqMessageBroker/` |
328
+ | Config file | `kafka.yaml` | `rabbitmq.yaml` |
329
+ | Routing | Topic name | Exchange + routing key |
330
+ | DLQ | Configured externally | Auto-generated DLQ + DLX per event |
331
+ | Config class | `KafkaConfig.java` (NewTopic beans) | `RabbitMQConfig.java` (Exchange + Queue + Binding beans) |
332
+ | Broker-agnostic port | `MessageBroker.java` (identical) | `MessageBroker.java` (identical) |
333
+
334
+ > **Mutual exclusivity:** Only one broker is allowed per project (`eva add kafka-client` or `eva add rabbitmq-client`, not both).
335
+
336
+ ## See Also
337
+
338
+ - [generate rabbitmq-listener](./GENERATE_RABBITMQ_LISTENER.md) — Create RabbitMQ event consumer
339
+ - [generate kafka-event](./GENERATE_KAFKA_EVENT.md) — Kafka equivalent of this command
340
+ - [generate usecase](./GENERATE_USECASE.md) — Create use case handlers
341
+ - [RabbitMQ Production Config](../RABBITMQ_PRODUCTION_CONFIG.md) — Production-ready configuration reference