diff --git a/.forge/ACM-FW-001-attempt-1-run-93ee9ccb3cf3.md b/.forge/ACM-FW-001-attempt-1-run-93ee9ccb3cf3.md
new file mode 100644
index 0000000..26e7979
--- /dev/null
+++ b/.forge/ACM-FW-001-attempt-1-run-93ee9ccb3cf3.md
@@ -0,0 +1,3 @@
+# ACM-FW-001-attempt-1-run-93ee9ccb3cf3
+
+Forge 이슈 작업 브랜치 `forge/ACM-FW-001-attempt-1-run-93ee9ccb3cf3`.
diff --git a/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/TxConfig.java b/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/TxConfig.java
new file mode 100644
index 0000000..95220fd
--- /dev/null
+++ b/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/TxConfig.java
@@ -0,0 +1,30 @@
+package com.klaro.acquirecore.framework;
+
+/**
+ * Transaction configuration DTO. Migrated from txcore.h tx_config_t.
+ */
+public class TxConfig {
+ private int timeoutSeconds = 30;
+ private int maxRetries = 3;
+ private boolean autoCommit = false;
+ private String isolationLevel = "READ_COMMITTED";
+ private boolean rollbackOnException = true;
+
+ public TxConfig() {}
+
+ public TxConfig(int timeoutSeconds, int maxRetries) {
+ this.timeoutSeconds = timeoutSeconds;
+ this.maxRetries = maxRetries;
+ }
+
+ public int getTimeoutSeconds() { return timeoutSeconds; }
+ public void setTimeoutSeconds(int timeoutSeconds) { this.timeoutSeconds = timeoutSeconds; }
+ public int getMaxRetries() { return maxRetries; }
+ public void setMaxRetries(int maxRetries) { this.maxRetries = maxRetries; }
+ public boolean isAutoCommit() { return autoCommit; }
+ public void setAutoCommit(boolean autoCommit) { this.autoCommit = autoCommit; }
+ public String getIsolationLevel() { return isolationLevel; }
+ public void setIsolationLevel(String isolationLevel) { this.isolationLevel = isolationLevel; }
+ public boolean isRollbackOnException() { return rollbackOnException; }
+ public void setRollbackOnException(boolean rollbackOnException) { this.rollbackOnException = rollbackOnException; }
+}
diff --git a/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/TxContext.java b/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/TxContext.java
index 1a56634..710de64 100644
--- a/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/TxContext.java
+++ b/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/TxContext.java
@@ -1,31 +1,53 @@
package com.klaro.acquirecore.framework;
-import java.util.HashMap;
import java.util.Map;
+import java.util.HashMap;
/**
- * 레거시 TxCore {@code TXBUF} (고정 슬롯 키/값 버퍼) 의 Spring 대체 자리표시자.
- *
- *
실 전환에서는 요청/응답 DTO(record) 가 정형 필드를 담고, 이 컨텍스트는
- * 서비스 체인({@code tx_call}) 간 전달되는 느슨한 키/값 상태만 보관한다.
+ * Transaction context DTO holding state for a single transaction lifecycle.
+ * Migrated from txcore.h tx_context_t struct.
*/
-public final class TxContext {
+public class TxContext {
- private final Map slots = new HashMap<>();
-
- /** TXBUF 필드 설정 (레거시 {@code Fchg} 상당). */
- public TxContext put(String key, Object value) {
- slots.put(key, value);
- return this;
+ /** Transaction state enumeration. Migrated from txcore.h tx_state_t. */
+ public enum TxState {
+ IDLE, PENDING, ACTIVE, COMMITTED, ROLLED_BACK, FAILED
}
- /** TXBUF 필드 조회 (레거시 {@code Fget} 상당). */
- public Object get(String key) {
- return slots.get(key);
+ private String txId;
+ private String serviceName;
+ private TxState state;
+ private long startTime;
+ private long endTime;
+ private Map attributes;
+ private String errorMessage;
+
+ public TxContext() {
+ this.attributes = new HashMap<>();
+ this.state = TxState.IDLE;
}
- /** 적재된 슬롯 개수. */
- public int size() {
- return slots.size();
+ public TxContext(String txId, String serviceName) {
+ this();
+ this.txId = txId;
+ this.serviceName = serviceName;
}
+
+ public String getTxId() { return txId; }
+ public void setTxId(String txId) { this.txId = txId; }
+ public String getServiceName() { return serviceName; }
+ public void setServiceName(String serviceName) { this.serviceName = serviceName; }
+ public TxState getState() { return state; }
+ public void setState(TxState state) { this.state = state; }
+ public long getStartTime() { return startTime; }
+ public void setStartTime(long startTime) { this.startTime = startTime; }
+ public long getEndTime() { return endTime; }
+ public void setEndTime(long endTime) { this.endTime = endTime; }
+ public Map getAttributes() { return attributes; }
+ public void setAttributes(Map attributes) { this.attributes = attributes; }
+ public Object getAttribute(String key) { return attributes.get(key); }
+ public void setAttribute(String key, Object value) { attributes.put(key, value); }
+ public String getErrorMessage() { return errorMessage; }
+ public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; }
+ public boolean isActive() { return state == TxState.ACTIVE || state == TxState.PENDING; }
}
diff --git a/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/TxCore.java b/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/TxCore.java
new file mode 100644
index 0000000..9ef868d
--- /dev/null
+++ b/boot/common-framework/src/main/java/com/klaro/acquirecore/framework/TxCore.java
@@ -0,0 +1,57 @@
+package com.klaro.acquirecore.framework;
+
+import org.springframework.stereotype.Component;
+import org.springframework.beans.factory.annotation.Autowired;
+import java.util.function.Supplier;
+
+/**
+ * TxCore main entry point. Migrated from txcore.h/txcore.c.
+ * Provides centralized transaction management facade.
+ */
+@Component
+public class TxCore {
+
+ private final TxServiceRegistry registry;
+ private final TxTemplate template;
+
+ @Autowired
+ public TxCore(TxServiceRegistry registry, TxTemplate template) {
+ this.registry = registry;
+ this.template = template;
+ }
+
+ public TxServiceRegistry getRegistry() { return registry; }
+ public TxTemplate getTemplate() { return template; }
+
+ public TxResult executeTransaction(String serviceName, Supplier