Backend
Functional Requirements
- Functional Requirements is covered by the attached Product Requirements Document.
- Implement RESTful APIs for all functionalities based on the attached OpenAPI specification.
- Use Spring Data REST for API implementation wherever applicable.
Build system
- Maven
- Try not to hard code dependencies versions, use versions from BOMs wherever possible
- If a dependency is available in Spring Boot BOM, use the version from there, if not, use the latest stable version
- For explicit version declarations, use properties in POM
Backend Tech Stack
- Java 21
- Spring Boot
- Spring Boot Actuator
- Spring Security OAuth2 Resource Server
- Spring Security LDAP
- org.springframework.ldap:spring-ldap-core
- org.springframework.security:spring-security-ldap
- com.unboundid:unboundid-ldapsdk
- Spring Web
- Spring REST Docs (spring-boot-starter-data-rest)
- Spring HATEOAS
- Spring Modulith
- org.springframework.modulith:spring-modulith-starter-core
- org.springframework.modulith:spring-modulith-events-api
- org.springframework.modulith:spring-modulith-events-kafka
- org.springframework.modulith:spring-modulith-starter-test
- Spring for Apache Kafka
- org.springframework.kafka:spring-kafka
- org.springframework.kafka:spring-kafka-test
- Springdoc OpenAPI
- springdoc-openapi-starter-webmvc-api
- springdoc-openapi-starter-webmvc-ui
- Spring Data JPA
- Flyway
- org.flywaydb:flyway-database-postgresql
- Lombok
- MapStruct
- Spring Boot Test
- org.springframework.boot:spring-boot-starter-test
- JUnit 5
- Testcontainers
Database
- PostgreSQL
- Use UUID as primary key type
- Use PostgreSQL enums wherever applicable
- Flyway for database migration
- Create DDL scripts for initial schema setup and use Flyway for subsequent migrations
- Create DML scripts for inserting sample data and use Flyway for subsequent migrations
Code organization
- Root package name: cq.playground
REST API
- Follow
RESTfulprinciples andHypermedia as the engine of application state(HATEOAS) - Implement proper exception handling and return appropriate HTTP status codes
- Use plural nouns for resource names in endpoints (e.g.,
/users,/orders) - HTTP 200 for successful
GET,PUT,PATCHrequests - HTTP 201 for successful
POSTrequests - HTTP 204 for successful
DELETErequests with no content - HTTP 400 for bad requests on client side errors
- HTTP 404 for missing resources
- HTTP 500 for server side errors
- Version the API using custom HTTP header
X-API-Versioninstead of URL path
Java
- Use
varfor local variable declaration. - Prefer
method referencesoverlambda expressionswherever applicable. - Use capitalized names for constants and enums.
DTO Classes
DTOs should be immutable by usingLombok@Valueannotation- Use
DTOs for all data transfer between client and server - Make all fields
finalinDTOclasses - Add
@AllArgsConstructortoDTOclasses - Use
MapStructfor transformation between entities andDTOs
Spring Web
- Define a global handler class annotated with
@ControllerAdvice(or@RestControllerAdvicefor REST APIs) using@ExceptionHandlermethods to handle specific exceptions. - Return consistent error responses. Consider using the ProblemDetails response format (RFC 9457 (opens in a new tab)).
- Use
@Validannotation on controller method parameters to trigger validation based on Jakarta Validation annotations in DTOs.
Persistence
Spring Data JPA
- Use
UUIDas primary key type - Use
@ManyToOne,@OneToMany,@OneToOne, and@ManyToManyannotations to define relationships between entities - Use
FetchType.LAZYfor all relationships unless there is a compelling reason to useEAGERfetching - Avoid bidirectional relationships unless necessary to prevent complexity and potential performance issues
- Disable Hibernate's automatic schema generation (e.g.,
spring.jpa.hibernate.ddl-auto=none) and use Flyway for database migrations instead - Disable
Open Session in Viewpattern by settingspring.jpa.open-in-view=false - Use
@Transactionalannotation on service layer methods that modify data - Use pagination for endpoints that return large lists of data
- Use
@Modifyingand@Queryannotations for custom update and delete operations in repositories - For JPA entities, use
@JdbcType(PostgreSQLEnumJdbcType.class)for mapping PostgreSQL enums - Use Spring Data JPA repositories for data access
- Define custom query methods using
@Queryin repository interfaces as needed
JPA/Hibernate
- Enable performance optimizations like second-level cache, query cache, and batch fetching
Configuration
Spring Framework
- Use constructor injection for Spring beans
- DO NOT use
publicvisibility for Spring beans, use package-private (default) visibility instead, except for@Service,@Component, and@Repositoryclasses
Spring Boot
- Use the latest stable version of Spring Boot
- Turn off console banner
Security
Spring Security
- (MUST) Sanitize all user inputs to prevent XSS attacks.
- (MUST) Implement Content Security Policy (CSP) headers.
- (MUST) Use HTTPS everywhere, implement proper CORS policies.
- (SHOULD) Implement proper authentication and authorization patterns.
- (MUST) Never expose sensitive data in client-side code or logs.
- Secure all endpoints except
/health,/info,/metrics,/swagger-ui/**,/v3/api-docs/**and/public/** - Use method-level security with
@PreAuthorizeannotations to enforce role-based access control - On Controller endpoints, verify user authorization with JWT claims wherever applicable
Spring Security OAuth2 Resource Server
- Validate JWT tokens using the public key from the authorization server
- Configure token validation settings in
application.ymlorapplication.properties
Spring Security LDAP
- Use LDAP for user management and identity provider
- Configure LDAP settings in
application.ymlorapplication.properties - Use
LdapAuthoritiesPopulatorto map LDAP groups to application roles - Set up an embedded LDAP server for development and testing using UnboundID
- Create a sample LDIF file to bootstrap LDAP server with users and groups, located in
src/main/resources/id.ldif
Secure coding
- Implement OWASP Top 10 (opens in a new tab)
Messaging
Spring for Apache Kafka
- Use Kafka for asynchronous messaging between microservices
- Configure Kafka settings in
application.ymlorapplication.properties - Use
KafkaTemplatefor producing messages - Use
@KafkaListenerannotation for consuming messages - Implement error handling and retries for message processing
- Use
Avrofor message serialization and deserialization - Use Schema Registry for managing Avro schemas
- Use embedded
Kafkabroker fromSpring for Apache Kafkafor development and testing
Observability
Observability - Metrics
- Use
Micrometerfor metrics collection, withPrometheusas the metrics backend
Observability - Tracing
- Use
Micrometer Observationfor application tracing - Use
datasource-micrometer-spring-bootfor JDBC tracing - Use
OpenTelemetryfor distributed tracing
Observability - Logging
- DO NOT use
System.out.println()for application logging - Use
SLF4Jfor application logging withLogbackas the logging implementation - Avoid logging sensitive information or redact sensitive data before logging
- Guard expensive log calls with conditional checks (e.g.,
if (log.isDebugEnabled()) { ... }) - Enable log rotation and archiving to manage log file sizes
- Enable SQL statement logging by setting
logging.level.sql=DEBUGandlogging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE - Enable Web HTTP request logging by setting
logging.level.web=DEBUGandlogging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUG
Observability - Monitoring
- Use
Grafanafor observability visualization
Spring Boot Actuator
- Expose only essential actuator endpoints (such as
/health,/info,/metrics) without requiring authentication. All the other actuator endpoints must be secured. - Expose all actuator endpoints for
localprofile
Coding style
- Use the following
Lombokannotations wherever applicable:@Data,@Builder,@NoArgsConstructor, but don't use@Dataon JPA entities - Use
@EqualsAndHashCodeforequalsandhashCodemethods - Use
@Slf4jin all classes to enable logging withSLF4J - For constructors or methods with more than 3 arguments, use a new line for every argument
- Use
@RequiredArgsConstructorto help constructor injection for Spring beans, - Use
Objects.toStringto convert raw values if String is needed - Externalizes all user-facing text such as labels, prompts, and messages into
ResourceBundlesrather than embedding them in code.
Testing
- Use
AssertJfor assertions and matchers - DO NOT use mocks in test cases, and use
Testcontainersfor integration testing, don't useH2or any embedded DB - Use
@SneakyThrowsfor methods that throw checked exceptions - Use
@ParameterizedTestfor parameterized tests - Use
Spring REST Docsfor API documentation and testing