600 lines
17 KiB
Markdown
600 lines
17 KiB
Markdown
|
|
# 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<EntityJoinConfig[]>;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Entity 조인이 포함된 SQL 쿼리 생성
|
||
|
|
*/
|
||
|
|
buildJoinQuery(
|
||
|
|
tableName: string,
|
||
|
|
joinConfigs: EntityJoinConfig[],
|
||
|
|
selectColumns: string[],
|
||
|
|
whereClause: string,
|
||
|
|
orderBy: string,
|
||
|
|
limit: number,
|
||
|
|
offset: number
|
||
|
|
): string;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 참조 테이블 데이터 캐싱
|
||
|
|
*/
|
||
|
|
async cacheReferenceData(tableName: string): Promise<void>;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 2. 캐시 시스템
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// src/services/referenceCache.ts
|
||
|
|
|
||
|
|
export class ReferenceCacheService {
|
||
|
|
private cache = new Map<string, Map<string, any>>();
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 작은 참조 테이블 전체 캐싱 (user_info, departments 등)
|
||
|
|
*/
|
||
|
|
async preloadReferenceTable(
|
||
|
|
tableName: string,
|
||
|
|
keyColumn: string,
|
||
|
|
displayColumn: string
|
||
|
|
): Promise<void>;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 캐시에서 참조 값 조회
|
||
|
|
*/
|
||
|
|
getLookupValue(table: string, key: string): any | null;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 배치 룩업 (성능 최적화)
|
||
|
|
*/
|
||
|
|
async batchLookup(
|
||
|
|
requests: BatchLookupRequest[]
|
||
|
|
): Promise<BatchLookupResponse[]>;
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 3. 테이블 데이터 서비스 확장
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// tableManagementService.ts 확장
|
||
|
|
|
||
|
|
export class TableManagementService {
|
||
|
|
/**
|
||
|
|
* Entity 조인이 포함된 데이터 조회
|
||
|
|
*/
|
||
|
|
async getTableDataWithEntityJoins(
|
||
|
|
tableName: string,
|
||
|
|
options: {
|
||
|
|
page: number;
|
||
|
|
size: number;
|
||
|
|
search?: Record<string, any>;
|
||
|
|
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" && (
|
||
|
|
<div className="space-y-2">
|
||
|
|
{/* 기존: 참조 테이블 선택 */}
|
||
|
|
<Select value={column.referenceTable} onValueChange={...}>
|
||
|
|
<SelectContent>
|
||
|
|
{referenceTableOptions.map(option => ...)}
|
||
|
|
</SelectContent>
|
||
|
|
</Select>
|
||
|
|
|
||
|
|
{/* 🎯 새로 추가: 표시할 컬럼 선택 */}
|
||
|
|
<Select value={column.displayColumn} onValueChange={...}>
|
||
|
|
<SelectTrigger>
|
||
|
|
<SelectValue placeholder="표시할 컬럼 선택" />
|
||
|
|
</SelectTrigger>
|
||
|
|
<SelectContent>
|
||
|
|
{getDisplayColumnOptions(column.referenceTable).map(option => (
|
||
|
|
<SelectItem key={option.value} value={option.value}>
|
||
|
|
{option.label}
|
||
|
|
</SelectItem>
|
||
|
|
))}
|
||
|
|
</SelectContent>
|
||
|
|
</Select>
|
||
|
|
</div>
|
||
|
|
)}
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 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 조인된 컬럼 시각적 구분
|
||
|
|
<TableHead>
|
||
|
|
<div className="flex items-center space-x-1">
|
||
|
|
{isEntityJoinedColumn && (
|
||
|
|
<span className="text-xs text-blue-600" title="Entity 조인됨">
|
||
|
|
🔗
|
||
|
|
</span>
|
||
|
|
)}
|
||
|
|
<span className={cn(isEntityJoinedColumn && "text-blue-700 font-medium")}>
|
||
|
|
{getColumnDisplayName(column)}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</TableHead>;
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 3. API 타입 확장
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// frontend/lib/api/screen.ts 확장
|
||
|
|
|
||
|
|
export const tableTypeApi = {
|
||
|
|
// 🎯 Entity 조인 지원 데이터 조회
|
||
|
|
getTableDataWithEntityJoins: async (
|
||
|
|
tableName: string,
|
||
|
|
params: {
|
||
|
|
page?: number;
|
||
|
|
size?: number;
|
||
|
|
search?: Record<string, any>;
|
||
|
|
sortBy?: string;
|
||
|
|
sortOrder?: "asc" | "desc";
|
||
|
|
enableEntityJoin?: boolean;
|
||
|
|
}
|
||
|
|
): Promise<{
|
||
|
|
data: Record<string, any>[];
|
||
|
|
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에서 이름으로, 데이터에서 정보로의 진화!"**
|