# 액션 노드 타겟 선택 시스템 개선 계획

## 📋 현재 문제점

### 1. 타겟 타입 구분 부재
- INSERT/UPDATE/DELETE/UPSERT 액션 노드가 타겟 테이블만 선택 가능
- 내부 DB인지, 외부 DB인지, REST API인지 구분 없음
- 실행 시 항상 내부 DB로만 동작

### 2. 외부 시스템 연동 불가
- 외부 DB에 데이터 저장 불가
- 외부 REST API 호출 불가
- 하이브리드 플로우 구성 불가 (내부 → 외부 데이터 전송)

---

## 🎯 개선 목표

액션 노드에서 다음 3가지 타겟 타입을 선택할 수 있도록 개선:

### 1. 내부 데이터베이스 (Internal DB)
- 현재 시스템의 PostgreSQL
- 기존 동작 유지

### 2. 외부 데이터베이스 (External DB)
- 외부 커넥션 관리에서 설정한 DB
- PostgreSQL, MySQL, Oracle, MSSQL, MariaDB 지원

### 3. REST API
- 외부 REST API 호출
- HTTP 메서드: POST, PUT, PATCH, DELETE
- 인증: None, Basic, Bearer Token, API Key

---

## 📐 타입 정의 확장

### TargetType 추가
```typescript
export type TargetType = "internal" | "external" | "api";

export interface BaseActionNodeData {
  displayName: string;
  targetType: TargetType; // 🔥 새로 추가
  
  // targetType === "internal"
  targetTable?: string;
  targetTableLabel?: string;
  
  // targetType === "external"
  externalConnectionId?: number;
  externalConnectionName?: string;
  externalDbType?: string;
  externalTargetTable?: string;
  externalTargetSchema?: string;
  
  // targetType === "api"
  apiEndpoint?: string;
  apiMethod?: "POST" | "PUT" | "PATCH" | "DELETE";
  apiAuthType?: "none" | "basic" | "bearer" | "apikey";
  apiAuthConfig?: {
    username?: string;
    password?: string;
    token?: string;
    apiKey?: string;
    apiKeyHeader?: string;
  };
  apiHeaders?: Record<string, string>;
  apiBodyTemplate?: string; // JSON 템플릿
}
```

---

## 🎨 UI 설계

### 1. 타겟 타입 선택 (공통)
```
┌─────────────────────────────────────┐
│ 타겟 타입                            │
│ ○ 내부 데이터베이스 (기본)           │
│ ○ 외부 데이터베이스                  │
│ ○ REST API                          │
└─────────────────────────────────────┘
```

### 2-A. 내부 DB 선택 시 (기존 UI 유지)
```
┌─────────────────────────────────────┐
│ 테이블 선택: [검색 가능 Combobox]    │
│ 필드 매핑:                           │
│  • source_field → target_field      │
│  • ...                              │
└─────────────────────────────────────┘
```

### 2-B. 외부 DB 선택 시
```
┌─────────────────────────────────────┐
│ 외부 커넥션: [🐘 PostgreSQL - 운영DB]│
│ 스키마: [public ▼]                   │
│ 테이블: [users ▼]                    │
│ 필드 매핑:                           │
│  • source_field → target_field      │
└─────────────────────────────────────┘
```

### 2-C. REST API 선택 시
```
┌─────────────────────────────────────┐
│ API 엔드포인트:                      │
│ [https://api.example.com/users]     │
│                                     │
│ HTTP 메서드: [POST ▼]                │
│                                     │
│ 인증 타입: [Bearer Token ▼]          │
│ Token: [••••••••••••••]             │
│                                     │
│ 헤더 (선택):                         │
│  Content-Type: application/json     │
│  + 헤더 추가                         │
│                                     │
│ 바디 템플릿:                         │
│ {                                   │
│   "name": "{{source.name}}",        │
│   "email": "{{source.email}}"       │
│ }                                   │
└─────────────────────────────────────┘
```

---

## 🔧 구현 단계

### Phase 1: 타입 정의 및 기본 UI (1-2시간)
- [ ] `types/node-editor.ts`에 `TargetType` 추가
- [ ] `InsertActionNodeData` 등 인터페이스 확장
- [ ] 속성 패널에 타겟 타입 선택 라디오 버튼 추가

### Phase 2: 내부 DB 타입 (기존 유지)
- [ ] `targetType === "internal"` 처리
- [ ] 기존 로직 그대로 유지
- [ ] 기본값으로 설정

### Phase 3: 외부 DB 타입 (2-3시간)
- [ ] 외부 커넥션 선택 UI
- [ ] 외부 테이블/컬럼 로드 (기존 API 재사용)
- [ ] 백엔드: `nodeFlowExecutionService.ts`에 외부 DB 실행 로직 추가
- [ ] `DatabaseConnectorFactory` 활용

