ERP-node/화면_임베딩_시스템_충돌_분석_보고서.md

12 KiB

화면 임베딩 시스템 - 기존 시스템 충돌 분석 보고서

📋 분석 개요

새로 구현한 화면 임베딩 및 데이터 전달 시스템이 기존 화면 관리 시스템과 충돌할 가능성을 분석합니다.


충돌 없음 (안전한 부분)

1. 데이터베이스 스키마

새로운 테이블 (독립적)

- screen_embedding          (신규)
- screen_data_transfer      (신규)
- screen_split_panel        (신규)

충돌 없는 이유:

  • 완전히 새로운 테이블명
  • 기존 테이블과 이름 중복 없음
  • 외래키는 기존 screen_definitions만 참조 (읽기 전용)

기존 테이블 (영향 없음)

- screen_definitions        (변경 없음)
- screen_layouts            (변경 없음)
- screen_widgets            (변경 없음)
- screen_templates          (변경 없음)
- screen_menu_assignments   (변경 없음)

확인 사항:

  • 기존 테이블 구조 변경 없음
  • 기존 데이터 마이그레이션 불필요
  • 기존 쿼리 영향 없음

2. API 엔드포인트

새로운 엔드포인트 (독립적)

POST   /api/screen-embedding
GET    /api/screen-embedding
PUT    /api/screen-embedding/:id
DELETE /api/screen-embedding/:id

POST   /api/screen-data-transfer
GET    /api/screen-data-transfer
PUT    /api/screen-data-transfer/:id
DELETE /api/screen-data-transfer/:id

POST   /api/screen-split-panel
GET    /api/screen-split-panel/:screenId
PUT    /api/screen-split-panel/:id
DELETE /api/screen-split-panel/:id

