eva4j 1.0.0

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 (115) hide show
  1. package/LICENSE +21 -0
  2. package/QUICK_REFERENCE.md +204 -0
  3. package/README.md +912 -0
  4. package/USAGE.md +349 -0
  5. package/bin/eva4j.js +234 -0
  6. package/config/defaults.json +46 -0
  7. package/package.json +57 -0
  8. package/src/commands/add-kafka-client.js +193 -0
  9. package/src/commands/add-module.js +221 -0
  10. package/src/commands/create.js +92 -0
  11. package/src/commands/detach.js +495 -0
  12. package/src/commands/generate-http-exchange.js +309 -0
  13. package/src/commands/generate-kafka-event.js +453 -0
  14. package/src/commands/generate-kafka-listener.js +267 -0
  15. package/src/commands/generate-resource.js +265 -0
  16. package/src/commands/generate-usecase.js +198 -0
  17. package/src/commands/info.js +63 -0
  18. package/src/generators/base-generator.js +150 -0
  19. package/src/generators/module-generator.js +48 -0
  20. package/src/generators/shared-generator.js +153 -0
  21. package/src/utils/config-manager.js +156 -0
  22. package/src/utils/context-builder.js +149 -0
  23. package/src/utils/naming.js +137 -0
  24. package/src/utils/template-engine.js +55 -0
  25. package/src/utils/validator.js +159 -0
  26. package/templates/base/application/Application.java.ejs +27 -0
  27. package/templates/base/docker/docker-compose.yml.ejs +41 -0
  28. package/templates/base/gradle/build.gradle.ejs +70 -0
  29. package/templates/base/gradle/settings.gradle.ejs +1 -0
  30. package/templates/base/resources/application-develop.yml.ejs +5 -0
  31. package/templates/base/resources/application-local.yml.ejs +5 -0
  32. package/templates/base/resources/application-production.yml.ejs +9 -0
  33. package/templates/base/resources/application-test.yml.ejs +5 -0
  34. package/templates/base/resources/application.yml.ejs +31 -0
  35. package/templates/base/resources/parameters/develop/cors.yml.ejs +4 -0
  36. package/templates/base/resources/parameters/develop/db.yaml.ejs +21 -0
  37. package/templates/base/resources/parameters/develop/kafka.yml.ejs +26 -0
  38. package/templates/base/resources/parameters/local/cors.yml.ejs +4 -0
  39. package/templates/base/resources/parameters/local/db.yaml.ejs +21 -0
  40. package/templates/base/resources/parameters/local/kafka.yml.ejs +26 -0
  41. package/templates/base/resources/parameters/production/cors.yml.ejs +4 -0
  42. package/templates/base/resources/parameters/production/db.yaml.ejs +21 -0
  43. package/templates/base/resources/parameters/production/kafka.yml.ejs +26 -0
  44. package/templates/base/root/README.md.ejs +126 -0
  45. package/templates/base/root/gitignore.ejs +42 -0
  46. package/templates/http-exchange/Adapter.java.ejs +39 -0
  47. package/templates/http-exchange/Config.java.ejs +24 -0
  48. package/templates/http-exchange/FeignClient.java.ejs +23 -0
  49. package/templates/http-exchange/Port.java.ejs +14 -0
  50. package/templates/kafka-event/Event.java.ejs +10 -0
  51. package/templates/kafka-event/KafkaConfigBean.java.ejs +7 -0
  52. package/templates/kafka-event/KafkaMessageBroker.java.ejs +32 -0
  53. package/templates/kafka-event/MessageBroker.java.ejs +8 -0
  54. package/templates/kafka-event/MessageBrokerImplMethod.java.ejs +9 -0
  55. package/templates/kafka-event/MessageBrokerMethod.java.ejs +1 -0
  56. package/templates/kafka-listener/KafkaController.java.ejs +34 -0
  57. package/templates/kafka-listener/ListenerMethod.java.ejs +9 -0
  58. package/templates/kafka-listener/ValueField.java.ejs +4 -0
  59. package/templates/module/controller.java.ejs +96 -0
  60. package/templates/module/exception.java.ejs +18 -0
  61. package/templates/module/mapper.java.ejs +67 -0
  62. package/templates/module/model.java.ejs +29 -0
  63. package/templates/module/package-info.java.ejs +7 -0
  64. package/templates/module/repository.java.ejs +26 -0
  65. package/templates/module/request-dto.java.ejs +24 -0
  66. package/templates/module/response-dto.java.ejs +26 -0
  67. package/templates/module/service-impl.java.ejs +112 -0
  68. package/templates/module/service.java.ejs +45 -0
  69. package/templates/module/update-dto.java.ejs +25 -0
  70. package/templates/resource/Command.java.ejs +9 -0
  71. package/templates/resource/CommandHandler.java.ejs +22 -0
  72. package/templates/resource/Controller.java.ejs +73 -0
  73. package/templates/resource/Query.java.ejs +12 -0
  74. package/templates/resource/QueryHandler.java.ejs +31 -0
  75. package/templates/resource/ResponseDto.java.ejs +6 -0
  76. package/templates/shared/annotations/ApplicationComponent.java.ejs +9 -0
  77. package/templates/shared/annotations/DomainComponent.java.ejs +9 -0
  78. package/templates/shared/annotations/LogAfter.java.ejs +11 -0
  79. package/templates/shared/annotations/LogBefore.java.ejs +11 -0
  80. package/templates/shared/annotations/LogExceptions.java.ejs +11 -0
  81. package/templates/shared/annotations/LogTimer.java.ejs +11 -0
  82. package/templates/shared/configurations/kafkaConfig/KafkaConfig.java.ejs +49 -0
  83. package/templates/shared/configurations/loggerConfig/HandlerLogs.java.ejs +56 -0
  84. package/templates/shared/configurations/securityConfig/SecurityConfig.java.ejs +57 -0
  85. package/templates/shared/configurations/swaggerConfig/SwaggerConfig.java.ejs +31 -0
  86. package/templates/shared/configurations/useCaseConfig/UseCaseAutoRegister.java.ejs +51 -0
  87. package/templates/shared/configurations/useCaseConfig/UseCaseConfig.java.ejs +25 -0
  88. package/templates/shared/configurations/useCaseConfig/UseCaseContainer.java.ejs +29 -0
  89. package/templates/shared/configurations/useCaseConfig/UseCaseMediator.java.ejs +38 -0
  90. package/templates/shared/customExceptions/BadRequestException.java.ejs +11 -0
  91. package/templates/shared/customExceptions/ConflictException.java.ejs +8 -0
  92. package/templates/shared/customExceptions/ForbiddenException.java.ejs +8 -0
  93. package/templates/shared/customExceptions/ImportFileException.java.ejs +6 -0
  94. package/templates/shared/customExceptions/NotFoundException.java.ejs +8 -0
  95. package/templates/shared/customExceptions/UnauthorizedException.java.ejs +9 -0
  96. package/templates/shared/customExceptions/ValidationException.java.ejs +17 -0
  97. package/templates/shared/errorMessage/ErrorMessage.java.ejs +5 -0
  98. package/templates/shared/errorMessage/FullErrorMessage.java.ejs +9 -0
  99. package/templates/shared/errorMessage/ShortErrorMessage.java.ejs +6 -0
  100. package/templates/shared/eventEnvelope/EventEnvelope.java.ejs +13 -0
  101. package/templates/shared/eventEnvelope/EventMetadata.java.ejs +24 -0
  102. package/templates/shared/filters/CorrelationIdFilter.java.ejs +45 -0
  103. package/templates/shared/handlerException/HandlerExceptions.java.ejs +148 -0
  104. package/templates/shared/interfaces/Command.java.ejs +4 -0
  105. package/templates/shared/interfaces/CommandHandler.java.ejs +5 -0
  106. package/templates/shared/interfaces/Dispatchable.java.ejs +4 -0
  107. package/templates/shared/interfaces/Handler.java.ejs +4 -0
  108. package/templates/shared/interfaces/Query.java.ejs +4 -0
  109. package/templates/shared/interfaces/QueryHandler.java.ejs +5 -0
  110. package/templates/shared/package-info.java.ejs +8 -0
  111. package/templates/usecase/command/Command.java.ejs +7 -0
  112. package/templates/usecase/command/CommandHandler.java.ejs +21 -0
  113. package/templates/usecase/query/Query.java.ejs +10 -0
  114. package/templates/usecase/query/QueryHandler.java.ejs +22 -0
  115. package/templates/usecase/query/ResponseDto.java.ejs +5 -0
