Appearance
Code Structure
This document provides a detailed overview of the codebase organization, conventions, and key project files for the IT Ticketing Service. A thorough understanding of this structure is essential for effective development and maintenance. The project's core philosophy, as outlined in CLAUDE.md, emphasizes a clean, conventional structure that facilitates migration through externalized configuration rather than code modification.
Package Organization
The project follows a "package-by-layer" (or package-by-function) organization, a standard convention in Spring Boot applications. This approach groups classes by their technical role within the application architecture.
The base package for all source code is com.slalom.demo.ticketing.
java
// src/main/java/com/slalom/demo/ticketing/ItTicketingApplication.java
package com.slalom.demo.ticketing;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ItTicketingApplication {
public static void main(String[] args) {
SpringApplication.run(ItTicketingApplication.class, args);
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
The @SpringBootApplication annotation on the main class enables component scanning, which automatically discovers and registers beans within this package and its subpackages.
The typical package structure is as follows:
com.slalom.demo.ticketing
├── ItTicketingApplication.java // Main application entry point
├── config/ // Spring configuration classes (e.g., RabbitMQ topology)
├── controller/ // REST API controllers (handling HTTP requests)
├── dto/ // Data Transfer Objects (for API request/response bodies)
├── entity/ // JPA entity classes mapped to database tables
├── exception/ // Custom exception classes and global exception handlers
├── repository/ // Spring Data JPA repositories for data access
└── service/ // Business logic and service layer1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
Package Responsibilities:
| Package | Responsibility |
|---|---|
config | Contains @Configuration classes for defining beans, such as RabbitMQ queues and exchanges, or custom security settings. |
controller | Exposes RESTful endpoints using @RestController. Responsible for handling incoming HTTP requests, validating input, and delegating to the service layer. |
dto | Defines plain Java objects used for transferring data between the client and the server. This decouples the API contract from the internal database model (entity). |
entity | Contains JPA @Entity classes that map directly to database tables. These are managed by the persistence layer (Hibernate/JPA). |
exception | Houses custom application-specific exceptions and @ControllerAdvice classes for centralized exception handling, translating exceptions into appropriate HTTP responses. |
repository | Defines interfaces that extend Spring Data JPA's JpaRepository. These provide standardized CRUD operations and the ability to define custom queries without boilerplate. |
service | Implements the core business logic. It orchestrates calls to repositories and other services and is the primary consumer of dependency injection. |
Naming Conventions
Consistent naming is crucial for readability and maintainability. The project adheres to standard Java and Spring conventions.
| Component Type | Naming Pattern | Example |
|---|---|---|
| Classes | PascalCase with a descriptive suffix. | TicketController |
| Interfaces | PascalCase with a descriptive suffix. | TicketRepository |
| JPA Entities | PascalCase, singular noun. | Ticket |
| DTOs | PascalCase with Request, Response, or Dto suffix. | CreateTicketRequest |
| Methods | camelCase, verb-first. | getTicketById(Long id) |
| Variables | camelCase. | ticketCount |
| Constants | SCREAMING_SNAKE_CASE. | MAX_TICKET_PRIORITY |
| Configuration Properties | kebab-case. | spring.datasource.url |
Method Naming Examples:
- Repository: Follows Spring Data JPA query derivation (e.g.,
findById,findByStatus). - Service: Business-oriented actions (e.g.,
createTicket,assignTicketToUser). - Controller: Maps to HTTP methods (e.g.,
getTicket,createTicket,updateTicket).
Code Style
The project's code style is guided by modern Spring Boot practices, aiming for clean, declarative, and minimally complex code.
Spring Boot Conventions
The application heavily leverages Spring Boot's "convention over configuration" paradigm.
- Stereotype Annotations: Classes are annotated with
@RestController,@Service, and@Repositoryto clearly define their role and make them candidates for component scanning. - Auto-Configuration: The use of starters like
spring-boot-starter-webandspring-boot-starter-data-jpainpom.xmlenables Spring Boot to automatically configure the application context, web server, and data source based on classpath contents and properties.
Lombok Usage
Lombok is used extensively to reduce boilerplate code, making entities and DTOs more concise.
xml
<!-- pom.xml -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
<optional>true</optional>
</dependency>1
2
3
4
5
6
7
2
3
4
5
6
7
A typical entity or DTO might look like this:
java
// Example DTO
package com.slalom.demo.ticketing.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
@Data // Generates getters, setters, toString(), equals(), and hashCode()
@NoArgsConstructor
@AllArgsConstructor
public class TicketDto {
private Long id;
private String title;
private String description;
private String status;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Developer Note: To work with this codebase, you must have the Lombok plugin installed and enabled in your IDE. Otherwise, the IDE will report compilation errors for missing methods (getters, setters, etc.).
Validation
The project uses spring-boot-starter-validation to enable Bean Validation (JSR-380) for input validation. This allows DTOs and request objects to be annotated with validation constraints, which are automatically enforced by Spring when used with @Valid or @Validated.
xml
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>1
2
3
4
5
2
3
4
5
A typical request DTO using validation annotations:
java
package com.slalom.demo.ticketing.dto;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Data;
@Data
public class CreateTicketRequest {
@NotBlank(message = "Title is required")
@Size(max = 200, message = "Title must not exceed 200 characters")
private String title;
@NotBlank(message = "Description is required")
private String description;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
In controllers, the @Valid annotation triggers validation before the method is executed:
java
@PostMapping
public ResponseEntity<Ticket> createTicket(@Valid @RequestBody CreateTicketRequest request) {
// If validation fails, Spring automatically returns 400 Bad Request
// with error details
}1
2
3
4
5
2
3
4
5
Dependency Injection Patterns
The project strictly follows the constructor-based dependency injection pattern. This is the recommended approach for several reasons:
- Immutability: Dependencies can be declared as
final, ensuring they are not changed after object construction. - Clarity: A class's required dependencies are explicit in its constructor signature.
- Testability: It simplifies unit testing, as dependencies can be easily mocked and passed to the constructor without needing a Spring context.
See the Dependency Injection page for a more detailed explanation.
java
// Example of constructor injection in a Controller
@RestController
@RequestMapping("/api/tickets")
public class TicketController {
private final TicketService ticketService; // Dependency is final
// Constructor injection
public TicketController(TicketService ticketService) {
this.ticketService = ticketService;
}
@GetMapping("/{id}")
public ResponseEntity<Ticket> getTicketById(@PathVariable Long id) {
// ... implementation
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Project Files
Several key files at the root of the project define its structure, dependencies, and configuration.
pom.xml
This is the Maven Project Object Model file. It is the single source of truth for the project's dependencies and build process.
Key Sections:
<parent>: Inherits fromspring-boot-starter-parent, which provides sensible default configurations and manages dependency versions.xml<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.4</version> <relativePath/> </parent>1
2
3
4
5
6<properties>: Defines project-wide properties, most importantly the Java version.xml<properties> <java.version>17</java.version> </properties>1
2
3<dependencies>: Lists all required libraries, such as Spring Boot starters (web, JPA, validation, AMQP, actuator), the MySQL driver, and Lombok. Thespring-boot-starter-actuatorprovides production-ready endpoints for monitoring application health and metrics at/actuator.<build>: Configures the build process, including thespring-boot-maven-pluginwhich packages the application as an executable JAR, and themaven-compiler-pluginconfigured to process Lombok annotations.
application.properties
Located in src/main/resources, this file is central to the project's migration strategy. It externalizes all environment-specific configurations. No environment-specific values should be hardcoded in the Java source code.
Example Configuration:
properties
# Server Configuration
server.port=8080
# Database Connection (for local on-prem environment)
spring.datasource.url=jdbc:mysql://legacydb.next26.slalomlab.com:3306/ticketing
spring.datasource.username=user
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# JPA/Hibernate Configuration
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
# RabbitMQ Connection
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
By modifying only this file (or providing an environment-specific version like application-gcp.properties), the application can be pointed to different databases and message brokers without any code changes.
docker-compose.yml
This file defines the local development infrastructure using Docker. It allows developers to spin up required services like MySQL and RabbitMQ with a single command, ensuring a consistent environment for everyone on the team. For detailed usage, refer to the Environment Setup guide.
CLAUDE.md
This file serves as the project's charter. It provides critical context on the application's purpose: to serve as a "legacy on-premises application" running in a VMware environment for the Agentic AI Modernization workshop at Google Next 2026, demonstrating migration to Google Cloud Platform using AI-assisted techniques. It outlines the core philosophy of minimizing code changes and maximizing externalized configuration. All developers should read this file before contributing to understand the strategic constraints and goals that shape the architecture and code style.