AI-powered answers for case documents — every response cited and auditable.
Spring Boot 4 (Java 21), PostgreSQL + Flyway, production-ready observability, and CI-friendly *
Gradle* build.
- Features
- Tech stack
- Project layout
- Prerequisites
- Build & test (Gradle)
- Run locally (Gradle)
- Run with Docker Compose
- Integration tests with Docker Compose
- Configuration
- API & docs
- Observability
- SBOM / dependency insights
- Troubleshooting
- License
- PostgreSQL persistence with Flyway migrations
- Observability: Actuator health, Prometheus metrics, OTLP tracing, structured JSON logs
- Quality gates: PMD, JaCoCo coverage
- Gradle 9 build with Docker-Compose-backed integration tests
Note: HTTP security/authorization is intentionally minimal by default. Integrate with your gateway or add your own authorization as needed.
- Java 21, Spring Boot 4.0.0-M2
- Spring MVC, Spring Data JPA, PostgreSQL 16, Flyway
- Micrometer + Prometheus, OpenTelemetry OTLP exporter
- Gradle 9, PMD, JaCoCo
- Docker / Docker Compose v2
.
├─ src/main/java/... # application code
├─ src/main/resources/
│ ├─ application.yml # prod-ready defaults
│ └─ db/migration/ # Flyway migrations
├─ src/test/java/... # unit tests
├─ src/integrationTest/java/... # integration tests (Gradle sourceSet)
├─ docker/
│ ├─ Dockerfile
│ └─ docker-compose.integration.yml
└─ build.gradle # Gradle build
- Java 21
- Docker Engine v27+ and Docker Compose v2 (
docker composeCLI) - Nothing else required — use the Gradle (
gradle)
# Clean & full build (unit tests)
gradle clean build
# Faster local build (skip tests)
gradle -x test clean build
# Run only unit tests
gradle test
# Run only integration tests
gradle integration
# Code quality reports
gradle pmdMain pmdTest jacocoTestReport
# Open reports
open build/reports/pmd/main.html
open build/reports/tests/test/index.html
open build/reports/jacoco/test/html/index.html
# Dependency insight (useful for conflicts)
gradle dependencyInsight --dependency <group-or-module>By default the app starts on :8082 and looks for Postgres at localhost:55432 ( see Configuration).
# Start with your local Java 21
gradle bootRunThis brings up PostgreSQL 16 (exposed as localhost:55432) and the app (exposed as
localhost:8082).
It uses docker/docker-compose.integration.yml.
# Build image & start stack
docker compose -f docker/docker-compose.integration.yml up -d --build
# Tail logs
docker compose -f docker/docker-compose.integration.yml logs -f app
# Stop & remove (keep volumes)
docker compose -f docker/docker-compose.integration.yml down
# Remove everything inc. volumes (⚠️ deletes DB data)
docker compose -f docker/docker-compose.integration.yml down -vIntegration tests automatically bring up Postgres + app, wait until they’re healthy, run tests, then **tear down ** the stack.
gradle clean integrationWhat happens under the hood:
- Gradle task
integrationdepends oncomposeUp(from the Compose plugin) composeUpbuilds the app image, starts Postgres (host port 55432) and app (8082), and waits for health- Tests run against
http://localhost:8082 composeDownis always called to clean up
The application is configured via environment variables with sensible defaults. Key settings:
| Property | Default | Notes |
|---|---|---|
server.port |
8082 |
API & Actuator port |
SPRING_DATASOURCE_URL |
jdbc:postgresql://localhost:55432/casedocumentknowledgeDatabase |
Postgres JDBC URL |
SPRING_DATASOURCE_USERNAME |
app |
DB user |
SPRING_DATASOURCE_PASSWORD |
app |
DB password |
DB_POOL_SIZE |
10 |
Hikari pool size |
TRACING_SAMPLER_PROBABILITY |
1.0 |
OTel tracing sample rate |
OTEL_TRACES_URL |
http://localhost:4318/traces |
OTLP traces endpoint |
OTEL_METRICS_ENABLED |
false |
Export metrics via OTLP if true |
OTEL_METRICS_URL |
http://localhost:4318/metrics |
OTLP metrics endpoint |
Flyway is enabled and points at classpath:db/migration.
- Base URL:
http://localhost:8082
Example smoke:
curl -fsS "http://localhost:8082/actuator/health" | jqPlease see the API Marketplace documentation for details on api versioning, etc : Supporting Documents
Actuator endpoints (same port as API):
| Endpoint | Purpose |
|---|---|
/actuator/health |
Overall health (UP/DOWN) |
/actuator/health/liveness |
Liveness probe |
/actuator/health/readiness |
Readiness probe |
/actuator/info |
App/build info (if configured) |
/actuator/prometheus |
Prometheus/OpenMetrics scrape |
The service logs JSON to STDOUT (Logback + logstash-encoder).
OTel tracing is pre-wired; set the OTEL_* env vars above to export.
Quick checks:
curl -fsS http://localhost:8082/actuator/health
curl -fsS http://localhost:8082/actuator/prometheus | headGenerate a CycloneDX SBOM:
gradle cyclonedxBom
# Output at: build/reports/bom.json (or .xml depending on configuration)Print dependency trees:
gradle -q dependencies --configuration runtimeClasspathBuild tasks and their dependencies:
flowchart TD
build[build] --> check[check]
check --> test[test]
check --> integration[integration - docker-compose integration tests]
integration --> composeUp[composeUp]
composeUp --> composeBuild[composeBuild]
composeBuild --> bootJar[bootJar]
bootJar --> jar[jar]
integration --> composeDown[composeDown - finalizedBy]
- Port in use — Change ports in
application.ymlor Compose file. DB uses 55432 to avoid conflicts with a local 5432. - Compose not found — You need Docker Compose v2 (
docker compose). The Gradle plugin calls the Docker CLI directly. - DB auth failures — Ensure env vars match Postgres service in Compose:
app/app@appdb. - Slow startup in CI — Increase Compose wait timeouts (plugin
upAdditionalArgs) if needed. - Gradle “buildDir deprecated” — The build uses
layout.buildDirectory; avoid legacybuildDirin custom tasks.
MIT