Skip to content

Commit 5913568

Browse files
spring boot with IT test
1 parent c18846e commit 5913568

40 files changed

+773
-1498
lines changed

Dockerfile

Lines changed: 0 additions & 36 deletions
This file was deleted.

README.md

Lines changed: 195 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,116 +1,240 @@
1-
# HMCTS Service Spring Boot Template
1+
# case-document-knowledge-service
22

3-
This repository provides a template for building Spring Boot applications. While the initial use case was for the HMCTS API Marketplace, the template is designed to be reusable across jurisdictions and is intended as a base paved path for wider adoption.
3+
**AI-powered answers for case documents — every response cited and auditable.**
4+
Spring Boot 4 (Java 21) REST API with OpenAPI docs, PostgreSQL + Flyway, production-ready observability, and CI-friendly **Gradle** build.
45

5-
It includes essential configurations, dependencies, and recommended practices to help teams get started quickly.
6+
---
67

7-
**Note:** This template is not a framework, nor is it intended to evolve into one. It simply leverages the Spring ecosystem and proven libraries from the wider engineering community.
8+
## Table of contents
89

9-
As HMCTS services are hosted on Azure, the included dependencies reflect this. Our aim is to stay as close to the cloud as possible in order to maximise alignment with the Shared Responsibility Model and achieve optimal security and operability.
10+
- [Features](#features)
11+
- [Tech stack](#tech-stack)
12+
- [Project layout](#project-layout)
13+
- [Prerequisites](#prerequisites)
14+
- [Build & test (Gradle)](#build--test-gradle)
15+
- [Run locally (Gradle)](#run-locally-gradle)
16+
- [Run with Docker Compose](#run-with-docker-compose)
17+
- [Integration tests with Docker Compose](#integration-tests-with-docker-compose)
18+
- [Configuration](#configuration)
19+
- [API & docs](#api--docs)
20+
- [Observability](#observability)
21+
- [SBOM / dependency insights](#sbom--dependency-insights)
22+
- [Troubleshooting](#troubleshooting)
23+
- [License](#license)
1024

11-
## Want to Build Your Own Path?
25+
---
1226

13-
That’s absolutely fine — but if you do, make sure your approach meets the following baseline requirements:
27+
## Features
1428

15-
* Security – All services must meet HMCTS security standards, including vulnerability scanning and least privilege access.
16-
* Observability – Logs, metrics, and traces must be integrated into HMCTS observability stack (e.g. Azure Monitoring).
17-
* Audit – Systems must produce audit trails that meet legal and operational requirements.
18-
* CI/CD Integration – Pipelines must include automated testing, deployments to multiple environments, and use approved tooling (e.g. GitHub Actions or Azure DevOps).
19-
* Compliance & Policy Alignment – Services must align with HMCTS/MoJ policies (e.g. Coding in the Open, mandatory security practices).
20-
* Ownership & Support – Domain teams must clearly own the service, maintain a support model, and define escalation paths.
29+
- Versioned **REST API** under `/api/v1/**`
30+
- **OpenAPI / Swagger UI**
31+
- **PostgreSQL** persistence with **Flyway** migrations
32+
- **Observability**: Actuator health, Prometheus metrics, OTLP tracing, structured JSON logs
33+
- **Quality gates**: PMD, JaCoCo coverage
34+
- **Gradle 9** build with Docker-Compose-backed **integration tests**
2135

22-
## Installation
36+
> Note: HTTP security/authorization is intentionally minimal by default. Integrate with your gateway or add your own authorization as needed.
2337
24-
To get started with this project, you'll need Java and Gradle installed.
38+
---
2539

26-
### Prerequisites
40+
## Tech stack
2741

28-
- ☕️ **Java 21 or later**: Ensure Java is installed and available on your `PATH`.
29-
- ⚙️ **Gradle**: You can install Gradle using your preferred method:
42+
- **Java 21**, **Spring Boot 4.0.0-M2**
43+
- Spring MVC, Spring Data JPA, **PostgreSQL 16**, Flyway
44+
- springdoc-openapi 3.x (Swagger UI)
45+
- Micrometer + **Prometheus**, OpenTelemetry OTLP exporter
46+
- Gradle 9, PMD, JaCoCo
47+
- Docker / Docker Compose v2
3048

31-
**macOS (Recommended with Homebrew):**
32-
```bash
33-
brew install gradle
34-
```
49+
---
3550

36-
**Other Platforms:**
37-
Visit the [Gradle installation guide](https://gradle.org/install/) for platform-specific instructions.
51+
## Project layout
52+
53+
```
54+
.
55+
├─ src/main/java/... # application code
56+
├─ src/main/resources/
57+
│ ├─ application.yml # prod-ready defaults
58+
│ └─ db/migration/ # Flyway migrations
59+
├─ src/test/java/... # unit tests
60+
├─ src/integrationTest/java/... # integration tests (Gradle sourceSet)
61+
├─ docker/
62+
│ ├─ Dockerfile
63+
│ └─ docker-compose.integration.yml
64+
└─ build.gradle # Gradle build
65+
```
66+
67+
---
68+
69+
## Prerequisites
70+
71+
- Java **21**
72+
- Docker Engine **v27+** and **Docker Compose v2** (`docker compose` CLI)
73+
- Nothing else required — use the Gradle wrapper (`./gradlew`)
74+
75+
---
76+
77+
## Build & test (Gradle)
78+
79+
```bash
80+
# Clean & full build (unit tests)
81+
./gradlew clean build
82+
83+
# Faster local build (skip tests)
84+
./gradlew -x test clean build
85+
86+
# Run only unit tests
87+
./gradlew test
88+
89+
# Run only integration tests
90+
./gradlew integration
91+
# Code quality reports
92+
./gradlew pmdMain pmdTest jacocoTestReport
93+
# Open reports
94+
open build/reports/pmd/main.html
95+
open build/reports/tests/test/index.html
96+
open build/reports/jacoco/test/html/index.html
97+
98+
# Dependency insight (useful for conflicts)
99+
./gradlew dependencyInsight --dependency <group-or-module>
100+
```
101+
102+
---
103+
104+
## Run locally (Gradle)
105+
106+
By default the app starts on **:8082** and looks for Postgres at **localhost:55432** (see [Configuration](#configuration)).
107+
108+
```bash
109+
# Start with your local Java 21
110+
./gradlew bootRun
111+
```
112+
113+
---
114+
115+
## Run with Docker Compose
116+
117+
This brings up **PostgreSQL 16** (exposed as `localhost:55432`) and the **app** (exposed as `localhost:8082`).
118+
It uses `docker/docker-compose.integration.yml`.
38119

39-
You can verify installation with:
40120
```bash
41-
java -version
42-
gradle -v
121+
# Build image & start stack
122+
docker compose -f docker/docker-compose.integration.yml up -d --build
123+
124+
# Tail logs
125+
docker compose -f docker/docker-compose.integration.yml logs -f app
126+
127+
# Stop & remove (keep volumes)
128+
docker compose -f docker/docker-compose.integration.yml down
129+
130+
# Remove everything inc. volumes (⚠️ deletes DB data)
131+
docker compose -f docker/docker-compose.integration.yml down -v
132+
```
133+
134+
---
135+
136+
## Integration tests with Docker Compose
137+
138+
Integration tests automatically **bring up** Postgres + app, **wait** until they’re healthy, run tests, then **tear down** the stack.
139+
140+
```bash
141+
./gradlew clean integration
43142
```
44143

45-
#### Add Gradle Wrapper
144+
What happens under the hood:
46145

47-
run `gradle wrapper`
146+
- Gradle task `integration` depends on `composeUp` (from the Compose plugin)
147+
- `composeUp` builds the app image, starts Postgres (host port **55432**) and app (**8082**), and waits for health
148+
- Tests run against `http://localhost:8082`
149+
- `composeDown` is always called to clean up
48150

49-
### Environment Setup for Local Builds
151+
---
50152

51-
Recommended Approach for macOS Users (using `direnv`)
153+
## Configuration
52154

53-
If you're on macOS, you can use [direnv](https://direnv.net/) to automatically load these environment variables per project:
155+
The application is configured via environment variables with sensible defaults. Key settings:
54156

55-
1. Install `direnv`:
56-
```bash
57-
brew install direnv
58-
```
157+
| Property | Default | Notes |
158+
|----------------------------------|----------------------------------------------|-------------------------------------|
159+
| `server.port` | `8082` | API & Actuator port |
160+
| `SPRING_DATASOURCE_URL` | `jdbc:postgresql://localhost:55432/appdb` | Postgres JDBC URL |
161+
| `SPRING_DATASOURCE_USERNAME` | `app` | DB user |
162+
| `SPRING_DATASOURCE_PASSWORD` | `app` | DB password |
163+
| `DB_POOL_SIZE` | `10` | Hikari pool size |
164+
| `TRACING_SAMPLER_PROBABILITY` | `1.0` | OTel tracing sample rate |
165+
| `OTEL_TRACES_URL` | `http://localhost:4318/v1/traces` | OTLP traces endpoint |
166+
| `OTEL_METRICS_ENABLED` | `false` | Export metrics via OTLP if `true` |
167+
| `OTEL_METRICS_URL` | `http://localhost:4318/v1/metrics` | OTLP metrics endpoint |
59168

60-
2. Hook it into your shell (example for bash or zsh):
61-
```bash
62-
echo 'eval "$(direnv hook bash)"' >> ~/.bash_profile
63-
# or for zsh
64-
echo 'eval "$(direnv hook zsh)"' >> ~/.zshrc
65-
```
169+
Flyway is enabled and points at `classpath:db/migration`.
66170

67-
4. Allow `direnv` to load:
68-
```bash
69-
direnv allow
70-
```
171+
---
71172

72-
This will ensure your environment is correctly set up every time you enter the project directory.
173+
## API & docs
73174

74-
## Static code analysis
175+
- Base URL: `http://localhost:8082`
176+
- Swagger UI: `http://localhost:8082/swagger-ui.html`
177+
(OpenAPI JSON at `/v3/api-docs`)
75178

76-
Install PMD
179+
Example smoke:
77180

78181
```bash
79-
brew install pmd
182+
curl -fsS "http://localhost:8082/actuator/health" | jq
80183
```
184+
185+
---
186+
187+
## Observability
188+
189+
Actuator endpoints (same port as API):
190+
191+
| Endpoint | Purpose |
192+
|-----------------------------|---------------------------------|
193+
| `/actuator/health` | Overall health (UP/DOWN) |
194+
| `/actuator/health/liveness` | Liveness probe |
195+
| `/actuator/health/readiness`| Readiness probe |
196+
| `/actuator/info` | App/build info (if configured) |
197+
| `/actuator/prometheus` | Prometheus/OpenMetrics scrape |
198+
199+
The service logs JSON to STDOUT (Logback + logstash-encoder).
200+
OTel tracing is pre-wired; set the `OTEL_*` env vars above to export.
201+
202+
Quick checks:
203+
81204
```bash
82-
pmd check \
83-
--dir src/main/java \
84-
--rulesets \
85-
.github/pmd-ruleset.xml \
86-
--format html \
87-
-r build/reports/pmd/pmd-report.html
205+
curl -fsS http://localhost:8082/actuator/health
206+
curl -fsS http://localhost:8082/actuator/prometheus | head
88207
```
89208

90-
## Pact Provider Test
209+
---
210+
211+
## SBOM / dependency insights
91212

92-
Run pact provider test and publish verification report to pact broker locally
213+
Generate a CycloneDX SBOM:
93214

94-
Update .env file with below details (replacing placeholders with actual values):
95215
```bash
96-
export PACT_PROVIDER_VERSION="0.1.0-local-YOUR-INITIALS" # or any version you want to use
97-
export PACT_VERIFIER_PUBLISH_RESULTS=true
98-
export PACT_PROVIDER_BRANCH="ANY_BRANCH_NAME_THAT_IS_NOT_A_DEFAULT_ONE"
99-
export PACT_BROKER_TOKEN="YOUR_PACTFLOW_BROKER_TOKEN"
100-
export PACT_BROKER_URL="https://hmcts-dts.pactflow.io"
101-
export PACT_ENV="local" # or value based on the environment you are testing against
216+
./gradlew cyclonedxBom
217+
# Output at: build/reports/bom.json (or .xml depending on configuration)
102218
```
103-
Run Pact tests:
219+
220+
Print dependency trees:
221+
104222
```bash
105-
gradle pactVerificationTest
223+
./gradlew -q dependencies --configuration runtimeClasspath
106224
```
107225

108-
### Contribute to This Repository
226+
---
227+
228+
## Troubleshooting
109229

110-
Contributions are welcome! Please see the [CONTRIBUTING.md](.github/CONTRIBUTING.md) file for guidelines.
230+
- **Port in use** — Change ports in `application.yml` or Compose file. DB uses **55432** to avoid conflicts with a local 5432.
231+
- **Compose not found** — You need **Docker Compose v2** (`docker compose`). The Gradle plugin calls the Docker CLI directly.
232+
- **DB auth failures** — Ensure env vars match Postgres service in Compose: `app/app@appdb`.
233+
- **Slow startup in CI** — Increase Compose wait timeouts (plugin `upAdditionalArgs`) if needed.
234+
- **Gradle “buildDir deprecated”** — The build uses `layout.buildDirectory`; avoid legacy `buildDir` in custom tasks.
111235

112-
See also: [JWTFilter documentation](docs/JWTFilter.md)
236+
---
113237

114238
## License
115239

116-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details
240+
MIT

bin/run-in-docker.sh

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,9 @@ GRADLE_INSTALL=false
2424

2525
# TODO custom environment variables application requires.
2626
# TODO also consider enlisting them in help string above ^
27-
# TODO sample: DB_PASSWORD Defaults to 'dev'
27+
# TODO sample: CP_CDK_DB_PASSWORD Defaults to 'dev'
2828
# environment variables
29-
#DB_PASSWORD=dev
29+
#CP_CDK_DB_PASSWORD=dev
3030
#S2S_URL=localhost
3131
#S2S_SECRET=secret
3232

@@ -47,7 +47,7 @@ execute_script() {
4747

4848
# echo "Assigning environment variables.."
4949
#
50-
# export DB_PASSWORD=${DB_PASSWORD}
50+
# export CP_CDK_DB_PASSWORD=${CP_CDK_DB_PASSWORD}
5151
# export S2S_URL=${S2S_URL}
5252
# export S2S_SECRET=${S2S_SECRET}
5353

@@ -63,7 +63,7 @@ while true ; do
6363
-i|--install) GRADLE_INSTALL=true ; shift ;;
6464
-p|--param)
6565
case "$2" in
66-
# DB_PASSWORD=*) DB_PASSWORD="${2#*=}" ; shift 2 ;;
66+
# CP_CDK_DB_PASSWORD=*) CP_CDK_DB_PASSWORD="${2#*=}" ; shift 2 ;;
6767
# S2S_URL=*) S2S_URL="${2#*=}" ; shift 2 ;;
6868
# S2S_SECRET=*) S2S_SECRET="${2#*=}" ; shift 2 ;;
6969
*) shift 2 ;;

0 commit comments

Comments
 (0)