충돌 없는 이유:

  • 기존 /api/screen-management/* 와 다른 경로
  • 새로운 라우트 추가만 (기존 라우트 수정 없음)
  • 독립적인 컨트롤러 파일

기존 엔드포인트 (영향 없음)

/api/screen-management/*    (변경 없음)
/api/screen/*               (변경 없음)
/api/layouts/*              (변경 없음)

3. TypeScript 타입

새로운 타입 파일 (독립적)

frontend / types / screen - embedding.ts(신규);

충돌 없는 이유:

  • 기존 screen.ts, screen-management.ts 와 별도 파일
  • 타입명 중복 없음
  • 독립적인 네임스페이스

기존 타입 (영향 없음)

frontend/types/screen.ts              (변경 없음)
frontend/types/screen-management.ts   (변경 없음)
backend-node/src/types/screen.ts      (변경 없음)

4. 프론트엔드 컴포넌트

새로운 컴포넌트 (독립적)

frontend/components/screen-embedding/
  ├── EmbeddedScreen.tsx       (신규)
  ├── ScreenSplitPanel.tsx     (신규)
  └── index.ts                 (신규)

충돌 없는 이유:

  • 별도 디렉토리 (screen-embedding/)
  • 기존 컴포넌트 수정 없음
  • 독립적으로 import 가능

기존 컴포넌트 (영향 없음)

frontend/components/screen/          (변경 없음)
frontend/app/(main)/screens/[screenId]/page.tsx  (변경 없음)

⚠️ 주의 필요 (잠재적 충돌 가능성)

1. screen_definitions 테이블 참조

현재 구조:

-- 새 테이블들이 screen_definitions를 참조
CONSTRAINT fk_parent_screen FOREIGN KEY (parent_screen_id)
  REFERENCES screen_definitions(screen_id) ON DELETE CASCADE

잠재적 문제:

  • ⚠️ 기존 화면 삭제 시 임베딩 설정도 함께 삭제됨 (CASCADE)
  • ⚠️ 화면 ID 변경 시 임베딩 설정이 깨질 수 있음

해결 방법:

-- 이미 구현됨: ON DELETE CASCADE
-- 화면 삭제 시 자동으로 관련 임베딩도 삭제
-- 추가 조치 불필요

권장 사항:

  • 화면 삭제 전 임베딩 사용 여부 확인 UI 추가 (Phase 6)
  • 삭제 시 경고 메시지 표시

2. 화면 렌더링 로직

현재 화면 렌더링:

// frontend/app/(main)/screens/[screenId]/page.tsx
function ScreenViewPage() {
  // 기존: 단일 화면 렌더링
  const screenId = parseInt(params.screenId as string);

  // 레이아웃 로드
  const layout = await screenApi.getScreenLayout(screenId);

  // 컴포넌트 렌더링
  <DynamicComponentRenderer components={layout.components} />;
}

새로운 렌더링 (분할 패널):

// 분할 패널 화면인 경우
if (isSplitPanelScreen) {
  const config = await getScreenSplitPanel(screenId);
  return <ScreenSplitPanel config={config} />;
}

// 일반 화면인 경우
return <DynamicComponentRenderer components={layout.components} />;

잠재적 문제:

  • ⚠️ 화면 타입 구분 로직 필요
  • ⚠️ 기존 화면 렌더링 로직 수정 필요

해결 방법:

// 1. screen_definitions에 screen_type 컬럼 추가 (선택사항)
ALTER TABLE screen_definitions ADD COLUMN screen_type VARCHAR(20) DEFAULT 'normal';
-- 'normal', 'split_panel', 'embedded'

// 2. 또는 screen_split_panel 존재 여부로 판단
const splitPanelConfig = await getScreenSplitPanel(screenId);
if (splitPanelConfig.success && splitPanelConfig.data) {
  return <ScreenSplitPanel config={splitPanelConfig.data} />;
}

권장 구현:

// frontend/app/(main)/screens/[screenId]/page.tsx 수정
useEffect(() => {
  const loadScreen = async () => {
    // 1. 분할 패널 확인
    const splitPanelResult = await getScreenSplitPanel(screenId);

    if (splitPanelResult.success && splitPanelResult.data) {
      // 분할 패널 화면
      setScreenType("split_panel");
      setSplitPanelConfig(splitPanelResult.data);
      return;
    }

    // 2. 일반 화면
    const screenResult = await screenApi.getScreen(screenId);
    const layoutResult = await screenApi.getScreenLayout(screenId);

    setScreenType("normal");
    setScreen(screenResult.data);
    setLayout(layoutResult.data);
  };

  loadScreen();
}, [screenId]);

// 렌더링
{
  screenType === "split_panel" && splitPanelConfig && (
    <ScreenSplitPanel config={splitPanelConfig} />
  );
}

{
  screenType === "normal" && layout && (
    <DynamicComponentRenderer components={layout.components} />
  );
}

3. 컴포넌트 등록 시스템

현재 시스템:

// frontend/lib/registry/components.ts
const componentRegistry = new Map<string, ComponentDefinition>();

export function registerComponent(id: string, component: any) {
  componentRegistry.set(id, component);
}

새로운 요구사항:

// DataReceivable 인터페이스 구현 필요
interface DataReceivable {
  componentId: string;
  componentType: ComponentType;
  receiveData(data: any[], mode: DataReceiveMode): Promise<void>;
  getData(): any;
  clearData(): void;
}

잠재적 문제:

  • ⚠️ 기존 컴포넌트들이 DataReceivable 인터페이스 미구현
  • ⚠️ 데이터 수신 기능 없음

해결 방법:

// Phase 5에서 구현 예정
// 기존 컴포넌트를 래핑하는 어댑터 패턴 사용

class TableComponentAdapter implements DataReceivable {
  constructor(private tableComponent: any) {}

  async receiveData(data: any[], mode: DataReceiveMode) {
    if (mode === "append") {
      this.tableComponent.addRows(data);
    } else if (mode === "replace") {
      this.tableComponent.setRows(data);
    }
  }

  getData() {
    return this.tableComponent.getRows();
  }

  clearData() {
    this.tableComponent.clearRows();
  }
}

권장 사항:

  • 기존 컴포넌트 수정 없이 어댑터로 래핑
  • 점진적으로 DataReceivable 구현
  • 하위 호환성 유지

🔧 필요한 수정 사항

1. 화면 페이지 수정 (필수)

파일: frontend/app/(main)/screens/[screenId]/page.tsx

수정 내용:

import { getScreenSplitPanel } from "@/lib/api/screenEmbedding";
import { ScreenSplitPanel } from "@/components/screen-embedding";

function ScreenViewPage() {
  const [screenType, setScreenType] = useState<"normal" | "split_panel">(
    "normal"
  );
  const [splitPanelConfig, setSplitPanelConfig] = useState<any>(null);

  useEffect(() => {
    const loadScreen = async () => {
      // 분할 패널 확인
      const splitResult = await getScreenSplitPanel(screenId);

      if (splitResult.success && splitResult.data) {
        setScreenType("split_panel");
        setSplitPanelConfig(splitResult.data);
        setLoading(false);
        return;
      }

      // 일반 화면 로드 (기존 로직)
      // ...
    };

    loadScreen();
  }, [screenId]);

  // 렌더링
  if (screenType === "split_panel" && splitPanelConfig) {
    return <ScreenSplitPanel config={splitPanelConfig} />;
  }

  // 기존 렌더링 로직
  // ...
}

영향도: 중간 (기존 로직에 조건 추가)


2. 화면 관리 UI 수정 (선택사항)

파일: 화면 관리 페이지

추가 기능:

  • 화면 생성 시 "분할 패널" 타입 선택
  • 분할 패널 설정 UI
  • 임베딩 설정 UI
  • 데이터 매핑 설정 UI

영향도: 낮음 (새로운 UI 추가)


📊 충돌 위험도 평가

항목 위험도 설명 조치 필요
데이터베이스 스키마 🟢 낮음 독립적인 새 테이블 불필요
API 엔드포인트 🟢 낮음 새로운 경로 추가 불필요
TypeScript 타입 🟢 낮음 별도 파일 불필요
프론트엔드 컴포넌트 🟢 낮음 별도 디렉토리 불필요
화면 렌더링 로직 🟡 중간 조건 분기 추가 필요 필요
컴포넌트 등록 시스템 🟡 중간 어댑터 패턴 필요 필요 (Phase 5)
외래키 CASCADE 🟡 중간 화면 삭제 시 주의 ⚠️ 주의

전체 위험도: 🟢 낮음 (대부분 독립적)


안전성 체크리스트

데이터베이스

  • 새 테이블명이 기존과 중복되지 않음
  • 기존 테이블 구조 변경 없음
  • 외래키 CASCADE 설정 완료
  • 멀티테넌시 (company_code) 지원

백엔드

  • 새 라우트가 기존과 충돌하지 않음
  • 독립적인 컨트롤러 파일
  • 기존 API 수정 없음
  • 에러 핸들링 완료

프론트엔드

  • 새 컴포넌트가 별도 디렉토리
  • 기존 컴포넌트 수정 없음
  • 독립적인 타입 정의
  • 화면 페이지 수정 필요 (조건 분기)

호환성

  • 기존 화면 동작 영향 없음
  • 하위 호환성 유지
  • 컴포넌트 어댑터 구현 (Phase 5)

🎯 권장 조치 사항

즉시 조치 (필수)

  1. 화면 페이지 수정

    // frontend/app/(main)/screens/[screenId]/page.tsx
    // 분할 패널 확인 로직 추가
    
  2. 에러 처리 강화

    // 분할 패널 로드 실패 시 일반 화면으로 폴백
    try {
      const splitResult = await getScreenSplitPanel(screenId);
      if (splitResult.success) {
        return <ScreenSplitPanel />;
      }
    } catch (error) {
      // 일반 화면으로 폴백
    }
    

단계적 조치 (Phase 5-6)

  1. 컴포넌트 어댑터 구현

    • TableComponent → DataReceivable
    • InputComponent → DataReceivable
    • 기타 컴포넌트들
  2. 설정 UI 개발

    • 분할 패널 생성 UI
    • 매핑 규칙 설정 UI
    • 미리보기 기능
  3. 테스트

    • 기존 화면 정상 동작 확인
    • 분할 패널 화면 동작 확인
    • 화면 전환 테스트

📝 결론

안전성 평가: 높음

이유:

  1. 대부분의 코드가 독립적으로 추가됨
  2. 기존 시스템 수정 최소화
  3. 하위 호환성 유지
  4. 외래키 CASCADE로 데이터 무결성 보장

⚠️ 주의 사항

  1. 화면 페이지 수정 필요

    • 분할 패널 확인 로직 추가
    • 조건부 렌더링 구현
  2. 점진적 구현 권장

    • Phase 5: 컴포넌트 어댑터
    • Phase 6: 설정 UI
    • 단계별 테스트
  3. 화면 삭제 시 주의

    • 임베딩 사용 여부 확인
    • CASCADE로 자동 삭제됨

🎉 최종 결론

충돌 위험도: 낮음 (🟢)

새로운 시스템은 기존 시스템과 독립적으로 동작하며, 최소한의 수정만으로 통합 가능합니다. 화면 페이지에 조건 분기만 추가하면 바로 사용할 수 있습니다.