482 lines
12 KiB
Markdown
482 lines
12 KiB
Markdown
|
|
# 노드 구조 개선안 - FROM/TO 테이블 명확화
|
||
|
|
|
||
|
|
**작성일**: 2025-01-02
|
||
|
|
**버전**: 1.0
|
||
|
|
**상태**: 🤔 검토 중
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📋 문제 인식
|
||
|
|
|
||
|
|
### 현재 설계의 한계
|
||
|
|
|
||
|
|
```
|
||
|
|
현재 플로우:
|
||
|
|
TableSource(user_info) → FieldMapping → InsertAction(targetTable: "orders")
|
||
|
|
```
|
||
|
|
|
||
|
|
**문제점**:
|
||
|
|
|
||
|
|
1. 타겟 테이블(orders)이 노드로 표현되지 않음
|
||
|
|
2. InsertAction의 속성으로만 존재 → 시각적으로 불명확
|
||
|
|
3. FROM(user_info)과 TO(orders)의 관계가 직관적이지 않음
|
||
|
|
4. 타겟 테이블의 스키마 정보를 참조하기 어려움
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 💡 개선 방안
|
||
|
|
|
||
|
|
### 옵션 1: TableTarget 노드 추가 (권장 ⭐)
|
||
|
|
|
||
|
|
**새로운 플로우**:
|
||
|
|
|
||
|
|
```
|
||
|
|
TableSource(user_info) → FieldMapping → TableTarget(orders) → InsertAction
|
||
|
|
```
|
||
|
|
|
||
|
|
**노드 추가**:
|
||
|
|
|
||
|
|
- `TableTarget` - 타겟 테이블을 명시적으로 표현
|
||
|
|
|
||
|
|
**장점**:
|
||
|
|
|
||
|
|
- ✅ FROM/TO가 시각적으로 명확
|
||
|
|
- ✅ 타겟 테이블 스키마를 미리 로드 가능
|
||
|
|
- ✅ FieldMapping에서 타겟 필드 자동 완성 가능
|
||
|
|
- ✅ 데이터 흐름이 직관적
|
||
|
|
|
||
|
|
**단점**:
|
||
|
|
|
||
|
|
- ⚠️ 노드 개수 증가 (복잡도 증가)
|
||
|
|
- ⚠️ 기존 설계와 호환성 문제
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 옵션 2: Action 노드에 Target 속성 유지 (현재 방식)
|
||
|
|
|
||
|
|
**현재 플로우 유지**:
|
||
|
|
|
||
|
|
```
|
||
|
|
TableSource(user_info) → FieldMapping → InsertAction(targetTable: "orders")
|
||
|
|
```
|
||
|
|
|
||
|
|
**개선 방법**:
|
||
|
|
|
||
|
|
- Action 노드에서 타겟 테이블을 더 명확히 표시
|
||
|
|
- 노드 UI에 타겟 테이블명을 크게 표시
|
||
|
|
- Properties Panel에서 타겟 테이블 선택 시 스키마 정보 제공
|
||
|
|
|
||
|
|
**장점**:
|
||
|
|
|
||
|
|
- ✅ 기존 설계 유지 (구현 완료된 상태)
|
||
|
|
- ✅ 노드 개수가 적음 (간결함)
|
||
|
|
- ✅ 빠른 플로우 구성 가능
|
||
|
|
|
||
|
|
**단점**:
|
||
|
|
|
||
|
|
- ❌ 시각적으로 FROM/TO 관계가 불명확
|
||
|
|
- ❌ FieldMapping 단계에서 타겟 필드 정보 접근이 어려움
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 옵션 3: 가상 노드 자동 표시 (신규 제안 ⭐⭐)
|
||
|
|
|
||
|
|
**개념**:
|
||
|
|
Action 노드에서 targetTable 속성을 설정하면, **시각적으로만** 타겟 테이블 노드를 자동 생성
|
||
|
|
|
||
|
|
**실제 플로우 (저장되는 구조)**:
|
||
|
|
|
||
|
|
```
|
||
|
|
TableSource(user_info) → FieldMapping → InsertAction(targetTable: "orders")
|
||
|
|
```
|
||
|
|
|
||
|
|
**시각적 표시 (화면에 보이는 모습)**:
|
||
|
|
|
||
|
|
```
|
||
|
|
TableSource(user_info)
|
||
|
|
→ FieldMapping
|
||
|
|
→ InsertAction(targetTable: "orders")
|
||
|
|
→ 👻 orders (가상 노드, 자동 생성)
|
||
|
|
```
|
||
|
|
|
||
|
|
**특징**:
|
||
|
|
|
||
|
|
- 가상 노드는 선택/이동/삭제 불가능
|
||
|
|
- 반투명하게 표시하여 가상임을 명확히 표시
|
||
|
|
- Action 노드의 targetTable 속성 변경 시 자동 업데이트
|
||
|
|
- 저장 시에는 가상 노드 제외
|
||
|
|
|
||
|
|
**장점**:
|
||
|
|
|
||
|
|
- ✅ 사용자는 기존대로 사용 (노드 추가 불필요)
|
||
|
|
- ✅ 시각적으로 FROM/TO 관계 명확
|
||
|
|
- ✅ 기존 설계 100% 유지
|
||
|
|
- ✅ 구현 복잡도 낮음
|
||
|
|
- ✅ 기존 플로우와 완벽 호환
|
||
|
|
|
||
|
|
**단점**:
|
||
|
|
|
||
|
|
- ⚠️ 가상 노드의 상호작용 제한 필요
|
||
|
|
- ⚠️ "왜 클릭이 안 되지?" 혼란 가능성
|
||
|
|
- ⚠️ 가상 노드 렌더링 로직 추가
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 옵션 4: 하이브리드 방식
|
||
|
|
|
||
|
|
**조건부 사용**:
|
||
|
|
|
||
|
|
```
|
||
|
|
// 단순 케이스: TableTarget 생략
|
||
|
|
TableSource → FieldMapping → InsertAction(targetTable 지정)
|
||
|
|
|
||
|
|
// 복잡한 케이스: TableTarget 사용
|
||
|
|
TableSource → FieldMapping → TableTarget → InsertAction
|
||
|
|
```
|
||
|
|
|
||
|
|
**장점**:
|
||
|
|
|
||
|
|
- ✅ 유연성 제공
|
||
|
|
- ✅ 단순/복잡한 케이스 모두 대응
|
||
|
|
|
||
|
|
**단점**:
|
||
|
|
|
||
|
|
- ❌ 사용자 혼란 가능성
|
||
|
|
- ❌ 검증 로직 복잡
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🎯 권장 방안 비교
|
||
|
|
|
||
|
|
### 옵션 재평가
|
||
|
|
|
||
|
|
| 항목 | 옵션 1<br/>(TableTarget) | 옵션 2<br/>(현재 방식) | 옵션 3<br/>(가상 노드) ⭐ |
|
||
|
|
| ----------------- | ------------------------ | ---------------------- | ------------------------- |
|
||
|
|
| **시각적 명확성** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
|
||
|
|
| **구현 복잡도** | ⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ |
|
||
|
|
| **사용자 편의성** | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
|
||
|
|
| **기존 호환성** | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
|
||
|
|
| **자동 완성** | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐ |
|
||
|
|
| **유지보수성** | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
|
||
|
|
| **학습 곡선** | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
|
||
|
|
|
||
|
|
### 최종 권장: **옵션 3 (가상 노드 자동 표시)** ⭐⭐
|
||
|
|
|
||
|
|
**선택 이유**:
|
||
|
|
|
||
|
|
1. ✅ **최고의 시각적 명확성** - FROM/TO 관계가 한눈에 보임
|
||
|
|
2. ✅ **사용자 편의성** - 기존 방식 그대로, 노드 추가 불필요
|
||
|
|
3. ✅ **완벽한 호환성** - 기존 플로우 수정 불필요
|
||
|
|
4. ✅ **낮은 학습 곡선** - 새로운 노드 타입 학습 불필요
|
||
|
|
5. ✅ **적절한 구현 복잡도** - React Flow의 커스텀 렌더링 활용
|
||
|
|
|
||
|
|
**구현 방식**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// Action 노드가 있으면 자동으로 가상 타겟 노드 생성
|
||
|
|
function generateVirtualTargetNodes(nodes: FlowNode[]): VirtualNode[] {
|
||
|
|
return nodes
|
||
|
|
.filter((node) => isActionNode(node.type) && node.data.targetTable)
|
||
|
|
.map((actionNode) => ({
|
||
|
|
id: `virtual-target-${actionNode.id}`,
|
||
|
|
type: "virtualTarget",
|
||
|
|
position: {
|
||
|
|
x: actionNode.position.x,
|
||
|
|
y: actionNode.position.y + 150,
|
||
|
|
},
|
||
|
|
data: {
|
||
|
|
tableName: actionNode.data.targetTable,
|
||
|
|
sourceActionId: actionNode.id,
|
||
|
|
isVirtual: true,
|
||
|
|
},
|
||
|
|
}));
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🎯 대안: 옵션 1 (TableTarget 추가)
|
||
|
|
|
||
|
|
### 새로운 노드 타입 추가
|
||
|
|
|
||
|
|
#### TableTarget 노드
|
||
|
|
|
||
|
|
**타입**: `tableTarget`
|
||
|
|
|
||
|
|
**데이터 구조**:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
interface TableTargetNodeData {
|
||
|
|
tableName: string; // 타겟 테이블명
|
||
|
|
schema?: string; // 스키마 (선택)
|
||
|
|
columns?: Array<{
|
||
|
|
// 타겟 컬럼 정보
|
||
|
|
name: string;
|
||
|
|
type: string;
|
||
|
|
nullable: boolean;
|
||
|
|
primaryKey: boolean;
|
||
|
|
}>;
|
||
|
|
displayName?: string;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**특징**:
|
||
|
|
|
||
|
|
- 입력: FieldMapping, DataTransform 등에서 받음
|
||
|
|
- 출력: Action 노드로 전달
|
||
|
|
- 타겟 테이블 스키마를 미리 로드하여 검증 가능
|
||
|
|
|
||
|
|
**시각적 표현**:
|
||
|
|
|
||
|
|
```
|
||
|
|
┌────────────────────┐
|
||
|
|
│ 📊 Table Target │
|
||
|
|
├────────────────────┤
|
||
|
|
│ orders │
|
||
|
|
│ schema: public │
|
||
|
|
├────────────────────┤
|
||
|
|
│ 컬럼: │
|
||
|
|
│ • order_id (PK) │
|
||
|
|
│ • customer_id │
|
||
|
|
│ • order_date │
|
||
|
|
│ • total_amount │
|
||
|
|
└────────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 개선된 연결 규칙
|
||
|
|
|
||
|
|
#### TableTarget 추가 시 연결 규칙
|
||
|
|
|
||
|
|
**허용되는 연결**:
|
||
|
|
|
||
|
|
```
|
||
|
|
✅ FieldMapping → TableTarget
|
||
|
|
✅ DataTransform → TableTarget
|
||
|
|
✅ Condition → TableTarget
|
||
|
|
✅ TableTarget → InsertAction
|
||
|
|
✅ TableTarget → UpdateAction
|
||
|
|
✅ TableTarget → UpsertAction
|
||
|
|
```
|
||
|
|
|
||
|
|
**금지되는 연결**:
|
||
|
|
|
||
|
|
```
|
||
|
|
❌ TableSource → TableTarget (직접 연결 불가)
|
||
|
|
❌ TableTarget → DeleteAction (DELETE는 타겟 불필요)
|
||
|
|
❌ TableTarget → TableTarget
|
||
|
|
```
|
||
|
|
|
||
|
|
**새로운 검증 규칙**:
|
||
|
|
|
||
|
|
1. Action 노드는 TableTarget 또는 targetTable 속성 중 하나 필수
|
||
|
|
2. TableTarget이 있으면 Action의 targetTable 속성 무시
|
||
|
|
3. FieldMapping 이후에 TableTarget이 오면 자동 필드 매칭 제안
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 실제 사용 예시
|
||
|
|
|
||
|
|
#### 예시 1: 단순 데이터 복사
|
||
|
|
|
||
|
|
**기존 방식**:
|
||
|
|
|
||
|
|
```
|
||
|
|
TableSource(user_info)
|
||
|
|
→ FieldMapping(user_id → customer_id, user_name → name)
|
||
|
|
→ InsertAction(targetTable: "customers")
|
||
|
|
```
|
||
|
|
|
||
|
|
**개선 방식**:
|
||
|
|
|
||
|
|
```
|
||
|
|
TableSource(user_info)
|
||
|
|
→ FieldMapping(user_id → customer_id)
|
||
|
|
→ TableTarget(customers)
|
||
|
|
→ InsertAction
|
||
|
|
```
|
||
|
|
|
||
|
|
**장점**:
|
||
|
|
|
||
|
|
- customers 테이블 스키마를 FieldMapping에서 참조 가능
|
||
|
|
- 필드 자동 완성 제공
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### 예시 2: 조건부 데이터 처리
|
||
|
|
|
||
|
|
**개선 방식**:
|
||
|
|
|
||
|
|
```
|
||
|
|
TableSource(user_info)
|
||
|
|
→ Condition(age >= 18)
|
||
|
|
├─ TRUE → TableTarget(adult_users) → InsertAction
|
||
|
|
└─ FALSE → TableTarget(minor_users) → InsertAction
|
||
|
|
```
|
||
|
|
|
||
|
|
**장점**:
|
||
|
|
|
||
|
|
- TRUE/FALSE 분기마다 다른 타겟 테이블 명확히 표시
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
#### 예시 3: 멀티 소스 + 단일 타겟
|
||
|
|
|
||
|
|
**개선 방식**:
|
||
|
|
|
||
|
|
```
|
||
|
|
┌─ TableSource(users) ────┐
|
||
|
|
│ ↓
|
||
|
|
└─ ExternalDB(orders) ─→ FieldMapping → TableTarget(user_orders) → InsertAction
|
||
|
|
```
|
||
|
|
|
||
|
|
**장점**:
|
||
|
|
|
||
|
|
- 여러 소스에서 데이터를 받아 하나의 타겟으로 통합
|
||
|
|
- 타겟 테이블이 시각적으로 명확
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔧 구현 계획
|
||
|
|
|
||
|
|
### Phase 1: TableTarget 노드 구현
|
||
|
|
|
||
|
|
**작업 항목**:
|
||
|
|
|
||
|
|
1. ✅ `TableTargetNodeData` 인터페이스 정의
|
||
|
|
2. ✅ `TableTargetNode.tsx` 컴포넌트 생성
|
||
|
|
3. ✅ `TableTargetProperties.tsx` 속성 패널 생성
|
||
|
|
4. ✅ Node Palette에 추가
|
||
|
|
5. ✅ FlowEditor에 등록
|
||
|
|
|
||
|
|
**예상 시간**: 2시간
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Phase 2: 연결 규칙 업데이트
|
||
|
|
|
||
|
|
**작업 항목**:
|
||
|
|
|
||
|
|
1. ✅ `validateConnection`에 TableTarget 규칙 추가
|
||
|
|
2. ✅ Action 노드가 TableTarget 입력을 받도록 수정
|
||
|
|
3. ✅ 검증 로직 업데이트
|
||
|
|
|
||
|
|
**예상 시간**: 1시간
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Phase 3: 자동 필드 매핑 개선
|
||
|
|
|
||
|
|
**작업 항목**:
|
||
|
|
|
||
|
|
1. ✅ TableTarget이 연결되면 타겟 스키마 자동 로드
|
||
|
|
2. ✅ FieldMapping에서 타겟 필드 자동 완성 제공
|
||
|
|
3. ✅ 필드 타입 호환성 검증
|
||
|
|
|
||
|
|
**예상 시간**: 2시간
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Phase 4: 기존 플로우 마이그레이션
|
||
|
|
|
||
|
|
**작업 항목**:
|
||
|
|
|
||
|
|
1. ✅ 기존 InsertAction의 targetTable을 TableTarget으로 변환
|
||
|
|
2. ✅ 자동 마이그레이션 스크립트 작성
|
||
|
|
3. ✅ 호환성 유지 모드 제공
|
||
|
|
|
||
|
|
**예상 시간**: 2시간
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🤔 고려사항
|
||
|
|
|
||
|
|
### 1. 기존 플로우와의 호환성
|
||
|
|
|
||
|
|
**문제**: 이미 저장된 플로우는 TableTarget 없이 구성됨
|
||
|
|
|
||
|
|
**해결 방안**:
|
||
|
|
|
||
|
|
- **옵션 A**: 자동 마이그레이션
|
||
|
|
|
||
|
|
- 플로우 로드 시 InsertAction의 targetTable을 TableTarget 노드로 변환
|
||
|
|
- 기존 데이터는 보존
|
||
|
|
|
||
|
|
- **옵션 B**: 호환성 모드
|
||
|
|
- TableTarget 없이도 동작하도록 유지
|
||
|
|
- 새 플로우만 TableTarget 사용 권장
|
||
|
|
|
||
|
|
**권장**: 옵션 B (호환성 모드)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 2. 사용자 경험
|
||
|
|
|
||
|
|
**우려**: 노드가 하나 더 추가되어 복잡해짐
|
||
|
|
|
||
|
|
**완화 방안**:
|
||
|
|
|
||
|
|
- 템플릿 제공: "TableSource → FieldMapping → TableTarget → InsertAction" 세트를 템플릿으로 제공
|
||
|
|
- 자동 생성: InsertAction 생성 시 TableTarget 자동 생성 옵션
|
||
|
|
- 가이드: 처음 사용자를 위한 튜토리얼
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### 3. 성능
|
||
|
|
|
||
|
|
**우려**: TableTarget이 스키마를 로드하면 성능 저하 가능성
|
||
|
|
|
||
|
|
**완화 방안**:
|
||
|
|
|
||
|
|
- 캐싱: 한 번 로드한 스키마는 캐싱
|
||
|
|
- 지연 로딩: 필요할 때만 스키마 로드
|
||
|
|
- 백그라운드 로딩: 비동기로 스키마 로드
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📊 비교 분석
|
||
|
|
|
||
|
|
| 항목 | 옵션 1 (TableTarget) | 옵션 2 (현재 방식) |
|
||
|
|
| ------------------- | -------------------- | ------------------ |
|
||
|
|
| **시각적 명확성** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
|
||
|
|
| **구현 복잡도** | ⭐⭐⭐⭐ | ⭐⭐ |
|
||
|
|
| **사용자 학습곡선** | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
|
||
|
|
| **자동 완성 지원** | ⭐⭐⭐⭐⭐ | ⭐⭐ |
|
||
|
|
| **유지보수성** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
|
||
|
|
| **기존 호환성** | ⭐⭐ | ⭐⭐⭐⭐⭐ |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🎯 결론
|
||
|
|
|
||
|
|
### 권장 사항: **옵션 1 (TableTarget 추가)**
|
||
|
|
|
||
|
|
**이유**:
|
||
|
|
|
||
|
|
1. ✅ 데이터 흐름이 시각적으로 명확
|
||
|
|
2. ✅ 스키마 기반 자동 완성 가능
|
||
|
|
3. ✅ 향후 확장성 우수
|
||
|
|
4. ✅ 복잡한 데이터 흐름에서 특히 유용
|
||
|
|
|
||
|
|
**단계적 도입**:
|
||
|
|
|
||
|
|
- Phase 1: TableTarget 노드 추가 (선택 사항)
|
||
|
|
- Phase 2: 기존 방식과 공존
|
||
|
|
- Phase 3: 사용자 피드백 수집
|
||
|
|
- Phase 4: 장기적으로 TableTarget 방식 권장
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📝 다음 단계
|
||
|
|
|
||
|
|
1. **의사 결정**: 옵션 1 vs 옵션 2 선택
|
||
|
|
2. **프로토타입**: TableTarget 노드 간단히 구현
|
||
|
|
3. **테스트**: 실제 사용 시나리오로 검증
|
||
|
|
4. **문서화**: 사용 가이드 작성
|
||
|
|
5. **배포**: 단계적 릴리스
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**피드백 환영**: 이 설계에 대한 의견을 주시면 개선하겠습니다! 💬
|