@@ -0,0 +1,41 @@
1
+ <% if (features.includeDocker && dependencies.includes('data-jpa') && databaseType !== 'h2') { %>version: '3.8'
2
+
3
+ services:
4
+ <% if (databaseType === 'postgresql') { %> postgres:
5
+ image: postgres:16-alpine
6
+ container_name: <%= artifactId %>-postgres
7
+ environment:
8
+ POSTGRES_DB: <%= databaseName %>
9
+ POSTGRES_USER: <%= databaseUsername %>
10
+ POSTGRES_PASSWORD: <%= databasePassword %>
11
+ ports:
12
+ - "5432:5432"
13
+ volumes:
14
+ - postgres-data:/var/lib/postgresql/data
15
+ networks:
16
+ - <%= artifactId %>-network
17
+ <% } else if (databaseType === 'mysql') { %> mysql:
18
+ image: mysql:8.0
19
+ container_name: <%= artifactId %>-mysql
20
+ environment:
21
+ MYSQL_DATABASE: <%= databaseName %>
22
+ MYSQL_USER: <%= databaseUsername %>
23
+ MYSQL_PASSWORD: <%= databasePassword %>
24
+ MYSQL_ROOT_PASSWORD: <%= databasePassword %>
25
+ ports:
26
+ - "3306:3306"
27
+ volumes:
28
+ - mysql-data:/var/lib/mysql
29
+ networks:
30
+ - <%= artifactId %>-network
31
+ <% } %>
32
+
33
+ volumes:
34
+ <% if (databaseType === 'postgresql') { %> postgres-data:
35
+ <% } else if (databaseType === 'mysql') { %> mysql-data:
36
+ <% } %>
37
+
38
+ networks:
39
+ <%= artifactId %>-network:
40
+ driver: bridge
41
+ <% } %>
@@ -0,0 +1,70 @@
1
+ plugins {
2
+ id 'java'
3
+ id 'org.springframework.boot' version '<%= springBootVersion %>'
4
+ id 'io.spring.dependency-management' version '<%= dependencyManagementVersion %>'
5
+ }
6
+
7
+ group = '<%= groupId %>'
8
+ version = '<%= version %>'
9
+
10
+ java {
11
+ toolchain {
12
+ languageVersion = JavaLanguageVersion.of(<%= javaVersion %>)
13
+ }
14
+ }
15
+
16
+ configurations {
17
+ compileOnly {
18
+ extendsFrom annotationProcessor
19
+ }
20
+ }
21
+
22
+ repositories {
23
+ mavenCentral()
24
+ }
25
+
26
+ dependencyManagement {
27
+ imports {
28
+ <% if (typeof isDetached === 'undefined' || !isDetached) { %> mavenBom "org.springframework.modulith:spring-modulith-bom:<%= springModulithVersion %>"
29
+ <% } %> mavenBom "org.springframework.cloud:spring-cloud-dependencies:<%= springCloudVersion %>"
30
+ }
31
+ }
32
+
33
+ dependencies {
34
+ implementation 'org.springframework.boot:spring-boot-starter'
35
+
36
+ <% if (typeof isDetached === 'undefined' || !isDetached) { %> // Spring Modulith - Mandatory
37
+ implementation 'org.springframework.modulith:spring-modulith-starter-core'
38
+ implementation 'org.springframework.modulith:spring-modulith-starter-jpa'
39
+ testImplementation 'org.springframework.modulith:spring-modulith-starter-test'
40
+
41
+ <% } %> // Spring Cloud OpenFeign
42
+ implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
43
+ <% if (features.hasKafka) { %>
44
+ // Kafka
45
+ implementation 'org.springframework.kafka:spring-kafka'
46
+ testImplementation 'org.springframework.kafka:spring-kafka-test'
47
+
48
+ <% } %><% if (dependencies.includes('web')) { %> implementation 'org.springframework.boot:spring-boot-starter-web'
49
+ <% } %><% if (dependencies.includes('data-jpa')) { %> implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
50
+ <% } %><% if (dependencies.includes('security')) { %> implementation 'org.springframework.boot:spring-boot-starter-security'
51
+ <% } %><% if (dependencies.includes('validation')) { %> implementation 'org.springframework.boot:spring-boot-starter-validation'
52
+ <% } %><% if (dependencies.includes('actuator')) { %> implementation 'org.springframework.boot:spring-boot-starter-aop'
53
+ <% } %><% if (features.includeDevtools) { %> developmentOnly 'org.springframework.boot:spring-boot-devtools'
54
+ <% } %><% if (features.includeLombok) { %>
55
+ compileOnly 'org.projectlombok:lombok'
56
+ annotationProcessor 'org.projectlombok:lombok'
57
+ <% } %><% if (dependencies.includes('data-jpa')) { %>
58
+ runtimeOnly '<%= databaseDriver %>'
59
+ <% } %><% if (features.includeSwagger) { %>
60
+ implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.3.0'
61
+ <% } %>
62
+ testImplementation 'org.springframework.boot:spring-boot-starter-test'
63
+ <% if (dependencies.includes('security')) { %> testImplementation 'org.springframework.security:spring-security-test'
64
+ <% } %><% if (testing.includeTestcontainers && dependencies.includes('data-jpa')) { %> testImplementation 'org.testcontainers:testcontainers:1.19.3'
65
+ testImplementation 'org.testcontainers:<%= databaseTestcontainer %>:1.19.3'
66
+ <% } %>}
67
+
68
+ tasks.named('test') {
69
+ useJUnitPlatform()
70
+ }
@@ -0,0 +1 @@
1
+ rootProject.name = '<%= artifactId %>'
@@ -0,0 +1,5 @@
1
+ spring:
2
+ config:
3
+ import:
4
+ - "classpath:parameters/develop/db.yaml"
5
+ - "classpath:parameters/develop/cors.yml"
@@ -0,0 +1,5 @@
1
+ spring:
2
+ config:
3
+ import:
4
+ - "classpath:parameters/local/db.yaml"
5
+ - "classpath:parameters/local/cors.yml"
@@ -0,0 +1,9 @@
1
+ spring:
2
+ config:
3
+ import:
4
+ - "classpath:parameters/production/db.yaml"
5
+ - "classpath:parameters/production/cors.yml"
6
+
7
+ springdoc:
8
+ swagger-ui:
9
+ enabled: false
@@ -0,0 +1,5 @@
1
+ spring:
2
+ config:
3
+ import:
4
+ - "classpath:parameters/test/db.yaml"
5
+ - "classpath:parameters/test/cors.yml"
@@ -0,0 +1,31 @@
1
+ server:
2
+ port: <%= serverPort %>
3
+ servlet:
4
+ context-path: /
5
+
6
+ springdoc:
7
+ swagger-ui:
8
+ path: /swagger-ui.html
9
+ enabled: true
10
+ api-docs:
11
+ path: /api-docs
12
+
13
+ management:
14
+ endpoint:
15
+ health:
16
+ probes:
17
+ enabled: true
18
+ show-details: always
19
+ endpoints:
20
+ web:
21
+ exposure:
22
+ include: "health"
23
+
24
+ spring:
25
+ threads:
26
+ virtual:
27
+ enabled: true
28
+ application:
29
+ name: <%= artifactId %>
30
+ profiles:
31
+ active: ${PROFILE:local}
@@ -0,0 +1,4 @@
1
+ cors:
2
+ allowedOrigins: http://localhost:4200, http://localhost:5173
3
+ allowedMethods: POST, GET, PATCH, DELETE, PUT
4
+ allowedHeaders: "*"
@@ -0,0 +1,21 @@
1
+ <% if (dependencies.includes('data-jpa')) { %>spring:
2
+ datasource:
3
+ url: ${DB_URL:<%= databaseUrl %>}
4
+ username: ${DB_USERNAME:<%= databaseUsername %>}
5
+ password: ${DB_PASSWORD:<%= databasePassword %>}
6
+ driver-class-name: <%= databaseDriverClass %>
7
+
8
+ jpa:
9
+ hibernate:
10
+ ddl-auto: update
11
+ show-sql: false
12
+ properties:
13
+ hibernate:
14
+ format_sql: false
15
+ dialect: <%= hibernateDialect %>
16
+
17
+ logging:
18
+ level:
19
+ root: INFO
20
+ <%= packageName %>: DEBUG
21
+ <% } %>
@@ -0,0 +1,26 @@
1
+ spring:
2
+ kafka:
3
+ bootstrap-servers:
4
+ - localhost:9092 # Lista de brokers Kafka
5
+ producer:
6
+ properties:
7
+ spring.json.add.type.headers: false
8
+ key-serializer: org.apache.kafka.common.serialization.StringSerializer
9
+ value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
10
+ retries: 3
11
+ consumer:
12
+ group-id: <%= projectName %>-api-group
13
+ auto-offset-reset: earliest
14
+ enable-auto-commit: false
15
+ key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
16
+ value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
17
+ properties:
18
+ spring.json.trusted.packages: "*"
19
+ spring.json.use.type.headers: false
20
+ spring.json.value.default.type: <%= packageName %>.shared.infrastructure.eventEnvelope.EventEnvelope
21
+ listener:
22
+ ack-mode: manual
23
+ concurrency: 3
24
+ retry:
25
+ max-attempts: 2
26
+ backoff-delay: 1500
@@ -0,0 +1,4 @@
1
+ cors:
2
+ allowedOrigins: http://localhost:4200, http://localhost:5173
3
+ allowedMethods: POST, GET, PATCH, DELETE, PUT
4
+ allowedHeaders: "*"
@@ -0,0 +1,21 @@
1
+ <% if (dependencies.includes('data-jpa')) { %>spring:
2
+ datasource:
3
+ url: <%= databaseUrl %>
4
+ username: <%= databaseUsername %>
5
+ password: <%= databasePassword %>
6
+ driver-class-name: <%= databaseDriverClass %>
7
+
8
+ jpa:
9
+ hibernate:
10
+ ddl-auto: update
11
+ show-sql: true
12
+ properties:
13
+ hibernate:
14
+ format_sql: true
15
+ dialect: <%= hibernateDialect %>
16
+
17
+ logging:
18
+ level:
19
+ root: INFO
20
+ <%= packageName %>: DEBUG
21
+ <% } %>
@@ -0,0 +1,26 @@
1
+ spring:
2
+ kafka:
3
+ bootstrap-servers:
4
+ - localhost:9092 # Lista de brokers Kafka
5
+ producer:
6
+ properties:
7
+ spring.json.add.type.headers: false
8
+ key-serializer: org.apache.kafka.common.serialization.StringSerializer
9
+ value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
10
+ retries: 3
11
+ consumer:
12
+ group-id: <%= projectName %>-api-group
13
+ auto-offset-reset: earliest
14
+ enable-auto-commit: false
15
+ key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
16
+ value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
17
+ properties:
18
+ spring.json.trusted.packages: "*"
19
+ spring.json.use.type.headers: false
20
+ spring.json.value.default.type: <%= packageName %>.shared.infrastructure.eventEnvelope.EventEnvelope
21
+ listener:
22
+ ack-mode: manual
23
+ concurrency: 3
24
+ retry:
25
+ max-attempts: 2
26
+ backoff-delay: 1500
@@ -0,0 +1,4 @@
1
+ cors:
2
+ allowedOrigins: http://localhost:4200, http://localhost:5173
3
+ allowedMethods: POST, GET, PATCH, DELETE, PUT
4
+ allowedHeaders: "*"
@@ -0,0 +1,21 @@
1
+ <% if (dependencies.includes('data-jpa')) { %>spring:
2
+ datasource:
3
+ url: ${DB_URL}
4
+ username: ${DB_USERNAME}
5
+ password: ${DB_PASSWORD}
6
+ driver-class-name: <%= databaseDriverClass %>
7
+
8
+ jpa:
9
+ hibernate:
10
+ ddl-auto: validate
11
+ show-sql: false
12
+ properties:
13
+ hibernate:
14
+ format_sql: false
15
+ dialect: <%= hibernateDialect %>
16
+
17
+ logging:
18
+ level:
19
+ root: WARN
20
+ <%= packageName %>: INFO
21
+ <% } %>
@@ -0,0 +1,26 @@
1
+ spring:
2
+ kafka:
3
+ bootstrap-servers:
4
+ - localhost:9092 # Lista de brokers Kafka
5
+ producer:
6
+ properties:
7
+ spring.json.add.type.headers: false
8
+ key-serializer: org.apache.kafka.common.serialization.StringSerializer
9
+ value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
10
+ retries: 3
11
+ consumer:
12
+ group-id: <%= projectName %>-api-group
13
+ auto-offset-reset: earliest
14
+ enable-auto-commit: false
15
+ key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
16
+ value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
17
+ properties:
18
+ spring.json.trusted.packages: "*"
19
+ spring.json.use.type.headers: false
20
+ spring.json.value.default.type: <%= packageName %>.shared.infrastructure.eventEnvelope.EventEnvelope
21
+ listener:
22
+ ack-mode: manual
23
+ concurrency: 3
24
+ retry:
25
+ max-attempts: 2
26
+ backoff-delay: 1500
@@ -0,0 +1,126 @@
1
+ # <%= projectName %>
2
+
3
+ <%= description %>
4
+
5
+ ## Built with eva4j CLI
6
+
7
+ This project was generated using [eva4j](https://github.com/your-repo/eva4j), a CLI tool for generating Spring Boot projects with modular architecture.
8
+
9
+ ## Technologies
10
+
11
+ - **Java**: <%= javaVersion %>
12
+ - **Spring Boot**: <%= springBootVersion %>
13
+ - **Build Tool**: Gradle <%= gradleVersion %>
14
+ <% if (dependencies.includes('data-jpa')) { %>- **Database**: <%= databaseType.toUpperCase() %>
15
+ <% } %><% if (dependencies.includes('web')) { %>- **REST API**: Spring Web
16
+ <% } %><% if (dependencies.includes('security')) { %>- **Security**: Spring Security
17
+ <% } %><% if (features.includeSwagger) { %>- **API Documentation**: Swagger/OpenAPI
18
+ <% } %>
19
+
20
+ ## Project Structure
21
+
22
+ ```
23
+ <%= artifactId %>/
24
+ ├── src/
25
+ │ ├── main/
26
+ │ │ ├── java/
27
+ │ │ │ └── <%= packagePath %>/
28
+ │ │ │ ├── <%= applicationClassName %>.java
29
+ │ │ │ ├── common/ # Infrastructure layer
30
+ │ │ │ │ ├── config/
31
+ │ │ │ │ ├── exception/
32
+ │ │ │ │ └── util/
33
+ │ │ │ ├── shared/ # Shared domain layer (generated with first module)
34
+ │ │ │ └── [modules]/ # Domain modules (user, product, etc.)
35
+ │ │ └── resources/
36
+ │ │ └── application.yml
37
+ │ └── test/
38
+ ├── build.gradle
39
+ └── docker-compose.yml
40
+ ```
41
+
42
+ ## Getting Started
43
+
44
+ ### Prerequisites
45
+
46
+ - Java <%= javaVersion %> or higher
47
+ - Gradle <%= gradleVersion %> or use included wrapper
48
+ <% if (dependencies.includes('data-jpa') && databaseType !== 'h2') { %>- <%= databaseType.toUpperCase() %> database
49
+ <% } %>
50
+
51
+ ### Running the Application
52
+
53
+ ```bash
54
+ # Using Gradle wrapper
55
+ ./gradlew bootRun
56
+
57
+ # Or build and run
58
+ ./gradlew build
59
+ java -jar build/libs/<%= artifactId %>-<%= version %>.jar
60
+ ```
61
+
62
+ <% if (features.includeDocker && dependencies.includes('data-jpa') && databaseType !== 'h2') { %>### Using Docker Compose
63
+
64
+ Start the database:
65
+
66
+ ```bash
67
+ docker-compose up -d
68
+ ```
69
+ <% } %>
70
+
71
+ ### Running Tests
72
+
73
+ ```bash
74
+ ./gradlew test
75
+ ```
76
+
77
+ <% if (features.includeSwagger) { %>## API Documentation
78
+
79
+ Once the application is running, you can access the API documentation at:
80
+
81
+ - Swagger UI: http://localhost:<%= serverPort %>/swagger-ui.html
82
+ - OpenAPI JSON: http://localhost:<%= serverPort %>/api-docs
83
+ <% } %>
84
+
85
+ <% if (dependencies.includes('actuator')) { %>## Actuator Endpoints
86
+
87
+ Health check and metrics are available at:
88
+
89
+ - Health: http://localhost:<%= serverPort %>/actuator/health
90
+ - Metrics: http://localhost:<%= serverPort %>/actuator/metrics
91
+ <% } %>
92
+
93
+ ## Adding Modules
94
+
95
+ To add a new domain module (e.g., user, product):
96
+
97
+ ```bash
98
+ eva4j add module user
99
+ ```
100
+
101
+ This will generate:
102
+ - Controller layer (REST endpoints)
103
+ - Service layer (business logic)
104
+ - Repository layer (data access)
105
+ - Model/Entity (domain object)
106
+ - DTOs (data transfer objects)
107
+ - Mapper (entity ↔ DTO conversion)
108
+ - Tests
109
+
110
+ ## Architecture
111
+
112
+ This project follows a **modular monolith** architecture with **package-by-feature** organization:
113
+
114
+ - **common**: Infrastructure and technical concerns (config, global exception handling)
115
+ - **shared**: Cross-cutting domain concerns (base entities, value objects, domain exceptions)
116
+ - **[module]**: Feature-based modules (user, product, order, etc.)
117
+
118
+ Each module is self-contained with its own controller, service, repository, model, and DTOs.
119
+
120
+ ## License
121
+
122
+ <%= license || 'MIT' %>
123
+
124
+ ## Author
125
+
126
+ <%= author %>
@@ -0,0 +1,42 @@
1
+ # Gradle
2
+ .gradle/
3
+ build/
4
+ !gradle/wrapper/gradle-wrapper.jar
5
+ !**/src/main/**/build/
6
+ !**/src/test/**/build/
7
+
8
+ # IDE
9
+ .idea/
10
+ .vscode/
11
+ *.iml
12
+ *.iws
13
+ *.ipr
14
+ out/
15
+ .DS_Store
16
+
17
+ # Compiled class files
18
+ *.class
19
+
20
+ # Log files
21
+ *.log
22
+
23
+ # Package Files
24
+ *.jar
25
+ *.war
26
+ *.nar
27
+ *.ear
28
+ *.zip
29
+ *.tar.gz
30
+ *.rar
31
+
32
+ # Virtual machine crash logs
33
+ hs_err_pid*
34
+
35
+ # Spring Boot
36
+ application-local.yml
37
+ application-local.properties
38
+
39
+ # Environment variables
40
+ .env
41
+
42
+ # Note: .eva4j.json is tracked to preserve project configuration across team members
@@ -0,0 +1,39 @@
1
+ package <%= packageName %>.<%= moduleName %>.infrastructure.adapters.<%= portNameCamelCase %>;
2
+
3
+ import <%= packageName %>.<%= moduleName %>.application.ports.<%= portName %>;
4
+ import org.springframework.stereotype.Component;
5
+
6
+ @Component
7
+ public class <%= portName %>Adapter implements <%= portName %> {
8
+
9
+ private final <%= portName %>FeignClient feignClient;
10
+
11
+ public <%= portName %>Adapter(<%= portName %>FeignClient feignClient) {
12
+ this.feignClient = feignClient;
13
+ }
14
+
15
+ @Override
16
+ public Object findAll() {
17
+ return feignClient.findAll();
18
+ }
19
+
20
+ @Override
21
+ public Object findById(Long id) {
22
+ return feignClient.findById(id);
23
+ }
24
+
25
+ @Override
26
+ public Object create(Object request) {
27
+ return feignClient.create(request);
28
+ }
29
+
30
+ @Override
31
+ public Object update(Long id, Object request) {
32
+ return feignClient.update(id, request);
33
+ }
34
+
35
+ @Override
36
+ public void delete(Long id) {
37
+ feignClient.delete(id);
38
+ }
39
+ }
@@ -0,0 +1,24 @@
1
+ package <%= packageName %>.<%= moduleName %>.infrastructure.adapters.<%= portNameCamelCase %>;
2
+
3
+ import feign.Logger;
4
+ import feign.Request;
5
+ import org.springframework.context.annotation.Bean;
6
+
7
+ import java.util.concurrent.TimeUnit;
8
+
9
+ public class <%= portName %>Config {
10
+
11
+ @Bean
12
+ public Logger.Level feignLoggerLevel() {
13
+ return Logger.Level.BASIC;
14
+ }
15
+
16
+ @Bean
17
+ public Request.Options feignOptions() {
18
+ return new Request.Options(
19
+ 15, TimeUnit.SECONDS, // connect timeout
20
+ 15, TimeUnit.SECONDS, // read timeout
21
+ true
22
+ );
23
+ }
24
+ }
@@ -0,0 +1,23 @@
1
+ package <%= packageName %>.<%= moduleName %>.infrastructure.adapters.<%= portNameCamelCase %>;
2
+
3
+ import org.springframework.cloud.openfeign.FeignClient;
4
+ import org.springframework.web.bind.annotation.*;
5
+
6
+ @FeignClient(name = "<%= feignClientName %>", url = "${<%= baseUrlProperty %>}", configuration = <%= portName %>Config.class)
7
+ public interface <%= portName %>FeignClient {
8
+
9
+ @GetMapping("/api/resources")
10
+ Object findAll();
11
+
12
+ @GetMapping("/api/resources/{id}")
13
+ Object findById(@PathVariable("id") Long id);
14
+
15
+ @PostMapping("/api/resources")
16
+ Object create(@RequestBody Object request);
17
+
18
+ @PutMapping("/api/resources/{id}")
19
+ Object update(@PathVariable("id") Long id, @RequestBody Object request);
20
+
21
+ @DeleteMapping("/api/resources/{id}")
22
+ void delete(@PathVariable("id") Long id);
23
+ }
@@ -0,0 +1,14 @@
1
+ package <%= packageName %>.<%= moduleName %>.application.ports;
2
+
3
+ public interface <%= portName %> {
4
+
5
+ Object findAll();
6
+
7
+ Object findById(Long id);
8
+
9
+ Object create(Object request);
10
+
11
+ Object update(Long id, Object request);
12
+
13
+ void delete(Long id);
14
+ }
@@ -0,0 +1,10 @@
1
+ package <%= packageName %>.<%= moduleName %>.application.events;
2
+
3
+ public record <%= eventClassName %>(
4
+ // TODO: Add your event fields here
5
+ // Example:
6
+ // Long id,
7
+ // String name,
8
+ // LocalDateTime createdAt
9
+ ) {
10
+ }
@@ -0,0 +1,7 @@
1
+ @Value("<%= topicSpringProperty %>")
2
+ private String <%= valueFieldName %>;
3
+
4
+ @Bean
5
+ public NewTopic <%= beanMethodName %>() {
6
+ return new NewTopic(<%= valueFieldName %>, <%= partitions %>, (short) <%= replicas %>);
7
+ }
@@ -0,0 +1,32 @@
1
+ package <%= packageName %>.<%= moduleName %>.infrastructure.adapters.kafkaMessageBroker;
2
+
3
+ import <%= packageName %>.<%= moduleName %>.application.events.<%= eventClassName %>;
4
+ import <%= packageName %>.<%= moduleName %>.application.ports.MessageBroker;
5
+ import <%= packageName %>.shared.infrastructure.eventEnvelope.EventEnvelope;
6
+ import org.springframework.beans.factory.annotation.Value;
7
+ import org.springframework.kafka.core.KafkaTemplate;
8
+ import org.springframework.stereotype.Component;
9
+ import org.slf4j.MDC;
10
+
11
+ @Component
12
+ public class KafkaMessageBroker implements MessageBroker {
13
+
14
+ @Value("<%= topicSpringProperty %>")
15
+ private String <%= topicNameKebab.replace(/-/g, '') %>Topic;
16
+
17
+ private final KafkaTemplate<String, Object> kafkaTemplate;
18
+
19
+ public KafkaMessageBroker(KafkaTemplate<String, Object> kafkaTemplate) {
20
+ this.kafkaTemplate = kafkaTemplate;
21
+ }
22
+
23
+ @Override
24
+ public void publish<%= eventClassName %>(<%= eventClassName %> event) {
25
+ EventEnvelope<<%= eventClassName %>> envelope = EventEnvelope.of(
26
+ <%= topicNameKebab.replace(/-/g, '') %>Topic,
27
+ event,
28
+ MDC.get("correlationId")
29
+ );
30
+ kafkaTemplate.send(<%= topicNameKebab.replace(/-/g, '') %>Topic, envelope);
31
+ }
32
+ }