853 lines
22 KiB
Markdown
853 lines
22 KiB
Markdown
# 제어관리 시스템 트랜잭션 및 조건부 실행 개선방안
|
|
|
|
## 🚨 현재 문제점 분석
|
|
|
|
### 1. 트랜잭션 처리 부재
|
|
|
|
**문제**: 여러 액션 중 하나가 실패해도 이전 액션들이 그대로 유지됨
|
|
|
|
#### 현재 상황:
|
|
|
|
```
|
|
저장액션1 (성공) → 저장액션2 (실패)
|
|
결과: 저장액션1의 데이터는 DB에 그대로 남아있음 (데이터 불일치)
|
|
```
|
|
|
|
#### 예시 시나리오:
|
|
|
|
1. **고객정보 저장** (성공)
|
|
2. **주문정보 저장** (실패)
|
|
3. **결제정보 저장** (실행되지 않음)
|
|
|
|
→ 고객정보만 저장되어 데이터 정합성 깨짐
|
|
|
|
### 2. 조건부 실행 로직 부재
|
|
|
|
**문제**: AND/OR 조건에 따른 유연한 액션 실행이 불가능
|
|
|
|
#### 현재 한계:
|
|
|
|
- 모든 액션이 순차적으로 실행됨
|
|
- 하나 실패하면 전체 중단
|
|
- 대안 액션 실행 불가
|
|
|
|
#### 원하는 동작:
|
|
|
|
```
|
|
액션그룹1: (저장액션1 AND 저장액션2) OR 저장액션3
|
|
→ 저장액션1,2가 모두 성공하면 완료
|
|
→ 둘 중 하나라도 실패하면 저장액션3 실행
|
|
```
|
|
|
|
## 🎯 해결방안 설계
|
|
|
|
## Phase 1: 트랜잭션 관리 시스템 구축
|
|
|
|
### 1.1 트랜잭션 단위 정의
|
|
|
|
```typescript
|
|
// frontend/types/control-management.ts
|
|
|
|
export interface TransactionGroup {
|
|
id: string;
|
|
name: string;
|
|
description?: string;
|
|
actions: DataflowAction[];
|
|
rollbackStrategy: RollbackStrategy;
|
|
executionMode: "sequential" | "parallel";
|
|
onFailure: FailureHandling;
|
|
}
|
|
|
|
export type RollbackStrategy =
|
|
| "none" // 롤백 안함 (현재 방식)
|
|
| "partial" // 실패한 액션만 롤백
|
|
| "complete"; // 전체 트랜잭션 롤백
|
|
|
|
export type FailureHandling =
|
|
| "stop" // 실패 시 중단 (현재 방식)
|
|
| "continue" // 실패해도 계속 진행
|
|
| "alternative"; // 대안 액션 실행
|
|
```
|
|
|
|
### 1.2 조건부 실행 로직 구조
|
|
|
|
```typescript
|
|
export interface ConditionalExecutionPlan {
|
|
id: string;
|
|
name: string;
|
|
conditions: ExecutionCondition[];
|
|
logic: "AND" | "OR" | "CUSTOM";
|
|
customLogic?: string; // "(A AND B) OR (C AND D)"
|
|
}
|
|
|
|
export interface ExecutionCondition {
|
|
id: string;
|
|
type: "action_group" | "validation" | "data_check";
|
|
|
|
// 액션 그룹 조건
|
|
actionGroup?: TransactionGroup;
|
|
|
|
// 검증 조건
|
|
validation?: {
|
|
field: string;
|
|
operator: ConditionOperator;
|
|
value: unknown;
|
|
};
|
|
|
|
// 성공/실패 조건
|
|
expectedResult: "success" | "failure" | "any";
|
|
}
|
|
```
|
|
|
|
### 1.3 액션 실행 결과 추적
|
|
|
|
```typescript
|
|
export interface ActionExecutionResult {
|
|
actionId: string;
|
|
transactionId: string;
|
|
status: "pending" | "running" | "success" | "failed" | "rolled_back";
|
|
startTime: Date;
|
|
endTime?: Date;
|
|
result?: unknown;
|
|
error?: {
|
|
code: string;
|
|
message: string;
|
|
details?: unknown;
|
|
};
|
|
rollbackData?: unknown; // 롤백을 위한 데이터
|
|
}
|
|
|
|
export interface TransactionExecutionState {
|
|
transactionId: string;
|
|
status:
|
|
| "pending"
|
|
| "running"
|
|
| "success"
|
|
| "failed"
|
|
| "rolling_back"
|
|
| "rolled_back";
|
|
actions: ActionExecutionResult[];
|
|
rollbackActions?: ActionExecutionResult[];
|
|
startTime: Date;
|
|
endTime?: Date;
|
|
}
|
|
```
|
|
|
|
## Phase 2: 고급 조건부 실행 시스템
|
|
|
|
### 2.1 조건부 액션 그룹 정의
|
|
|
|
```typescript
|
|
export interface ConditionalActionGroup {
|
|
id: string;
|
|
name: string;
|
|
description?: string;
|
|
|
|
// 실행 조건
|
|
executionCondition: {
|
|
type: "always" | "conditional" | "fallback";
|
|
conditions?: DataflowCondition[];
|
|
logic?: "AND" | "OR";
|
|
};
|
|
|
|
// 액션들
|
|
actions: DataflowAction[];
|
|
|
|
// 성공/실패 조건 정의
|
|
successCriteria: {
|
|
type: "all_success" | "any_success" | "custom";
|
|
customLogic?: string; // "action1 AND (action2 OR action3)"
|
|
};
|
|
|
|
// 다음 단계 정의
|
|
onSuccess?: {
|
|
nextGroup?: string;
|
|
completeTransaction?: boolean;
|
|
};
|
|
|
|
onFailure?: {
|
|
retryCount?: number;
|
|
fallbackGroup?: string;
|
|
rollbackStrategy?: RollbackStrategy;
|
|
};
|
|
}
|
|
```
|
|
|
|
### 2.2 복잡한 실행 계획 예시
|
|
|
|
```typescript
|
|
// 예시: 주문 처리 시스템
|
|
const orderProcessingPlan: ConditionalExecutionPlan = {
|
|
id: "order_processing",
|
|
name: "주문 처리",
|
|
conditions: [
|
|
{
|
|
id: "primary_payment",
|
|
type: "action_group",
|
|
actionGroup: {
|
|
id: "payment_group_1",
|
|
name: "주결제 수단",
|
|
actions: [
|
|
{
|
|
type: "database",
|
|
operation: "UPDATE",
|
|
tableName: "customer" /* ... */,
|
|
},
|
|
{
|
|
type: "database",
|
|
operation: "INSERT",
|
|
tableName: "orders" /* ... */,
|
|
},
|
|
{ type: "api", endpoint: "/payment/card" /* ... */ },
|
|
],
|
|
rollbackStrategy: "complete",
|
|
executionMode: "sequential",
|
|
},
|
|
expectedResult: "success",
|
|
},
|
|
{
|
|
id: "alternative_payment",
|
|
type: "action_group",
|
|
actionGroup: {
|
|
id: "payment_group_2",
|
|
name: "대안 결제 수단",
|
|
actions: [
|
|
{ type: "api", endpoint: "/payment/bank" /* ... */ },
|
|
{
|
|
type: "database",
|
|
operation: "UPDATE",
|
|
tableName: "orders" /* ... */,
|
|
},
|
|
],
|
|
rollbackStrategy: "complete",
|
|
executionMode: "sequential",
|
|
},
|
|
expectedResult: "success",
|
|
},
|
|
],
|
|
logic: "OR", // primary_payment OR alternative_payment
|
|
customLogic: "primary_payment OR alternative_payment",
|
|
};
|
|
```
|
|
|
|
## Phase 3: 트랜잭션 실행 엔진 구현
|
|
|
|
### 3.1 트랜잭션 매니저 클래스
|
|
|
|
```typescript
|
|
// frontend/lib/services/transactionManager.ts
|
|
|
|
export class TransactionManager {
|
|
private activeTransactions: Map<string, TransactionExecutionState> =
|
|
new Map();
|
|
private rollbackHandlers: Map<string, RollbackHandler[]> = new Map();
|
|
|
|
/**
|
|
* 트랜잭션 실행
|
|
*/
|
|
async executeTransaction(
|
|
plan: ConditionalExecutionPlan,
|
|
context: ExtendedControlContext
|
|
): Promise<TransactionExecutionResult> {
|
|
const transactionId = this.generateTransactionId();
|
|
const state: TransactionExecutionState = {
|
|
transactionId,
|
|
status: "pending",
|
|
actions: [],
|
|
startTime: new Date(),
|
|
};
|
|
|
|
this.activeTransactions.set(transactionId, state);
|
|
|
|
try {
|
|
state.status = "running";
|
|
|
|
// 조건부 실행 로직 평가
|
|
const executionResult = await this.evaluateExecutionPlan(
|
|
plan,
|
|
context,
|
|
transactionId
|
|
);
|
|
|
|
if (executionResult.success) {
|
|
state.status = "success";
|
|
} else {
|
|
state.status = "failed";
|
|
|
|
// 실패 시 롤백 처리
|
|
if (executionResult.requiresRollback) {
|
|
await this.rollbackTransaction(transactionId);
|
|
}
|
|
}
|
|
|
|
state.endTime = new Date();
|
|
return executionResult;
|
|
} catch (error) {
|
|
state.status = "failed";
|
|
state.endTime = new Date();
|
|
|
|
await this.rollbackTransaction(transactionId);
|
|
|
|
throw error;
|
|
} finally {
|
|
// 트랜잭션 정리 (일정 시간 후)
|
|
setTimeout(() => this.cleanupTransaction(transactionId), 300000); // 5분 후
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 실행 계획 평가
|
|
*/
|
|
private async evaluateExecutionPlan(
|
|
plan: ConditionalExecutionPlan,
|
|
context: ExtendedControlContext,
|
|
transactionId: string
|
|
): Promise<TransactionExecutionResult> {
|
|
const results: Map<string, boolean> = new Map();
|
|
|
|
// 각 조건별로 실행
|
|
for (const condition of plan.conditions) {
|
|
const result = await this.executeCondition(
|
|
condition,
|
|
context,
|
|
transactionId
|
|
);
|
|
results.set(condition.id, result.success);
|
|
|
|
// 실패 시 즉시 중단할지 결정
|
|
if (!result.success && this.shouldStopOnFailure(plan, condition)) {
|
|
return {
|
|
success: false,
|
|
message: `조건 ${condition.id} 실행 실패`,
|
|
requiresRollback: true,
|
|
results: Array.from(results.entries()),
|
|
};
|
|
}
|
|
}
|
|
|
|
// 전체 로직 평가
|
|
const overallSuccess = this.evaluateLogic(
|
|
plan.logic,
|
|
plan.customLogic,
|
|
results
|
|
);
|
|
|
|
return {
|
|
success: overallSuccess,
|
|
message: overallSuccess ? "모든 조건 실행 성공" : "조건 실행 실패",
|
|
requiresRollback: !overallSuccess,
|
|
results: Array.from(results.entries()),
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 개별 조건 실행
|
|
*/
|
|
private async executeCondition(
|
|
condition: ExecutionCondition,
|
|
context: ExtendedControlContext,
|
|
transactionId: string
|
|
): Promise<{ success: boolean; result?: unknown }> {
|
|
if (condition.type === "action_group" && condition.actionGroup) {
|
|
return await this.executeActionGroup(
|
|
condition.actionGroup,
|
|
context,
|
|
transactionId
|
|
);
|
|
}
|
|
|
|
// 다른 조건 타입들 처리...
|
|
return { success: true };
|
|
}
|
|
|
|
/**
|
|
* 액션 그룹 실행
|
|
*/
|
|
private async executeActionGroup(
|
|
group: TransactionGroup,
|
|
context: ExtendedControlContext,
|
|
transactionId: string
|
|
): Promise<{ success: boolean; result?: unknown }> {
|
|
const state = this.activeTransactions.get(transactionId)!;
|
|
const groupResults: ActionExecutionResult[] = [];
|
|
|
|
try {
|
|
if (group.executionMode === "sequential") {
|
|
// 순차 실행
|
|
for (const action of group.actions) {
|
|
const result = await this.executeAction(
|
|
action,
|
|
context,
|
|
transactionId
|
|
);
|
|
groupResults.push(result);
|
|
state.actions.push(result);
|
|
|
|
if (result.status === "failed" && group.onFailure === "stop") {
|
|
throw new Error(
|
|
`액션 ${action.id} 실행 실패: ${result.error?.message}`
|
|
);
|
|
}
|
|
}
|
|
} else {
|
|
// 병렬 실행
|
|
const promises = group.actions.map((action) =>
|
|
this.executeAction(action, context, transactionId)
|
|
);
|
|
const results = await Promise.allSettled(promises);
|
|
|
|
results.forEach((result, index) => {
|
|
const actionResult: ActionExecutionResult = {
|
|
actionId: group.actions[index].id,
|
|
transactionId,
|
|
status:
|
|
result.status === "fulfilled" && result.value.status === "success"
|
|
? "success"
|
|
: "failed",
|
|
startTime: new Date(),
|
|
endTime: new Date(),
|
|
result:
|
|
result.status === "fulfilled" ? result.value.result : undefined,
|
|
error:
|
|
result.status === "rejected"
|
|
? { code: "EXECUTION_ERROR", message: result.reason }
|
|
: undefined,
|
|
};
|
|
|
|
groupResults.push(actionResult);
|
|
state.actions.push(actionResult);
|
|
});
|
|
}
|
|
|
|
// 성공 기준 평가
|
|
const success = this.evaluateSuccessCriteria(
|
|
group.successCriteria,
|
|
groupResults
|
|
);
|
|
|
|
if (!success && group.rollbackStrategy === "complete") {
|
|
// 그룹 내 모든 액션 롤백
|
|
await this.rollbackActionGroup(group, groupResults, transactionId);
|
|
}
|
|
|
|
return { success, result: groupResults };
|
|
} catch (error) {
|
|
// 오류 발생 시 롤백
|
|
if (group.rollbackStrategy !== "none") {
|
|
await this.rollbackActionGroup(group, groupResults, transactionId);
|
|
}
|
|
|
|
return { success: false, result: error };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 개별 액션 실행
|
|
*/
|
|
private async executeAction(
|
|
action: DataflowAction,
|
|
context: ExtendedControlContext,
|
|
transactionId: string
|
|
): Promise<ActionExecutionResult> {
|
|
const result: ActionExecutionResult = {
|
|
actionId: action.id,
|
|
transactionId,
|
|
status: "running",
|
|
startTime: new Date(),
|
|
};
|
|
|
|
try {
|
|
// 액션 타입별 실행
|
|
let executionResult: unknown;
|
|
|
|
switch (action.type) {
|
|
case "database":
|
|
executionResult = await this.executeDatabaseAction(action, context);
|
|
|
|
// 롤백 데이터 저장 (UPDATE/DELETE의 경우)
|
|
if (action.operation === "UPDATE" || action.operation === "DELETE") {
|
|
result.rollbackData = await this.captureRollbackData(
|
|
action,
|
|
context
|
|
);
|
|
}
|
|
break;
|
|
|
|
case "api":
|
|
executionResult = await this.executeApiAction(action, context);
|
|
break;
|
|
|
|
case "notification":
|
|
executionResult = await this.executeNotificationAction(
|
|
action,
|
|
context
|
|
);
|
|
break;
|
|
|
|
default:
|
|
throw new Error(`Unsupported action type: ${action.type}`);
|
|
}
|
|
|
|
result.status = "success";
|
|
result.result = executionResult;
|
|
result.endTime = new Date();
|
|
|
|
return result;
|
|
} catch (error) {
|
|
result.status = "failed";
|
|
result.error = {
|
|
code: "ACTION_EXECUTION_ERROR",
|
|
message: error.message,
|
|
details: error,
|
|
};
|
|
result.endTime = new Date();
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 트랜잭션 롤백
|
|
*/
|
|
private async rollbackTransaction(transactionId: string): Promise<void> {
|
|
const state = this.activeTransactions.get(transactionId);
|
|
if (!state) return;
|
|
|
|
state.status = "rolling_back";
|
|
|
|
// 성공한 액션들을 역순으로 롤백
|
|
const successfulActions = state.actions
|
|
.filter((action) => action.status === "success")
|
|
.reverse();
|
|
|
|
const rollbackResults: ActionExecutionResult[] = [];
|
|
|
|
for (const action of successfulActions) {
|
|
try {
|
|
const rollbackResult = await this.rollbackAction(action);
|
|
rollbackResults.push(rollbackResult);
|
|
} catch (error) {
|
|
console.error(`롤백 실패: ${action.actionId}`, error);
|
|
// 롤백 실패는 로그만 남기고 계속 진행
|
|
}
|
|
}
|
|
|
|
state.rollbackActions = rollbackResults;
|
|
state.status = "rolled_back";
|
|
state.endTime = new Date();
|
|
}
|
|
|
|
/**
|
|
* 개별 액션 롤백
|
|
*/
|
|
private async rollbackAction(
|
|
action: ActionExecutionResult
|
|
): Promise<ActionExecutionResult> {
|
|
// 롤백 액션 실행
|
|
// 이 부분은 액션 타입별로 구체적인 롤백 로직 구현 필요
|
|
|
|
return {
|
|
actionId: `rollback_${action.actionId}`,
|
|
transactionId: action.transactionId,
|
|
status: "success",
|
|
startTime: new Date(),
|
|
endTime: new Date(),
|
|
result: "롤백 완료",
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 로직 평가 (AND/OR/CUSTOM)
|
|
*/
|
|
private evaluateLogic(
|
|
logic: "AND" | "OR" | "CUSTOM",
|
|
customLogic: string | undefined,
|
|
results: Map<string, boolean>
|
|
): boolean {
|
|
switch (logic) {
|
|
case "AND":
|
|
return Array.from(results.values()).every((result) => result);
|
|
|
|
case "OR":
|
|
return Array.from(results.values()).some((result) => result);
|
|
|
|
case "CUSTOM":
|
|
if (!customLogic) return false;
|
|
return this.evaluateCustomLogic(customLogic, results);
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 커스텀 로직 평가
|
|
*/
|
|
private evaluateCustomLogic(
|
|
logic: string,
|
|
results: Map<string, boolean>
|
|
): boolean {
|
|
// "(A AND B) OR (C AND D)" 형태의 로직 파싱 및 평가
|
|
let expression = logic;
|
|
|
|
// 변수를 실제 결과값으로 치환
|
|
for (const [id, result] of results) {
|
|
expression = expression.replace(
|
|
new RegExp(`\\b${id}\\b`, "g"),
|
|
result.toString()
|
|
);
|
|
}
|
|
|
|
// AND/OR를 JavaScript 연산자로 변환
|
|
expression = expression
|
|
.replace(/\bAND\b/g, "&&")
|
|
.replace(/\bOR\b/g, "||")
|
|
.replace(/\btrue\b/g, "true")
|
|
.replace(/\bfalse\b/g, "false");
|
|
|
|
try {
|
|
// 안전한 평가를 위해 Function 생성자 사용
|
|
return new Function(`return ${expression}`)();
|
|
} catch (error) {
|
|
console.error("커스텀 로직 평가 오류:", error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// ... 기타 헬퍼 메서드들
|
|
}
|
|
|
|
export interface TransactionExecutionResult {
|
|
success: boolean;
|
|
message: string;
|
|
requiresRollback: boolean;
|
|
results: [string, boolean][];
|
|
}
|
|
|
|
export interface RollbackHandler {
|
|
actionId: string;
|
|
rollbackFn: () => Promise<void>;
|
|
}
|
|
```
|
|
|
|
### 3.2 데이터베이스 액션 실행기
|
|
|
|
```typescript
|
|
// frontend/lib/services/databaseActionExecutor.ts
|
|
|
|
export class DatabaseActionExecutor {
|
|
/**
|
|
* 데이터베이스 액션 실행
|
|
*/
|
|
static async executeAction(
|
|
action: DataflowAction,
|
|
context: ExtendedControlContext
|
|
): Promise<unknown> {
|
|
const { tableName, operation, fields, conditions } = action;
|
|
|
|
switch (operation) {
|
|
case "INSERT":
|
|
return await this.executeInsert(tableName!, fields!, context);
|
|
|
|
case "UPDATE":
|
|
return await this.executeUpdate(
|
|
tableName!,
|
|
fields!,
|
|
conditions!,
|
|
context
|
|
);
|
|
|
|
case "DELETE":
|
|
return await this.executeDelete(tableName!, conditions!, context);
|
|
|
|
case "SELECT":
|
|
return await this.executeSelect(
|
|
tableName!,
|
|
fields!,
|
|
conditions!,
|
|
context
|
|
);
|
|
|
|
default:
|
|
throw new Error(`Unsupported database operation: ${operation}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 롤백 데이터 캡처
|
|
*/
|
|
static async captureRollbackData(
|
|
action: DataflowAction,
|
|
context: ExtendedControlContext
|
|
): Promise<unknown> {
|
|
const { tableName, conditions } = action;
|
|
|
|
if (action.operation === "UPDATE" || action.operation === "DELETE") {
|
|
// 변경 전 데이터를 조회하여 저장
|
|
return await this.executeSelect(tableName!, ["*"], conditions!, context);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* 롤백 실행
|
|
*/
|
|
static async executeRollback(
|
|
originalAction: ActionExecutionResult,
|
|
rollbackData: unknown
|
|
): Promise<void> {
|
|
// 원본 액션의 반대 작업 수행
|
|
// INSERT -> DELETE
|
|
// UPDATE -> UPDATE (원본 데이터로)
|
|
// DELETE -> INSERT (원본 데이터로)
|
|
// 구체적인 롤백 로직 구현...
|
|
}
|
|
|
|
// ... 개별 operation 구현 메서드들
|
|
}
|
|
```
|
|
|
|
## Phase 4: 사용자 인터페이스 개선
|
|
|
|
### 4.1 조건부 실행 설정 UI
|
|
|
|
```typescript
|
|
// frontend/components/screen/config-panels/ConditionalExecutionPanel.tsx
|
|
|
|
export const ConditionalExecutionPanel: React.FC<{
|
|
config: ButtonDataflowConfig;
|
|
onConfigChange: (config: ButtonDataflowConfig) => void;
|
|
}> = ({ config, onConfigChange }) => {
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* 실행 모드 선택 */}
|
|
<div>
|
|
<Label>실행 모드</Label>
|
|
<Select>
|
|
<SelectItem value="simple">단순 실행</SelectItem>
|
|
<SelectItem value="conditional">조건부 실행</SelectItem>
|
|
<SelectItem value="transaction">트랜잭션 실행</SelectItem>
|
|
</Select>
|
|
</div>
|
|
|
|
{/* 트랜잭션 설정 */}
|
|
<div>
|
|
<Label>트랜잭션 롤백 전략</Label>
|
|
<Select>
|
|
<SelectItem value="none">롤백 안함</SelectItem>
|
|
<SelectItem value="partial">부분 롤백</SelectItem>
|
|
<SelectItem value="complete">전체 롤백</SelectItem>
|
|
</Select>
|
|
</div>
|
|
|
|
{/* 액션 그룹 설정 */}
|
|
<div>
|
|
<Label>액션 그룹</Label>
|
|
<ActionGroupEditor />
|
|
</div>
|
|
|
|
{/* 조건부 로직 설정 */}
|
|
<div>
|
|
<Label>실행 조건</Label>
|
|
<ConditionalLogicEditor />
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
```
|
|
|
|
### 4.2 트랜잭션 모니터링 UI
|
|
|
|
```typescript
|
|
// frontend/components/screen/TransactionMonitor.tsx
|
|
|
|
export const TransactionMonitor: React.FC = () => {
|
|
const [transactions, setTransactions] = useState<TransactionExecutionState[]>(
|
|
[]
|
|
);
|
|
|
|
return (
|
|
<div className="space-y-4">
|
|
<h3>트랜잭션 실행 현황</h3>
|
|
|
|
{transactions.map((transaction) => (
|
|
<Card key={transaction.transactionId}>
|
|
<CardHeader>
|
|
<div className="flex justify-between">
|
|
<span>트랜잭션 {transaction.transactionId}</span>
|
|
<Badge variant={getStatusVariant(transaction.status)}>
|
|
{transaction.status}
|
|
</Badge>
|
|
</div>
|
|
</CardHeader>
|
|
|
|
<CardContent>
|
|
<div className="space-y-2">
|
|
{transaction.actions.map((action) => (
|
|
<div key={action.actionId} className="flex justify-between">
|
|
<span>{action.actionId}</span>
|
|
<Badge variant={getStatusVariant(action.status)}>
|
|
{action.status}
|
|
</Badge>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
{transaction.status === "failed" && (
|
|
<Button
|
|
onClick={() => retryTransaction(transaction.transactionId)}
|
|
>
|
|
재시도
|
|
</Button>
|
|
)}
|
|
</CardContent>
|
|
</Card>
|
|
))}
|
|
</div>
|
|
);
|
|
};
|
|
```
|
|
|
|
## 📋 구현 우선순위
|
|
|
|
### 🔥 즉시 구현 (Critical)
|
|
|
|
1. **TransactionManager 기본 구조** - 트랜잭션 단위 실행
|
|
2. **롤백 메커니즘** - 실패 시 이전 상태 복구
|
|
3. **AND/OR 조건부 실행** - 기본적인 조건부 로직
|
|
|
|
### ⚡ 단기 구현 (High)
|
|
|
|
4. **데이터베이스 액션 실행기** - 실제 DB 작업 처리
|
|
5. **에러 핸들링 강화** - 상세한 오류 정보 제공
|
|
6. **트랜잭션 상태 추적** - 실행 과정 모니터링
|
|
|
|
### 📅 중장기 구현 (Medium)
|
|
|
|
7. **복잡한 조건부 로직** - 커스텀 로직 지원
|
|
8. **병렬 실행 지원** - 성능 최적화
|
|
9. **모니터링 UI** - 실시간 트랜잭션 추적
|
|
|
|
## 💡 기대 효과
|
|
|
|
### 데이터 일관성 보장
|
|
|
|
- 트랜잭션 롤백으로 부분 실행 방지
|
|
- All-or-Nothing 원칙 적용
|
|
- 데이터 정합성 확보
|
|
|
|
### 유연한 비즈니스 로직
|
|
|
|
- 복잡한 조건부 실행 지원
|
|
- 대안 액션 자동 실행
|
|
- 비즈니스 요구사항 정확한 반영
|
|
|
|
### 시스템 안정성 향상
|
|
|
|
- 실패 시 자동 복구
|
|
- 상세한 실행 로그
|
|
- 문제 상황 신속 파악
|
|
|
|
이 개선방안에 대한 의견이나 우선순위 조정이 필요한 부분이 있으시면 말씀해 주세요!
|