eva4j 1.0.13 → 1.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/AGENTS.md +51 -9
  2. package/DOMAIN_YAML_GUIDE.md +150 -0
  3. package/bin/eva4j.js +31 -1
  4. package/design-system.md +797 -0
  5. package/docs/commands/EVALUATE_SYSTEM.md +542 -0
  6. package/docs/commands/GENERATE_ENTITIES.md +196 -0
  7. package/docs/commands/INDEX.md +10 -1
  8. package/examples/domain-endpoints-relations.yaml +353 -0
  9. package/examples/domain-endpoints-versioned.yaml +144 -0
  10. package/examples/domain-endpoints.yaml +135 -0
  11. package/examples/system.yaml +289 -0
  12. package/package.json +1 -1
  13. package/src/commands/create.js +6 -3
  14. package/src/commands/evaluate-system.js +384 -0
  15. package/src/commands/generate-entities.js +677 -14
  16. package/src/commands/generate-kafka-event.js +59 -5
  17. package/src/commands/generate-system.js +243 -0
  18. package/src/generators/base-generator.js +9 -1
  19. package/src/utils/naming.js +3 -2
  20. package/src/utils/system-validator.js +314 -0
  21. package/src/utils/yaml-to-entity.js +31 -2
  22. package/templates/aggregate/AggregateRepository.java.ejs +5 -0
  23. package/templates/aggregate/AggregateRepositoryImpl.java.ejs +9 -0
  24. package/templates/aggregate/DomainEventHandler.java.ejs +24 -20
  25. package/templates/aggregate/JpaRepository.java.ejs +5 -0
  26. package/templates/base/root/skill-build-domain-yaml-references-generate-entities.md.ejs +1103 -0
  27. package/templates/base/root/skill-build-domain-yaml.ejs +292 -0
  28. package/templates/base/root/skill-build-system-yaml.ejs +252 -0
  29. package/templates/base/root/system.yaml.ejs +97 -0
  30. package/templates/crud/EndpointsController.java.ejs +178 -0
  31. package/templates/crud/FindByQuery.java.ejs +17 -0
  32. package/templates/crud/FindByQueryHandler.java.ejs +57 -0
  33. package/templates/crud/ScaffoldCommand.java.ejs +12 -0
  34. package/templates/crud/ScaffoldCommandHandler.java.ejs +43 -0
  35. package/templates/crud/ScaffoldQuery.java.ejs +12 -0
  36. package/templates/crud/ScaffoldQueryHandler.java.ejs +40 -0
  37. package/templates/crud/SubEntityAddCommand.java.ejs +17 -0
  38. package/templates/crud/SubEntityAddCommandHandler.java.ejs +43 -0
  39. package/templates/crud/SubEntityRemoveCommand.java.ejs +9 -0
  40. package/templates/crud/SubEntityRemoveCommandHandler.java.ejs +42 -0
  41. package/templates/crud/TransitionCommand.java.ejs +9 -0
  42. package/templates/crud/TransitionCommandHandler.java.ejs +39 -0
  43. package/templates/evaluate/report.html.ejs +971 -0
  44. package/templates/kafka-event/Event.java.ejs +7 -0
@@ -26,7 +26,8 @@ async function parseDomainYaml(yamlPath, packageName = '', moduleName = '') {
26
26
 
27
27
  return {
28
28
  aggregates,
29
- allEnums: extractAllEnums(domainData.aggregates)
29
+ allEnums: extractAllEnums(domainData.aggregates),
30
+ endpoints: parseEndpoints(domainData)
30
31
  };
31
32
  }
32
33
 
@@ -91,7 +92,8 @@ function parseAggregate(aggregateData) {
91
92
  valueObjects: parsedValueObjects,
92
93
  aggregateMethods,
93
94
  allEntities: parsedEntities,
94
- domainEvents
95
+ domainEvents,
96
+ enums: aggregateEnums
95
97
  };
96
98
  }
97
99
 
