ERP-node/버튼_제어관리_기능_통합_잠재적_문제점_분석.md

8.9 KiB

🚨 버튼 제어관리 기능 통합 - 잠재적 문제점 및 해결방안

📊 성능 관련 문제점

1. 버튼 클릭 시 지연 시간 증가

문제점:

  • 기존 버튼은 단순한 액션만 수행 (50-100ms)
  • 제어관리 추가 시 복합적인 처리로 인한 지연 가능성
    • 데이터베이스 조건 검증: 100-300ms
    • 복잡한 비즈니스 로직 실행: 500ms-2초
    • 다중 테이블 업데이트: 1-5초

현재 코드에서 확인된 문제:

// InteractiveScreenViewer.tsx에서 버튼 클릭 처리가 동기적
const handleButtonClick = async () => {
  // 기존에는 단순한 액션만
  switch (actionType) {
    case "save":
      await handleSaveAction();
      break; // ~100ms
    // 제어관리 추가 시 복합 처리로 증가 예상
  }
};

해결방안:

  1. 비동기 처리 + 로딩 상태
const [isExecuting, setIsExecuting] = useState(false);

const handleButtonClick = async () => {
  setIsExecuting(true);
  try {
    // 제어관리 실행
  } finally {
    setIsExecuting(false);
  }
};
  1. 백그라운드 실행 옵션
// 긴급하지 않은 제어관리는 백그라운드에서 실행
if (config.executionOptions?.asyncExecution) {
  // 즉시 성공 응답
  // 백그라운드에서 제어관리 실행
}

2. 메모리 사용량 증가

문제점:

  • 각 버튼마다 제어관리 설정을 메모리에 보관
  • 복잡한 조건/액션 설정으로 인한 메모리 사용량 증가
  • 대량의 버튼이 있는 화면에서 메모리 부족 가능성

해결방안:

  1. 지연 로딩
// 제어관리 설정을 필요할 때만 로드
const loadDataflowConfig = useCallback(async () => {
  if (config.enableDataflowControl && !dataflowConfig) {
    const config = await apiClient.get(`/button-dataflow/config/${buttonId}`);
    setDataflowConfig(config.data);
  }
}, [buttonId, config.enableDataflowControl]);
  1. 설정 캐싱
// LRU 캐시로 자주 사용되는 설정만 메모리 보관
const configCache = new LRUCache({ max: 100, ttl: 300000 }); // 5분 TTL

3. 데이터베이스 성능 영향

문제점:

  • 버튼 클릭마다 복잡한 SQL 쿼리 실행
  • EventTriggerService의 현재 구조상 전체 관계도 스캔
// eventTriggerService.ts - 모든 관계도를 검색하는 비효율적인 쿼리
const diagrams = await prisma.$queryRaw`
  SELECT * FROM dataflow_diagrams 
  WHERE company_code = ${companyCode}
  AND (category::text = '"data-save"' OR ...)
`;

해결방안:

  1. 인덱스 최적화
-- 복합 인덱스 추가
CREATE INDEX idx_dataflow_button_lookup ON dataflow_diagrams
USING GIN ((control->'buttonId'))
WHERE category @> '["button-trigger"]';
  1. 캐싱 계층 추가
// 버튼별 제어관리 매핑을 캐시
const buttonDataflowCache = new Map<string, DataflowConfig[]>();

🔧 확장성 관련 문제점

4. 설정 복잡도 증가

문제점:

  • 기존 단순한 버튼 설정에서 복잡한 제어관리 설정 추가
  • 사용자 혼란 가능성
  • UI가 너무 복잡해질 위험

현재 UI 구조 문제:

// ButtonConfigPanel.tsx가 이미 복잡함
return (
  <div className="space-y-4">
    {/* 기존 15개+ 설정 항목 */}
    {/* + 제어관리 설정 추가 시 더욱 복잡해짐 */}
  </div>
);

해결방안:

  1. 탭 구조로 분리
<Tabs defaultValue="basic">
  <TabsList>
    <TabsTrigger value="basic">기본 설정</TabsTrigger>
    <TabsTrigger value="dataflow">제어관리</TabsTrigger>
    <TabsTrigger value="advanced">고급 설정</TabsTrigger>
  </TabsList>
  <TabsContent value="basic">{/* 기존 설정 */}</TabsContent>
  <TabsContent value="dataflow">{/* 제어관리 설정 */}</TabsContent>
</Tabs>
  1. 단계별 설정 마법사
const DataflowConfigWizard = () => {
  const [step, setStep] = useState(1);
  // 1단계: 활성화 여부
  // 2단계: 실행 타이밍
  // 3단계: 제어 모드
  // 4단계: 상세 설정
};

5. 타입 안전성 문제

문제점:

  • 기존 ButtonTypeConfig에 새로운 필드 추가로 인한 호환성 문제
  • 런타임 오류 가능성

현재 타입 구조 문제:

