ERP-node/docs/노드_연결_규칙_설계.md

11 KiB

노드 연결 규칙 설계

작성일: 2025-01-02
버전: 1.0
상태: 🔄 설계 중


📋 목차

  1. 개요
  2. 노드 분류
  3. 연결 규칙 매트릭스
  4. 상세 연결 규칙
  5. 구현 계획

개요

목적

노드 간 연결 가능 여부를 명확히 정의하여:

  • 사용자의 실수 방지
  • 논리적으로 올바른 플로우만 생성 가능
  • 명확한 오류 메시지 제공

기본 원칙

  1. 데이터 흐름 방향: 소스 → 변환 → 액션
  2. 타입 안전성: 출력과 입력 타입이 호환되어야 함
  3. 논리적 정합성: 의미 없는 연결 방지

노드 분류

1. 데이터 소스 노드 (Source)

역할: 데이터를 생성하는 시작점

  • tableSource - 내부 테이블
  • externalDBSource - 외부 DB
  • restAPISource - REST API

특징:

  • 출력만 가능 (소스 핸들)
  • 입력 불가능
  • 플로우의 시작점

2. 변환/조건 노드 (Transform)

역할: 데이터를 가공하거나 흐름을 제어

2.1 데이터 변환

  • fieldMapping - 필드 매핑
  • dataTransform - 데이터 변환

특징:

  • 입력 가능 (타겟 핸들)
  • 출력 가능 (소스 핸들)
  • 중간 파이프라인 역할

2.2 조건 분기

  • condition - 조건 분기

특징:

  • 입력 가능 (타겟 핸들)
  • 출력 가능 (TRUE/FALSE 2개의 소스 핸들)
  • 흐름을 분기

3. 액션 노드 (Action)

역할: 실제 데이터베이스 작업 수행

  • insertAction - INSERT
  • updateAction - UPDATE
  • deleteAction - DELETE
  • upsertAction - 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: 시각적 피드백 (우선순위: 낮음)

기능:

  1. 드래그 중 호환 가능한 노드 하이라이트
  2. 불가능한 연결 시도 시 빨간색 표시
  3. 경고가 있는 연결은 노란색 표시

예상 작업 시간: 2시간


테스트 케이스

금지 테스트

  • tableSource → tableSource (금지)
  • fieldMapping → comment (금지)
  • 자기 자신 → 자기 자신 (금지)

경고 테스트

  • fieldMapping → fieldMapping (경고)
  • insertAction → updateAction (경고)

정상 테스트

  • tableSource → fieldMapping → insertAction
  • externalDBSource → condition → (TRUE) → updateAction
  • restAPISource → log → dataTransform → upsertAction

향후 확장

추가 고려사항

  1. 핸들별 제약:

    • Condition 노드의 TRUE/FALSE 출력 구분
    • 특정 핸들만 특정 노드 타입과 연결 가능
  2. 데이터 타입 검증:

    • 숫자 필드만 계산 노드로 연결 가능
    • 문자열 필드만 텍스트 변환 노드로 연결 가능
  3. 순서 제약:

    • UPDATE/DELETE 전에 반드시 SELECT 필요
    • 특정 변환 순서 강제

변경 이력

버전 날짜 변경 내용 작성자
1.0 2025-01-02 초안 작성 AI

다음 단계: Phase 1 구현 시작