11 KiB
11 KiB
노드 연결 규칙 설계
작성일: 2025-01-02
버전: 1.0
상태: 🔄 설계 중
📋 목차
개요
목적
노드 간 연결 가능 여부를 명확히 정의하여:
- 사용자의 실수 방지
- 논리적으로 올바른 플로우만 생성 가능
- 명확한 오류 메시지 제공
기본 원칙
- 데이터 흐름 방향: 소스 → 변환 → 액션
- 타입 안전성: 출력과 입력 타입이 호환되어야 함
- 논리적 정합성: 의미 없는 연결 방지
노드 분류
1. 데이터 소스 노드 (Source)
역할: 데이터를 생성하는 시작점
tableSource- 내부 테이블externalDBSource- 외부 DBrestAPISource- REST API
특징:
- ✅ 출력만 가능 (소스 핸들)
- ❌ 입력 불가능
- 플로우의 시작점
2. 변환/조건 노드 (Transform)
역할: 데이터를 가공하거나 흐름을 제어
2.1 데이터 변환
fieldMapping- 필드 매핑dataTransform- 데이터 변환
특징:
- ✅ 입력 가능 (타겟 핸들)
- ✅ 출력 가능 (소스 핸들)
- 중간 파이프라인 역할
2.2 조건 분기
condition- 조건 분기
특징:
- ✅ 입력 가능 (타겟 핸들)
- ✅ 출력 가능 (TRUE/FALSE 2개의 소스 핸들)
- 흐름을 분기
3. 액션 노드 (Action)
역할: 실제 데이터베이스 작업 수행
insertAction- INSERTupdateAction- UPDATEdeleteAction- DELETEupsertAction- UPSERT
특징:
- ✅ 입력 가능 (타겟 핸들)
- ⚠️ 출력 제한적 (성공/실패 결과만)
- 플로우의 종착점 또는 중간 액션
4. 유틸리티 노드 (Utility)
역할: 보조적인 기능 제공
log- 로그 출력comment- 주석
특징:
log: 입력/출력 모두 가능 (패스스루)comment: 연결 불가능 (독립 노드)
연결 규칙 매트릭스
출력(From) → 입력(To) 연결 가능 여부
| From ↓ / To → | tableSource | externalDB | restAPI | condition | fieldMapping | dataTransform | insert | update | delete | upsert | log | comment |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| tableSource | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| externalDB | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| restAPI | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| condition | ❌ | ❌ | ❌ | ⚠️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| fieldMapping | ❌ | ❌ | ❌ | ✅ | ⚠️ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| dataTransform | ❌ | ❌ | ❌ | ✅ | ✅ | ⚠️ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| insert | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ⚠️ | ⚠️ | ⚠️ | ⚠️ | ✅ | ❌ |
| update | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ⚠️ | ⚠️ | ⚠️ | ⚠️ | ✅ | ❌ |
| delete | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ⚠️ | ⚠️ | ⚠️ | ⚠️ | ✅ | ❌ |
| upsert | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ⚠️ | ⚠️ | ⚠️ | ⚠️ | ✅ | ❌ |
| log | ❌ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
| comment | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
범례:
- ✅ 허용
- ❌ 금지
- ⚠️ 조건부 허용 (경고 메시지와 함께)
상세 연결 규칙
규칙 1: 소스 노드는 입력을 받을 수 없음
금지되는 연결:
❌ 어떤 노드 → tableSource
❌ 어떤 노드 → externalDBSource
❌ 어떤 노드 → restAPISource
이유: 소스 노드는 데이터의 시작점이므로 외부 입력이 의미 없음
오류 메시지:
"소스 노드는 입력을 받을 수 없습니다. 소스 노드는 플로우의 시작점입니다."
규칙 2: 소스 노드끼리 연결 불가
금지되는 연결:
❌ tableSource → externalDBSource
❌ restAPISource → tableSource
이유: 소스 노드는 독립적으로 데이터를 생성하므로 서로 연결 불필요
오류 메시지:
"소스 노드끼리는 연결할 수 없습니다. 각 소스는 독립적으로 동작합니다."
규칙 3: Comment 노드는 연결 불가
금지되는 연결:
❌ 어떤 노드 → comment
❌ comment → 어떤 노드
이유: Comment는 설명 전용 노드로 데이터 흐름에 영향을 주지 않음
오류 메시지:
"주석 노드는 연결할 수 없습니다. 주석은 플로우 설명 용도로만 사용됩니다."
규칙 4: 동일한 타입의 변환 노드 연속 연결 경고
경고가 필요한 연결:
⚠️ fieldMapping → fieldMapping
⚠️ dataTransform → dataTransform
⚠️ condition → condition
이유: 논리적으로 가능하지만 비효율적일 수 있음
경고 메시지:
"동일한 타입의 변환 노드가 연속으로 연결되었습니다. 하나의 노드로 통합하는 것이 효율적입니다."
규칙 5: 액션 노드 연속 연결 경고
경고가 필요한 연결:
⚠️ insertAction → updateAction
⚠️ updateAction → deleteAction
⚠️ deleteAction → insertAction
이유: 트랜잭션 관리나 성능에 영향을 줄 수 있음
경고 메시지:
"액션 노드가 연속으로 연결되었습니다. 트랜잭션과 성능을 고려해주세요."
규칙 6: 자기 자신에게 연결 금지
금지되는 연결:
❌ 모든 노드 → 자기 자신
이유: 무한 루프 방지
오류 메시지:
"노드는 자기 자신에게 연결할 수 없습니다."
규칙 7: Log 노드는 패스스루
허용되는 연결:
✅ 모든 노드 → log → 모든 노드 (소스 제외)
특징:
- Log 노드는 데이터를 그대로 전달
- 디버깅 및 모니터링 용도
- 데이터 흐름에 영향 없음
구현 계획
Phase 1: 기본 금지 규칙 (우선순위: 높음)
구현 위치: frontend/lib/stores/flowEditorStore.ts - validateConnection 함수
function validateConnection(
connection: Connection,
nodes: FlowNode[]
): { valid: boolean; error?: string } {
const sourceNode = nodes.find((n) => n.id === connection.source);
const targetNode = nodes.find((n) => n.id === connection.target);
if (!sourceNode || !targetNode) {
return { valid: false, error: "노드를 찾을 수 없습니다" };
}
// 규칙 1: 소스 노드는 입력을 받을 수 없음
if (isSourceNode(targetNode.type)) {
return {
valid: false,
error:
"소스 노드는 입력을 받을 수 없습니다. 소스 노드는 플로우의 시작점입니다.",
};
}
// 규칙 2: 소스 노드끼리 연결 불가
if (isSourceNode(sourceNode.type) && isSourceNode(targetNode.type)) {
return {
valid: false,
error: "소스 노드끼리는 연결할 수 없습니다.",
};
}
// 규칙 3: Comment 노드는 연결 불가
if (sourceNode.type === "comment" || targetNode.type === "comment") {
return {
valid: false,
error: "주석 노드는 연결할 수 없습니다.",
};
}
// 규칙 6: 자기 자신에게 연결 금지
if (connection.source === connection.target) {
return {
valid: false,
error: "노드는 자기 자신에게 연결할 수 없습니다.",
};
}
return { valid: true };
}
예상 작업 시간: 30분
Phase 2: 경고 규칙 (우선순위: 중간)
구현 방법: 연결은 허용하되 경고 표시
function getConnectionWarning(
connection: Connection,
nodes: FlowNode[]
): string | null {
const sourceNode = nodes.find((n) => n.id === connection.source);
const targetNode = nodes.find((n) => n.id === connection.target);
if (!sourceNode || !targetNode) return null;
// 규칙 4: 동일한 타입의 변환 노드 연속 연결
if (sourceNode.type === targetNode.type && isTransformNode(sourceNode.type)) {
return "동일한 타입의 변환 노드가 연속으로 연결되었습니다. 하나로 통합하는 것이 효율적입니다.";
}
// 규칙 5: 액션 노드 연속 연결
if (isActionNode(sourceNode.type) && isActionNode(targetNode.type)) {
return "액션 노드가 연속으로 연결되었습니다. 트랜잭션과 성능을 고려해주세요.";
}
return null;
}
UI 구현:
- 경고 아이콘을 연결선 위에 표시
- 호버 시 경고 메시지 툴팁 표시
예상 작업 시간: 1시간
Phase 3: 시각적 피드백 (우선순위: 낮음)
기능:
- 드래그 중 호환 가능한 노드 하이라이트
- 불가능한 연결 시도 시 빨간색 표시
- 경고가 있는 연결은 노란색 표시
예상 작업 시간: 2시간
테스트 케이스
금지 테스트
- tableSource → tableSource (금지)
- fieldMapping → comment (금지)
- 자기 자신 → 자기 자신 (금지)
경고 테스트
- fieldMapping → fieldMapping (경고)
- insertAction → updateAction (경고)
정상 테스트
- tableSource → fieldMapping → insertAction
- externalDBSource → condition → (TRUE) → updateAction
- restAPISource → log → dataTransform → upsertAction
향후 확장
추가 고려사항
-
핸들별 제약:
- Condition 노드의 TRUE/FALSE 출력 구분
- 특정 핸들만 특정 노드 타입과 연결 가능
-
데이터 타입 검증:
- 숫자 필드만 계산 노드로 연결 가능
- 문자열 필드만 텍스트 변환 노드로 연결 가능
-
순서 제약:
- UPDATE/DELETE 전에 반드시 SELECT 필요
- 특정 변환 순서 강제
변경 이력
| 버전 | 날짜 | 변경 내용 | 작성자 |
|---|---|---|---|
| 1.0 | 2025-01-02 | 초안 작성 | AI |
다음 단계: Phase 1 구현 시작