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.
- package/AGENTS.md +2 -0
- package/DOMAIN_YAML_GUIDE.md +3 -1
- package/QUICK_REFERENCE.md +8 -4
- package/bin/eva4j.js +70 -2
- package/config/defaults.json +1 -0
- package/docs/CAMUNDA_DMN_GUIDE.md +1380 -0
- package/docs/KAFKA_PRODUCTION_CONFIG.md +441 -0
- package/docs/RABBITMQ_PRODUCTION_CONFIG.md +227 -0
- package/docs/commands/ADD_RABBITMQ_CLIENT.md +192 -0
- package/docs/commands/EVALUATE_SYSTEM.md +272 -8
- package/docs/commands/GENERATE_RABBITMQ_EVENT.md +341 -0
- package/docs/commands/GENERATE_RABBITMQ_LISTENER.md +595 -0
- package/docs/commands/GENERATE_TEMPORAL_FLOW.md +52 -12
- package/docs/commands/INDEX.md +27 -3
- package/docs/prototype/TEMPORAL_COMMUNICATION_PATTERNS.md +731 -0
- package/docs/prototype/TEMPORAL_DESIGN_METHODOLOGY.md +740 -0
- package/docs/prototype/system/RISKS.md +277 -0
- package/docs/prototype/system/customers.yaml +133 -0
- package/docs/prototype/system/inventory.yaml +109 -0
- package/docs/prototype/system/notifications.yaml +131 -0
- package/docs/prototype/system/orders.yaml +241 -0
- package/docs/prototype/system/payments.yaml +256 -0
- package/docs/prototype/system/products.yaml +168 -0
- package/docs/prototype/system/system.yaml +269 -0
- package/examples/domain-endpoints-multi-aggregate.yaml +140 -0
- package/examples/domain-read-models.yaml +2 -2
- package/examples/system/customer.yaml +89 -0
- package/examples/system/orders.yaml +119 -0
- package/examples/system/product.yaml +27 -0
- package/examples/system/system.yaml +80 -0
- package/package.json +1 -1
- package/src/agents/design-gap-analyst-temporal.agent.md +452 -0
- package/src/agents/design-gap-analyst.agent.md +383 -0
- package/src/agents/design-reviewer-temporal.agent.md +412 -0
- package/src/agents/design-reviewer.agent.md +31 -5
- package/src/agents/implement-use-cases.prompt.md +179 -0
- package/src/agents/ux-gap-analyst.agent.md +412 -0
- package/src/commands/add-rabbitmq-client.js +261 -0
- package/src/commands/add-temporal-client.js +22 -2
- package/src/commands/build.js +267 -11
- package/src/commands/evaluate-system.js +700 -13
- package/src/commands/generate-entities.js +308 -16
- package/src/commands/generate-rabbitmq-event.js +665 -0
- package/src/commands/generate-rabbitmq-listener.js +205 -0
- package/src/commands/generate-temporal-activity.js +968 -34
- package/src/commands/generate-temporal-flow.js +95 -38
- package/src/commands/generate-temporal-system.js +708 -0
- package/src/skills/build-system-yaml/SKILL.md +222 -2
- package/src/skills/build-system-yaml/references/domain-yaml-spec.md +50 -4
- package/src/skills/build-system-yaml/references/module-spec.md +57 -8
- package/src/skills/build-temporal-system/SKILL.md +752 -0
- package/src/skills/build-temporal-system/references/temporal-communication-patterns.md +167 -0
- package/src/skills/build-temporal-system/references/temporal-domain-yaml-spec.md +449 -0
- package/src/skills/build-temporal-system/references/temporal-module-spec.md +353 -0
- package/src/skills/build-temporal-system/references/temporal-system-yaml-spec.md +326 -0
- package/src/skills/implement-use-case/SKILL.md +350 -0
- package/src/skills/implement-use-case/references/use-case-patterns.md +980 -0
- package/src/skills/requirements-elicitation/SKILL.md +228 -0
- package/src/skills/requirements-elicitation/references/interview-framework.md +260 -0
- package/src/skills/requirements-elicitation/references/output-templates.md +368 -0
- package/src/utils/bounded-context-diagram.js +844 -0
- package/src/utils/domain-validator.js +266 -4
- package/src/utils/naming.js +10 -0
- package/src/utils/system-validator.js +169 -11
- package/src/utils/system-yaml-parser.js +318 -0
- package/src/utils/temporal-validator.js +497 -0
- package/src/utils/yaml-to-entity.js +10 -7
- package/templates/aggregate/DomainEventHandler.java.ejs +116 -22
- package/templates/aggregate/JpaAggregateRoot.java.ejs +2 -2
- package/templates/aggregate/JpaEntity.java.ejs +2 -2
- package/templates/base/docker/rabbitmq-services.yaml.ejs +12 -0
- package/templates/base/resources/parameters/develop/kafka.yaml.ejs +5 -0
- package/templates/base/resources/parameters/develop/rabbitmq.yaml.ejs +15 -0
- package/templates/base/resources/parameters/develop/temporal.yaml.ejs +0 -3
- package/templates/base/resources/parameters/local/kafka.yaml.ejs +5 -0
- package/templates/base/resources/parameters/local/rabbitmq.yaml.ejs +15 -0
- package/templates/base/resources/parameters/local/temporal.yaml.ejs +0 -3
- package/templates/base/resources/parameters/production/kafka.yaml.ejs +39 -8
- package/templates/base/resources/parameters/production/rabbitmq.yaml.ejs +32 -0
- package/templates/base/resources/parameters/production/temporal.yaml.ejs +0 -3
- package/templates/base/resources/parameters/test/kafka.yaml.ejs +12 -6
- package/templates/base/resources/parameters/test/rabbitmq.yaml.ejs +15 -0
- package/templates/base/resources/parameters/test/temporal.yaml.ejs +0 -3
- package/templates/base/root/AGENTS.md.ejs +1 -1
- package/templates/crud/EndpointsController.java.ejs +1 -1
- package/templates/crud/ScaffoldCommand.java.ejs +5 -2
- package/templates/crud/ScaffoldCommandHandler.java.ejs +3 -1
- package/templates/crud/ScaffoldQuery.java.ejs +5 -2
- package/templates/crud/ScaffoldQueryHandler.java.ejs +3 -1
- package/templates/crud/SubEntityRemoveCommand.java.ejs +1 -1
- package/templates/evaluate/report.html.ejs +1447 -90
- package/templates/kafka-event/KafkaConfigBean.java.ejs +1 -1
- package/templates/kafka-event/KafkaMessageBroker.java.ejs +3 -3
- package/templates/ports/PortAclMapper.java.ejs +35 -0
- package/templates/ports/PortFeignAdapter.java.ejs +7 -22
- package/templates/ports/PortFeignClient.java.ejs +4 -0
- package/templates/ports/PortResponseDto.java.ejs +1 -1
- package/templates/rabbitmq-event/RabbitConfigBean.java.ejs +33 -0
- package/templates/rabbitmq-event/RabbitConfigExchange.java.ejs +12 -0
- package/templates/rabbitmq-event/RabbitMessageBroker.java.ejs +35 -0
- package/templates/rabbitmq-event/RabbitMessageBrokerMethod.java.ejs +9 -0
- package/templates/rabbitmq-listener/RabbitConfigConsumerBean.java.ejs +33 -0
- package/templates/rabbitmq-listener/RabbitConfigConsumerExchange.java.ejs +12 -0
- package/templates/rabbitmq-listener/RabbitListenerClass.java.ejs +82 -0
- package/templates/rabbitmq-listener/RabbitListenerSimple.java.ejs +56 -0
- package/templates/read-model/ReadModelJpa.java.ejs +1 -1
- package/templates/read-model/ReadModelJpaRepository.java.ejs +2 -0
- package/templates/read-model/ReadModelRabbitListener.java.ejs +71 -0
- package/templates/read-model/ReadModelRepositoryImpl.java.ejs +9 -5
- package/templates/read-model/ReadModelSyncHandler.java.ejs +2 -0
- package/templates/shared/configurations/kafkaConfig/KafkaConfig.java.ejs +18 -4
- package/templates/shared/configurations/rabbitmqConfig/RabbitMQConfig.java.ejs +100 -0
- package/templates/shared/configurations/temporalConfig/TemporalConfig.java.ejs +2 -64
- package/templates/shared/configurations/temporalConfig/TemporalWorkerFactoryLifecycle.java.ejs +41 -0
- package/templates/temporal-activity/ActivityImpl.java.ejs +68 -2
- package/templates/temporal-activity/ActivityInput.java.ejs +14 -0
- package/templates/temporal-activity/ActivityInterface.java.ejs +7 -1
- package/templates/temporal-activity/ActivityOutput.java.ejs +14 -0
- package/templates/temporal-activity/NestedType.java.ejs +12 -0
- package/templates/temporal-activity/SharedActivityInput.java.ejs +14 -0
- package/templates/temporal-activity/SharedActivityInterface.java.ejs +15 -0
- package/templates/temporal-activity/SharedActivityOutput.java.ejs +14 -0
- package/templates/temporal-activity/SharedNestedType.java.ejs +12 -0
- package/templates/temporal-flow/ModuleHeavyActivity.java.ejs +6 -0
- package/templates/temporal-flow/ModuleLightActivity.java.ejs +6 -0
- package/templates/temporal-flow/ModuleTemporalWorkerConfig.java.ejs +58 -0
- package/templates/temporal-flow/WorkFlowImpl.java.ejs +172 -12
- package/templates/temporal-flow/WorkFlowInput.java.ejs +11 -0
- package/templates/temporal-flow/WorkFlowInterface.java.ejs +5 -4
- package/templates/temporal-flow/WorkFlowService.java.ejs +42 -12
- package/COMMAND_EVALUATION.md +0 -911
- package/test-c2010.js +0 -49
- package/test-update-compat.js +0 -109
- package/test-update-lifecycle.js +0 -121
|
@@ -5,7 +5,7 @@ const path = require('path');
|
|
|
5
5
|
const fs = require('fs-extra');
|
|
6
6
|
const ConfigManager = require('../utils/config-manager');
|
|
7
7
|
const { isEva4jProject, moduleExists } = require('../utils/validator');
|
|
8
|
-
const { toPackagePath, toPascalCase, toCamelCase } = require('../utils/naming');
|
|
8
|
+
const { toPackagePath, toPascalCase, toCamelCase, toScreamingSnakeCase } = require('../utils/naming');
|
|
9
9
|
const { renderAndWrite } = require('../utils/template-engine');
|
|
10
10
|
const ChecksumManager = require('../utils/checksum-manager');
|
|
11
11
|
|
|
@@ -75,6 +75,8 @@ async function generateTemporalFlowCommand(moduleName, flowName, options = {}) {
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
const flowPascalCase = toPascalCase(flowName);
|
|
78
|
+
const modulePascalCase = toPascalCase(moduleName);
|
|
79
|
+
const moduleScreamingSnake = toScreamingSnakeCase(moduleName);
|
|
78
80
|
|
|
79
81
|
const moduleBasePath = path.join(
|
|
80
82
|
projectDir,
|
|
@@ -95,6 +97,9 @@ async function generateTemporalFlowCommand(moduleName, flowName, options = {}) {
|
|
|
95
97
|
packageName,
|
|
96
98
|
moduleName,
|
|
97
99
|
flowPascalCase,
|
|
100
|
+
modulePascalCase,
|
|
101
|
+
moduleCamelCase: moduleName,
|
|
102
|
+
moduleScreamingSnake,
|
|
98
103
|
};
|
|
99
104
|
|
|
100
105
|
const templatesDir = path.join(__dirname, '..', '..', 'templates', 'temporal-flow');
|
|
@@ -128,9 +133,42 @@ async function generateTemporalFlowCommand(moduleName, flowName, options = {}) {
|
|
|
128
133
|
writeOptions
|
|
129
134
|
);
|
|
130
135
|
|
|
131
|
-
// 4.
|
|
132
|
-
spinner.text =
|
|
133
|
-
|
|
136
|
+
// 4. Generate module-scoped marker interfaces (idempotent)
|
|
137
|
+
spinner.text = `Generating ${modulePascalCase} Temporal interfaces...`;
|
|
138
|
+
const interfacesDir = path.join(moduleBasePath, 'domain', 'interfaces');
|
|
139
|
+
await renderAndWrite(
|
|
140
|
+
path.join(templatesDir, 'ModuleHeavyActivity.java.ejs'),
|
|
141
|
+
path.join(interfacesDir, `${modulePascalCase}HeavyActivity.java`),
|
|
142
|
+
context,
|
|
143
|
+
writeOptions
|
|
144
|
+
);
|
|
145
|
+
await renderAndWrite(
|
|
146
|
+
path.join(templatesDir, 'ModuleLightActivity.java.ejs'),
|
|
147
|
+
path.join(interfacesDir, `${modulePascalCase}LightActivity.java`),
|
|
148
|
+
context,
|
|
149
|
+
writeOptions
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// 5. Generate ModuleTemporalWorkerConfig (idempotent)
|
|
153
|
+
spinner.text = `Generating ${modulePascalCase}TemporalWorkerConfig...`;
|
|
154
|
+
const configDir = path.join(moduleBasePath, 'infrastructure', 'configurations');
|
|
155
|
+
await renderAndWrite(
|
|
156
|
+
path.join(templatesDir, 'ModuleTemporalWorkerConfig.java.ejs'),
|
|
157
|
+
path.join(configDir, `${modulePascalCase}TemporalWorkerConfig.java`),
|
|
158
|
+
context,
|
|
159
|
+
writeOptions
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
// 6. Register workflow in module worker config
|
|
163
|
+
spinner.text = 'Registering workflow in module worker config...';
|
|
164
|
+
await registerWorkflowInModuleWorkerConfig(
|
|
165
|
+
path.join(configDir, `${modulePascalCase}TemporalWorkerConfig.java`),
|
|
166
|
+
packageName, moduleName, flowPascalCase, modulePascalCase
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
// 7. Append module queue section to temporal.yaml (idempotent)
|
|
170
|
+
spinner.text = 'Updating temporal.yaml with module queues...';
|
|
171
|
+
await appendModuleQueues(projectDir, moduleName, moduleScreamingSnake);
|
|
134
172
|
|
|
135
173
|
spinner.succeed(chalk.green(`ā
${flowPascalCase}WorkFlow generated successfully`));
|
|
136
174
|
|
|
@@ -138,8 +176,13 @@ async function generateTemporalFlowCommand(moduleName, flowName, options = {}) {
|
|
|
138
176
|
console.log(chalk.gray(` ${moduleName}/application/usecases/${flowPascalCase}WorkFlow.java`));
|
|
139
177
|
console.log(chalk.gray(` ${moduleName}/application/usecases/${flowPascalCase}WorkFlowImpl.java`));
|
|
140
178
|
console.log(chalk.gray(` ${moduleName}/application/usecases/${flowPascalCase}WorkFlowService.java`));
|
|
141
|
-
console.log(chalk.
|
|
142
|
-
console.log(chalk.gray(
|
|
179
|
+
console.log(chalk.gray(` ${moduleName}/domain/interfaces/${modulePascalCase}HeavyActivity.java`));
|
|
180
|
+
console.log(chalk.gray(` ${moduleName}/domain/interfaces/${modulePascalCase}LightActivity.java`));
|
|
181
|
+
console.log(chalk.gray(` ${moduleName}/infrastructure/configurations/${modulePascalCase}TemporalWorkerConfig.java`));
|
|
182
|
+
console.log(chalk.blue('\nš Queue names:'));
|
|
183
|
+
console.log(chalk.gray(` Flow: ${moduleScreamingSnake}_WORKFLOW_QUEUE`));
|
|
184
|
+
console.log(chalk.gray(` Heavy: ${moduleScreamingSnake}_HEAVY_TASK_QUEUE`));
|
|
185
|
+
console.log(chalk.gray(` Light: ${moduleScreamingSnake}_LIGHT_TASK_QUEUE`));
|
|
143
186
|
|
|
144
187
|
await checksumManager.save();
|
|
145
188
|
} catch (error) {
|
|
@@ -149,22 +192,9 @@ async function generateTemporalFlowCommand(moduleName, flowName, options = {}) {
|
|
|
149
192
|
}
|
|
150
193
|
}
|
|
151
194
|
|
|
152
|
-
async function
|
|
153
|
-
const configPath = path.join(
|
|
154
|
-
projectDir,
|
|
155
|
-
'src',
|
|
156
|
-
'main',
|
|
157
|
-
'java',
|
|
158
|
-
packagePath,
|
|
159
|
-
'shared',
|
|
160
|
-
'infrastructure',
|
|
161
|
-
'configurations',
|
|
162
|
-
'temporalConfig',
|
|
163
|
-
'TemporalConfig.java'
|
|
164
|
-
);
|
|
165
|
-
|
|
195
|
+
async function registerWorkflowInModuleWorkerConfig(configPath, packageName, moduleName, flowPascalCase, modulePascalCase) {
|
|
166
196
|
if (!(await fs.pathExists(configPath))) {
|
|
167
|
-
console.warn(chalk.yellow(
|
|
197
|
+
console.warn(chalk.yellow(`\nā ļø ${modulePascalCase}TemporalWorkerConfig.java not found ā skipping auto-registration`));
|
|
168
198
|
return;
|
|
169
199
|
}
|
|
170
200
|
|
|
@@ -175,40 +205,31 @@ async function registerWorkflowInTemporalConfig(projectDir, packagePath, package
|
|
|
175
205
|
|
|
176
206
|
// Add import if not already present
|
|
177
207
|
if (!content.includes(importLine)) {
|
|
178
|
-
const
|
|
179
|
-
if (
|
|
180
|
-
|
|
181
|
-
const
|
|
182
|
-
|
|
183
|
-
const lastImport = allImports[allImports.length - 1];
|
|
184
|
-
const insertPos = lastImport.index + lastImport[0].length;
|
|
185
|
-
content = content.slice(0, insertPos) + '\n' + importLine + content.slice(insertPos);
|
|
186
|
-
}
|
|
208
|
+
const allImports = [...content.matchAll(/^import .+;/gm)];
|
|
209
|
+
if (allImports.length > 0) {
|
|
210
|
+
const lastImport = allImports[allImports.length - 1];
|
|
211
|
+
const insertPos = lastImport.index + lastImport[0].length;
|
|
212
|
+
content = content.slice(0, insertPos) + '\n' + importLine + content.slice(insertPos);
|
|
187
213
|
}
|
|
188
214
|
}
|
|
189
215
|
|
|
190
|
-
// Remove TODO comment and commented-out example placeholder
|
|
191
|
-
content = content.replace(/[ \t]*\/\/ TODO: register your workflow implementation types here\r?\n/g, '');
|
|
192
|
-
content = content.replace(/[ \t]*\/\/ workflowWorker\.registerWorkflowImplementationTypes\(MyWorkflowImpl\.class\);\r?\n?/g, '');
|
|
193
|
-
|
|
194
216
|
// Check if there is already an active registerWorkflowImplementationTypes call
|
|
195
217
|
const activeRegisterRegex = /workflowWorker\.registerWorkflowImplementationTypes\(([^)]+)\);/;
|
|
196
218
|
if (activeRegisterRegex.test(content)) {
|
|
197
|
-
// Add the new class, filtering out the stale MyWorkflowImpl example if still present
|
|
198
219
|
content = content.replace(activeRegisterRegex, (match, classes) => {
|
|
199
220
|
const classList = classes
|
|
200
221
|
.split(',')
|
|
201
222
|
.map((c) => c.trim())
|
|
202
|
-
.filter((c) => c
|
|
223
|
+
.filter((c) => c.length > 0);
|
|
203
224
|
if (!classList.includes(`${implClass}.class`)) {
|
|
204
225
|
classList.push(`${implClass}.class`);
|
|
205
226
|
}
|
|
206
227
|
return `workflowWorker.registerWorkflowImplementationTypes(${classList.join(', ')});`;
|
|
207
228
|
});
|
|
208
229
|
} else {
|
|
209
|
-
// Insert active registration after the
|
|
230
|
+
// Insert active registration after the comment marker
|
|
210
231
|
content = content.replace(
|
|
211
|
-
/(
|
|
232
|
+
/(\/\/ registered by eva g temporal-flow\r?\n)/,
|
|
212
233
|
`$1 workflowWorker.registerWorkflowImplementationTypes(${implClass}.class);\n`
|
|
213
234
|
);
|
|
214
235
|
}
|
|
@@ -216,4 +237,40 @@ async function registerWorkflowInTemporalConfig(projectDir, packagePath, package
|
|
|
216
237
|
await fs.writeFile(configPath, content, 'utf-8');
|
|
217
238
|
}
|
|
218
239
|
|
|
240
|
+
/**
|
|
241
|
+
* Append module-specific queue configuration to temporal.yaml files (idempotent)
|
|
242
|
+
*/
|
|
243
|
+
async function appendModuleQueues(projectDir, moduleName, moduleScreamingSnake) {
|
|
244
|
+
const environments = ['local', 'develop', 'test', 'production'];
|
|
245
|
+
const resourcesDir = path.join(projectDir, 'src', 'main', 'resources', 'parameters');
|
|
246
|
+
|
|
247
|
+
const moduleSection = [
|
|
248
|
+
` ${moduleName}:`,
|
|
249
|
+
` flow-queue: ${moduleScreamingSnake}_WORKFLOW_QUEUE`,
|
|
250
|
+
` heavy-queue: ${moduleScreamingSnake}_HEAVY_TASK_QUEUE`,
|
|
251
|
+
` light-queue: ${moduleScreamingSnake}_LIGHT_TASK_QUEUE`,
|
|
252
|
+
].join('\n');
|
|
253
|
+
|
|
254
|
+
for (const env of environments) {
|
|
255
|
+
const yamlPath = path.join(resourcesDir, env, 'temporal.yaml');
|
|
256
|
+
|
|
257
|
+
if (!(await fs.pathExists(yamlPath))) continue;
|
|
258
|
+
|
|
259
|
+
let content = await fs.readFile(yamlPath, 'utf-8');
|
|
260
|
+
|
|
261
|
+
// Skip if module already registered
|
|
262
|
+
if (content.includes(`${moduleName}:`)) continue;
|
|
263
|
+
|
|
264
|
+
// Add modules: section if not present
|
|
265
|
+
if (!content.includes('modules:')) {
|
|
266
|
+
content = content.trimEnd() + '\n modules:\n' + moduleSection + '\n';
|
|
267
|
+
} else {
|
|
268
|
+
// Append under existing modules: section
|
|
269
|
+
content = content.trimEnd() + '\n' + moduleSection + '\n';
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
await fs.writeFile(yamlPath, content, 'utf-8');
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
219
276
|
module.exports = generateTemporalFlowCommand;
|