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
package/test-c2010.js DELETED
@@ -1,49 +0,0 @@
1
- const fs = require('fs');
2
- const yaml = require('js-yaml');
3
-
4
- // Test 1: Clean products.yaml should have 0 C2-010 errors
5
- const p = yaml.load(fs.readFileSync('system/products.yaml', 'utf8'));
6
- const agg = p.aggregates[0];
7
- const root = agg.entities.find(e => e.isRoot);
8
- const flds = new Set(root.fields.map(f => f.name));
9
- const base = root.name[0].toLowerCase() + root.name.slice(1);
10
-
11
- let errors = 0;
12
- for (const ev of agg.events || []) {
13
- if (!ev.lifecycle) continue;
14
- for (const ef of ev.fields || []) {
15
- if (ef.name === base + 'Id') continue;
16
- if (ef.name.endsWith('At') && ef.type === 'LocalDateTime') continue;
17
- if (!flds.has(ef.name)) {
18
- console.log(' C2-010:', ev.name, '->', ef.name);
19
- errors++;
20
- }
21
- }
22
- }
23
- console.log('Test 1 (clean): C2-010 errors =', errors, errors === 0 ? 'PASS' : 'FAIL');
24
-
25
- // Test 2: Simulate adding 'status' field — should trigger C2-010
26
- const fakeEvent = { name: 'FakeEvent', lifecycle: 'create', fields: [
27
- { name: 'productId', type: 'String' },
28
- { name: 'name', type: 'String' },
29
- { name: 'status', type: 'String' }, // NOT in entity
30
- { name: 'deletedAt', type: 'LocalDateTime' } // auto-resolved, should be excluded
31
- ]};
32
- let errors2 = 0;
33
- for (const ef of fakeEvent.fields) {
34
- if (ef.name === base + 'Id') continue;
35
- if (ef.name.endsWith('At') && ef.type === 'LocalDateTime') continue;
36
- if (!flds.has(ef.name)) {
37
- console.log(' C2-010:', fakeEvent.name, '->', ef.name);
38
- errors2++;
39
- }
40
- }
41
- console.log('Test 2 (with status): C2-010 errors =', errors2, errors2 === 1 ? 'PASS' : 'FAIL');
42
-
43
- // Test 3: Verify exclusions work
44
- console.log('Test 3: productId excluded =', !flds.has('productId') ? 'YES (correct)' : 'NO');
45
- console.log('Test 3: deactivatedAt excluded = YES (correct, auto-temporal)');
46
- console.log('Test 3: name included =', flds.has('name') ? 'YES (correct, entity field)' : 'NO');
47
-
48
- // Cleanup
49
- process.exit(errors === 0 && errors2 === 1 ? 0 : 1);
@@ -1,109 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Verification: backward compatibility — no lifecycle events → old reconstruction pattern.
4
- * Also tests: lifecycle: update + lifecycle: delete → raise() is public.
5
- */
6
- const ejs = require('ejs');
7
- const fs = require('fs');
8
- const path = require('path');
9
-
10
- const { resolveLifecycleEventArgs } = require('./src/utils/yaml-to-entity');
11
-
12
- // ── Test 1: No lifecycle events ─────────────────────────────────────────────
13
-
14
- const entityFields = [
15
- { name: 'id', javaType: 'String' },
16
- { name: 'name', javaType: 'String' },
17
- { name: 'price', javaType: 'BigDecimal' },
18
- { name: 'createdAt', javaType: 'LocalDateTime' },
19
- { name: 'updatedAt', javaType: 'LocalDateTime' }
20
- ];
21
-
22
- const commandFields = entityFields.filter(f =>
23
- f.name !== 'id' && f.name !== 'createdAt' && f.name !== 'updatedAt' &&
24
- f.name !== 'createdBy' && f.name !== 'updatedBy' && f.name !== 'deletedAt' && !f.readOnly
25
- );
26
-
27
- const handlerTemplate = fs.readFileSync(path.join(__dirname, 'templates/crud/UpdateCommandHandler.java.ejs'), 'utf8');
28
-
29
- const handlerNoLifecycle = ejs.render(handlerTemplate, {
30
- packageName: 'com.test',
31
- moduleName: 'products',
32
- aggregateName: 'Product',
33
- rootEntity: { fields: entityFields },
34
- commandFields: commandFields,
35
- oneToOneRelationships: [],
36
- oneToManyRelationships: [],
37
- lifecycleEventsMap: {}
38
- });
39
-
40
- let passed = 0;
41
- let failed = 0;
42
-
43
- function assert(condition, msg) {
44
- if (condition) { passed++; console.log(`✅ ${msg}`); }
45
- else { failed++; console.log(`❌ ${msg}`); }
46
- }
47
-
48
- console.log('=== Test 1: No lifecycle events (backward compat) ===\n');
49
-
50
- assert(handlerNoLifecycle.includes('Product updated = new Product('), 'Handler uses full-constructor reconstruction');
51
- assert(handlerNoLifecycle.includes('repository.save(updated)'), 'Handler saves updated (reconstructed)');
52
- assert(!handlerNoLifecycle.includes('existing.update('), 'Handler does NOT call existing.update()');
53
- assert(handlerNoLifecycle.includes('Reconstructs the Product'), 'Javadoc mentions reconstruction');
54
-
55
- // ── Test 2: lifecycle: update + delete → raise() is public ──────────────────
56
-
57
- console.log('\n=== Test 2: lifecycle update + delete → public raise() ===\n');
58
-
59
- const lifecycleBoth = {
60
- update: [{ name: 'PUpdated', lifecycle: 'update', fields: [{ name: 'productId', javaType: 'String' }] }],
61
- delete: [{ name: 'PDeleted', lifecycle: 'delete', fields: [{ name: 'productId', javaType: 'String' }] }]
62
- };
63
- const resolvedBoth = resolveLifecycleEventArgs(lifecycleBoth, 'Product', entityFields, []);
64
-
65
- const rootTemplate = fs.readFileSync(path.join(__dirname, 'templates/aggregate/AggregateRoot.java.ejs'), 'utf8');
66
- const rootBoth = ejs.render(rootTemplate, {
67
- packageName: 'com.test',
68
- moduleName: 'products',
69
- name: 'Product',
70
- fields: entityFields,
71
- relationships: [],
72
- imports: ['import java.math.BigDecimal;'],
73
- valueObjects: [],
74
- aggregateMethods: [],
75
- auditable: true,
76
- hasSoftDelete: false,
77
- domainEvents: [{ name: 'PUpdated' }, { name: 'PDeleted' }],
78
- triggeredEventsMap: {},
79
- lifecycleEventsMap: resolvedBoth
80
- });
81
-
82
- const raiseMatch = rootBoth.match(/(public|protected) void raise\(DomainEvent/);
83
- assert(raiseMatch && raiseMatch[1] === 'public', 'raise() is public when lifecycle:delete exists');
84
- assert(rootBoth.includes('public void update('), 'update() method generated alongside delete lifecycle');
85
-
86
- // ── Test 3: AggregateRoot without lifecycle → no update() method ────────────
87
-
88
- console.log('\n=== Test 3: No lifecycle → no update() method ===\n');
89
-
90
- const rootNoLifecycle = ejs.render(rootTemplate, {
91
- packageName: 'com.test',
92
- moduleName: 'products',
93
- name: 'Product',
94
- fields: entityFields,
95
- relationships: [],
96
- imports: ['import java.math.BigDecimal;'],
97
- valueObjects: [],
98
- aggregateMethods: [],
99
- auditable: true,
100
- hasSoftDelete: false,
101
- domainEvents: [],
102
- triggeredEventsMap: {},
103
- lifecycleEventsMap: {}
104
- });
105
-
106
- assert(!rootNoLifecycle.includes('public void update('), 'No update() method when no lifecycle events');
107
-
108
- console.log(`\n${passed} passed, ${failed} failed`);
109
- process.exit(failed > 0 ? 1 : 0);
@@ -1,121 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Verification script: renders AggregateRoot.java.ejs and UpdateCommandHandler.java.ejs
4
- * with lifecycle: update event data and checks the output.
5
- */
6
- const ejs = require('ejs');
7
- const fs = require('fs');
8
- const path = require('path');
9
-
10
- const { resolveLifecycleEventArgs } = require('./src/utils/yaml-to-entity');
11
-
12
- // ── Test data ──────────────────────────────────────────────────────────────
13
-
14
- const lifecycleEventsMapRaw = {
15
- update: [{
16
- name: 'ProductUpdatedEvent',
17
- lifecycle: 'update',
18
- fields: [
19
- { name: 'productId', javaType: 'String' },
20
- { name: 'name', javaType: 'String' },
21
- { name: 'price', javaType: 'BigDecimal' },
22
- { name: 'updatedAt', javaType: 'LocalDateTime' }
23
- ]
24
- }]
25
- };
26
-
27
- const entityFields = [
28
- { name: 'id', javaType: 'String' },
29
- { name: 'name', javaType: 'String' },
30
- { name: 'description', javaType: 'String' },
31
- { name: 'price', javaType: 'BigDecimal' },
32
- { name: 'status', javaType: 'ProductStatus', readOnly: true, autoInit: true, autoInitValue: 'DRAFT' },
33
- { name: 'createdAt', javaType: 'LocalDateTime' },
34
- { name: 'updatedAt', javaType: 'LocalDateTime' },
35
- { name: 'createdBy', javaType: 'String' },
36
- { name: 'updatedBy', javaType: 'String' }
37
- ];
38
-
39
- const resolvedLifecycle = resolveLifecycleEventArgs(lifecycleEventsMapRaw, 'Product', entityFields, []);
40
-
41
- // ── Render AggregateRoot ────────────────────────────────────────────────────
42
-
43
- const rootTemplate = fs.readFileSync(path.join(__dirname, 'templates/aggregate/AggregateRoot.java.ejs'), 'utf8');
44
- const rootResult = ejs.render(rootTemplate, {
45
- packageName: 'com.test',
46
- moduleName: 'products',
47
- name: 'Product',
48
- fields: entityFields,
49
- relationships: [],
50
- imports: ['import java.math.BigDecimal;'],
51
- valueObjects: [],
52
- aggregateMethods: [],
53
- auditable: true,
54
- hasSoftDelete: false,
55
- domainEvents: [{ name: 'ProductUpdatedEvent' }],
56
- triggeredEventsMap: {},
57
- lifecycleEventsMap: resolvedLifecycle
58
- });
59
-
60
- console.log('=== AggregateRoot.java (relevant sections) ===\n');
61
-
62
- // Extract raise() visibility
63
- const raiseMatch = rootResult.match(/(public|protected) void raise\(DomainEvent/);
64
- console.log(`raise() visibility: ${raiseMatch ? raiseMatch[1] : 'NOT FOUND'}`);
65
-
66
- // Extract update() method
67
- const updateMethodMatch = rootResult.match(/\/\/ ─── Update Method[\s\S]*?(?=\n \/\/ )/);
68
- if (updateMethodMatch) {
69
- console.log('\nupdate() method:\n');
70
- console.log(updateMethodMatch[0]);
71
- } else {
72
- console.log('\n❌ ERROR: update() method NOT generated!');
73
- }
74
-
75
- // ── Render UpdateCommandHandler ──────────────────────────────────────────────
76
-
77
- const handlerTemplate = fs.readFileSync(path.join(__dirname, 'templates/crud/UpdateCommandHandler.java.ejs'), 'utf8');
78
-
79
- const commandFields = entityFields.filter(f =>
80
- f.name !== 'id' && f.name !== 'createdAt' && f.name !== 'updatedAt' &&
81
- f.name !== 'createdBy' && f.name !== 'updatedBy' && f.name !== 'deletedAt' && !f.readOnly
82
- );
83
-
84
- const handlerResult = ejs.render(handlerTemplate, {
85
- packageName: 'com.test',
86
- moduleName: 'products',
87
- aggregateName: 'Product',
88
- rootEntity: { fields: entityFields },
89
- commandFields: commandFields,
90
- oneToOneRelationships: [],
91
- oneToManyRelationships: [],
92
- lifecycleEventsMap: resolvedLifecycle
93
- });
94
-
95
- console.log('\n\n=== UpdateCommandHandler.java ===\n');
96
- console.log(handlerResult);
97
-
98
- // ── Assertions ──────────────────────────────────────────────────────────────
99
-
100
- let passed = 0;
101
- let failed = 0;
102
-
103
- function assert(condition, msg) {
104
- if (condition) { passed++; console.log(`✅ ${msg}`); }
105
- else { failed++; console.log(`❌ ${msg}`); }
106
- }
107
-
108
- console.log('\n=== Assertions ===\n');
109
-
110
- assert(raiseMatch && raiseMatch[1] === 'protected', 'raise() is protected (no lifecycle:delete)');
111
- assert(rootResult.includes('public void update('), 'AggregateRoot has update() method');
112
- assert(rootResult.includes('raise(new ProductUpdatedEvent('), 'update() method calls raise()');
113
- assert(rootResult.includes('this.name = name;'), 'update() assigns fields');
114
- assert(!handlerResult.includes('updated.raise('), 'Handler does NOT call updated.raise()');
115
- assert(!handlerResult.includes('import com.test.products.domain.models.events'), 'Handler does NOT import domain events');
116
- assert(handlerResult.includes('existing.update('), 'Handler calls existing.update()');
117
- assert(handlerResult.includes('repository.save(existing)'), 'Handler saves existing (not updated)');
118
- assert(!handlerResult.includes('Product updated = new Product('), 'Handler does NOT reconstruct entity');
119
-
120
- console.log(`\n${passed} passed, ${failed} failed`);
121
- process.exit(failed > 0 ? 1 : 0);