# ADR 0001 — Stack, build tooling, and quality gates

- Status: Accepted
- Date: 2026-08-19

## Context

We are building a production-grade Spring Boot service (Item CRUD + full auth)
that runs over TLS on port 4455, per `docs/PROMT.md`. Phase 0 establishes the
repository skeleton, the build, and the quality gates that every later phase
must satisfy. The repository arrived with a Spring Initializr scaffold that did
**not** match the specification, so the first decision is how to reconcile it.

## Decisions

### 1. Discard the scaffold; align to the spec

The generated scaffold used **Spring Boot 4.1.0**, Java **17**, package
`com.codebyte.api.demo`, and the `spring-boot-starter-webmvc` starter. The spec
mandates **Spring Boot 3.5.x**, **Java 21**, and base package
`com.codebyte.api`. Spring Boot 3.5.x is the current LTS-track line with the
richest ecosystem support for the libraries we need (Testcontainers service
connections, springdoc, PEM SSL bundles). We therefore rewrote `pom.xml` to
**Spring Boot 3.5.16** (the latest 3.5 patch at time of writing — verified
against Maven Central metadata, not guessed), Java 21, base package
`com.codebyte.api`, and the standard `spring-boot-starter-web`.

Consequence: the Initializr output is gone; nothing downstream depends on it.

### 2. Build tool: Maven

Chosen per the spec default. The Spring Boot parent POM gives us a curated,
reproducible dependency BOM with pinned versions, which satisfies the
"dependency versions pinned via BOM" requirement without hand-maintaining a
`<dependencyManagement>` block.

### 3. Java 21, built with a pinned toolchain

We target `release 21`. The local machine currently runs JDK 25; the build is
executed with the installed **`21-tem`** JDK (`JAVA_HOME` pointed at it) and CI
pins Java 21 via `setup-java`. Targeting `release 21` guarantees 21-compatible
bytecode regardless of the compiling JDK. A `.mvn/jvm.config` adds the
`--add-exports/--add-opens` flags that google-java-format requires on modern
JDKs.

### 4. Test source-set split: Surefire (`*Test`/`*Tests`) vs Failsafe (`*IT`)

Unit tests (`*Test`, `*Tests`) run under Surefire during `test`; integration
tests (`*IT`, Testcontainers-backed from Phase 2) run under Failsafe during
`integration-test`/`verify`. This lets `mvn test` stay fast and Docker-free
while `mvn verify` runs the full suite, matching the CI job split (§9).

### 5. Quality gates wired now, enforced when there is code to measure

Spotless (google-java-format **AOSP**), Checkstyle, and SpotBugs run on every
`verify` and fail the build immediately — they are enforced from Phase 0.

JaCoCo and PIT are **wired but held off by properties** (`coverage.gate.skip`,
`pitest.skip`, both default `true`). An empty skeleton cannot meet an 80% line /
70% branch coverage bar or a 60% mutation bar, so enforcing them in Phase 0
would fail the build for a vacuous reason. The gates flip on in the phases where
the measured code lands — `item.service` and `auth.service` (Phases 3 and 5) —
and unconditionally in CI (Phase 9), via `-Dcoverage.gate.skip=false`
`-Dpitest.skip=false`. The thresholds themselves are already declared in the
POM, so turning them on is a one-flag change, not new configuration.

### 6. Formatting authority: Spotless owns layout, Checkstyle owns structure

To avoid two tools fighting over the same rules, Spotless/google-java-format is
the sole authority on indentation, wrapping, and spacing. Checkstyle enforces
only what a formatter cannot: import hygiene, mandatory braces, naming, banned
types (`java.util.Date`), and banned `System.out`/`System.err`. ArchUnit (Phase
2) enforces the layering rules; Checkstyle gives faster local feedback on the
banned-construct subset.

## Consequences

- `mvn -q verify` (with `JAVA_HOME=21-tem`) is the local gate and is green for
  the Phase 0 skeleton.
- Deferred, still-open decisions (recorded here so they are not re-litigated):
  JWT library (jjwt vs Nimbus) — Phase 5; primary-key strategy — **UUIDv7,
  application-generated**; the two-file SSL chain problem — the **preferred
  in-memory `SslBundleRegistrar`** — Phase 7. Each gets its own ADR when built.
