# 화면 임베딩 시스템 - 기존 시스템 충돌 분석 보고서 ## 📋 분석 개요 새로 구현한 **화면 임베딩 및 데이터 전달 시스템**이 기존 화면 관리 시스템과 충돌할 가능성을 분석합니다. --- ## ✅ 충돌 없음 (안전한 부분) ### 1. 데이터베이스 스키마 #### 새로운 테이블 (독립적) ```sql - screen_embedding (신규) - screen_data_transfer (신규) - screen_split_panel (신규) ``` **충돌 없는 이유**: - ✅ 완전히 새로운 테이블명 - ✅ 기존 테이블과 이름 중복 없음 - ✅ 외래키는 기존 `screen_definitions`만 참조 (읽기 전용) #### 기존 테이블 (영향 없음) ```sql - 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 타입 #### 새로운 타입 파일 (독립적) ```typescript frontend / types / screen - embedding.ts(신규); ``` **충돌 없는 이유**: - ✅ 기존 `screen.ts`, `screen-management.ts` 와 별도 파일 - ✅ 타입명 중복 없음 - ✅ 독립적인 네임스페이스 #### 기존 타입 (영향 없음) ```typescript 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 테이블 참조 **현재 구조**: ```sql -- 새 테이블들이 screen_definitions를 참조 CONSTRAINT fk_parent_screen FOREIGN KEY (parent_screen_id) REFERENCES screen_definitions(screen_id) ON DELETE CASCADE ``` **잠재적 문제**: - ⚠️ 기존 화면 삭제 시 임베딩 설정도 함께 삭제됨 (CASCADE) - ⚠️ 화면 ID 변경 시 임베딩 설정이 깨질 수 있음 **해결 방법**: ```sql -- 이미 구현됨: ON DELETE CASCADE -- 화면 삭제 시 자동으로 관련 임베딩도 삭제 -- 추가 조치 불필요 ``` **권장 사항**: - ✅ 화면 삭제 전 임베딩 사용 여부 확인 UI 추가 (Phase 6) - ✅ 삭제 시 경고 메시지 표시 --- ### 2. 화면 렌더링 로직 **현재 화면 렌더링**: ```typescript // frontend/app/(main)/screens/[screenId]/page.tsx function ScreenViewPage() { // 기존: 단일 화면 렌더링 const screenId = parseInt(params.screenId as string); // 레이아웃 로드 const layout = await screenApi.getScreenLayout(screenId); // 컴포넌트 렌더링 ; } ``` **새로운 렌더링 (분할 패널)**: ```typescript // 분할 패널 화면인 경우 if (isSplitPanelScreen) { const config = await getScreenSplitPanel(screenId); return ; } // 일반 화면인 경우 return ; ``` **잠재적 문제**: - ⚠️ 화면 타입 구분 로직 필요 - ⚠️ 기존 화면 렌더링 로직 수정 필요 **해결 방법**: ```typescript // 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 ; } ``` **권장 구현**: ```typescript // 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 && ( ); } { screenType === "normal" && layout && ( ); } ``` --- ### 3. 컴포넌트 등록 시스템 **현재 시스템**: ```typescript // frontend/lib/registry/components.ts const componentRegistry = new Map(); export function registerComponent(id: string, component: any) { componentRegistry.set(id, component); } ``` **새로운 요구사항**: ```typescript // DataReceivable 인터페이스 구현 필요 interface DataReceivable { componentId: string; componentType: ComponentType; receiveData(data: any[], mode: DataReceiveMode): Promise; getData(): any; clearData(): void; } ``` **잠재적 문제**: - ⚠️ 기존 컴포넌트들이 DataReceivable 인터페이스 미구현 - ⚠️ 데이터 수신 기능 없음 **해결 방법**: ```typescript // 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` **수정 내용**: ```typescript 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(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 ; } // 기존 렌더링 로직 // ... } ``` **영향도**: 중간 (기존 로직에 조건 추가) --- ### 2. 화면 관리 UI 수정 (선택사항) **파일**: 화면 관리 페이지 **추가 기능**: - 화면 생성 시 "분할 패널" 타입 선택 - 분할 패널 설정 UI - 임베딩 설정 UI - 데이터 매핑 설정 UI **영향도**: 낮음 (새로운 UI 추가) --- ## 📊 충돌 위험도 평가 | 항목 | 위험도 | 설명 | 조치 필요 | | -------------------- | ------- | ------------------- | ----------------- | | 데이터베이스 스키마 | 🟢 낮음 | 독립적인 새 테이블 | ❌ 불필요 | | API 엔드포인트 | 🟢 낮음 | 새로운 경로 추가 | ❌ 불필요 | | TypeScript 타입 | 🟢 낮음 | 별도 파일 | ❌ 불필요 | | 프론트엔드 컴포넌트 | 🟢 낮음 | 별도 디렉토리 | ❌ 불필요 | | 화면 렌더링 로직 | 🟡 중간 | 조건 분기 추가 필요 | ✅ 필요 | | 컴포넌트 등록 시스템 | 🟡 중간 | 어댑터 패턴 필요 | ✅ 필요 (Phase 5) | | 외래키 CASCADE | 🟡 중간 | 화면 삭제 시 주의 | ⚠️ 주의 | **전체 위험도**: 🟢 **낮음** (대부분 독립적) --- ## ✅ 안전성 체크리스트 ### 데이터베이스 - [x] 새 테이블명이 기존과 중복되지 않음 - [x] 기존 테이블 구조 변경 없음 - [x] 외래키 CASCADE 설정 완료 - [x] 멀티테넌시 (company_code) 지원 ### 백엔드 - [x] 새 라우트가 기존과 충돌하지 않음 - [x] 독립적인 컨트롤러 파일 - [x] 기존 API 수정 없음 - [x] 에러 핸들링 완료 ### 프론트엔드 - [x] 새 컴포넌트가 별도 디렉토리 - [x] 기존 컴포넌트 수정 없음 - [x] 독립적인 타입 정의 - [ ] 화면 페이지 수정 필요 (조건 분기) ### 호환성 - [x] 기존 화면 동작 영향 없음 - [x] 하위 호환성 유지 - [ ] 컴포넌트 어댑터 구현 (Phase 5) --- ## 🎯 권장 조치 사항 ### 즉시 조치 (필수) 1. **화면 페이지 수정** ```typescript // frontend/app/(main)/screens/[screenId]/page.tsx // 분할 패널 확인 로직 추가 ``` 2. **에러 처리 강화** ```typescript // 분할 패널 로드 실패 시 일반 화면으로 폴백 try { const splitResult = await getScreenSplitPanel(screenId); if (splitResult.success) { return ; } } 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로 자동 삭제됨 ### 🎉 최종 결론 **충돌 위험도: 낮음 (🟢)** 새로운 시스템은 기존 시스템과 **독립적으로 동작**하며, 최소한의 수정만으로 통합 가능합니다. 화면 페이지에 조건 분기만 추가하면 바로 사용할 수 있습니다.