|
1 | | -# HMCTS Service Spring Boot Template |
| 1 | +# case-document-knowledge-service |
2 | 2 |
|
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. |
4 | 5 |
|
5 | | -It includes essential configurations, dependencies, and recommended practices to help teams get started quickly. |
| 6 | +--- |
6 | 7 |
|
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 |
8 | 9 |
|
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) |
10 | 24 |
|
11 | | -## Want to Build Your Own Path? |
| 25 | +--- |
12 | 26 |
|
13 | | -That’s absolutely fine — but if you do, make sure your approach meets the following baseline requirements: |
| 27 | +## Features |
14 | 28 |
|
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** |
21 | 35 |
|
22 | | -## Installation |
| 36 | +> Note: HTTP security/authorization is intentionally minimal by default. Integrate with your gateway or add your own authorization as needed. |
23 | 37 |
|
24 | | -To get started with this project, you'll need Java and Gradle installed. |
| 38 | +--- |
25 | 39 |
|
26 | | -### Prerequisites |
| 40 | +## Tech stack |
27 | 41 |
|
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 |
30 | 48 |
|
31 | | - **macOS (Recommended with Homebrew):** |
32 | | - ```bash |
33 | | - brew install gradle |
34 | | - ``` |
| 49 | +--- |
35 | 50 |
|
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`. |
38 | 119 |
|
39 | | -You can verify installation with: |
40 | 120 | ```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 |
43 | 142 | ``` |
44 | 143 |
|
45 | | -#### Add Gradle Wrapper |
| 144 | +What happens under the hood: |
46 | 145 |
|
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 |
48 | 150 |
|
49 | | -### Environment Setup for Local Builds |
| 151 | +--- |
50 | 152 |
|
51 | | -Recommended Approach for macOS Users (using `direnv`) |
| 153 | +## Configuration |
52 | 154 |
|
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: |
54 | 156 |
|
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 | |
59 | 168 |
|
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`. |
66 | 170 |
|
67 | | -4. Allow `direnv` to load: |
68 | | - ```bash |
69 | | - direnv allow |
70 | | - ``` |
| 171 | +--- |
71 | 172 |
|
72 | | -This will ensure your environment is correctly set up every time you enter the project directory. |
| 173 | +## API & docs |
73 | 174 |
|
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`) |
75 | 178 |
|
76 | | -Install PMD |
| 179 | +Example smoke: |
77 | 180 |
|
78 | 181 | ```bash |
79 | | -brew install pmd |
| 182 | +curl -fsS "http://localhost:8082/actuator/health" | jq |
80 | 183 | ``` |
| 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 | + |
81 | 204 | ```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 |
88 | 207 | ``` |
89 | 208 |
|
90 | | -## Pact Provider Test |
| 209 | +--- |
| 210 | + |
| 211 | +## SBOM / dependency insights |
91 | 212 |
|
92 | | -Run pact provider test and publish verification report to pact broker locally |
| 213 | +Generate a CycloneDX SBOM: |
93 | 214 |
|
94 | | -Update .env file with below details (replacing placeholders with actual values): |
95 | 215 | ```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) |
102 | 218 | ``` |
103 | | -Run Pact tests: |
| 219 | + |
| 220 | +Print dependency trees: |
| 221 | + |
104 | 222 | ```bash |
105 | | -gradle pactVerificationTest |
| 223 | +./gradlew -q dependencies --configuration runtimeClasspath |
106 | 224 | ``` |
107 | 225 |
|
108 | | -### Contribute to This Repository |
| 226 | +--- |
| 227 | + |
| 228 | +## Troubleshooting |
109 | 229 |
|
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. |
111 | 235 |
|
112 | | -See also: [JWTFilter documentation](docs/JWTFilter.md) |
| 236 | +--- |
113 | 237 |
|
114 | 238 | ## License |
115 | 239 |
|
116 | | -This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details |
| 240 | +MIT |
0 commit comments