타입 관리 개선 및 화면 비율조정 중간커밋
This commit is contained in:
852
제어관리_트랜잭션_및_조건부실행_개선방안.md
Normal file
852
제어관리_트랜잭션_및_조건부실행_개선방안.md
Normal file
@@ -0,0 +1,852 @@
|
||||
# 제어관리 시스템 트랜잭션 및 조건부 실행 개선방안
|
||||
|
||||
## 🚨 현재 문제점 분석
|
||||
|
||||
### 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 원칙 적용
|
||||
- 데이터 정합성 확보
|
||||
|
||||
### 유연한 비즈니스 로직
|
||||
|
||||
- 복잡한 조건부 실행 지원
|
||||
- 대안 액션 자동 실행
|
||||
- 비즈니스 요구사항 정확한 반영
|
||||
|
||||
### 시스템 안정성 향상
|
||||
|
||||
- 실패 시 자동 복구
|
||||
- 상세한 실행 로그
|
||||
- 문제 상황 신속 파악
|
||||
|
||||
이 개선방안에 대한 의견이나 우선순위 조정이 필요한 부분이 있으시면 말씀해 주세요!
|
||||
Reference in New Issue
Block a user