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
@@ -1,10 +1,176 @@
1
1
  package <%= packageName %>.<%= moduleName %>.application.usecases;
2
+ <%
3
+ // ─── Dual mode: rich (from temporal-system) or simple (from temporal-flow) ──
4
+ const isRichMode = typeof stubActivities !== 'undefined' && Array.isArray(stubActivities);
5
+ -%>
6
+ <% if (isRichMode) { -%>
7
+ <%
8
+ // ─── Helper: parse timeout string to Duration call ──────────────────────────
9
+ function durationOf(t) {
10
+ if (!t) return 'Duration.ofSeconds(30)';
11
+ return `Duration.of${t.unit}(${t.value})`;
12
+ }
13
+ -%>
14
+
15
+ import io.temporal.activity.ActivityOptions;
16
+ import io.temporal.common.RetryOptions;
17
+ <% if (isSaga) { -%>
18
+ import io.temporal.workflow.Saga;
19
+ <% } -%>
20
+ <% if (hasParallelSteps || hasAsyncSteps) { -%>
21
+ import io.temporal.workflow.Async;
22
+ <% } -%>
23
+ <% if (hasParallelSteps) { -%>
24
+ import io.temporal.workflow.Promise;
25
+ <% } -%>
26
+ import io.temporal.workflow.Workflow;
27
+
28
+ import java.time.Duration;
29
+ <% /* Collect imports for all shared + local activity interfaces and DTOs */ -%>
30
+ <%
31
+ // Build imports with a Map keyed by simple name to prevent duplicate-simple-name
32
+ // compile errors when a local nestedType and a shared type share the same class name.
33
+ // Rule: shared imports (*.shared.domain.contracts.*) always win over local ones.
34
+ const importMap = new Map(); // simpleName → full import statement
35
+ function addImport(fqn) {
36
+ const simpleName = fqn.split('.').pop().replace(';', '');
37
+ const existing = importMap.get(simpleName);
38
+ if (!existing) {
39
+ importMap.set(simpleName, fqn);
40
+ } else if (existing !== fqn) {
41
+ // Collision: prefer shared contract over local dtos/temporal
42
+ if (fqn.includes('.shared.domain.contracts.')) importMap.set(simpleName, fqn);
43
+ }
44
+ }
45
+ -%>
46
+ <% for (const stub of stubActivities) { -%>
47
+ <% if (stub.isLocal) { -%>
48
+ <% addImport(`import ${packageName}.${moduleName}.application.ports.${stub.interfaceName};`); -%>
49
+ <% if (stub.hasInput) addImport(`import ${packageName}.${moduleName}.application.dtos.temporal.${stub.activityName}Input;`); -%>
50
+ <% if (stub.hasOutput) addImport(`import ${packageName}.${moduleName}.application.dtos.temporal.${stub.activityName}Output;`); -%>
51
+ <% if (stub.nestedTypeImports) for (const nti of stub.nestedTypeImports) { addImport(nti.isExternal ? `import ${packageName}.shared.domain.contracts.${nti.sourceModule}.${nti.name};` : `import ${packageName}.${moduleName}.application.dtos.temporal.${nti.name};`); } -%>
52
+ <% } else { -%>
53
+ <% addImport(`import ${packageName}.shared.domain.contracts.${stub.targetModule}.${stub.interfaceName};`); -%>
54
+ <% if (stub.hasInput) addImport(`import ${packageName}.shared.domain.contracts.${stub.targetModule}.${stub.activityName}Input;`); -%>
55
+ <% if (stub.hasOutput) addImport(`import ${packageName}.shared.domain.contracts.${stub.targetModule}.${stub.activityName}Output;`); -%>
56
+ <% if (stub.nestedTypeImports) for (const nti of stub.nestedTypeImports) { addImport(nti.isExternal ? `import ${packageName}.shared.domain.contracts.${nti.sourceModule}.${nti.name};` : `import ${packageName}.shared.domain.contracts.${stub.targetModule}.${nti.name};`); } -%>
57
+ <% } -%>
58
+ <% } -%>
59
+ <%= Array.from(importMap.values()).sort().join('\n') %>
60
+
61
+ public class <%= flowPascalCase %>WorkFlowImpl implements <%= flowPascalCase %>WorkFlow {
62
+
63
+ // ─── Activity stubs ─────────────────────────────────────────────────────
64
+ <% for (const stub of stubActivities) { %>
65
+ private final <%= stub.interfaceName %> <%= stub.stubVarName %> = Workflow.newActivityStub(
66
+ <%= stub.interfaceName %>.class,
67
+ ActivityOptions.newBuilder()
68
+ .setTaskQueue("<%= stub.queue %>")
69
+ .setStartToCloseTimeout(<%= durationOf(stub.timeout) %>)
70
+ .setRetryOptions(
71
+ RetryOptions.newBuilder()
72
+ .setMaximumAttempts(2)
73
+ .setInitialInterval(Duration.ofSeconds(1))
74
+ .setMaximumInterval(Duration.ofSeconds(10))
75
+ .setBackoffCoefficient(2.0)
76
+ .build()
77
+ ).build());
78
+ <% } -%>
79
+
80
+ private String status = "PENDING";
81
+
82
+ @Override
83
+ public void start(<%= flowPascalCase %>Input input) {
84
+ <% if (isSaga) { -%>
85
+ Saga saga = new Saga(new Saga.Options.Builder().setParallelCompensation(false).build());
86
+ try {
87
+ <% } -%>
88
+ <%
89
+ // ─── Render blocks ──────────────────────────────────────────────────────────
90
+ const indent = isSaga ? ' ' : ' ';
91
+ for (const block of renderBlocks) {
92
+ if (block.type === 'sequential') {
93
+ const step = block.step;
94
+ -%>
95
+ <%= indent %>// Step <%= step.index + 1 %>: <%= step.activityName %><%= step.isLocal ? ' (local)' : ` (→ ${step.targetModule})` %><%= step.isOptional ? ' [optional]' : '' %>
96
+ <% if (step.isOptional) { -%>
97
+ <%= indent %>try {
98
+ <% } -%>
99
+ <% const optIndent = step.isOptional ? indent + ' ' : indent; -%>
100
+ <% if (step.hasOutput) { -%>
101
+ <%= optIndent %><%= step.activityName %>Output <%= step.activityCamel %>Result = <%= step.activityCamel %>Activity.execute(<% if (step.hasInput) { %>
102
+ <%= optIndent %> new <%= step.activityName %>Input(<%= step.inputSources.map(src => src.source === 'input' ? `input.${src.fieldName}()` : `${src.varName}.${src.fieldName}()`).join(', ') %>)<% } %>);
103
+ <% } else { -%>
104
+ <%= optIndent %><%= step.activityCamel %>Activity.execute(<% if (step.hasInput) { %>
105
+ <%= optIndent %> new <%= step.activityName %>Input(<%= step.inputSources.map(src => src.source === 'input' ? `input.${src.fieldName}()` : `${src.varName}.${src.fieldName}()`).join(', ') %>)<% } %>);
106
+ <% } -%>
107
+ <% if (step.compensation && isSaga) { -%>
108
+ <%= optIndent %>saga.addCompensation(() -> <%= step.compensation.name.charAt(0).toLowerCase() + step.compensation.name.slice(1) %>Activity.execute(
109
+ <%= optIndent %> new <%= step.compensation.name %>Input(<%= step.compensation.inputSources.map(src => src.source === 'input' ? `input.${src.fieldName}()` : `${src.varName}.${src.fieldName}()`).join(', ') %>)));
110
+ <% } -%>
111
+ <% if (step.isOptional) { -%>
112
+ <%= indent %>} catch (Exception e) {
113
+ <%= indent %> // Optional step — continue on failure
114
+ <%= indent %>}
115
+ <% } -%>
116
+
117
+ <% } else if (block.type === 'parallel') { -%>
118
+ <%= indent %>// Steps <%= block.steps.map(s => s.index + 1).join('-') %>: Parallel execution
119
+ <% for (const step of block.steps) { -%>
120
+ <% if (step.hasOutput) { -%>
121
+ <%= indent %>Promise<<%= step.activityName %>Output> <%= step.activityCamel %>Promise = Async.function(
122
+ <%= indent %> () -> <%= step.activityCamel %>Activity.execute(<% if (step.hasInput) { %>new <%= step.activityName %>Input(<%= step.inputSources.map(src => src.source === 'input' ? `input.${src.fieldName}()` : `${src.varName}.${src.fieldName}()`).join(', ') %>)<% } %>));
123
+ <% } else { -%>
124
+ <%= indent %>Promise<Void> <%= step.activityCamel %>Promise = Async.procedure(
125
+ <%= indent %> () -> <%= step.activityCamel %>Activity.execute(<% if (step.hasInput) { %>new <%= step.activityName %>Input(<%= step.inputSources.map(src => src.source === 'input' ? `input.${src.fieldName}()` : `${src.varName}.${src.fieldName}()`).join(', ') %>)<% } %>));
126
+ <% } -%>
127
+ <% if (step.compensation && isSaga) { -%>
128
+ <%= indent %>saga.addCompensation(() -> <%= step.compensation.name.charAt(0).toLowerCase() + step.compensation.name.slice(1) %>Activity.execute(
129
+ <%= indent %> new <%= step.compensation.name %>Input(<%= step.compensation.inputSources.map(src => src.source === 'input' ? `input.${src.fieldName}()` : `${src.varName}.${src.fieldName}()`).join(', ') %>)));
130
+ <% } -%>
131
+ <% } -%>
132
+
133
+ <%= indent %>// Wait for parallel results
134
+ <% for (const step of block.steps) { -%>
135
+ <% if (step.hasOutput) { -%>
136
+ <%= indent %><%= step.activityName %>Output <%= step.activityCamel %>Result = <%= step.activityCamel %>Promise.get();
137
+ <% } else { -%>
138
+ <%= indent %><%= step.activityCamel %>Promise.get();
139
+ <% } -%>
140
+ <% } -%>
141
+
142
+ <% } else if (block.type === 'async') {
143
+ const step = block.step;
144
+ -%>
145
+ <%= indent %>// Step <%= step.index + 1 %>: <%= step.activityName %> (fire-and-forget → <%= step.targetModule %>)
146
+ <%= indent %>Async.procedure(() -> <%= step.activityCamel %>Activity.execute(<% if (step.hasInput) { %>
147
+ <%= indent %> new <%= step.activityName %>Input(<%= step.inputSources.map(src => src.source === 'input' ? `input.${src.fieldName}()` : `${src.varName}.${src.fieldName}()`).join(', ') %>)<% } %>));
148
+
149
+ <% }
150
+ } /* end renderBlocks loop */ -%>
151
+ <% if (isSaga) { -%>
152
+ this.status = "COMPLETED";
153
+ } catch (Exception e) {
154
+ saga.compensate();
155
+ this.status = "COMPENSATED";
156
+ throw e;
157
+ }
158
+ <% } else { -%>
159
+ this.status = "COMPLETED";
160
+ <% } -%>
161
+ }
162
+
163
+ @Override
164
+ public String getStatus() {
165
+ return this.status;
166
+ }
167
+ }
168
+ <% } else { -%>
169
+ <%/* ─── Simple mode (from eva g temporal-flow) ─────────────────────────────── */%>
2
170
 
3
171
  import io.temporal.activity.ActivityOptions;
4
172
  import io.temporal.common.RetryOptions;
5
173
  import io.temporal.workflow.Saga;
6
- import io.temporal.workflow.SignalMethod;
7
- import io.temporal.workflow.QueryMethod;
8
174
  import io.temporal.workflow.Workflow;
9
175
 
10
176
  import java.time.Duration;
@@ -19,7 +185,7 @@ public class <%= flowPascalCase %>WorkFlowImpl implements <%= flowPascalCase %>W
19
185
 
20
186
  private final ActivityOptions lightActivityOptions = ActivityOptions.newBuilder()
21
187
  .setStartToCloseTimeout(Duration.ofSeconds(30))
22
- .setTaskQueue("LIGHT_TASK_QUEUE")
188
+ .setTaskQueue("<%= moduleScreamingSnake %>_LIGHT_TASK_QUEUE")
23
189
  .setRetryOptions(
24
190
  RetryOptions.newBuilder()
25
191
  .setMaximumAttempts(2)
@@ -31,7 +197,7 @@ public class <%= flowPascalCase %>WorkFlowImpl implements <%= flowPascalCase %>W
31
197
 
32
198
  private final ActivityOptions heavyActivityOptions = ActivityOptions.newBuilder()
33
199
  .setStartToCloseTimeout(Duration.ofSeconds(120))
34
- .setTaskQueue("HEAVY_TASK_QUEUE")
200
+ .setTaskQueue("<%= moduleScreamingSnake %>_HEAVY_TASK_QUEUE")
35
201
  .setRetryOptions(
36
202
  RetryOptions.newBuilder()
37
203
  .setMaximumAttempts(2)
@@ -42,7 +208,7 @@ public class <%= flowPascalCase %>WorkFlowImpl implements <%= flowPascalCase %>W
42
208
  ).build();
43
209
 
44
210
  @Override
45
- public void start(String workFlowId) {
211
+ public void start(String flowId) {
46
212
  try {
47
213
  //todo: workflow logic
48
214
  } catch (Exception e) {
@@ -50,15 +216,9 @@ public class <%= flowPascalCase %>WorkFlowImpl implements <%= flowPascalCase %>W
50
216
  }
51
217
  }
52
218
 
53
- @SignalMethod
54
- @Override
55
- public void confirm() {
56
-
57
- }
58
-
59
- @QueryMethod
60
219
  @Override
61
220
  public String getStatus() {
62
221
  return "";
63
222
  }
64
223
  }
224
+ <% } -%>
@@ -0,0 +1,11 @@
1
+ package <%= packageName %>.<%= moduleName %>.application.usecases;
2
+ <% if (inputImports && inputImports.length > 0) { %>
3
+ <% inputImports.forEach(imp => { -%>
4
+ <%= imp %>
5
+ <% }); -%>
6
+ <% } %>
7
+ public record <%= flowPascalCase %>Input(
8
+ <% inputFields.forEach((field, i) => { -%>
9
+ <%- field.javaType %> <%= field.name %><%= i < inputFields.length - 1 ? ',' : '' %>
10
+ <% }); -%>
11
+ ) {}
@@ -1,18 +1,19 @@
1
1
  package <%= packageName %>.<%= moduleName %>.application.usecases;
2
2
 
3
3
  import io.temporal.workflow.QueryMethod;
4
- import io.temporal.workflow.SignalMethod;
5
4
  import io.temporal.workflow.WorkflowInterface;
6
5
  import io.temporal.workflow.WorkflowMethod;
7
6
 
8
7
  @WorkflowInterface
9
8
  public interface <%= flowPascalCase %>WorkFlow {
9
+ <% const hasTypedInput = typeof inputFields !== 'undefined' && inputFields.length > 0; -%>
10
10
 
11
11
  @WorkflowMethod
12
+ <% if (hasTypedInput) { -%>
13
+ void start(<%= flowPascalCase %>Input input);
14
+ <% } else { -%>
12
15
  void start(String flowId);
13
-
14
- @SignalMethod
15
- void confirm();
16
+ <% } -%>
16
17
 
17
18
  @QueryMethod
18
19
  String getStatus();
@@ -10,38 +10,68 @@ public class <%= flowPascalCase %>WorkFlowService {
10
10
 
11
11
  private final WorkflowClient workflowClient;
12
12
  private final String flowQueue;
13
+ <% const hasTypedInput = typeof inputFields !== 'undefined' && inputFields.length > 0; -%>
13
14
 
14
15
  public <%= flowPascalCase %>WorkFlowService(
15
16
  WorkflowClient workflowClient,
16
- @Value("${temporal.flow-queue}") String flowQueue
17
+ @Value("${temporal.modules.<%= moduleName %>.flow-queue}") String flowQueue
17
18
  ) {
18
19
  this.workflowClient = workflowClient;
19
20
  this.flowQueue = flowQueue;
20
21
  }
21
22
 
23
+ <% if (hasTypedInput) { -%>
24
+ /**
25
+ * Starts the workflow asynchronously with the full typed input.
26
+ */
27
+ public void startAsync(String workflowId, <%= flowPascalCase %>Input input) {
28
+ <%= flowPascalCase %>WorkFlow workflow = getWorkflow(workflowId);
29
+ WorkflowClient.start(workflow::start, input);
30
+ }
31
+
32
+ /**
33
+ * Starts the workflow synchronously with the full typed input.
34
+ */
35
+ public void startSync(String workflowId, <%= flowPascalCase %>Input input) {
36
+ <%= flowPascalCase %>WorkFlow workflow = getWorkflow(workflowId);
37
+ workflow.start(input);
38
+ }
39
+
40
+ /**
41
+ * Bridge method — starts the workflow using only the aggregate ID.
42
+ * <p>
43
+ * The generated {@code DomainEventHandler} calls
44
+ * {@link #startAsync(String, <%= flowPascalCase %>Input)} directly with a
45
+ * typed input constructed from the domain event fields. Use this overload
46
+ * only from custom code that can build the input by other means.
47
+ *
48
+ * @throws UnsupportedOperationException always — override or call the typed variant
49
+ */
50
+ public void startAsync(String workflowId) {
51
+ throw new UnsupportedOperationException(
52
+ "Use startAsync(workflowId, " + "<%= flowPascalCase %>Input) — "
53
+ + "the DomainEventHandler already calls the typed variant");
54
+ }
55
+ <% } else { -%>
22
56
  public void startAsync(String flowId) {
23
- <%= flowPascalCase %>WorkFlow workflow = get<%= flowPascalCase %>WorkFlow(flowId);
57
+ <%= flowPascalCase %>WorkFlow workflow = getWorkflow(flowId);
24
58
  WorkflowClient.start(workflow::start, flowId);
25
59
  }
26
60
 
27
61
  public void startSync(String flowId) {
28
- <%= flowPascalCase %>WorkFlow workflow = get<%= flowPascalCase %>WorkFlow(flowId);
62
+ <%= flowPascalCase %>WorkFlow workflow = getWorkflow(flowId);
29
63
  workflow.start(flowId);
30
64
  }
65
+ <% } -%>
31
66
 
32
- public void confirm(String flowId) {
33
- <%= flowPascalCase %>WorkFlow workflow = get<%= flowPascalCase %>WorkFlow(flowId);
34
- workflow.confirm();
35
- }
36
-
37
- public String getStatus(String flowId) {
38
- <%= flowPascalCase %>WorkFlow workflow = get<%= flowPascalCase %>WorkFlow(flowId);
67
+ public String getStatus(String workflowId) {
68
+ <%= flowPascalCase %>WorkFlow workflow = getWorkflow(workflowId);
39
69
  return workflow.getStatus();
40
70
  }
41
71
 
42
- private <%= flowPascalCase %>WorkFlow get<%= flowPascalCase %>WorkFlow(String flowId) {
72
+ private <%= flowPascalCase %>WorkFlow getWorkflow(String workflowId) {
43
73
  WorkflowOptions options = WorkflowOptions.newBuilder()
44
- .setWorkflowId(flowId)
74
+ .setWorkflowId(workflowId)
45
75
  .setTaskQueue(flowQueue)
46
76
  .build();
47
77
  return workflowClient.newWorkflowStub(<%= flowPascalCase %>WorkFlow.class, options);