Appearance
Overview
This document provides a high-level technical overview of the IT Ticketing Service. It is intended for developers responsible for maintaining, extending, and migrating the application. The document covers the system's architecture, its layered design, and the core principles that guide its development.
System Architecture
The IT Ticketing Service is a monolithic Spring Boot application designed to function as a "legacy" on-premises service, with a clear migration path to a cloud-native environment like Google Cloud Platform. Its primary function is to provide a RESTful API for managing IT support tickets.
Overall System Design
The system is composed of three main parts:
- The Core Application: A Java 17 / Spring Boot 3.2.4 web service that exposes REST endpoints for ticket management.
- A Relational Database: A MySQL database used for persisting all ticket data.
- A Message Broker: A RabbitMQ instance for publishing events related to ticket lifecycle changes (e.g., creation, updates), enabling asynchronous processing and integration with other systems.
The application is designed to be environment-agnostic, relying heavily on externalized configuration to connect to its dependencies. This is a key architectural decision to facilitate migration from an on-premises environment to the cloud with minimal code changes.
Component Interaction
The typical request and event flow is as follows:
- A client (e.g., a frontend application or an API tool) sends an HTTP request to one of the REST endpoints (e.g.,
POST /api/tickets). - The API Layer (Controller) receives the request, validates the input, and delegates the operation to the Service Layer.
- The Service Layer executes the core business logic. For data persistence, it calls the appropriate method on a Data Access Layer (Repository).
- The Repository (a Spring Data JPA interface) translates the call into a SQL query via Hibernate and interacts with the MySQL Database.
- After successfully persisting the data, the Service Layer constructs a ticket event message.
- The service uses a Spring AMQP
RabbitTemplateto publish the event to a RabbitMQ Exchange (ticket.exchangewith routing keyticket.routing.key). Downstream consumers can then process this event asynchronously. - A response is returned up the call stack and sent back to the client as an HTTP response.
Technology Stack Summary
The application is built with Apache Maven and runs on Java 17. The core framework is Spring Boot, which manages the web, data access, and messaging components.
| Technology | Version | Notes |
|---|---|---|
| Java | 17 | Defined in the pom.xml properties. |
| Spring Boot | 3.2.4 | The parent POM version, manages most dependencies. |
| Spring Data JPA | 3.2.4 | Provides repository abstraction over Hibernate for ORM. |
| Spring AMQP | 3.2.4 | Integrates with RabbitMQ for asynchronous messaging. |
| MySQL Connector | - | mysql-connector-j driver for database connectivity. |
| Lombok | 1.18.34 | Reduces boilerplate code in model and DTO classes. |
| JUnit 5 | - | Core testing framework provided by spring-boot-starter-test. |
| Mockito | - | Mocking framework for unit and integration tests. |
Layered Architecture
The application follows a classic three-layer architecture to enforce separation of concerns, which enhances maintainability, testability, and scalability.
API Layer (Controllers)
This layer is the entry point for all external communication. It is responsible for:
- Exposing RESTful endpoints over HTTP.
- Handling serialization and deserialization of JSON request/response bodies.
- Performing input validation using
spring-boot-starter-validation(Java Bean Validation). - Translating HTTP-specific details into method calls on the Service Layer.
This layer should contain no business logic. Its primary role is protocol translation and data mapping. The API endpoints are defined in REST controllers, as shown in the README.md examples.
bash
# Example: Creating a new ticket via the API Layer
POST /api/tickets
Content-Type: application/json
{
"title": "Laptop won't start",
"description": "My laptop won't turn on after the latest update",
"status": "OPEN",
"priority": "HIGH",
"requesterEmail": "user@example.com",
"assignedTo": "support@example.com"
}1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
Service Layer (Business Logic)
This is the heart of the application, where all business rules and logic reside. The Service Layer is responsible for:
- Orchestrating calls to one or more repositories to fulfill a business operation.
- Implementing complex business rules and validations that go beyond simple field constraints.
- Managing transactions (declaratively via
@Transactionalannotations). - Publishing domain events to the message broker after a state change occurs.
By isolating business logic here, the application becomes more resilient to changes in the data access or API layers.
Data Access Layer (Repositories)
This layer abstracts the underlying data store (MySQL). It is implemented using Spring Data JPA.
- Entities: Plain Old Java Objects (POJOs) annotated with
@Entitythat map to database tables. - Repositories: Interfaces that extend
JpaRepository. Spring Data automatically provides implementations for standard CRUD operations at runtime, eliminating the need for boilerplate DAO implementation code.
Custom queries can be defined using the query derivation mechanism (e.g., findByStatus(String status)) or with the @Query annotation for more complex JPQL or native SQL queries. This layer's sole responsibility is data persistence and retrieval.
Design Principles
The application's design is guided by several key principles to ensure it is robust, maintainable, and ready for its intended migration.
Spring Boot Best Practices
The codebase adheres to established Spring Boot conventions to maximize developer productivity and leverage the framework's powerful features.
- Dependency Injection: Services, repositories, and other components are managed by the Spring IoC container and injected where needed using constructor injection.
- Auto-configuration: The application relies heavily on Spring Boot's auto-configuration for setting up the database connection pool,
RabbitTemplate,JpaTransactionManager, and web server. - Component Scanning: The main application class uses
@SpringBootApplication, which enables component scanning to automatically discover and register beans.
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
14
2
3
4
5
6
7
8
9
10
11
12
13
14
12-Factor App Principles
The application is designed with the 12-Factor App methodology in mind, particularly Factor III: Config. All environment-specific configuration is strictly externalized from the code. This is the most critical principle for achieving the project's goal of a low-effort cloud migration.
There are no hardcoded database URLs, credentials, or message broker hostnames in the source code. All such values are managed in application.properties and can be overridden by environment variables or command-line arguments, allowing the same compiled artifact (.jar file) to run in any environment.
Environment-Agnostic Design
Building on the 12-Factor principles, the code is written to be completely unaware of its execution environment. Whether it's running on a local developer machine, an on-premises VMware server, or in a Google Cloud Run container, the application logic remains identical. The operational behavior is steered entirely by the configuration it receives at startup.
This approach decouples the application from its infrastructure, which is essential for portability and migration.
Configuration-Driven Deployment
This is the practical application of the principles above. The migration strategy from on-prem to cloud relies almost exclusively on changing configuration properties.
Example: Migrating the Database from On-Prem MySQL to Cloud SQL
No code changes are required. The deployment process only needs to provide updated configuration values.
On-Prem Configuration (
application.properties):properties# Database connection for the on-premises environment spring.datasource.url=jdbc:mysql://legacydb.next26.slalomlab.com:3306/ticketing spring.datasource.username=ticketing_user spring.datasource.password=changeme1
2
3
4Cloud SQL Configuration (provided via environment variables in Cloud Run):
bash# Environment variables set in the cloud deployment environment SPRING_DATASOURCE_URL=jdbc:mysql://<cloud_sql_ip>:3306/ticketing SPRING_DATASOURCE_USERNAME=cloud_sql_user SPRING_DATASOURCE_PASSWORD=<secret_from_secret_manager>1
2
3
4
This configuration-driven model applies equally to the RabbitMQ connection and any other external service dependencies.