The keycloak project ended with four open questions that design could not
settle. A two-VM lab was built to answer them by measurement, and this is
that material: 26 experiments, 125 raw command outputs, 22 browser captures.
Follows the import procedure in README.md.
source/ the originating repository verbatim — 78 documents, 28 SVGs,
8 manifests, plus .source-revision recording the commit
final/ the SSOT
document.md 729 lines written from the 29 experiment documents, not
concatenated: what was predicted, what was measured, and
where the measurement itself was wrong
evidence/raw 125 outputs, flattened to <experiment>__<file> because
the originals collided (01-baseline.txt appeared three
times) and the audit only globs the top level
evidence/meta one per raw file; command and exitCode are null and the
README says why rather than inventing them
evidence/browser 22 captures
assets/ three diagrams through techviz
.techviz/ their VizSpecs
A separate project rather than an addition to keycloak: the B-layer answers
that project's four questions, but the A, C and D layers are about cluster
failure, SSO and operations, and one document.md should hold one subject.
The four question records there can point here through 관계.
Recorded rather than papered over: only three of the 28 diagrams were
remade. The repository forbids hand-drawn SVG and forbids titles inside the
canvas; all 28 originals carry both, so converting them is redrawing, not
reformatting. They stay in source/ and the gap is written into the document.
verify-pipeline.py passes. audit-records.py reports no issues.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
291 lines
22 KiB
Plaintext
291 lines
22 KiB
Plaintext
Command: printf '%s\n' '--- persistence root ---'; sed -n '1,115p' src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/persistencejpa/PersistenceJpaRootAutoConfiguration.java; printf '%s\n' '--- adapter component scan ---'; cat src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/config/JpaAdapterComponentsConfig.java; printf '%s\n' '--- runtime transaction beans ---'; sed -n '140,195p' src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformRuntimeAutoConfiguration.java; printf '%s\n' '--- canonical/application references ---'; git grep -n -E '\b(SpringTransactionPort|PolicyTransactionPort|FullTransactionRetryCoordinator|SpringJpaTransactionExecutor)\b' -- 'src/**/src/main/java/**/*.java'
|
|
Working directory: /shared/codebase/clean-architecture-backend-template
|
|
Executed at: 2026-08-29T08:01:16Z
|
|
Source revision: a24ece9cf797f7ea647e33bf846b115208ed1ba5
|
|
Observation boundary: Shows shipped persistence root imports, narrow adapter component scan, transaction bean factories, and exact production construction/reference sites for the two transaction stacks. Static wiring does not prove runtime invocation frequency.
|
|
--- stdout/stderr ---
|
|
--- persistence root ---
|
|
package dev.caskeleton.bootstrap.autoconfigure.persistencejpa;
|
|
|
|
import dev.caskeleton.adapter.outbound.persistence.config.JpaAdapterComponentsConfig;
|
|
import dev.caskeleton.adapter.outbound.persistence.config.PersistenceVendorSettings;
|
|
import dev.caskeleton.adapter.outbound.persistence.fileserver.FileserverJpaPersistenceConfig;
|
|
import dev.caskeleton.adapter.outbound.persistence.h2.H2PersistenceConfig;
|
|
import dev.caskeleton.adapter.outbound.persistence.notification.configuration.NotificationJpaPersistenceFacade;
|
|
import dev.caskeleton.adapter.outbound.persistence.postgresql.PostgreSqlPersistenceConfig;
|
|
import dev.caskeleton.bootstrap.autoconfigure.jpa.JpaDataSourceProfileValidator;
|
|
import dev.caskeleton.bootstrap.autoconfigure.jpa.JpaPlatformRuntimeAutoConfiguration;
|
|
import dev.caskeleton.bootstrap.autoconfigure.jpa.PostgreSqlVersionPolicy;
|
|
import dev.caskeleton.bootstrap.runtime.startup.MigrationStartupConfig;
|
|
import javax.sql.DataSource;
|
|
import org.springframework.beans.factory.InitializingBean;
|
|
import org.springframework.boot.autoconfigure.AutoConfiguration;
|
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
import org.springframework.context.annotation.Bean;
|
|
import org.springframework.context.annotation.Import;
|
|
import org.springframework.core.env.Environment;
|
|
|
|
/**
|
|
* The one place that decides whether this application has relational persistence.
|
|
*
|
|
* <p>Every JPA configuration is reached through this import rather than through the component scan,
|
|
* so a bean added to any of them next month is gated without anyone remembering to repeat a
|
|
* condition. That is the difference between a capability that is off and a capability whose known
|
|
* beans are individually conditioned.
|
|
*
|
|
* <p>Both vendor configurations are named here, and each is the leaf\'s real entry point: a vendor
|
|
* config imports the core JPA config, not the reverse. Inverting that to give this class a single
|
|
* import produced a package cycle inside the leaf, so the export surface admits the two vendor
|
|
* packages instead. They are mutually exclusive on {@code ca-skeleton.persistence.vendor}, so
|
|
* naming both lets the selector decide which one assembles while the decision about
|
|
* <em>whether</em> there is a database stays here, in one place.
|
|
*
|
|
* <p><b>The notification facade is named here only now that the payload is protected at rest.</b>
|
|
* Importing it makes {@code JpaNotificationRequestStore} reachable, and that store used to write
|
|
* the accepted request's template variables to {@code notification_request.variables_payload} in
|
|
* plaintext — caller content that can be a reset code, an order total or an address (NTF-INT-007).
|
|
* It was wired here once before that was true; the at-rest contract test failed on exactly that
|
|
* fact, which is what it was written to do, and the wiring was reverted rather than the test
|
|
* relaxed. The envelope came first, {@code NotificationRecordMapper} now takes the protection as a
|
|
* required constructor argument, and only then does this import become a wiring rather than an
|
|
* exposure.
|
|
*
|
|
* <p>{@code FileserverJpaPersistenceConfig} is named for a related reason. Its six entities map six
|
|
* {@code fs_*} tables that live only in {@code db/migration/jpa/fileserver}, a stream applied only
|
|
* when that capability is on, while the primary Flyway location creates none of them. They used to
|
|
* be in the unconditional entity scan, so {@code ddl-auto=validate} against real PostgreSQL failed
|
|
* on {@code fs_cleanup_item} in every deployment that had switched the capability off — which was
|
|
* every JPA-on Compose lane. The scan now carries the capability's own condition, and this is the
|
|
* only place that knows both that the capability is on and that a JPA vendor is composed. Neither
|
|
* the leaf's {@code config} package nor a component scan can register it: {@code config} may depend
|
|
* on {@code api} alone, and the whole persistence package is excluded from the root's scan.
|
|
*/
|
|
@AutoConfiguration
|
|
@ConditionalOnProperty(
|
|
prefix = "ca-skeleton.persistence-jpa",
|
|
name = "enabled",
|
|
havingValue = "true")
|
|
@Import({
|
|
JpaAdapterComponentsConfig.class,
|
|
PostgreSqlPersistenceConfig.class,
|
|
H2PersistenceConfig.class,
|
|
FileserverJpaPersistenceConfig.class,
|
|
NotificationJpaPersistenceFacade.class,
|
|
MigrationStartupConfig.class,
|
|
JpaPlatformRuntimeAutoConfiguration.class
|
|
})
|
|
public class PersistenceJpaRootAutoConfiguration {
|
|
|
|
/**
|
|
* Runs the datasource validator, which nothing used to run (JPA-INT-002).
|
|
*
|
|
* <p>{@code JpaDataSourceProfileValidator} was created as a bean and never invoked: both of its
|
|
* methods were reachable only from their own unit test. A validator nobody calls is a comment —
|
|
* and this one would have failed every deployment if called, because the namespace it read was
|
|
* supplied by nothing. The two defects cancelled, which is the only reason the application
|
|
* started.
|
|
*
|
|
* <p>Invoked from here rather than from the platform configuration so it runs exactly when JPA is
|
|
* on and never when it is off, and as an {@link InitializingBean} so the failure lands during
|
|
* startup rather than at whoever sends the first request.
|
|
*
|
|
* <p>The vendor is read from the {@link Environment} rather than injected as {@code
|
|
* PersistenceVendorSettings}, because that type is not a registered bean here: the composition
|
|
* root's {@code @ConfigurationPropertiesScan} deliberately excludes the persistence package so an
|
|
* optional capability cannot bind — or reject — its detail settings in a deployment that never
|
|
* switched it on. The default matches {@code PostgreSqlPersistenceConfig}'s {@code matchIfMissing
|
|
* = true}: an unset selector is PostgreSQL, which is the vendor this configuration was
|
|
* unconditional about before the selector existed.
|
|
*
|
|
* <p>The validator is constructed here rather than injected. It is stateless, and the bean that
|
|
* used to supply it comes from {@code JpaPlatformRuntimeAutoConfiguration}, which carries
|
|
* {@code @ConditionalOnBean(DataSource.class)} on a plain {@code @Configuration} imported by this
|
|
* root — a condition evaluated during configuration-class parsing, before the datasource bean
|
|
* definition is registered. That class therefore drops out silently in the real application,
|
|
* taking the whole JPA add-on layer with it. Depending on a bean from it would make this check
|
|
* disappear for the same reason the thing it checks disappeared. The condition-ordering defect is
|
|
* recorded separately; it is not this task's to fix quietly.
|
|
*
|
|
* @param dataSource the resolved datasource, injected so the database checked is the one in use
|
|
* @param environment the resolved environment, for the vendor selector
|
|
* @return the startup check
|
|
*/
|
|
@Bean
|
|
public InitializingBean jpaResolvedDataSourceCheck(
|
|
DataSource dataSource, Environment environment) {
|
|
JpaDataSourceProfileValidator validator =
|
|
new JpaDataSourceProfileValidator(new PostgreSqlVersionPolicy());
|
|
String vendor =
|
|
environment.getProperty(PersistenceVendorSettings.VENDOR_PROPERTY, "postgresql").trim();
|
|
return () -> validator.validateResolved(dataSource, "postgresql".equalsIgnoreCase(vendor));
|
|
}
|
|
}
|
|
--- adapter component scan ---
|
|
package dev.caskeleton.adapter.outbound.persistence.config;
|
|
|
|
import org.springframework.context.annotation.ComponentScan;
|
|
import org.springframework.context.annotation.Configuration;
|
|
|
|
/**
|
|
* Registers the JPA adapter's scanned components, which nothing registered (JPA-INT-006).
|
|
*
|
|
* <p>The composition root's {@code @ComponentScan} excludes {@code
|
|
* dev.caskeleton.adapter.outbound.persistence.**} by regex, and that exclusion is correct: it is
|
|
* what makes an optional capability optional, so a deployment with JPA off assembles no persistence
|
|
* beans rather than assembling them and hoping each one remembered to carry the switch.
|
|
*
|
|
* <p>What was missing is the other half. Eight classes in this leaf are written as scanned
|
|
* components — {@code SpringTransactionPort}, {@code PersistenceExceptionTranslator}, {@code
|
|
* StandardSqlStateErrorMapping}, {@code DomainContextAuditContextPort}, the idempotency store and
|
|
* its reaper, and the outbox store and its reaper — and once the broad scan stopped reaching them,
|
|
* nothing else did. They are annotated {@code @Component} and {@code @Repository} and were beans in
|
|
* no running application: {@code TransactionPort} in particular had no implementation at all, so
|
|
* every use case that opens a transaction had no port to open it with.
|
|
*
|
|
* <p>It surfaced as an unsatisfied dependency the first time a capability that needs a transaction
|
|
* was actually assembled — the notification orchestrator, in the local-notification-ingest lane —
|
|
* rather than as anything a unit test could see, because each of these classes is constructed
|
|
* directly by its own tests.
|
|
*
|
|
* <p>So the scan is restored, narrowed to the packages it should always have covered and reachable
|
|
* only through {@code PersistenceJpaRootAutoConfiguration}, which carries the JPA master switch.
|
|
* Off is still structural.
|
|
*
|
|
* <p>Two packages are deliberately absent:
|
|
*
|
|
* <ul>
|
|
* <li>{@code ..persistence.fileserver} — gated on its own capability switch, scanned by {@link
|
|
* dev.caskeleton.adapter.outbound.persistence.fileserver.FileserverJpaPersistenceConfig};
|
|
* <li>{@code ..persistence.notification} — assembled explicitly, bean by bean, by {@code
|
|
* NotificationJpaPersistenceFacade}.
|
|
* </ul>
|
|
*
|
|
* <p>Components under these packages keep their own {@code @ConditionalOnProperty} guards; being
|
|
* scanned makes them candidates, not unconditional beans.
|
|
*
|
|
* <p>{@code ..persistence.lock} is in the list for the same reason and with the same history.
|
|
* {@code DistributedLockPersistenceConfig} owns both lock providers — the in-process registry and
|
|
* the JDBC one — and was registered by nothing but a test calling {@code ctx.register(...)}. So a
|
|
* single-instance deployment had no {@code DistributedLockPort} at all, and a multi-instance one
|
|
* could not start: the composition root's own {@code DistributedLockConfig} asks for a bean
|
|
* qualified {@code jdbcDistributedLock} that only that configuration declares.
|
|
*
|
|
* <p>Each package's {@code @ConfigurationProperties} type is enabled by a configuration inside that
|
|
* same package — {@code JpaTransactionConfig} for {@code JpaTransactionSettings}, {@code
|
|
* DistributedLockPersistenceConfig} for {@code LockSettings} — rather than from here. Enabling them
|
|
* centrally would give {@code config} an edge to {@code lock} and {@code transaction} that the
|
|
* module map does not grant it, and the map is right: this class knows which packages to scan, not
|
|
* what is inside them. They need enabling at all because {@code @ConfigurationPropertiesScan}
|
|
* excludes this tree as deliberately as {@code @ComponentScan} does.
|
|
*/
|
|
@Configuration(proxyBeanMethods = false)
|
|
@ComponentScan(
|
|
basePackages = {
|
|
"dev.caskeleton.adapter.outbound.persistence.audit",
|
|
"dev.caskeleton.adapter.outbound.persistence.failure",
|
|
"dev.caskeleton.adapter.outbound.persistence.idempotency",
|
|
"dev.caskeleton.adapter.outbound.persistence.lock",
|
|
"dev.caskeleton.adapter.outbound.persistence.outbox",
|
|
"dev.caskeleton.adapter.outbound.persistence.transaction"
|
|
})
|
|
public class JpaAdapterComponentsConfig {}
|
|
--- runtime transaction beans ---
|
|
}
|
|
|
|
/**
|
|
* The programmatic transaction boundary, over whichever manager the application installed.
|
|
*
|
|
* <p>The composed vendor's translator is taken when one exists. Without it the executor's chain
|
|
* has no SQLSTATE stage, so a serialization failure or deadlock stays a raw {@code
|
|
* DataAccessException}, never becomes the {@code JpaPersistenceException} the retry coordinator
|
|
* catches, and contention is not retried at all.
|
|
*
|
|
* @param vendorFailures the composed vendor's SQLSTATE translator, when a vendor registered one
|
|
*/
|
|
@Bean
|
|
@ConditionalOnMissingBean
|
|
@ConditionalOnBean(PlatformTransactionManager.class)
|
|
public SpringJpaTransactionExecutor jpaTransactionExecutor(
|
|
PlatformTransactionManager transactionManager,
|
|
Clock clock,
|
|
ObjectProvider<VendorFailureTranslator> vendorFailures) {
|
|
JpaTransactionAutoConfiguration composition = new JpaTransactionAutoConfiguration(clock);
|
|
VendorFailureTranslator vendor = vendorFailures.getIfAvailable();
|
|
return vendor == null
|
|
? composition.transactionExecutor(transactionManager)
|
|
: composition.transactionExecutor(transactionManager, vendor);
|
|
}
|
|
|
|
/** The whole-transaction retry coordinator. */
|
|
@Bean
|
|
@ConditionalOnMissingBean
|
|
@ConditionalOnBean(SpringJpaTransactionExecutor.class)
|
|
public FullTransactionRetryCoordinator jpaRetryCoordinator(
|
|
SpringJpaTransactionExecutor executor, RetryEventListener retryListener, Clock clock) {
|
|
return new JpaTransactionAutoConfiguration(clock)
|
|
.retryCoordinator(
|
|
executor,
|
|
dev.caskeleton.adapter.outbound.persistence.api.transaction.RetryProfile
|
|
.boundedContention("jpa-platform-default", 3),
|
|
retryListener);
|
|
}
|
|
|
|
/**
|
|
* The retry listener.
|
|
*
|
|
* <p>The interface's methods all have defaults, so an empty implementation is the honest "no
|
|
* observer wired" value; an application that wants retry telemetry supplies its own bean.
|
|
*/
|
|
@Bean
|
|
@ConditionalOnMissingBean
|
|
public RetryEventListener jpaRetryEventListener() {
|
|
return new RetryEventListener() {};
|
|
}
|
|
|
|
/** Runs the dangerous-configuration guard during refresh. */
|
|
@Bean
|
|
public InitializingBean jpaPlatformStartupCheck(
|
|
JpaDangerousConfigurationGuard guard, Environment environment) {
|
|
--- canonical/application references ---
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/config/JpaAdapterComponentsConfig.java:15: * components — {@code SpringTransactionPort}, {@code PersistenceExceptionTranslator}, {@code
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/transaction/FullTransactionRetryCoordinator.java:30:public final class FullTransactionRetryCoordinator {
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/transaction/FullTransactionRetryCoordinator.java:32: private final SpringJpaTransactionExecutor transactionExecutor;
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/transaction/FullTransactionRetryCoordinator.java:50: public FullTransactionRetryCoordinator(
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/transaction/FullTransactionRetryCoordinator.java:51: SpringJpaTransactionExecutor transactionExecutor,
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/transaction/JpaTransactionConfig.java:9: * <p>{@link SpringTransactionPort} takes it as a constructor argument, and the composition root's
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/transaction/SpringJpaTransactionExecutor.java:21: * <p>This class does not retry. Retry lives in {@link FullTransactionRetryCoordinator}, which calls
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/transaction/SpringJpaTransactionExecutor.java:25:public final class SpringJpaTransactionExecutor implements JpaTransactionExecutor {
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/transaction/SpringJpaTransactionExecutor.java:32: public SpringJpaTransactionExecutor(PlatformTransactionManager transactionManager, Clock clock) {
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/transaction/SpringJpaTransactionExecutor.java:41: public SpringJpaTransactionExecutor(
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/transaction/SpringTransactionPort.java:8:import dev.caskeleton.application.transaction.PolicyTransactionPort;
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/transaction/SpringTransactionPort.java:26: * Spring-backed {@link PolicyTransactionPort}: one pre-built {@link TransactionTemplate} per mode,
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/transaction/SpringTransactionPort.java:31:public class SpringTransactionPort implements PolicyTransactionPort {
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/transaction/SpringTransactionPort.java:39: public SpringTransactionPort(PlatformTransactionManager transactionManager) {
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/transaction/SpringTransactionPort.java:49: SpringTransactionPort(
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/transaction/SpringTransactionPort.java:61: public SpringTransactionPort(
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/transaction/SpringTransactionPort.java:77: SpringTransactionPort(
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/transaction/SpringTransactionPort.java:90: SpringTransactionPort(
|
|
src/adapter/outbound/persistence-jpa/src/main/java/dev/caskeleton/adapter/outbound/persistence/transaction/SpringTransactionPort.java:105: SpringTransactionPort(
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformRuntimeAutoConfiguration.java:7:import dev.caskeleton.adapter.outbound.persistence.transaction.FullTransactionRetryCoordinator;
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformRuntimeAutoConfiguration.java:8:import dev.caskeleton.adapter.outbound.persistence.transaction.SpringJpaTransactionExecutor;
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformRuntimeAutoConfiguration.java:155: public SpringJpaTransactionExecutor jpaTransactionExecutor(
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformRuntimeAutoConfiguration.java:169: @ConditionalOnBean(SpringJpaTransactionExecutor.class)
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformRuntimeAutoConfiguration.java:170: public FullTransactionRetryCoordinator jpaRetryCoordinator(
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaPlatformRuntimeAutoConfiguration.java:171: SpringJpaTransactionExecutor executor, RetryEventListener retryListener, Clock clock) {
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaTransactionAutoConfiguration.java:9:import dev.caskeleton.adapter.outbound.persistence.transaction.FullTransactionRetryCoordinator;
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaTransactionAutoConfiguration.java:13:import dev.caskeleton.adapter.outbound.persistence.transaction.SpringJpaTransactionExecutor;
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaTransactionAutoConfiguration.java:37: * PolicyTransactionPort.inTransaction(TransactionRequest, Supplier)}; the retry coordinator below
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaTransactionAutoConfiguration.java:66: public SpringJpaTransactionExecutor transactionExecutor(
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaTransactionAutoConfiguration.java:68: return new SpringJpaTransactionExecutor(transactionManager, clock);
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaTransactionAutoConfiguration.java:82: public SpringJpaTransactionExecutor transactionExecutor(
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaTransactionAutoConfiguration.java:84: return new SpringJpaTransactionExecutor(
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaTransactionAutoConfiguration.java:99: public FullTransactionRetryCoordinator retryCoordinator(
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaTransactionAutoConfiguration.java:100: SpringJpaTransactionExecutor executor,
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaTransactionAutoConfiguration.java:107: public FullTransactionRetryCoordinator retryCoordinator(
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaTransactionAutoConfiguration.java:108: SpringJpaTransactionExecutor executor, JpaRetryPolicy policy, RetryEventListener listener) {
|
|
src/app-bootstrap/src/main/java/dev/caskeleton/bootstrap/autoconfigure/jpa/JpaTransactionAutoConfiguration.java:109: return new FullTransactionRetryCoordinator(
|
|
src/application-core/src/main/java/dev/caskeleton/application/transaction/PolicyTransactionPort.java:10:public interface PolicyTransactionPort extends TransactionPort {
|
|
src/application-core/src/main/java/dev/caskeleton/application/transaction/TransactionPort.java:8: * {@code SpringTransactionPort}) implements it over Spring's {@code PlatformTransactionManager}.
|
|
|
|
Exit code: 0
|