Skip to content

Commit d08311b

Browse files
committed
Merge remote-tracking branch 'upstream/master'
2 parents fe74746 + f8467ca commit d08311b

File tree

246 files changed

+9135
-2043
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

246 files changed

+9135
-2043
lines changed

.windsurfrules

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
# Avni Server Windsurf Rules
2+
version = 1.0.0
3+
4+
# Tech Stack
5+
- it uses JPA, Spring Security, Spring Batch, and Spring Rest
6+
- it connects to a Postgres database
7+
- flyway is used for database migrations
8+
9+
# Language usage
10+
- Do not add comments and null checks unless asked
11+
- Check Java version from .java_version
12+
- always add new methods at the end of the file
13+
14+
# Code organization
15+
- Repository and domain code goes in avni-serer-data module.
16+
- Service, controller, mapper, and dto code goes in avni-server-api module. Flyway migrations are in this module.
17+
18+
# Building blocks (or where to put which type of code)
19+
- There are following building blocks for request processing - Controller, Service, Mapper, Repository, and DTO.
20+
- Batch jobs use Tasklet/Job - which inturn should use Writer or Service
21+
- DTOs are of three types - Request, Response, and Contract.
22+
- Repository should have only basic database operations directly using JPA for single entity type usually. Repository should be responsible for calling external services like Metabase, S3, etc.
23+
- Service should have all the business logic. It can have mapper, repository, or other services
24+
- Mapper should map between domain objects and DTO objects and vice versa
25+
- take request in a typed dto and return response in a typed dto
26+
- use BaseRepository always and getPrisma method from it
27+
- the web response contract classes are called Response
28+
- Mapper should use Repository and not Service
29+
- Controller can use Service or Repository depending on the complexity of the operation
30+
31+
32+
#----------------------------------------------
33+
# PROJECT INFORMATION
34+
#----------------------------------------------
35+
project.name = avni-server
36+
project.type = java
37+
project.framework = spring-boot
38+
39+
#----------------------------------------------
40+
# PROJECT STRUCTURE
41+
#----------------------------------------------
42+
structure.sourceRoot = avni-server-api/src/main/java
43+
structure.resourceRoot = avni-server-api/src/main/resources
44+
structure.testRoot = avni-server-api/src/test
45+
structure.packagePrefix = org.avni
46+
47+
# Modules
48+
modules = avni-server-api, avni-server-data, avni-rule-server
49+
50+
# Module Organization
51+
organization.data = repository and domain code in avni-server-data module
52+
organization.api = service, controller, mapper, dto code and flyway migrations in avni-server-api module
53+
54+
#----------------------------------------------
55+
# BUILD CONFIGURATION
56+
#----------------------------------------------
57+
build.tool = gradle
58+
build.mainClass = org.avni.Avni
59+
build.javaVersion = 21
60+
build.command.build = ./gradlew clean bootJar
61+
build.command.test = ./gradlew test
62+
build.command.run = java -jar avni-server-api/build/libs/avni-server-0.0.1-SNAPSHOT.jar
63+
64+
#----------------------------------------------
65+
# TECH STACK AND DEPENDENCIES
66+
#----------------------------------------------
67+
# Core Technologies
68+
tech.frameworks = JPA, Spring Security, Spring Batch, Spring Rest
69+
tech.database = postgresql
70+
tech.migrations = flyway
71+
72+
# Basic Dependencies
73+
dependencies.database = postgresql
74+
dependencies.cache = ehcache
75+
dependencies.security = spring-security
76+
77+
# API Dependencies
78+
api.dependencies.spring-boot-version = 3.3.5
79+
api.dependencies.spring-boot-web = org.springframework.boot:spring-boot-starter-web
80+
api.dependencies.spring-boot-security = org.springframework.boot:spring-boot-starter-security
81+
api.dependencies.spring-boot-data-jpa = org.springframework.boot:spring-boot-starter-data-jpa
82+
api.dependencies.spring-boot-data-rest = org.springframework.boot:spring-boot-starter-data-rest
83+
api.dependencies.spring-boot-batch = org.springframework.boot:spring-boot-starter-batch
84+
api.dependencies.keycloak = org.keycloak:keycloak-spring-boot-starter:24.0.4
85+
api.dependencies.aws-s3 = com.amazonaws:aws-java-sdk-s3
86+
api.dependencies.aws-cognito = com.amazonaws:aws-java-sdk-cognitoidp
87+
api.dependencies.jackson = com.fasterxml.jackson.core:jackson-databind:2.15.4
88+
89+
# Library Usage
90+
library.datetime = Use Joda Time (org.joda.time) instead of java.time for all date and time handling, Maintain consistent date formatting patterns across the codebase
91+
92+
#----------------------------------------------
93+
# CODE STYLE AND CONVENTIONS
94+
#----------------------------------------------
95+
# General Code Style
96+
codeStyle.indentation = spaces
97+
codeStyle.indentSize = 4
98+
codeStyle.lineLength = 120
99+
codeStyle.packageNaming = org.avni.{module}.{component}
100+
101+
# Java-specific Code Style
102+
codestyle.java.braces = same_line
103+
codestyle.java.imports_order = java,javax,org,com
104+
codestyle.java.static_imports = bottom
105+
codestyle.java.wildcard_imports = false
106+
codestyle.java.final_parameters = false
107+
codestyle.java.final_locals = when_needed
108+
109+
# Coding Conventions
110+
coding.comments = add only when explicitly requested
111+
coding.nullchecks = add only when explicitly requested
112+
coding.javaversion.check = .java_version
113+
coding.methodplacement = add new methods at end of file
114+
115+
# Documentation Guidelines
116+
documentation.principles = Avoid JavaDocs in favor of self-documenting code, Use clear method and variable names that explain their purpose, Only add inline comments for complex logic that cannot be made clear through refactoring, Do not document what the code does (it should be obvious), Document why certain decisions were made when not obvious
117+
118+
# Refactoring Guidelines
119+
refactoring.documentation = Avoid JavaDocs, coding style preferred is single-line format, rely on self-documenting code and clear naming instead
120+
121+
#----------------------------------------------
122+
# ARCHITECTURE AND DESIGN PATTERNS
123+
#----------------------------------------------
124+
# Component Structure
125+
components.request = Controller, Service, Mapper, Repository, DTO
126+
components.batch = Tasklet/Job using Writer or Service
127+
components.dto.types = Request, Response, Contract
128+
components.repository = basic database operations using JPA, external service calls (Metabase, S3)
129+
components.service = business logic, can use mapper, repository, or other services
130+
components.mapper = map between domain objects and DTO objects
131+
components.api = typed request dto and typed response dto
132+
components.repository.base = BaseRepository, use getPrisma method
133+
components.response = web response contract classes named Response
134+
135+
# Code Patterns
136+
patterns.controllers = **/*Controller.java
137+
patterns.services = **/*Service.java
138+
patterns.repositories = **/*Repository.java
139+
patterns.entities = org/avni/server/domain/**/*.java
140+
141+
# API Architecture
142+
api.pattern.controllers = **/*Controller.java
143+
api.pattern.repositories = **/*Repository.java
144+
api.pattern.services = **/*Service.java
145+
api.pattern.domain = org/avni/server/domain/**/*.java
146+
api.pattern.framework = org/avni/server/framework/**/*.java
147+
148+
# API REST
149+
api.rest.hateoas = true
150+
api.rest.model-processors = true
151+
api.rest.base-path = /api
152+
153+
# API Build
154+
api.build.jar-name = avni-server
155+
api.build.jar-version = 0.0.1-SNAPSHOT
156+
api.build.main-class = org.avni.Avni
157+
api.build.custom-tasks = externalTest
158+
159+
# API Documentation
160+
api.docs.format = spring-data-rest
161+
api.docs.base-path = /api
162+
163+
# API Messaging
164+
api.messaging.enabled = true
165+
api.messaging.provider = glific
166+
api.messaging.package = org.avni.messaging
167+
168+
#----------------------------------------------
169+
# ARCHITECTURAL PRINCIPLES
170+
#----------------------------------------------
171+
# Code Structure and Modularity
172+
modularity.principles = Create small, focused methods with a single responsibility, Limit method size to improve readability and testability, Extract complex logic into separate utility classes, Use immutable objects wherever possible, Avoid deep nesting of methods and control structures
173+
174+
# Service Layer Principles
175+
service.principles = Follow the Single Responsibility Principle, Inject dependencies rather than creating them, Use interfaces for service contracts, Keep business logic in service layer not controllers, Validate input parameters at service boundaries
176+
177+
# Repository Layer Principles
178+
repository.principles = Use Spring Data interfaces where possible, Create custom queries with JPQL or native SQL when needed, Avoid N+1 query problems, Use pagination for large result sets, Consider using query projections for performance
179+
180+
# Controller Layer Principles
181+
controller.principles = Keep controllers thin, Delegate business logic to services, Use DTOs for request/response objects, Implement proper error handling, Document APIs with OpenAPI/Swagger
182+
183+
# Domain Model Guidelines
184+
domain.principles = Use rich domain models, Encapsulate business rules within domain objects, Validate domain invariants, Use value objects for immutable concepts, Consider using domain events for cross-aggregate communication
185+
186+
#----------------------------------------------
187+
# TESTING
188+
#----------------------------------------------
189+
# Testing Patterns
190+
testing.unitTestPattern = **/*Test.java
191+
testing.integrationTestPattern = **/*IT.java
192+
testing.coverageThreshold = 70
193+
194+
# Testing Principles
195+
testing.principles = Write tests for all new code, Follow the Arrange-Act-Assert pattern, Use meaningful test names that describe behavior, Mock external dependencies, Test edge cases and error conditions
196+
197+
# Testing Frameworks
198+
testing.framework.unit = junit4
199+
testing.framework.assertions = assertj
200+
testing.framework.mocking = mockito
201+
testing.framework.spring = spring-boot-test
202+
203+
# Test Patterns
204+
testing.pattern.baseControllerTest = AbstractControllerIntegrationTest
205+
testing.pattern.testBuilders = true
206+
testing.pattern.dataJpaTest = true
207+
208+
# Test Naming Conventions
209+
testing.naming.unitTests = *Test.java
210+
testing.naming.integrationTests = *IT.java,*IntegrationTest.java
211+
testing.naming.entityTests = *ET.java
212+
213+
# Test Structure
214+
testing.modules.api = avni-server-api/src/test
215+
testing.modules.data = avni-server-data/src/test
216+
testing.packagePrefix = org.avni
217+
218+
# Test Dependencies
219+
testing.dependencies.junit = junit:junit:4.13.2
220+
testing.dependencies.mockito = org.mockito:mockito-core:4.8.0
221+
testing.dependencies.assertj = org.assertj:assertj-core:3.23.1
222+
testing.dependencies.springTest = org.springframework.boot:spring-boot-starter-test
223+
224+
#----------------------------------------------
225+
# INFRASTRUCTURE
226+
#----------------------------------------------
227+
# Database
228+
database.migrations.tool = flyway
229+
database.migrations.location = avni-server-api/src/main/resources/db/migration/
230+
231+
# API Caching
232+
api.cache.provider = ehcache
233+
api.cache.implementation = org.ehcache:ehcache:3.10.8:jakarta
234+
api.cache.hibernate = org.hibernate.orm:hibernate-jcache:6.5.2.Final
235+
236+
# Security
237+
security.authentication = keycloak Or cognito
238+
security.authorization = role-based
239+
240+
# API Security
241+
api.security.provider = keycloak or cognito
242+
api.security.jwt = true
243+
api.security.role-based = true
244+
245+
# Logging
246+
logging.framework = logback
247+
logging.configFile = avni-server-api/src/main/resources/logback-spring.xml
248+
249+
#----------------------------------------------
250+
# DEPLOYMENT
251+
#----------------------------------------------
252+
deployment.containerization = docker
253+
deployment.baseImage = amazoncorretto:21
254+
deployment.port = 8080
255+
deployment.healthCheckPath = /actuator/health
256+
deployment.memory = 2Gi
257+
deployment.cpu = 1

