Files
clean-architecture-backend-…/docs/jpa/support-matrix.md
T
DongHyeonkaandClaude Opus 5 0e61f86eb5 feat(jpa): implement the JPA relational persistence platform
Implements the Stable and Experimental JPA persistence platform designs
against real PostgreSQL, adapted to this repository's fail-closed 19-leaf
registry.

The design models the platform as 25 Gradle projects. `src/settings.gradle`
throws unless the registry holds exactly 19 leaves, so the plan's modules
become packages inside `:adapter:outbound:persistence-jpa` (starter in
`:app-bootstrap`, testkit in its own source set). The full mapping, the
renames this repository's naming gate required, and every deliberate
substitution are recorded in `docs/jpa/repository-adaptation.md`.

Seven Docker-backed lanes replace the plan's seven JVM test suites. Each
fails closed: a lane that discovers nothing, or a container that cannot
start, is an error rather than a skip.

Three defects the contracts found against a real server:

- `CommitFailureClassifier` treated only SQLSTATE 40003, class 08, and
  transport breaks as completion-unknown. A backend terminated mid-commit
  reports 57P01, and the commit record may already be in the WAL — so a
  possibly-committed transaction could be re-run. 57P01/57P02/57P03 now
  classify as completion-unknown.
- `SchemaTenantMigrationOrchestrator` recorded `MigrateResult`'s target
  version, which is empty for a tenant already current, reporting migrated
  tenants as unmigrated during a partial rollout. It now reads the applied
  version back from the tenant's schema history.
- `JpaStreamExecutor` checked only the declared return type for reactive
  publishers, and `RegisteredPostgreSqlCopyLoader` passed the COPY timeout
  to `SET`, which is parsed before parameter binding.

`JpaModuleBoundaryTest` enforces the plan's module map as package rules;
`verifyCleanArchitectureDependencies` governs edges between leaves and
cannot see these. Its first assertion is that the import is non-empty,
because every rule under it is a `noClasses()` rule and would pass
vacuously on an empty import.

Verified: 128 container tests across all seven lanes, 1183 unit tests,
`:adapter:outbound:persistence-jpa:check`, `:app-bootstrap:check`,
`verifyCleanArchitectureDependencies`, `verifyOneTypePerFile`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-14 14:06:18 +09:00

3.6 KiB

JPA Persistence Platform — Support Matrix

The machine-readable source for JpaReleaseManifest. A release gate parses this file, so a version or gate that stops being named here stops being claimed — and the build fails rather than the document quietly drifting from the code.

Database

Database Support Evidence
PostgreSQL 16 Stable full contract suite, release lane
PostgreSQL 17 Stable full contract suite, release lane
PostgreSQL 18 Stable full contract suite, release lane
PostgreSQL 19 Experimental compatibility lane only; promotion requires an ADR
H2 Local convenience never evidence of PostgreSQL behaviour

H2 is not a second production target. It reports different SQLSTATEs for the same violation, has no SKIP LOCKED guarantee the platform relies on, no JSONB operators, no range types, and no concurrent index builds. A green H2 run is evidence that the code compiles and runs, and nothing more.

Specification and provider

Component Stable Experimental
Jakarta Persistence 3.2 4.0 (lane)
Hibernate ORM 7.4 declared baseline 8 (lane)
Spring Boot repository BOM

The Hibernate row needs a note. The design declares 7.4 as the Stable provider; this repository's Spring Boot BOM resolves 7.1.x. HibernateProviderPolicy holds both — the declared baseline as a constant, the resolved version read from Hibernate itself — and driftsFromDeclaredBaseline() makes the difference visible instead of asserting a constant against itself. See repository-adaptation.md §4.

Capability support levels

Capability Level
Full-transaction retry Stable
Commit completion evidence Stable
Keyset pagination Stable
JDBC batch Stable
Flyway schema gate Stable
Runtime role verification Stable
Observability Stable
PostgreSQL native write (ON CONFLICT/RETURNING) Advanced
PostgreSQL work claim (SKIP LOCKED) Advanced
PostgreSQL JSONB Advanced
PostgreSQL array and range Advanced
Bulk DML Advanced
Hibernate StatelessSession Advanced
PostgreSQL COPY Admin (J4)
Hibernate second-level cache Advanced
Hibernate Envers Advanced
Multi-tenancy (column, RLS, schema, database) Experimental
Consistency-aware read replica Experimental

Release gates

Each row is a way the platform could pass its tests and still be wrong in production.

Gate Kind What it prevents
postgresql-contract gate a release whose only database evidence came from H2
completion-unknown-no-retry gate automatically re-running a write that may already have committed
osiv-disabled gate lazy loading from the view layer, one query per rendered row
flyway-validate gate Hibernate mutating a deployed schema, or running against one it was not built for
runtime-role-no-ddl gate the application's own credential being able to alter or drop schema objects
hibernate-7.4-fetch-pagination gate a paged collection fetch silently reading the whole table and paginating in memory

Explicitly unsupported

  • Reactive JPA. JPA is a blocking specification; a reactive facade over it moves the blocking call onto an event loop rather than removing it.
  • Hibernate as the production schema writer. ddl-auto never mutates a deployed schema.
  • A platform-owned generic CRUD repository. Domains own their repositories (design §10.1).
  • Automatic reconciliation of a completion-unknown transaction. The platform records; the domain resolves.