# Entity 조인 기능 개발 계획서 > **ID값을 의미있는 데이터로 자동 변환하는 스마트 테이블 시스템** --- ## 📋 프로젝트 개요 ### 🎯 목표 테이블 타입 관리에서 Entity 웹타입으로 설정된 컬럼을 참조 테이블과 조인하여, ID값 대신 의미있는 데이터(예: 사용자명)를 TableList 컴포넌트에서 자동으로 표시하는 기능 구현 ### 🔍 현재 문제점 ``` Before: 회사 테이블에서 ┌─────────────┬─────────┬────────────┐ │ company_name│ writer │ created_at │ ├─────────────┼─────────┼────────────┤ │ 삼성전자 │ user001 │ 2024-01-15 │ │ LG전자 │ user002 │ 2024-01-16 │ └─────────────┴─────────┴────────────┘ 😕 user001이 누구인지 알 수 없음 ``` ``` After: Entity 조인 적용 시 ┌─────────────┬─────────────┬────────────┐ │ company_name│ writer_name │ created_at │ ├─────────────┼─────────────┼────────────┤ │ 삼성전자 │ 김철수 │ 2024-01-15 │ │ LG전자 │ 박영희 │ 2024-01-16 │ └─────────────┴─────────────┴────────────┘ 😍 즉시 누가 등록했는지 알 수 있음 ``` ### 🚀 핵심 기능 1. **자동 Entity 감지**: Entity 웹타입으로 설정된 컬럼 자동 스캔 2. **스마트 조인**: 참조 테이블과 자동 LEFT JOIN 수행 3. **컬럼 별칭**: `writer` → `writer_name`으로 자동 변환 4. **성능 최적화**: 필요한 컬럼만 선택적 조인 5. **캐시 시스템**: 참조 데이터 캐싱으로 성능 향상 --- ## 🔧 기술 설계 ### 📊 데이터베이스 구조 #### 현재 Entity 설정 (column_labels 테이블) ```sql column_labels 테이블: - table_name: 'companies' - column_name: 'writer' - web_type: 'entity' - reference_table: 'user_info' -- 참조할 테이블 - reference_column: 'user_id' -- 조인 조건 컬럼 - display_column: 'user_name' -- ⭐ 새로 추가할 필드 (표시할 컬럼) ``` #### 필요한 스키마 확장 ```sql -- column_labels 테이블에 display_column 컬럼 추가 ALTER TABLE column_labels ADD COLUMN display_column VARCHAR(255) NULL COMMENT '참조 테이블에서 표시할 컬럼명'; -- 기본값 설정 (없으면 reference_column 사용) UPDATE column_labels SET display_column = CASE WHEN web_type = 'entity' AND reference_table = 'user_info' THEN 'user_name' WHEN web_type = 'entity' AND reference_table = 'companies' THEN 'company_name' ELSE reference_column END WHERE web_type = 'entity' AND display_column IS NULL; ``` ### 🏗️ 백엔드 아키텍처 #### 1. Entity 조인 감지 서비스 ```typescript // src/services/entityJoinService.ts export interface EntityJoinConfig { sourceTable: string; // companies sourceColumn: string; // writer referenceTable: string; // user_info referenceColumn: string; // user_id (조인 키) displayColumn: string; // user_name (표시할 값) aliasColumn: string; // writer_name (결과 컬럼명) } export class EntityJoinService { /** * 테이블의 Entity 컬럼들을 감지하여 조인 설정 생성 */ async detectEntityJoins(tableName: string): Promise; /** * Entity 조인이 포함된 SQL 쿼리 생성 */ buildJoinQuery( tableName: string, joinConfigs: EntityJoinConfig[], selectColumns: string[], whereClause: string, orderBy: string, limit: number, offset: number ): string; /** * 참조 테이블 데이터 캐싱 */ async cacheReferenceData(tableName: string): Promise; } ``` #### 2. 캐시 시스템 ```typescript // src/services/referenceCache.ts export class ReferenceCacheService { private cache = new Map>(); /** * 작은 참조 테이블 전체 캐싱 (user_info, departments 등) */ async preloadReferenceTable( tableName: string, keyColumn: string, displayColumn: string ): Promise; /** * 캐시에서 참조 값 조회 */ getLookupValue(table: string, key: string): any | null; /** * 배치 룩업 (성능 최적화) */ async batchLookup( requests: BatchLookupRequest[] ): Promise; } ``` #### 3. 테이블 데이터 서비스 확장 ```typescript // tableManagementService.ts 확장 export class TableManagementService { /** * Entity 조인이 포함된 데이터 조회 */ async getTableDataWithEntityJoins( tableName: string, options: { page: number; size: number; search?: Record; sortBy?: string; sortOrder?: string; enableEntityJoin?: boolean; // 🎯 Entity 조인 활성화 } ): Promise<{ data: any[]; total: number; page: number; size: number; totalPages: number; entityJoinInfo?: { // 🎯 조인 정보 joinConfigs: EntityJoinConfig[]; strategy: "full_join" | "cache_lookup"; performance: { queryTime: number; cacheHitRate: number; }; }; }>; } ``` ### 🎨 프론트엔드 구조 #### 1. Entity 타입 설정 UI 확장 ```typescript // frontend/app/(main)/admin/tableMng/page.tsx 확장 // Entity 타입 설정 시 표시할 컬럼도 선택 가능하도록 확장 {column.webType === "entity" && (
{/* 기존: 참조 테이블 선택 */} {/* 🎯 새로 추가: 표시할 컬럼 선택 */}
)} ``` #### 2. TableList 컴포넌트 확장 ```typescript // TableListComponent.tsx 확장 // Entity 조인 데이터 조회 const result = await tableTypeApi.getTableDataWithEntityJoins( tableConfig.selectedTable, { page: currentPage, size: localPageSize, search: searchConditions, sortBy: sortColumn, sortOrder: sortDirection, enableEntityJoin: true, // 🎯 Entity 조인 활성화 } ); // Entity 조인된 컬럼 시각적 구분
{isEntityJoinedColumn && ( 🔗 )} {getColumnDisplayName(column)}
; ``` #### 3. API 타입 확장 ```typescript // frontend/lib/api/screen.ts 확장 export const tableTypeApi = { // 🎯 Entity 조인 지원 데이터 조회 getTableDataWithEntityJoins: async ( tableName: string, params: { page?: number; size?: number; search?: Record; sortBy?: string; sortOrder?: "asc" | "desc"; enableEntityJoin?: boolean; } ): Promise<{ data: Record[]; total: number; page: number; size: number; totalPages: number; entityJoinInfo?: { joinConfigs: EntityJoinConfig[]; strategy: string; performance: any; }; }> => { // 구현... }, // 🎯 참조 테이블의 표시 가능한 컬럼 목록 조회 getReferenceTableColumns: async ( tableName: string ): Promise< { columnName: string; displayName: string; dataType: string; }[] > => { // 구현... }, }; ``` --- ## 🗂️ 구현 단계 ### Phase 1: 백엔드 기반 구축 (2일) #### Day 1: Entity 조인 감지 시스템 ✅ **완료!** ```typescript ✅ 구현 목록: 1. EntityJoinService 클래스 생성 - detectEntityJoins(): Entity 컬럼 스캔 및 조인 설정 생성 - buildJoinQuery(): LEFT JOIN 쿼리 자동 생성 - validateJoinConfig(): 조인 설정 유효성 검증 2. 데이터베이스 스키마 확장 - column_labels 테이블에 display_column 추가 - 기존 Entity 설정 데이터 마이그레이션 3. 단위 테스트 작성 - Entity 감지 로직 테스트 - SQL 쿼리 생성 테스트 ``` #### Day 2: 캐시 시스템 및 성능 최적화 ```typescript ✅ 구현 목록: 1. ReferenceCacheService 구현 - 작은 참조 테이블 전체 캐싱 (user_info, departments) - 배치 룩업으로 성능 최적화 - TTL 기반 캐시 무효화 2. TableManagementService 확장 - getTableDataWithEntityJoins() 메서드 추가 - 조인 vs 캐시 룩업 전략 자동 선택 - 성능 메트릭 수집 3. 통합 테스트 - 실제 테이블 데이터로 조인 테스트 - 성능 벤치마크 (조인 vs 캐시) ``` ### Phase 2: 프론트엔드 연동 (2일) #### Day 3: 관리자 UI 확장 ```typescript ✅ 구현 목록: 1. 테이블 타입 관리 페이지 확장 - Entity 타입 설정 시 display_column 선택 UI - 참조 테이블 변경 시 표시 컬럼 목록 자동 업데이트 - 설정 미리보기 기능 2. API 연동 - Entity 설정 저장/조회 API 연동 - 참조 테이블 컬럼 목록 조회 API - 에러 처리 및 사용자 피드백 3. 사용성 개선 - 자동 추천 시스템 (user_info → user_name 자동 선택) - 설정 검증 및 경고 메시지 ``` #### Day 4: TableList 컴포넌트 확장 ```typescript ✅ 구현 목록: 1. Entity 조인 데이터 표시 - getTableDataWithEntityJoins API 호출 - 조인된 컬럼 시각적 구분 (🔗 아이콘) - 컬럼명 자동 변환 (writer → writer_name) 2. 성능 모니터링 UI - 조인 전략 표시 (full_join / cache_lookup) - 실시간 성능 메트릭 (쿼리 시간, 캐시 적중률) - 조인 정보 툴팁 3. 사용자 경험 최적화 - 로딩 상태 최적화 - 에러 발생 시 원본 데이터 표시 - 성능 경고 알림 ``` ### Phase 3: 고급 기능 및 최적화 (1일) #### Day 5: 고급 기능 및 완성도 ```typescript ✅ 구현 목록: 1. 다중 Entity 조인 지원 - 하나의 테이블에서 여러 Entity 컬럼 동시 조인 - 조인 순서 최적화 - 중복 조인 방지 2. 스마트 기능 - 자주 사용되는 Entity 설정 템플릿 - 조인 성능 기반 자동 추천 - 데이터 유효성 실시간 검증 3. 완성도 향상 - 상세한 로깅 및 모니터링 - 사용자 가이드 및 툴팁 - 전체 시스템 통합 테스트 ``` --- ## 📊 예상 결과 ### 🎯 핵심 사용 시나리오 #### 시나리오 1: 회사 관리 테이블 ```sql -- Entity 설정 companies.writer (entity) → user_info.user_name -- 실행되는 쿼리 SELECT c.*, u.user_name as writer_name FROM companies c LEFT JOIN user_info u ON c.writer = u.user_id WHERE c.company_name ILIKE '%삼성%' ORDER BY c.created_date DESC LIMIT 20; -- 화면 표시 ┌─────────────┬─────────────┬─────────────┐ │ company_name│ writer_name │ created_date│ ├─────────────┼─────────────┼─────────────┤ │ 삼성전자 │ 김철수 │ 2024-01-15 │ │ 삼성SDI │ 박영희 │ 2024-01-16 │ └─────────────┴─────────────┴─────────────┘ ``` #### 시나리오 2: 프로젝트 관리 테이블 ```sql -- Entity 설정 (다중) projects.manager_id (entity) → user_info.user_name projects.company_id (entity) → companies.company_name -- 실행되는 쿼리 SELECT p.*, u.user_name as manager_name, c.company_name as company_name FROM projects p LEFT JOIN user_info u ON p.manager_id = u.user_id LEFT JOIN companies c ON p.company_id = c.company_id ORDER BY p.created_date DESC; -- 화면 표시 ┌──────────────┬──────────────┬──────────────┬─────────────┐ │ project_name │ manager_name │ company_name │ created_date│ ├──────────────┼──────────────┼──────────────┼─────────────┤ │ ERP 개발 │ 김철수 │ 삼성전자 │ 2024-01-15 │ │ AI 프로젝트 │ 박영희 │ LG전자 │ 2024-01-16 │ └──────────────┴──────────────┴──────────────┴─────────────┘ ``` ### 📈 성능 예상 지표 #### 캐시 전략 성능 ``` 🎯 작은 참조 테이블 (user_info < 1000건) - 전체 캐싱: 메모리 사용량 ~1MB - 룩업 속도: O(1) - 평균 0.1ms - 캐시 적중률: 95%+ 🎯 큰 참조 테이블 (companies > 10000건) - 쿼리 조인: 평균 50-100ms - 인덱스 최적화로 성능 보장 - 페이징으로 메모리 효율성 확보 ``` #### 사용자 경험 개선 ``` Before: "user001이 누구지? 🤔" → 별도 조회 필요 (추가 5-10초) After: "김철수님이 등록하셨구나! 😍" → 즉시 이해 (0초) 💰 업무 효율성: 직원 1명당 하루 2-3분 절약 → 100명 기준 연간 80-120시간 절약 ``` --- ## 🔒 고려사항 및 제약 ### ⚠️ 주의사항 #### 1. 성능 영향 ``` ✅ 대응 방안: - 작은 참조 테이블 (< 1000건): 전체 캐싱 - 큰 참조 테이블 (> 1000건): 인덱스 최적화 + 쿼리 조인 - 조인 수 제한: 테이블당 최대 5개 Entity 컬럼 - 자동 성능 모니터링 및 알림 ``` #### 2. 데이터 일관성 ``` ✅ 대응 방안: - 참조 테이블 데이터 변경 시 캐시 자동 무효화 - Foreign Key 제약조건 권장 (필수 아님) - 참조 데이터 없는 경우 원본 ID 표시 - 실시간 데이터 유효성 검증 ``` #### 3. 사용자 설정 복잡도 ``` ✅ 대응 방안: - 자동 추천 시스템 (user_info → user_name) - 일반적인 Entity 설정 템플릿 제공 - 설정 미리보기 및 검증 기능 - 단계별 설정 가이드 제공 ``` ### 🚀 확장 가능성 #### 1. 고급 Entity 기능 - **조건부 조인**: WHERE 조건이 있는 Entity 조인 - **계층적 Entity**: Entity 안의 또 다른 Entity (user → department → company) - **집계 Entity**: 관련 데이터 개수나 합계 표시 (project_count, total_amount) #### 2. 성능 최적화 - **지능형 캐싱**: 사용 빈도 기반 캐시 전략 - **배경 업데이트**: 사용자 요청과 독립적인 캐시 갱신 - **분산 캐싱**: Redis 등 외부 캐시 서버 연동 #### 3. 사용자 경험 - **실시간 프리뷰**: Entity 설정 변경 시 즉시 미리보기 - **자동 완성**: Entity 설정 시 테이블/컬럼 자동 완성 - **성능 인사이트**: 조인 성능 분석 및 최적화 제안 --- ## 📋 체크리스트 ### 개발 완료 기준 #### 백엔드 ✅ - [x] EntityJoinService 구현 및 테스트 ✅ - [x] ReferenceCacheService 구현 및 테스트 ✅ - [x] column_labels 스키마 확장 (display_column) ✅ - [x] getTableDataWithEntityJoins API 구현 ✅ - [x] TableManagementService 확장 ✅ - [x] 새로운 API 엔드포인트 추가: `/api/table-management/tables/:tableName/data-with-joins` ✅ - [ ] 성능 벤치마크 (< 100ms 목표) - [ ] 에러 처리 및 fallback 로직 #### 프론트엔드 ✅ - [x] Entity 타입 설정 UI 확장 (display_column 선택) ✅ - [ ] TableList Entity 조인 데이터 표시 - [ ] 조인된 컬럼 시각적 구분 (🔗 아이콘) - [ ] 성능 모니터링 UI (쿼리 시간, 캐시 적중률) - [ ] 에러 상황 사용자 피드백 #### 시스템 통합 ✅ - [ ] 전체 기능 통합 테스트 - [ ] 성능 테스트 (다양한 데이터 크기) - [ ] 사용자 시나리오 테스트 - [ ] 문서화 및 사용 가이드 - [ ] 프로덕션 배포 준비 --- ## 🎯 결론 이 Entity 조인 기능은 단순한 데이터 표시 개선을 넘어서 **사용자 경험의 혁신**을 가져올 것입니다. **"user001"** 같은 의미없는 ID 대신 **"김철수님"** 같은 의미있는 정보를 즉시 보여줌으로써, 업무 효율성을 크게 향상시킬 수 있습니다. 특히 **자동 감지**와 **스마트 캐싱** 시스템으로 개발자와 사용자 모두에게 편리한 기능이 될 것으로 기대됩니다. --- **🚀 "ID에서 이름으로, 데이터에서 정보로의 진화!"**