@@ -961,6 +963,33 @@ function extractAllEnums(aggregates) {
961
963
  return Array.from(enumsMap.values());
962
964
  }
963
965
 
966
+ /**
967
+ * Parse the optional endpoints section from domain.yaml.
968
+ * When present, controls which use cases and versioned controllers are generated.
969
+ * @param {Object} domainData - Raw parsed YAML data
970
+ * @returns {Object|null} Parsed endpoints structure or null if not declared
971
+ */
972
+ function parseEndpoints(domainData) {
973
+ if (!domainData.endpoints) return null;
974
+ const { basePath = '/', versions = [] } = domainData.endpoints;
975
+ return {
976
+ basePath,
977
+ versions: versions.map(v => ({
978
+ version: v.version,
979
+ operations: (v.operations || []).map(op => {
980
+ const method = (op.method || 'GET').toUpperCase();
981
+ return {
982
+ method,
983
+ path: op.path || '/',
984
+ description: op.description || '',
985
+ useCase: toPascalCase(op.useCase),
986
+ type: method === 'GET' ? 'query' : 'command'
987
+ };
988
+ })
989
+ }))
990
+ };
991
+ }
992
+
964
993
  module.exports = {
965
994
  parseDomainYaml,
966
995
  parseAggregate,
@@ -20,4 +20,9 @@ public interface <%= rootEntity.name %>Repository {
20
20
  void deleteById(<%= rootEntity.fields[0].javaType %> id);
21
21
 
22
22
  boolean existsById(<%= rootEntity.fields[0].javaType %> id);
23
+ <% if (findByOps && findByOps.length > 0) { %>
24
+ <% findByOps.forEach(function(op) { %>
25
+ Page<<%= rootEntity.name %>> <%= op.jpaMethodName %>(<%= op.fieldJavaType %> <%= op.fieldName %>, Pageable pageable);
26
+ <% }); %>
27
+ <% } %>
23
28
  }
@@ -58,4 +58,13 @@ public class <%= rootEntity.name %>RepositoryImpl implements <%= rootEntity.name
58
58
  public boolean existsById(<%= rootEntity.fields[0].javaType %> id) {
59
59
  return jpaRepository.existsById(id);
60
60
  }
61
+ <% if (findByOps && findByOps.length > 0) { %>
62
+ <% findByOps.forEach(function(op) { %>
63
+ @Override
64
+ public Page<<%= rootEntity.name %>> <%= op.jpaMethodName %>(<%= op.fieldJavaType %> <%= op.fieldName %>, Pageable pageable) {
65
+ return jpaRepository.<%= op.jpaMethodName %>(<%= op.fieldName %>, pageable)
66
+ .map(mapper::toDomain);
67
+ }
68
+ <% }); %>
69
+ <% } %>
61
70
  }
@@ -6,32 +6,37 @@ import org.springframework.transaction.event.TransactionalEventListener;
6
6
  <% domainEvents.forEach(event => { %>
7
7
  import <%= packageName %>.<%= moduleName %>.domain.models.events.<%= event.name %>;
8
8
  <% }); %>
