eva4j 1.0.13 → 1.0.15
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 +314 -10
- package/COMMAND_EVALUATION.md +15 -16
- package/DOMAIN_YAML_GUIDE.md +576 -10
- package/FUTURE_FEATURES.md +1627 -1168
- package/README.md +318 -13
- package/bin/eva4j.js +34 -0
- package/config/defaults.json +1 -0
- package/design-system.md +797 -0
- package/docs/commands/EVALUATE_SYSTEM.md +994 -0
- package/docs/commands/GENERATE_ENTITIES.md +795 -6
- package/docs/commands/INDEX.md +10 -1
- package/examples/domain-endpoints-relations.yaml +353 -0
- package/examples/domain-endpoints-versioned.yaml +144 -0
- package/examples/domain-endpoints.yaml +135 -0
- package/examples/domain-events.yaml +166 -20
- package/examples/domain-listeners.yaml +212 -0
- package/examples/domain-one-to-many.yaml +1 -0
- package/examples/domain-one-to-one.yaml +1 -0
- package/examples/domain-ports.yaml +414 -0
- package/examples/domain-soft-delete.yaml +47 -44
- package/examples/system/notification.yaml +147 -0
- package/examples/system/product.yaml +185 -0
- package/examples/system/system.yaml +112 -0
- package/examples/system-report.html +971 -0
- package/examples/system.yaml +332 -0
- package/package.json +2 -1
- package/src/commands/build.js +714 -0
- package/src/commands/create.js +7 -3
- package/src/commands/detach.js +1 -0
- package/src/commands/evaluate-system.js +610 -0
- package/src/commands/generate-entities.js +1331 -49
- package/src/commands/generate-http-exchange.js +2 -0
- package/src/commands/generate-kafka-event.js +98 -11
- package/src/generators/base-generator.js +8 -1
- package/src/generators/postman-generator.js +188 -0
- package/src/generators/shared-generator.js +10 -0
- package/src/utils/config-manager.js +54 -0
- package/src/utils/context-builder.js +1 -0
- package/src/utils/domain-diagram.js +192 -0
- package/src/utils/domain-validator.js +970 -0
- package/src/utils/fake-data.js +376 -0
- package/src/utils/naming.js +3 -2
- package/src/utils/system-validator.js +434 -0
- package/src/utils/yaml-to-entity.js +302 -8
- package/templates/aggregate/AggregateMapper.java.ejs +3 -2
- package/templates/aggregate/AggregateRepository.java.ejs +8 -2
- package/templates/aggregate/AggregateRepositoryImpl.java.ejs +13 -3
- package/templates/aggregate/AggregateRoot.java.ejs +60 -2
- package/templates/aggregate/DomainEventHandler.java.ejs +27 -20
- package/templates/aggregate/DomainEventRecord.java.ejs +24 -8
- package/templates/aggregate/DomainEventSnapshot.java.ejs +46 -0
- package/templates/aggregate/JpaAggregateRoot.java.ejs +6 -0
- package/templates/aggregate/JpaRepository.java.ejs +5 -0
- package/templates/base/gradle/build.gradle.ejs +3 -2
- package/templates/base/root/AGENTS.md.ejs +306 -45
- package/templates/base/root/skill-build-domain-yaml-references-generate-entities.md.ejs +1663 -0
- package/templates/base/root/skill-build-system-yaml.ejs +1446 -0
- package/templates/base/root/system.yaml.ejs +97 -0
- package/templates/crud/ApplicationMapper.java.ejs +4 -0
- package/templates/crud/Controller.java.ejs +4 -4
- package/templates/crud/CreateCommand.java.ejs +4 -0
- package/templates/crud/CreateItemDto.java.ejs +4 -0
- package/templates/crud/CreateValueObjectDto.java.ejs +4 -0
- package/templates/crud/DeleteCommandHandler.java.ejs +10 -2
- package/templates/crud/EndpointsController.java.ejs +178 -0
- package/templates/crud/FindByQuery.java.ejs +17 -0
- package/templates/crud/FindByQueryHandler.java.ejs +57 -0
- package/templates/crud/ListQuery.java.ejs +1 -1
- package/templates/crud/ListQueryHandler.java.ejs +8 -8
- package/templates/crud/ScaffoldCommand.java.ejs +12 -0
- package/templates/crud/ScaffoldCommandHandler.java.ejs +43 -0
- package/templates/crud/ScaffoldQuery.java.ejs +13 -0
- package/templates/crud/ScaffoldQueryHandler.java.ejs +41 -0
- package/templates/crud/SubEntityAddCommand.java.ejs +21 -0
- package/templates/crud/SubEntityAddCommandHandler.java.ejs +43 -0
- package/templates/crud/SubEntityRemoveCommand.java.ejs +9 -0
- package/templates/crud/SubEntityRemoveCommandHandler.java.ejs +42 -0
- package/templates/crud/TransitionCommand.java.ejs +9 -0
- package/templates/crud/TransitionCommandHandler.java.ejs +39 -0
- package/templates/crud/UpdateCommand.java.ejs +4 -0
- package/templates/evaluate/report.html.ejs +1363 -0
- package/templates/kafka-event/DomainEventHandlerMethod.ejs +3 -1
- package/templates/kafka-event/Event.java.ejs +16 -0
- package/templates/kafka-listener/KafkaController.java.ejs +1 -1
- package/templates/kafka-listener/KafkaListenerClass.java.ejs +1 -1
- package/templates/kafka-listener/ListenerClass.java.ejs +65 -0
- package/templates/kafka-listener/ListenerCommand.java.ejs +31 -0
- package/templates/kafka-listener/ListenerCommandHandler.java.ejs +23 -0
- package/templates/kafka-listener/ListenerIntegrationEvent.java.ejs +37 -0
- package/templates/kafka-listener/ListenerMethod.java.ejs +1 -1
- package/templates/kafka-listener/ListenerNestedType.java.ejs +28 -0
- package/templates/mock/MockEvent.java.ejs +10 -0
- package/templates/mock/MockMessageBrokerImpl.java.ejs +35 -0
- package/templates/mock/MockMessageBrokerImplMethod.java.ejs +6 -0
- package/templates/mock/SpringEventListener.java.ejs +61 -0
- package/templates/ports/PortDomainModel.java.ejs +35 -0
- package/templates/ports/PortFeignAdapter.java.ejs +67 -0
- package/templates/ports/PortFeignClient.java.ejs +45 -0
- package/templates/ports/PortFeignConfig.java.ejs +24 -0
- package/templates/ports/PortInterface.java.ejs +45 -0
- package/templates/ports/PortNestedType.java.ejs +28 -0
- package/templates/ports/PortRequestDto.java.ejs +30 -0
- package/templates/ports/PortResponseDto.java.ejs +28 -0
- package/templates/postman/Collection.json.ejs +1 -1
- package/templates/postman/UnifiedCollection.json.ejs +185 -0
- package/templates/shared/configurations/eventPublicationConfig/EventPublicationSchemaConfig.java.ejs +109 -0
package/README.md
CHANGED
|
@@ -37,23 +37,124 @@ eva g entities product
|
|
|
37
37
|
|
|
38
38
|
## 💎 Why eva4j?
|
|
39
39
|
|
|
40
|
-
### The
|
|
40
|
+
### The real problem: AI agents cannot generate production-quality code directly
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
42
|
+
The biggest bottleneck is no longer writing repetitive code — it's the gap between **business requirements** and **production code with the right architecture**.
|
|
43
|
+
|
|
44
|
+
Teams today try to solve this in two ways, both with serious problems:
|
|
45
|
+
|
|
46
|
+
**Option A — Direct prompt to the agent:** _"Create an inventory system with Spring Boot, PostgreSQL, Kafka, hexagonal architecture, CQRS..."_
|
|
47
|
+
|
|
48
|
+
The agent generates something... but:
|
|
49
|
+
- ❌ Architecture varies between modules — inconsistent
|
|
50
|
+
- ❌ Hexagonal patterns are applied partially or incorrectly
|
|
51
|
+
- ❌ No convention on where each class belongs
|
|
52
|
+
- ❌ The code doesn't compile as a whole
|
|
53
|
+
- ❌ Each regeneration produces something different
|
|
54
|
+
- ❌ Impossible to iterate incrementally
|
|
55
|
+
|
|
56
|
+
**Option B — Spec Driven Development (SDD):** _"Given this functional specification document, generate the code following these patterns..."_
|
|
57
|
+
|
|
58
|
+
One step ahead of the free prompt: instead of an informal description, the agent receives a more structured functional specification — use cases, flows, business rules. The agent generates more organized code, but the underlying problem remains:
|
|
59
|
+
|
|
60
|
+
- ⚠️ The agent must simultaneously focus on **two different planes**: interpreting the functional domain and producing code with the right architecture — and it tends to lose one when it digs into the other
|
|
61
|
+
- ⚠️ Functional specifications don't dictate technical structure: the agent makes architecture decisions each session, producing different results
|
|
62
|
+
- ⚠️ Ensuring consistency across modules requires ever more exhaustive specifications — and even then the generated code needs deep review
|
|
63
|
+
- ⚠️ Every requirement change means regenerating and manually auditing the code to detect accumulated regressions or inconsistencies
|
|
64
|
+
- ⚠️ **A change in the system definition translates into a code refactoring** — with hard-to-measure impact, prone to integration errors, and potentially affecting modules that appear unrelated to the change
|
|
65
|
+
- ⚠️ Before working on business logic, the team must stand up the entire infrastructure (database, messaging broker)
|
|
66
|
+
|
|
67
|
+
SDD improves the situation, but **still sends the agent to the wrong plane**: from the functional specification straight to code — skipping a fundamental intermediate layer.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
### The new vision: technology-agnostic technical specifications as an intermediate step
|
|
72
|
+
|
|
73
|
+
The problem with SDD is not the specification itself — it's that the **functional** specification is converted directly into code. The solution is to introduce an intermediate step: transform functional requirements into **technology-agnostic technical specifications** before generating a single line of code.
|
|
74
|
+
|
|
75
|
+
These technical specifications don't talk about Spring Boot, JPA or Kafka. They talk about **domain entities, lifecycles, events, relationships between modules and API contracts**. They are understandable by the agent, the business team, and the generator — and can be reviewed, discussed, and iterated without touching code.
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
┌──────────────────────────────────────────────────────────────────┐
|
|
79
|
+
│ LAYER 1 — Functional requirements │
|
|
80
|
+
│ (business describes what the system must do) │
|
|
81
|
+
└───────────────────────────────┬──────────────────────────────────┘
|
|
82
|
+
│ AI agent
|
|
83
|
+
│ (translates domain into structure)
|
|
84
|
+
┌───────────────────────────────▼──────────────────────────────────┐
|
|
85
|
+
│ LAYER 2 — Technology-agnostic technical specification │
|
|
86
|
+
│ (agent + team iterate here — no code) │
|
|
87
|
+
│ │
|
|
88
|
+
│ system.yaml + {module}.yaml │
|
|
89
|
+
│ • Which modules (bounded contexts) make up the system? │
|
|
90
|
+
│ • How many aggregates does each module have? │
|
|
91
|
+
│ • Which entities form each aggregate? Which is the root? │
|
|
92
|
+
│ • What fields and types does each entity have? │
|
|
93
|
+
│ • What lifecycle do entities have (states/transitions)? │
|
|
94
|
+
│ • What events occur? Who produces them and who consumes them? │
|
|
95
|
+
│ • How do modules communicate with each other? │
|
|
96
|
+
│ • What endpoints does each module expose and what use case? │
|
|
97
|
+
│ │
|
|
98
|
+
│ Reviewable · Versionable · Evaluable · Iterable │
|
|
99
|
+
│ without needing to generate any code │
|
|
100
|
+
└───────────────────────────────┬──────────────────────────────────┘
|
|
101
|
+
│ eva build
|
|
102
|
+
│ (when the team validates
|
|
103
|
+
│ that the specification is correct)
|
|
104
|
+
┌───────────────────────────────▼──────────────────────────────────┐
|
|
105
|
+
│ LAYER 3 — Code (eva4j generates, team completes) │
|
|
106
|
+
│ │
|
|
107
|
+
│ technical specification ──▶ functional Spring Boot prototype │
|
|
108
|
+
│ • Compiles from the first build │
|
|
109
|
+
│ • Endpoints respond immediately │
|
|
110
|
+
│ • No infrastructure required │
|
|
111
|
+
│ (--mock: H2 + Spring Events) │
|
|
112
|
+
└──────────────────────────────────────────────────────────────────┘
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**The agent does what it does well:** translating functional requirements into technology-agnostic technical specifications — modeling the domain, identifying entities, defining lifecycles, designing contracts between modules. The result is a precise and verifiable YAML, not code.
|
|
116
|
+
|
|
117
|
+
**The team validates the specification** before a single line of Java exists — discussing entities, relationships and flows in a format readable by everyone.
|
|
118
|
+
|
|
119
|
+
**eva4j does what the agent cannot do reliably:** converting that specification into code with correct hexagonal architecture, CQRS, DDD patterns and multi-environment configuration — identically every time, no matter how many times it runs.
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
### From prototype to production with minimal friction
|
|
124
|
+
|
|
125
|
+
Eva4j does not generate a production-ready complete system in a single step — it generates a **functional and correct prototype** that the team can complement and iterate from day one:
|
|
126
|
+
|
|
127
|
+
| What `eva build` delivers | What the team completes |
|
|
128
|
+
|---|---|
|
|
129
|
+
| Domain entities with constructors, getters and lifecycle methods | Domain-specific business logic |
|
|
130
|
+
| Correctly structured CQRS handlers | The body of each handler (`UnsupportedOperationException` as a visible placeholder) |
|
|
131
|
+
| JSR-303 validations, DTOs, Application↔Domain↔JPA mappers | Complex business validations and cross-aggregate rules |
|
|
132
|
+
| Kafka, Feign, JPA multi-environment configuration | Specific queries, indexes, performance tuning |
|
|
133
|
+
| REST endpoints that respond from day 1 | Edge cases, business error handling |
|
|
134
|
+
| Optional mock infrastructure (H2 + Spring Events) | Integration with real infrastructure when the model is validated |
|
|
135
|
+
|
|
136
|
+
**The full cycle:**
|
|
137
|
+
|
|
138
|
+
1. The agent generates specifications from business requirements (`system.yaml` + `{module}.yaml`)
|
|
139
|
+
2. The team reviews and validates that the specification correctly reflects the domain — without seeing code
|
|
140
|
+
3. `eva build` → the prototype starts; endpoints respond; the team completes business logic **from day 1 without infrastructure**
|
|
141
|
+
4. Requirements evolve → update the YAML → `eva build` regenerates safely (checksums protect manual modifications)
|
|
142
|
+
5. When the prototype meets all verified requirements, moving to production is a configuration change — not a rewrite
|
|
143
|
+
|
|
144
|
+
**A change in the system definition is a YAML diff — not a code refactoring.** The impact is always measurable: exactly the files that correspond to what changed in the specification. The new build faithfully reflects the new design, with no residue from the previous one.
|
|
145
|
+
|
|
146
|
+
---
|
|
48
147
|
|
|
49
148
|
### The Solution
|
|
50
149
|
|
|
51
150
|
eva4j provides:
|
|
52
|
-
- ✅ **
|
|
53
|
-
- ✅ **
|
|
54
|
-
- ✅ **
|
|
55
|
-
- ✅ **
|
|
56
|
-
- ✅ **
|
|
151
|
+
- ✅ **Specification as contract** - The YAML is the artifact that the agent, the team and the generator share — reviewable, versionable, evaluable before generating a single line of code
|
|
152
|
+
- ✅ **Deterministic generation** - The same YAML always produces the same code, with no session-to-session variations
|
|
153
|
+
- ✅ **Functional prototype from day 1** - The team works on business logic while the specification continues to be refined
|
|
154
|
+
- ✅ **No infrastructure from the start** - `--mock` replaces Kafka and the DB with in-memory equivalents
|
|
155
|
+
- ✅ **Safe iteration** - Checksums prevent overwriting manual modifications on regeneration
|
|
156
|
+
- ✅ **Consistent architecture** - Same patterns across all modules, no architectural drift
|
|
157
|
+
- ✅ **Technology-agnostic specification** - The YAML describes domain structure, not framework details — while the current generator targets Spring Boot, the same specification is designed to power generators for other stacks and languages
|
|
57
158
|
|
|
58
159
|
---
|
|
59
160
|
|
|
@@ -195,7 +296,211 @@ Eva4j follows a **pragmatic approach** to microservices architecture:
|
|
|
195
296
|
|
|
196
297
|
---
|
|
197
298
|
|
|
198
|
-
##
|
|
299
|
+
## 📐 Specification Files: `system/`
|
|
300
|
+
|
|
301
|
+
eva4j projects store their specifications in the `system/` directory. These are the files an AI agent produces when designing a system: declarative structure, no side effects, verifiable before any code generation runs.
|
|
302
|
+
|
|
303
|
+
```
|
|
304
|
+
system/
|
|
305
|
+
├── system.yaml # Global architecture: modules, database, messaging, integrations
|
|
306
|
+
├── product.yaml # Domain model for the product module
|
|
307
|
+
├── notification.yaml # Domain model for the notification module
|
|
308
|
+
└── order.yaml # Domain model for the order module
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### `system.yaml` — The System Architecture
|
|
312
|
+
|
|
313
|
+
Defines which modules exist, how they communicate, and what infrastructure they use.
|
|
314
|
+
|
|
315
|
+
```yaml
|
|
316
|
+
system:
|
|
317
|
+
name: product-catalog
|
|
318
|
+
groupId: com.example
|
|
319
|
+
javaVersion: 21
|
|
320
|
+
springBootVersion: 3.5.5
|
|
321
|
+
database: postgresql # postgresql | mysql | h2
|
|
322
|
+
|
|
323
|
+
messaging:
|
|
324
|
+
enabled: true
|
|
325
|
+
broker: kafka
|
|
326
|
+
kafka:
|
|
327
|
+
bootstrapServers: localhost:9092
|
|
328
|
+
defaultGroupId: product-catalog
|
|
329
|
+
|
|
330
|
+
modules:
|
|
331
|
+
- name: product
|
|
332
|
+
description: "Product catalogue. Lifecycle: DRAFT → PUBLISHED → DISCONTINUED."
|
|
333
|
+
exposes:
|
|
334
|
+
- method: POST
|
|
335
|
+
path: /products
|
|
336
|
+
useCase: CreateProduct
|
|
337
|
+
- method: GET
|
|
338
|
+
path: /products/{id}
|
|
339
|
+
useCase: GetProduct
|
|
340
|
+
- method: PUT
|
|
341
|
+
path: /products/{id}/publish
|
|
342
|
+
useCase: PublishProduct
|
|
343
|
+
description: "Transition DRAFT → PUBLISHED. Emits ProductPublishedEvent."
|
|
344
|
+
|
|
345
|
+
- name: notification
|
|
346
|
+
description: "Notifications via EMAIL, SMS or PUSH. Reacts to product domain events."
|
|
347
|
+
exposes:
|
|
348
|
+
- method: PUT
|
|
349
|
+
path: /notifications/{id}/read
|
|
350
|
+
useCase: MarkNotificationRead
|
|
351
|
+
|
|
352
|
+
integrations:
|
|
353
|
+
async:
|
|
354
|
+
# Which module produces each event and which module consumes it
|
|
355
|
+
- event: ProductPublishedEvent
|
|
356
|
+
producer: product
|
|
357
|
+
topic: PRODUCT_PUBLISHED
|
|
358
|
+
consumers:
|
|
359
|
+
- module: notification
|
|
360
|
+
useCase: SendProductPublishedNotification
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
`eva build` reads this file and generates: modules with complete hexagonal architecture, Kafka dependencies, `KafkaConfig.java`, REST endpoints with their use cases, Integration Events, KafkaListeners and consumer CommandHandlers.
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
### `{module}.yaml` — The Domain Model
|
|
368
|
+
|
|
369
|
+
Each module has its own YAML that defines the complete domain model: entities, value objects, enums with lifecycle transitions, relationships, events and ports.
|
|
370
|
+
|
|
371
|
+
```yaml
|
|
372
|
+
# system/product.yaml
|
|
373
|
+
aggregates:
|
|
374
|
+
- name: Product
|
|
375
|
+
entities:
|
|
376
|
+
- name: Product
|
|
377
|
+
isRoot: true
|
|
378
|
+
tableName: products
|
|
379
|
+
audit:
|
|
380
|
+
enabled: true
|
|
381
|
+
trackUser: true
|
|
382
|
+
fields:
|
|
383
|
+
- name: id
|
|
384
|
+
type: String
|
|
385
|
+
- name: name
|
|
386
|
+
type: String
|
|
387
|
+
validations:
|
|
388
|
+
- type: NotBlank
|
|
389
|
+
message: "Product name is required"
|
|
390
|
+
- name: price
|
|
391
|
+
type: Price # Value Object defined below
|
|
392
|
+
- name: status
|
|
393
|
+
type: ProductStatus # Enum with lifecycle transitions
|
|
394
|
+
readOnly: true # Excluded from CreateDto and business constructor
|
|
395
|
+
|
|
396
|
+
valueObjects:
|
|
397
|
+
- name: Price
|
|
398
|
+
fields:
|
|
399
|
+
- name: amount
|
|
400
|
+
type: BigDecimal
|
|
401
|
+
- name: currency
|
|
402
|
+
type: String
|
|
403
|
+
methods:
|
|
404
|
+
- name: isPositive
|
|
405
|
+
returnType: boolean
|
|
406
|
+
parameters: []
|
|
407
|
+
body: "return this.amount.compareTo(BigDecimal.ZERO) > 0;"
|
|
408
|
+
|
|
409
|
+
enums:
|
|
410
|
+
- name: ProductStatus
|
|
411
|
+
initialValue: DRAFT
|
|
412
|
+
transitions:
|
|
413
|
+
- from: DRAFT
|
|
414
|
+
to: PUBLISHED
|
|
415
|
+
method: publish
|
|
416
|
+
- from: [DRAFT, PUBLISHED]
|
|
417
|
+
to: DISCONTINUED
|
|
418
|
+
method: discontinue
|
|
419
|
+
values: [DRAFT, PUBLISHED, DISCONTINUED]
|
|
420
|
+
|
|
421
|
+
events:
|
|
422
|
+
- name: ProductPublishedEvent
|
|
423
|
+
triggers: [publish] # raise() automatically injected inside publish()
|
|
424
|
+
fields:
|
|
425
|
+
- name: productId
|
|
426
|
+
type: String
|
|
427
|
+
- name: publishedAt
|
|
428
|
+
type: LocalDateTime
|
|
429
|
+
|
|
430
|
+
# Consuming external events
|
|
431
|
+
listeners:
|
|
432
|
+
- event: OrderPlacedEvent
|
|
433
|
+
producer: orders
|
|
434
|
+
topic: ORDER_PLACED
|
|
435
|
+
useCase: UpdateProductStock
|
|
436
|
+
fields:
|
|
437
|
+
- name: orderId
|
|
438
|
+
type: String
|
|
439
|
+
- name: quantity
|
|
440
|
+
type: Integer
|
|
441
|
+
|
|
442
|
+
# Synchronous HTTP clients
|
|
443
|
+
ports:
|
|
444
|
+
- name: findCategoryById
|
|
445
|
+
service: CategoryService
|
|
446
|
+
target: categories
|
|
447
|
+
baseUrl: http://localhost:8040
|
|
448
|
+
http: GET /categories/{id}
|
|
449
|
+
fields:
|
|
450
|
+
- name: id
|
|
451
|
+
type: String
|
|
452
|
+
- name: name
|
|
453
|
+
type: String
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
`eva g entities product` generates from this single YAML: domain entity (no setters, no empty constructor), JPA entity, repository, lifecycle methods (`publish()`, `discontinue()`, `canPublish()`, `isPublished()`), Integration Event, `MessageBroker` port, `KafkaMessageBroker` adapter, consumer `KafkaListener`, `FeignClient` with ACL, `CreateProductCommand`, `ProductResponseDto`, Application↔Domain↔JPA mappers and `ProductController`.
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
### The AI → YAML → Code cycle
|
|
461
|
+
|
|
462
|
+
```bash
|
|
463
|
+
# 1. The AI agent generates the YAMLs from business requirements
|
|
464
|
+
# → system/system.yaml, system/product.yaml, system/notification.yaml
|
|
465
|
+
|
|
466
|
+
# 2. One command turns the entire specification into code
|
|
467
|
+
eva build
|
|
468
|
+
# ✅ Modules created with full hexagonal architecture
|
|
469
|
+
# ✅ Kafka configured and wired
|
|
470
|
+
# ✅ Entities, handlers, DTOs, mappers generated
|
|
471
|
+
# ✅ The project compiles and starts immediately
|
|
472
|
+
|
|
473
|
+
./gradlew bootRun # Endpoints already respond
|
|
474
|
+
|
|
475
|
+
# 3. The developer implements only the domain-specific business logic
|
|
476
|
+
# Handlers have UnsupportedOperationException as a visible placeholder
|
|
477
|
+
# Entities have the correct structure ready to be completed
|
|
478
|
+
|
|
479
|
+
# 4. When the domain evolves, update the YAMLs and regenerate
|
|
480
|
+
eva build # Checksums protect manual modifications
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
### `eva build --mock` — Iterate without external infrastructure
|
|
484
|
+
|
|
485
|
+
Develop without needing to start Kafka or a real database:
|
|
486
|
+
|
|
487
|
+
```bash
|
|
488
|
+
eva build --mock # DB → H2 in-memory + Kafka → Spring Event bus
|
|
489
|
+
eva build --mock --only-broker # Broker only, keeps the configured database
|
|
490
|
+
eva build # Restores the original configuration
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
| Flag | Database | Broker |
|
|
494
|
+
|---|---|---|
|
|
495
|
+
| `eva build --mock` | H2 in-memory | Spring Event bus |
|
|
496
|
+
| `eva build --mock --only-broker` | Unchanged (PostgreSQL/MySQL) | Spring Event bus |
|
|
497
|
+
| `eva build` (restore) | Original | Kafka |
|
|
498
|
+
|
|
499
|
+
The original configuration is saved to `.eva4j.json` and restored automatically.
|
|
500
|
+
|
|
501
|
+
---
|
|
502
|
+
|
|
503
|
+
## �📥 Installation
|
|
199
504
|
|
|
200
505
|
```bash
|
|
201
506
|
npm install -g eva4j
|
package/bin/eva4j.js
CHANGED
|
@@ -16,6 +16,8 @@ const generateRecordCommand = require('../src/commands/generate-record');
|
|
|
16
16
|
const generateEntitiesCommand = require('../src/commands/generate-entities');
|
|
17
17
|
const generateTemporalFlowCommand = require('../src/commands/generate-temporal-flow');
|
|
18
18
|
const generateTemporalActivityCommand = require('../src/commands/generate-temporal-activity');
|
|
19
|
+
const buildCommand = require('../src/commands/build');
|
|
20
|
+
const evaluateSystemCommand = require('../src/commands/evaluate-system');
|
|
19
21
|
const infoCommand = require('../src/commands/info');
|
|
20
22
|
const detachCommand = require('../src/commands/detach');
|
|
21
23
|
|
|
@@ -278,6 +280,37 @@ program
|
|
|
278
280
|
process.exit(1);
|
|
279
281
|
});
|
|
280
282
|
|
|
283
|
+
// Build command
|
|
284
|
+
program
|
|
285
|
+
.command('build')
|
|
286
|
+
.description('Bootstrap project from system/system.yaml: create modules, install broker client, copy domain.yaml files, and generate entities')
|
|
287
|
+
.option('--force', 'Overwrite files even if they were manually modified (bypasses safe mode)')
|
|
288
|
+
.option('--mock', 'Replace database config with H2 in-memory before building (restored automatically after build)')
|
|
289
|
+
.option('--only-broker', 'Only switch the broker to Spring Event bus, keeping the current database unchanged (requires --mock)')
|
|
290
|
+
.action(async (options) => {
|
|
291
|
+
try {
|
|
292
|
+
await buildCommand(options);
|
|
293
|
+
} catch (error) {
|
|
294
|
+
console.error(chalk.red('Error:'), error.message);
|
|
295
|
+
process.exit(1);
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
// Evaluate command
|
|
300
|
+
program
|
|
301
|
+
.command('evaluate <type>')
|
|
302
|
+
.description('Validate and visualize project artifacts. type: system')
|
|
303
|
+
.option('--port <port>', 'Port for the web server (default: 3000)')
|
|
304
|
+
.option('--output <path>', 'Output path for the HTML report (default: ./system-report.html)')
|
|
305
|
+
.action(async (type, options) => {
|
|
306
|
+
try {
|
|
307
|
+
await evaluateSystemCommand(type, options);
|
|
308
|
+
} catch (error) {
|
|
309
|
+
console.error(chalk.red('Error:'), error.message);
|
|
310
|
+
process.exit(1);
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
|
|
281
314
|
// Info command
|
|
282
315
|
program
|
|
283
316
|
.command('info')
|
|
@@ -322,6 +355,7 @@ program.on('--help', () => {
|
|
|
322
355
|
console.log(chalk.gray(' $ eva4j g record'));
|
|
323
356
|
console.log(chalk.gray(' $ eva4j detach user'));
|
|
324
357
|
console.log(chalk.gray(' $ eva4j info'));
|
|
358
|
+
console.log(chalk.gray(' $ eva4j evaluate system'));
|
|
325
359
|
console.log('');
|
|
326
360
|
console.log(chalk.blue('For more information, visit:'));
|
|
327
361
|
console.log(chalk.gray(' https://github.com/your-repo/eva4j'));
|