avni-server-api/build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,9 @@ dependencies {
109109
testImplementation 'org.slf4j:slf4j-reload4j:2.0.6'
110110
implementation 'com.google.guava:guava:33.2.1-jre'
111111
implementation 'org.codehaus.jettison:jettison:1.5.4'
112+
implementation('org.apache.tika:tika-core:2.7.0') {
113+
exclude group: 'org.apache.tika', module: 'tika-parsers'
114+
}
112115
}
113116

114117
bootRun {

avni-server-api/src/main/java/org/avni/messaging/api/MessageRuleController.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package org.avni.messaging.api;
22

3-
import org.avni.messaging.contract.MessageRuleContract;
3+
import org.avni.messaging.contract.MessageRuleWebContract;
44
import org.avni.messaging.domain.EntityType;
55
import org.avni.messaging.domain.MessageRule;
66
import org.avni.messaging.service.MessagingService;
@@ -31,15 +31,15 @@ public MessageRuleController(MessagingService messagingService, AccessControlSer
3131

3232
@RequestMapping(value = "/web/messageRule", method = RequestMethod.POST)
3333
@Transactional
34-
public ResponseEntity<MessageRuleContract> save(@RequestBody MessageRuleContract messageRuleContract) {
34+
public ResponseEntity<MessageRuleWebContract> save(@RequestBody MessageRuleWebContract messageRuleContract) {
3535
accessControlService.checkPrivilege(entityTypeRetrieverService.findPrivilegeType(StringUtils
3636
.capitalize(messageRuleContract.getEntityType())));
3737

3838
MessageRule existingEntity = messagingService.findByIdOrUuid(messageRuleContract.getId(), messageRuleContract.getUuid());
3939
MessageRule messageRule = messageRuleContract.toModel(existingEntity);
4040

4141
messageRule = messagingService.saveRule(messageRule);
42-
return ResponseEntity.ok(new MessageRuleContract(messageRule, null));
42+
return ResponseEntity.ok(new MessageRuleWebContract(messageRule, null));
4343
}
4444

4545
/**
@@ -54,20 +54,20 @@ public ResponseEntity<MessageRuleContract> save(@RequestBody MessageRuleContract
5454
*/
5555
@RequestMapping(value = "/web/messageRule", method = RequestMethod.GET)
5656
@Transactional
57-
public Page<MessageRuleContract> find(@RequestParam(required = false) String entityType, @RequestParam (required = false) Long entityTypeId, Pageable pageable) {
57+
public Page<MessageRuleWebContract> find(@RequestParam(required = false) String entityType, @RequestParam (required = false) Long entityTypeId, Pageable pageable) {
5858
if (isAString(entityType) && entityTypeId != null) {
5959
EntityType entityTypeValue = EntityType.valueOf(StringUtils.capitalize(entityType));
60-
return messagingService.findByEntityTypeAndEntityTypeId(entityTypeValue, entityTypeId, pageable).map(messageRule -> new MessageRuleContract(messageRule, null));
60+
return messagingService.findByEntityTypeAndEntityTypeId(entityTypeValue, entityTypeId, pageable).map(messageRule -> new MessageRuleWebContract(messageRule, null));
6161
}
6262

63-
return messagingService.findAll(pageable).map(messageRule -> new MessageRuleContract(messageRule, null));
63+
return messagingService.findAll(pageable).map(messageRule -> new MessageRuleWebContract(messageRule, null));
6464
}
6565

6666
@RequestMapping(value = "/web/messageRule/{id}", method = RequestMethod.GET)
6767
@Transactional
68-
public ResponseEntity<MessageRuleContract> findOne(@PathVariable("id") Long id ) {
68+
public ResponseEntity<MessageRuleWebContract> findOne(@PathVariable("id") Long id ) {
6969
MessageRule messageRule = messagingService.find(id);
70-
return messageRule == null? ResponseEntity.notFound().build() : ResponseEntity.ok(new MessageRuleContract(messageRule, null));
70+
return messageRule == null? ResponseEntity.notFound().build() : ResponseEntity.ok(new MessageRuleWebContract(messageRule, null));
7171
}
7272

7373
private boolean isAString(String s) {

0 commit comments

Comments
 (0)