9
- <% if (hasKafkaEvents) { %>
10
- import <%= packageName %>.<%= moduleName %>.domain.repositories.MessageBroker;
9
+ <% if (broker) { %>
10
+ <% domainEvents.forEach(event => { %>
11
+ import <%= packageName %>.<%= moduleName %>.application.events.<%= event.integrationEventClassName %>;
12
+ <% }); %>
13
+ import <%= packageName %>.<%= moduleName %>.application.ports.MessageBroker;
11
14
  <% } %>
12
15
 
13
16
  /**
14
17
  * <%= aggregateName %>DomainEventHandler — Domain Event Bridge
15
18
  *
16
- * This handler connects the internal Spring event bus (ApplicationEventPublisher)
17
- * with the external messaging port (MessageBroker).
19
+ * Connects the internal Spring event bus (ApplicationEventPublisher) with the
20
+ * external messaging port (MessageBroker).
18
21
  *
19
22
  * Architecture:
20
23
  * AggregateRepositoryImpl.save()
21
- * → eventPublisher.publishEvent(domainEvent) [internal Spring bus]
22
- * → @TransactionalEventListener(AFTER_COMMIT) [this class]
23
- * → messageBroker.send*(event) [port — broker-agnostic]
24
+ * → eventPublisher.publishEvent(domainEvent) [internal Spring bus]
25
+ * → @TransactionalEventListener(AFTER_COMMIT) [this class]
26
+ * → messageBroker.publish*(integrationEvent) [port — broker-agnostic]
24
27
  *
25
- * AFTER_COMMIT ensures the external event is only published if the
26
- * database transaction committed successfully, preventing ghost events
27
- * from rolled-back operations.
28
+ * AFTER_COMMIT guarantees that external events are published only when the
29
+ * database transaction committed successfully, preventing ghost events from
30
+ * rolled-back operations.
28
31
  *
29
- * To switch brokers (Kafka RabbitMQ SNS): change only the MessageBroker
30
- * adapter in infrastructure/. This class never needs modification.
32
+ * Domain Events (domain/models/events/) — internal signals scoped to this bounded context.
33
+ * Integration Events (application/events/) broker-facing projections; changing broker
34
+ * technology (Kafka → RabbitMQ → SNS) only requires changing the MessageBroker adapter.
35
+ * Domain Events — and therefore this class — never need modification.
31
36
  */
32
37
  @ApplicationComponent
33
38
  public class <%= aggregateName %>DomainEventHandler {
34
- <% if (hasKafkaEvents) { %>
39
+ <% if (broker) { %>
35
40
 
36
41
  private final MessageBroker messageBroker;
37
42
 
@@ -42,16 +47,15 @@ public class <%= aggregateName %>DomainEventHandler {
42
47
  <% domainEvents.forEach(event => { %>
43
48
 
44
49
  /**
45
- * Handles {@link <%= event.name %>} after the wrapping transaction commits.
46
- * <% if (!event.kafka) { %>
50
+ * Handles {@link <%= event.name %>} after the wrapping transaction commits.<% if (!broker) { %>
51
+ * <p>
47
52
  * TODO: Implement the side effect for this event (e.g., send notification,
48
- * update a read model, trigger a saga step, etc.).
49
- * <% } %>
53
+ * update a read model, trigger a saga step, etc.).<% } %>
50
54
  */
51
55
  @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
52
- public void on<%= event.name %>(<%= event.name %> event) {
53
- <% if (event.kafka) { %>
54
- messageBroker.send<%= event.name %>(event);
56
+ public void on<%= event.name %>(<%= event.name %> event) {
57
+ <% if (broker) { %>
58
+ messageBroker.publish<%= event.integrationEventClassName %>(new <%= event.integrationEventClassName %>(<% if (event.fields && event.fields.length > 0) { event.fields.forEach(function(field, idx) { %>event.get<%= field.name.charAt(0).toUpperCase() + field.name.slice(1) %>()<%= idx < event.fields.length - 1 ? ', ' : '' %><% }); } %>));
55
59
  <% } else { %>
56
60
  // TODO: handle <%= event.name %> — add your side-effect logic here
57
61
  // e.g.: notificationService.notify(event);
@@ -8,4 +8,9 @@ import <%= packageName %>.<%= moduleName %>.infrastructure.database.entities.<%=
8
8
  * Spring Data JPA repository
9
9
  */
10
10
  public interface <%= rootEntity.name %>JpaRepository extends JpaRepository<<%= rootEntity.name %>Jpa, <%= rootEntity.fields[0].javaType %>> {
11
+ <% if (findByOps && findByOps.length > 0) { %>
12
+ <% findByOps.forEach(function(op) { %>
13
+ org.springframework.data.domain.Page<<%= rootEntity.name %>Jpa> <%= op.jpaMethodName %>(<%= op.fieldJavaType %> <%= op.fieldName %>, org.springframework.data.domain.Pageable pageable);
14
+ <% }); %>
15
+ <% } %>
11
16
  }