### Phase 4: REST API 타입 (3-4시간)
- [ ] API 엔드포인트 설정 UI
- [ ] HTTP 메서드 선택
- [ ] 인증 타입별 설정 UI
- [ ] 바디 템플릿 에디터 (변수 치환 지원)
- [ ] 백엔드: Axios를 사용한 API 호출 로직
- [ ] 응답 처리 및 에러 핸들링

### Phase 5: 노드 시각화 개선 (1시간)
- [ ] 노드에 타겟 타입 아이콘 표시
  - 내부 DB: 💾
  - 외부 DB: 🔌 + DB 타입 아이콘
  - REST API: 🌐
- [ ] 노드 색상 구분

### Phase 6: 검증 및 테스트 (2시간)
- [ ] 타겟 타입별 필수 값 검증
- [ ] 연결 규칙 업데이트
- [ ] 통합 테스트

---

## 🔍 백엔드 실행 로직

### nodeFlowExecutionService.ts
```typescript
private static async executeInsertAction(
  node: FlowNode,
  inputData: any[],
  context: ExecutionContext
): Promise<any[]> {
  const { targetType } = node.data;

  switch (targetType) {
    case "internal":
      return this.executeInternalInsert(node, inputData);
    
    case "external":
      return this.executeExternalInsert(node, inputData);
    
    case "api":
      return this.executeApiInsert(node, inputData);
    
    default:
      throw new Error(`지원하지 않는 타겟 타입: ${targetType}`);
  }
}

// 🔥 외부 DB INSERT
private static async executeExternalInsert(
  node: FlowNode,
  inputData: any[]
): Promise<any[]> {
  const { externalConnectionId, externalTargetTable, fieldMappings } = node.data;
  
  const connector = await DatabaseConnectorFactory.getConnector(
    externalConnectionId!,
    node.data.externalDbType!
  );

  const results = [];
  for (const row of inputData) {
    const values = fieldMappings.map(m => row[m.sourceField]);
    const columns = fieldMappings.map(m => m.targetField);
    
    const result = await connector.executeQuery(
      `INSERT INTO ${externalTargetTable} (${columns.join(", ")}) VALUES (${...})`,
      values
    );
    results.push(result);
  }

  await connector.disconnect();
  return results;
}

// 🔥 REST API INSERT (POST)
private static async executeApiInsert(
  node: FlowNode,
  inputData: any[]
): Promise<any[]> {
  const { 
    apiEndpoint, 
    apiMethod, 
    apiAuthType, 
    apiAuthConfig,
    apiHeaders,
    apiBodyTemplate 
  } = node.data;

  const axios = require("axios");
  const headers = { ...apiHeaders };

  // 인증 헤더 추가
  if (apiAuthType === "bearer" && apiAuthConfig?.token) {
    headers["Authorization"] = `Bearer ${apiAuthConfig.token}`;
  } else if (apiAuthType === "apikey" && apiAuthConfig?.apiKey) {
    headers[apiAuthConfig.apiKeyHeader || "X-API-Key"] = apiAuthConfig.apiKey;
  }

  const results = [];
  for (const row of inputData) {
    // 템플릿 변수 치환
    const body = this.replaceTemplateVariables(apiBodyTemplate, row);
    
    const response = await axios({
      method: apiMethod || "POST",
      url: apiEndpoint,
      headers,
      data: JSON.parse(body),
    });

    results.push(response.data);
  }

  return results;
}
```

---

## 📊 우선순위

### High Priority
1. **Phase 1**: 타입 정의 및 기본 UI
2. **Phase 2**: 내부 DB 타입 (기존 유지)
3. **Phase 3**: 외부 DB 타입

### Medium Priority
4. **Phase 4**: REST API 타입
5. **Phase 5**: 노드 시각화

### Low Priority
6. **Phase 6**: 고급 기능 (재시도, 배치 처리 등)

---

## 🎯 예상 효과

### 1. 유연성 증가
- 다양한 시스템 간 데이터 연동 가능
- 하이브리드 플로우 구성 (내부 → 외부 → API)

### 2. 사용 사례 확장
```
[사례 1] 내부 DB → 외부 DB 동기화
TableSource(내부) 
  → DataTransform 
  → INSERT(외부 DB)

[사례 2] 내부 DB → REST API 전송
TableSource(내부) 
  → DataTransform 
  → INSERT(REST API)

[사례 3] 복합 플로우
TableSource(내부)
  → INSERT(외부 DB)
  → INSERT(REST API - 알림)
```

### 3. 기존 기능과의 호환
- 기본값: `targetType = "internal"`
- 기존 플로우 마이그레이션 불필요

---

## ⚠️ 주의사항

### 1. 보안
- API 인증 정보 암호화 저장
- 민감 데이터 로깅 방지

### 2. 에러 핸들링
- 외부 시스템 타임아웃 처리
- 재시도 로직 (선택적)
- 부분 실패 처리 (이미 구현됨)

### 3. 성능
- 외부 DB 연결 풀 관리 (이미 구현됨)
- REST API Rate Limiting 고려