// 기존 코드들이 ButtonTypeConfig의 새 필드를 모름
const config = component.webTypeConfig; // enableDataflowControl 없을 수 있음
if (config.enableDataflowControl) { // undefined 체크 필요

해결방안:

  1. 점진적 타입 확장
// 기존 타입은 유지하고 새로운 타입 정의
interface ExtendedButtonTypeConfig extends ButtonTypeConfig {
  enableDataflowControl?: boolean;
  dataflowConfig?: ButtonDataflowConfig;
  dataflowTiming?: "before" | "after" | "replace";
}

// 타입 가드 함수
function hasDataflowConfig(
  config: ButtonTypeConfig
): config is ExtendedButtonTypeConfig {
  return "enableDataflowControl" in config;
}
  1. 마이그레이션 함수
const migrateButtonConfig = (
  config: ButtonTypeConfig
): ExtendedButtonTypeConfig => {
  return {
    ...config,
    enableDataflowControl: false, // 기본값
    dataflowConfig: undefined,
    dataflowTiming: "after",
  };
};

6. 버전 호환성 문제

문제점:

  • 기존 저장된 버튼 설정과 새로운 구조 간 호환성
  • 점진적 배포 시 일부 기능 불일치

해결방안:

  1. 버전 필드 추가
interface ButtonTypeConfig {
  version?: "1.0" | "2.0"; // 제어관리 추가 버전
  // ...기존 필드들
}
  1. 자동 마이그레이션
const migrateButtonConfig = (config: any) => {
  if (!config.version || config.version === "1.0") {
    return {
      ...config,
      version: "2.0",
      enableDataflowControl: false,
      dataflowConfig: undefined,
    };
  }
  return config;
};

🚫 보안 관련 문제점

7. 권한 검증 부재

문제점:

  • 제어관리 실행 시 추가적인 권한 검증 없음
  • 사용자가 설정한 제어관리를 통해 의도치 않은 데이터 조작 가능

해결방안:

  1. 제어관리 권한 체계
interface DataflowPermission {
  canExecuteDataflow: boolean;
  allowedTables: string[];
  allowedActions: ("insert" | "update" | "delete")[];
}

const checkDataflowPermission = async (
  userId: string,
  dataflowConfig: ButtonDataflowConfig
): Promise<boolean> => {
  // 사용자별 제어관리 권한 검증
};
  1. 실행 로그 및 감사
const logDataflowExecution = async (
  userId: string,
  buttonId: string,
  dataflowResult: ExecutionResult
) => {
  await prisma.dataflow_audit_log.create({
    data: {
      user_id: userId,
      button_id: buttonId,
      executed_actions: dataflowResult.executedActions,
      execution_time: dataflowResult.executionTime,
      timestamp: new Date(),
    },
  });
};

8. SQL 인젝션 위험

문제점:

  • 고급 모드에서 사용자가 직접 조건 설정 시 SQL 인젝션 가능성
  • 동적 테이블명, 필드명 처리 시 보안 취약점

해결방안:

  1. 화이트리스트 기반 검증
const ALLOWED_TABLES = ["user_info", "order_master" /* ... */];
const ALLOWED_OPERATORS = ["=", "!=", ">", "<", ">=", "<=", "LIKE"];

const validateDataflowConfig = (config: ButtonDataflowConfig) => {
  if (config.directControl) {
    if (!ALLOWED_TABLES.includes(config.directControl.sourceTable)) {
      throw new Error("허용되지 않은 테이블입니다.");
    }
    // 추가 검증...
  }
};
  1. 파라미터화된 쿼리 강제
// 모든 동적 쿼리를 파라미터화
const executeCondition = async (condition: DataflowCondition, data: any) => {
  const query = `SELECT * FROM ${tableName} WHERE ${fieldName} ${operator} $1`;
  return await prisma.$queryRaw(query, condition.value);
};

💡 권장 해결 전략

Phase 1: 안전한 시작 (MVP)

  1. 간편 모드만 구현 (기존 관계도 선택)
  2. "after" 타이밍만 지원 (기존 액션 후 실행)
  3. 기본적인 성능 최적화 (캐싱, 인덱스)
  4. 상세한 로깅 및 모니터링 추가

Phase 2: 점진적 확장

  1. 고급 모드 추가 (권한 검증 강화)
  2. "before", "replace" 타이밍 지원
  3. 성능 최적화 고도화 (비동기 실행, 큐잉)
  4. UI 개선 (탭, 마법사)

Phase 3: 고도화

  1. 배치 처리 지원
  2. 복잡한 비즈니스 로직 지원
  3. AI 기반 설정 추천
  4. 성능 대시보드

모니터링 지표

interface DataflowMetrics {
  averageExecutionTime: number;
  errorRate: number;
  memoryUsage: number;
  cacheHitRate: number;
  userSatisfactionScore: number;
}

이러한 문제점들을 사전에 고려하여 설계하면 안정적이고 확장 가능한 시스템을 구축할 수 있습니다.