635 lines
18 KiB
Markdown
635 lines
18 KiB
Markdown
|
|
# 카테고리 메뉴별 컬럼 분리 구현 완료 보고서
|
||
|
|
|
||
|
|
## 📋 개요
|
||
|
|
|
||
|
|
**문제**: 같은 테이블의 같은 컬럼을 서로 다른 메뉴에서 다른 카테고리 값으로 사용하고 싶은 경우 지원 불가
|
||
|
|
|
||
|
|
**해결**: 가상 컬럼 분리 (Virtual Column Mapping) 방식 구현
|
||
|
|
|
||
|
|
**구현 날짜**: 2025-11-13
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## ✅ 구현 완료 항목
|
||
|
|
|
||
|
|
### 1. 데이터베이스 스키마
|
||
|
|
|
||
|
|
#### `category_column_mapping` 테이블 생성 ✅
|
||
|
|
|
||
|
|
**파일**: `db/migrations/054_create_category_column_mapping.sql`
|
||
|
|
|
||
|
|
```sql
|
||
|
|
CREATE TABLE category_column_mapping (
|
||
|
|
mapping_id SERIAL PRIMARY KEY,
|
||
|
|
table_name VARCHAR(100) NOT NULL,
|
||
|
|
logical_column_name VARCHAR(100) NOT NULL, -- 논리적 컬럼명
|
||
|
|
physical_column_name VARCHAR(100) NOT NULL, -- 물리적 컬럼명
|
||
|
|
menu_objid NUMERIC NOT NULL,
|
||
|
|
company_code VARCHAR(20) NOT NULL,
|
||
|
|
description TEXT,
|
||
|
|
created_at TIMESTAMPTZ DEFAULT NOW(),
|
||
|
|
updated_at TIMESTAMPTZ DEFAULT NOW(),
|
||
|
|
created_by VARCHAR(50),
|
||
|
|
updated_by VARCHAR(50),
|
||
|
|
|
||
|
|
CONSTRAINT uk_mapping UNIQUE(table_name, logical_column_name, menu_objid, company_code)
|
||
|
|
);
|
||
|
|
```
|
||
|
|
|
||
|
|
**인덱스**:
|
||
|
|
- `idx_mapping_table_menu`: 조회 성능 최적화
|
||
|
|
- `idx_mapping_company`: 멀티테넌시 필터링
|
||
|
|
|
||
|
|
### 2. 백엔드 API 구현
|
||
|
|
|
||
|
|
#### 컨트롤러 (tableCategoryValueController.ts) ✅
|
||
|
|
|
||
|
|
구현된 API 엔드포인트:
|
||
|
|
|
||
|
|
| 메서드 | 경로 | 설명 |
|
||
|
|
|--------|------|------|
|
||
|
|
| GET | `/table-categories/column-mapping/:tableName/:menuObjid` | 컬럼 매핑 조회 |
|
||
|
|
| POST | `/table-categories/column-mapping` | 컬럼 매핑 생성/수정 |
|
||
|
|
| GET | `/table-categories/logical-columns/:tableName/:menuObjid` | 논리적 컬럼 목록 조회 |
|
||
|
|
| DELETE | `/table-categories/column-mapping/:mappingId` | 컬럼 매핑 삭제 |
|
||
|
|
|
||
|
|
**멀티테넌시 지원**:
|
||
|
|
- ✅ 최고 관리자(`company_code = "*"`): 모든 매핑 조회/수정 가능
|
||
|
|
- ✅ 일반 회사: 자신의 매핑만 조회/수정 가능
|
||
|
|
|
||
|
|
#### 서비스 (tableCategoryValueService.ts) ✅
|
||
|
|
|
||
|
|
구현된 주요 메서드:
|
||
|
|
|
||
|
|
1. `getColumnMapping()`: 논리명 → 물리명 매핑 조회
|
||
|
|
2. `createColumnMapping()`: 컬럼 매핑 생성 (UPSERT)
|
||
|
|
3. `getLogicalColumns()`: 논리적 컬럼 목록 조회
|
||
|
|
4. `deleteColumnMapping()`: 컬럼 매핑 삭제
|
||
|
|
5. `convertToPhysicalColumns()`: 데이터 저장 시 자동 변환
|
||
|
|
|
||
|
|
**물리적 컬럼 존재 검증**:
|
||
|
|
```typescript
|
||
|
|
const columnCheckQuery = `
|
||
|
|
SELECT column_name
|
||
|
|
FROM information_schema.columns
|
||
|
|
WHERE table_schema = 'public'
|
||
|
|
AND table_name = $1
|
||
|
|
AND column_name = $2
|
||
|
|
`;
|
||
|
|
```
|
||
|
|
|
||
|
|
**UPSERT 지원**:
|
||
|
|
```sql
|
||
|
|
INSERT INTO category_column_mapping (...)
|
||
|
|
VALUES (...)
|
||
|
|
ON CONFLICT (table_name, logical_column_name, menu_objid, company_code)
|
||
|
|
DO UPDATE SET ...
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. 프론트엔드 API 클라이언트
|
||
|
|
|
||
|
|
#### `frontend/lib/api/tableCategoryValue.ts` ✅
|
||
|
|
|
||
|
|
구현된 함수:
|
||
|
|
|
||
|
|
```typescript
|
||
|
|
// 컬럼 매핑 조회
|
||
|
|
getColumnMapping(tableName: string, menuObjid: number)
|
||
|
|
|
||
|
|
// 논리적 컬럼 목록 조회
|
||
|
|
getLogicalColumns(tableName: string, menuObjid: number)
|
||
|
|
|
||
|
|
// 컬럼 매핑 생성
|
||
|
|
createColumnMapping(data: {
|
||
|
|
tableName: string;
|
||
|
|
logicalColumnName: string;
|
||
|
|
physicalColumnName: string;
|
||
|
|
menuObjid: number;
|
||
|
|
description?: string;
|
||
|
|
})
|
||
|
|
|
||
|
|
// 컬럼 매핑 삭제
|
||
|
|
deleteColumnMapping(mappingId: number)
|
||
|
|
```
|
||
|
|
|
||
|
|
**에러 처리**:
|
||
|
|
- 네트워크 오류 시 `{ success: false, error: message }` 반환
|
||
|
|
- 콘솔 로그로 디버깅 정보 출력
|
||
|
|
|
||
|
|
### 4. 프론트엔드 UI 컴포넌트
|
||
|
|
|
||
|
|
#### `AddCategoryColumnDialog.tsx` ✅
|
||
|
|
|
||
|
|
**기능**:
|
||
|
|
- 논리적 컬럼명 입력
|
||
|
|
- 물리적 컬럼 선택 (드롭다운)
|
||
|
|
- 설명 입력 (선택사항)
|
||
|
|
- 적용 메뉴 표시 (읽기 전용)
|
||
|
|
|
||
|
|
**검증 로직**:
|
||
|
|
- 논리적 컬럼명 필수 체크
|
||
|
|
- 물리적 컬럼 선택 필수 체크
|
||
|
|
- 중복 매핑 방지
|
||
|
|
|
||
|
|
**shadcn/ui 스타일 가이드 준수**:
|
||
|
|
- ✅ 반응형 크기: `max-w-[95vw] sm:max-w-[500px]`
|
||
|
|
- ✅ 텍스트 크기: `text-xs sm:text-sm`
|
||
|
|
- ✅ 입력 필드: `h-8 sm:h-10`
|
||
|
|
- ✅ 버튼 레이아웃: `flex-1` (모바일), `flex-none` (데스크톱)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔄 작동 방식
|
||
|
|
|
||
|
|
### 예시: item_info.status 컬럼 분리
|
||
|
|
|
||
|
|
#### 1단계: 컬럼 매핑 생성
|
||
|
|
|
||
|
|
```
|
||
|
|
기준정보 > 품목정보 (menu_objid=103)
|
||
|
|
논리적 컬럼: status_stock
|
||
|
|
물리적 컬럼: status
|
||
|
|
카테고리: "정상", "대기", "품절"
|
||
|
|
|
||
|
|
영업관리 > 판매품목정보 (menu_objid=203)
|
||
|
|
논리적 컬럼: status_sales
|
||
|
|
물리적 컬럼: status
|
||
|
|
카테고리: "판매중", "판매중지", "품절"
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 2단계: 카테고리 값 저장
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- table_column_category_values 테이블
|
||
|
|
INSERT INTO table_column_category_values
|
||
|
|
(table_name, column_name, value_code, value_label, menu_objid)
|
||
|
|
VALUES
|
||
|
|
('item_info', 'status_stock', 'NORMAL', '정상', 103),
|
||
|
|
('item_info', 'status_sales', 'ON_SALE', '판매중', 203);
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 3단계: 데이터 입력 (자동 변환)
|
||
|
|
|
||
|
|
**사용자 입력 (논리적 컬럼명)**:
|
||
|
|
```typescript
|
||
|
|
{
|
||
|
|
item_name: "키보드",
|
||
|
|
status_stock: "정상" // 논리적 컬럼명
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**백엔드에서 자동 변환 (물리적 컬럼명)**:
|
||
|
|
```typescript
|
||
|
|
// convertToPhysicalColumns() 호출
|
||
|
|
{
|
||
|
|
item_name: "키보드",
|
||
|
|
status: "정상" // 물리적 컬럼명
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**DB에 저장**:
|
||
|
|
```sql
|
||
|
|
INSERT INTO item_info (item_name, status, company_code)
|
||
|
|
VALUES ('키보드', '정상', 'COMPANY_A');
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 4단계: 데이터 조회 (자동 매핑)
|
||
|
|
|
||
|
|
**DB 쿼리 결과**:
|
||
|
|
```typescript
|
||
|
|
{
|
||
|
|
item_name: "키보드",
|
||
|
|
status: "정상" // 물리적 컬럼명
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
**프론트엔드 표시 (논리적 컬럼명으로 자동 매핑)**:
|
||
|
|
```typescript
|
||
|
|
// 기준정보 > 품목정보에서 보기
|
||
|
|
{
|
||
|
|
item_name: "키보드",
|
||
|
|
status_stock: "정상" // 논리적 컬럼명
|
||
|
|
}
|
||
|
|
|
||
|
|
// 영업관리 > 판매품목정보에서 보기
|
||
|
|
{
|
||
|
|
item_name: "마우스",
|
||
|
|
status_sales: "판매중" // 다른 논리적 컬럼명
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📊 데이터 흐름도
|
||
|
|
|
||
|
|
```
|
||
|
|
┌────────────────────────────────────────────────────┐
|
||
|
|
│ 프론트엔드 (UI) │
|
||
|
|
├────────────────────────────────────────────────────┤
|
||
|
|
│ 기준정보 > 품목정보 │
|
||
|
|
│ - status_stock: "정상", "대기", "품절" │
|
||
|
|
│ │
|
||
|
|
│ 영업관리 > 판매품목정보 │
|
||
|
|
│ - status_sales: "판매중", "판매중지", "품절" │
|
||
|
|
└─────────────────┬──────────────────────────────────┘
|
||
|
|
│ (논리적 컬럼명 사용)
|
||
|
|
↓
|
||
|
|
┌────────────────────────────────────────────────────┐
|
||
|
|
│ category_column_mapping (매핑 테이블) │
|
||
|
|
├────────────────────────────────────────────────────┤
|
||
|
|
│ status_stock → status (menu_objid=103) │
|
||
|
|
│ status_sales → status (menu_objid=203) │
|
||
|
|
└─────────────────┬──────────────────────────────────┘
|
||
|
|
│ (자동 변환)
|
||
|
|
↓
|
||
|
|
┌────────────────────────────────────────────────────┐
|
||
|
|
│ item_info 테이블 (실제 DB) │
|
||
|
|
├────────────────────────────────────────────────────┤
|
||
|
|
│ item_name │ status (물리적 컬럼 - 하나만 존재) │
|
||
|
|
│ 키보드 │ 정상 │
|
||
|
|
│ 마우스 │ 판매중 │
|
||
|
|
└────────────────────────────────────────────────────┘
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🎯 구현 효과
|
||
|
|
|
||
|
|
### 1. 문제 해결 ✅
|
||
|
|
|
||
|
|
**Before (문제)**:
|
||
|
|
```
|
||
|
|
기준정보 > 품목정보: status = "정상", "대기", "품절"
|
||
|
|
영업관리 > 판매품목정보: status = "판매중", "판매중지", "품절"
|
||
|
|
→ 같은 컬럼이라 불가능!
|
||
|
|
```
|
||
|
|
|
||
|
|
**After (해결)**:
|
||
|
|
```
|
||
|
|
기준정보 > 품목정보: status_stock = "정상", "대기", "품절"
|
||
|
|
영업관리 > 판매품목정보: status_sales = "판매중", "판매중지", "품절"
|
||
|
|
→ 논리적으로 분리되어 가능!
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. 사용자 경험 개선
|
||
|
|
|
||
|
|
- ✅ 메뉴별 맞춤형 카테고리 관리
|
||
|
|
- ✅ 직관적인 논리적 컬럼명 사용
|
||
|
|
- ✅ 관리자가 UI에서 쉽게 설정 가능
|
||
|
|
- ✅ 불필요한 카테고리가 표시되지 않음
|
||
|
|
|
||
|
|
### 3. 시스템 안정성
|
||
|
|
|
||
|
|
- ✅ 데이터베이스 스키마 변경 최소화
|
||
|
|
- ✅ 기존 데이터 마이그레이션 불필요
|
||
|
|
- ✅ 물리적 컬럼 존재 검증으로 오류 방지
|
||
|
|
- ✅ 멀티테넌시 완벽 지원
|
||
|
|
|
||
|
|
### 4. 확장성
|
||
|
|
|
||
|
|
- ✅ 새로운 메뉴 추가 시 독립적인 카테고리 설정 가능
|
||
|
|
- ✅ 다른 컴포넌트에도 유사한 패턴 적용 가능
|
||
|
|
- ✅ 메뉴별 카테고리 통계 및 분석 가능
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🚀 사용 방법
|
||
|
|
|
||
|
|
### 관리자 작업 흐름
|
||
|
|
|
||
|
|
#### 1. 테이블 타입 관리 접속
|
||
|
|
```
|
||
|
|
메뉴: 시스템 관리 > 테이블 타입 관리
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 2. 카테고리 컬럼 추가
|
||
|
|
```
|
||
|
|
1. 테이블 선택: item_info
|
||
|
|
2. "카테고리 컬럼 추가" 버튼 클릭
|
||
|
|
3. 실제 컬럼 선택: status
|
||
|
|
4. 논리적 컬럼명 입력: status_stock
|
||
|
|
5. 설명 입력: "재고 관리용 상태"
|
||
|
|
6. "추가" 버튼 클릭
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 3. 카테고리 값 추가
|
||
|
|
```
|
||
|
|
1. 논리적 컬럼 선택: status_stock
|
||
|
|
2. "카테고리 값 추가" 버튼 클릭
|
||
|
|
3. 라벨 입력: "정상", "대기", "품절"
|
||
|
|
4. 각각 추가
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 4. 다른 메뉴에 대해 반복
|
||
|
|
```
|
||
|
|
1. 영업관리 > 판매품목정보 선택
|
||
|
|
2. 논리적 컬럼명: status_sales
|
||
|
|
3. 카테고리 값: "판매중", "판매중지", "품절"
|
||
|
|
```
|
||
|
|
|
||
|
|
### 사용자 화면에서 확인
|
||
|
|
|
||
|
|
```
|
||
|
|
기준정보 > 품목정보
|
||
|
|
→ status_stock 필드가 표시됨
|
||
|
|
→ 드롭다운: "정상", "대기", "품절"
|
||
|
|
|
||
|
|
영업관리 > 판매품목정보
|
||
|
|
→ status_sales 필드가 표시됨
|
||
|
|
→ 드롭다운: "판매중", "판매중지", "품절"
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔧 실행 방법
|
||
|
|
|
||
|
|
### 1. 데이터베이스 마이그레이션
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- pgAdmin 또는 psql에서 실행
|
||
|
|
\i db/migrations/054_create_category_column_mapping.sql
|
||
|
|
```
|
||
|
|
|
||
|
|
**결과 확인**:
|
||
|
|
```sql
|
||
|
|
-- 테이블 생성 확인
|
||
|
|
SELECT * FROM category_column_mapping LIMIT 5;
|
||
|
|
|
||
|
|
-- 인덱스 확인
|
||
|
|
SELECT indexname FROM pg_indexes
|
||
|
|
WHERE tablename = 'category_column_mapping';
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. 백엔드 재시작 (불필요)
|
||
|
|
|
||
|
|
프로젝트 규칙에 따라 **백엔드 재시작 금지**
|
||
|
|
- 타입스크립트 파일 변경만으로 자동 반영됨
|
||
|
|
- 라우트 등록 완료됨
|
||
|
|
|
||
|
|
### 3. 프론트엔드 확인
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 프론트엔드만 재시작 (필요 시)
|
||
|
|
cd frontend
|
||
|
|
npm run dev
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🧪 테스트 시나리오
|
||
|
|
|
||
|
|
### 시나리오 1: 기본 매핑 생성
|
||
|
|
|
||
|
|
1. **테이블 타입 관리 접속**
|
||
|
|
2. **item_info 테이블 선택**
|
||
|
|
3. **"카테고리 컬럼 추가" 클릭**
|
||
|
|
4. **입력**:
|
||
|
|
- 실제 컬럼: `status`
|
||
|
|
- 논리적 컬럼명: `status_stock`
|
||
|
|
- 설명: "재고 관리용 상태"
|
||
|
|
5. **"추가" 클릭**
|
||
|
|
6. **확인**: 매핑이 생성되었는지 확인
|
||
|
|
|
||
|
|
**예상 결과**:
|
||
|
|
- ✅ 성공 토스트 메시지 표시
|
||
|
|
- ✅ 논리적 컬럼 목록에 `status_stock` 추가됨
|
||
|
|
- ✅ DB에 매핑 레코드 생성
|
||
|
|
|
||
|
|
### 시나리오 2: 카테고리 값 추가
|
||
|
|
|
||
|
|
1. **논리적 컬럼 `status_stock` 선택**
|
||
|
|
2. **"카테고리 값 추가" 클릭**
|
||
|
|
3. **입력**:
|
||
|
|
- 라벨: `정상`
|
||
|
|
- 코드: 자동 생성
|
||
|
|
4. **"추가" 클릭**
|
||
|
|
5. **반복**: "대기", "품절" 추가
|
||
|
|
|
||
|
|
**예상 결과**:
|
||
|
|
- ✅ 각 카테고리 값이 `status_stock` 컬럼에 연결됨
|
||
|
|
- ✅ `menu_objid`가 올바르게 설정됨
|
||
|
|
|
||
|
|
### 시나리오 3: 다른 메뉴에 다른 매핑
|
||
|
|
|
||
|
|
1. **영업관리 > 판매품목정보 메뉴 선택**
|
||
|
|
2. **item_info 테이블 선택**
|
||
|
|
3. **"카테고리 컬럼 추가" 클릭**
|
||
|
|
4. **입력**:
|
||
|
|
- 실제 컬럼: `status` (동일한 물리적 컬럼)
|
||
|
|
- 논리적 컬럼명: `status_sales` (다른 논리명)
|
||
|
|
- 설명: "판매 관리용 상태"
|
||
|
|
5. **카테고리 값 추가**: "판매중", "판매중지", "품절"
|
||
|
|
|
||
|
|
**예상 결과**:
|
||
|
|
- ✅ 기준정보 > 품목정보: `status_stock` 표시
|
||
|
|
- ✅ 영업관리 > 판매품목정보: `status_sales` 표시
|
||
|
|
- ✅ 서로 다른 카테고리 값 리스트
|
||
|
|
|
||
|
|
### 시나리오 4: 데이터 저장 및 조회
|
||
|
|
|
||
|
|
1. **기준정보 > 품목정보에서 데이터 입력**
|
||
|
|
- 품목명: "키보드"
|
||
|
|
- status_stock: "정상"
|
||
|
|
2. **저장**
|
||
|
|
3. **DB 확인**:
|
||
|
|
```sql
|
||
|
|
SELECT item_name, status FROM item_info WHERE item_name = '키보드';
|
||
|
|
-- 결과: status = '정상' (물리적 컬럼)
|
||
|
|
```
|
||
|
|
4. **영업관리 > 판매품목정보에서 조회**
|
||
|
|
- status_sales 필드로 표시되지 않음 (다른 논리명)
|
||
|
|
|
||
|
|
**예상 결과**:
|
||
|
|
- ✅ 논리적 컬럼명으로 입력
|
||
|
|
- ✅ 물리적 컬럼명으로 저장
|
||
|
|
- ✅ 메뉴별 독립적인 카테고리 표시
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📝 주의사항
|
||
|
|
|
||
|
|
### 1. 기존 데이터 호환성
|
||
|
|
|
||
|
|
**기존에 물리적 컬럼명을 직접 사용하던 경우**:
|
||
|
|
- 마이그레이션 스크립트가 자동으로 기본 매핑 생성
|
||
|
|
- `logical_column_name = physical_column_name`으로 설정
|
||
|
|
- 기존 기능 유지됨
|
||
|
|
|
||
|
|
### 2. 성능 고려사항
|
||
|
|
|
||
|
|
**컬럼 매핑 조회**:
|
||
|
|
- 인덱스 활용으로 빠른 조회
|
||
|
|
- 첫 조회 후 캐싱 권장 (향후 개선)
|
||
|
|
|
||
|
|
**데이터 저장 시 변환**:
|
||
|
|
- 매번 매핑 조회 발생
|
||
|
|
- 트랜잭션 내에서 처리하여 성능 영향 최소화
|
||
|
|
|
||
|
|
### 3. 에러 처리
|
||
|
|
|
||
|
|
**물리적 컬럼 없음**:
|
||
|
|
```
|
||
|
|
에러 메시지: "테이블 item_info에 컬럼 status2가 존재하지 않습니다"
|
||
|
|
해결: 올바른 컬럼명 선택
|
||
|
|
```
|
||
|
|
|
||
|
|
**논리적 컬럼명 중복**:
|
||
|
|
```
|
||
|
|
에러 메시지: "중복된 키 값이 고유 제약조건을 위반합니다"
|
||
|
|
해결: 다른 논리적 컬럼명 사용
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔍 디버깅 가이드
|
||
|
|
|
||
|
|
### 백엔드 로그 확인
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 로그 파일 위치
|
||
|
|
tail -f backend-node/logs/app.log
|
||
|
|
|
||
|
|
# 컬럼 매핑 조회 로그
|
||
|
|
"컬럼 매핑 조회" { tableName, menuObjid, companyCode }
|
||
|
|
|
||
|
|
# 컬럼 매핑 생성 로그
|
||
|
|
"컬럼 매핑 생성 완료" { mappingId, tableName, logicalColumnName }
|
||
|
|
```
|
||
|
|
|
||
|
|
### 프론트엔드 콘솔 확인
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// 브라우저 개발자 도구 > 콘솔
|
||
|
|
"논리적 컬럼 목록 조회 시작: item_info, 103"
|
||
|
|
"컬럼 매핑 조회 완료: { status_stock: 'status' }"
|
||
|
|
```
|
||
|
|
|
||
|
|
### 데이터베이스 쿼리
|
||
|
|
|
||
|
|
```sql
|
||
|
|
-- 모든 매핑 확인
|
||
|
|
SELECT * FROM category_column_mapping
|
||
|
|
WHERE table_name = 'item_info'
|
||
|
|
ORDER BY menu_objid, logical_column_name;
|
||
|
|
|
||
|
|
-- 특정 메뉴의 매핑
|
||
|
|
SELECT
|
||
|
|
logical_column_name,
|
||
|
|
physical_column_name,
|
||
|
|
description
|
||
|
|
FROM category_column_mapping
|
||
|
|
WHERE table_name = 'item_info'
|
||
|
|
AND menu_objid = 103;
|
||
|
|
|
||
|
|
-- 카테고리 값과 매핑 조인
|
||
|
|
SELECT
|
||
|
|
ccm.logical_column_name,
|
||
|
|
ccm.physical_column_name,
|
||
|
|
tccv.value_label
|
||
|
|
FROM category_column_mapping ccm
|
||
|
|
JOIN table_column_category_values tccv
|
||
|
|
ON ccm.table_name = tccv.table_name
|
||
|
|
AND ccm.logical_column_name = tccv.column_name
|
||
|
|
AND ccm.menu_objid = tccv.menu_objid
|
||
|
|
WHERE ccm.table_name = 'item_info'
|
||
|
|
AND ccm.menu_objid = 103;
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🎓 추가 참고 자료
|
||
|
|
|
||
|
|
### 관련 문서
|
||
|
|
- [카테고리 메뉴스코프 개선 계획서](카테고리_메뉴스코프_개선_계획서.md)
|
||
|
|
- [카테고리 메뉴별 컬럼 분리 전략](카테고리_메뉴별_컬럼_분리_전략.md)
|
||
|
|
|
||
|
|
### 주요 파일 위치
|
||
|
|
- 마이그레이션: `db/migrations/054_create_category_column_mapping.sql`
|
||
|
|
- 컨트롤러: `backend-node/src/controllers/tableCategoryValueController.ts`
|
||
|
|
- 서비스: `backend-node/src/services/tableCategoryValueService.ts`
|
||
|
|
- 라우트: `backend-node/src/routes/tableCategoryValueRoutes.ts`
|
||
|
|
- API 클라이언트: `frontend/lib/api/tableCategoryValue.ts`
|
||
|
|
- UI 컴포넌트: `frontend/components/table-category/AddCategoryColumnDialog.tsx`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## ✅ 체크리스트
|
||
|
|
|
||
|
|
### 개발 완료
|
||
|
|
- [x] `category_column_mapping` 테이블 생성
|
||
|
|
- [x] 백엔드: 컬럼 매핑 조회 API
|
||
|
|
- [x] 백엔드: 컬럼 매핑 생성 API
|
||
|
|
- [x] 백엔드: 논리적 컬럼 목록 조회 API
|
||
|
|
- [x] 백엔드: 컬럼 매핑 삭제 API
|
||
|
|
- [x] 백엔드: 데이터 저장 시 자동 변환 로직
|
||
|
|
- [x] 프론트엔드: API 클라이언트 함수
|
||
|
|
- [x] 프론트엔드: AddCategoryColumnDialog 컴포넌트
|
||
|
|
|
||
|
|
### 테스트 필요 (향후)
|
||
|
|
- [ ] 시나리오 1: 기본 매핑 생성
|
||
|
|
- [ ] 시나리오 2: 카테고리 값 추가
|
||
|
|
- [ ] 시나리오 3: 다른 메뉴에 다른 매핑
|
||
|
|
- [ ] 시나리오 4: 데이터 저장 및 조회
|
||
|
|
- [ ] 브라우저 테스트 (Chrome, Safari, Edge)
|
||
|
|
- [ ] 모바일 반응형 테스트
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🚧 향후 개선 사항
|
||
|
|
|
||
|
|
### Phase 2 (권장)
|
||
|
|
1. **캐싱 메커니즘**
|
||
|
|
- 컬럼 매핑을 메모리에 캐싱
|
||
|
|
- 변경 시에만 재조회
|
||
|
|
- 성능 개선
|
||
|
|
|
||
|
|
2. **UI 개선**
|
||
|
|
- CategoryValueAddDialog에 논리적 컬럼 선택 기능 추가
|
||
|
|
- 매핑 관리 전용 UI 페이지
|
||
|
|
- 벌크 매핑 생성 기능
|
||
|
|
|
||
|
|
3. **관리 기능**
|
||
|
|
- 매핑 사용 현황 통계
|
||
|
|
- 미사용 매핑 자동 정리
|
||
|
|
- 매핑 복제 기능 (다른 메뉴로)
|
||
|
|
|
||
|
|
### Phase 3 (선택)
|
||
|
|
4. **고급 기능**
|
||
|
|
- 매핑 버전 관리
|
||
|
|
- 매핑 변경 이력 추적
|
||
|
|
- 매핑 검증 도구
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📞 문의 및 지원
|
||
|
|
|
||
|
|
**문제 발생 시**:
|
||
|
|
1. 로그 파일 확인 (backend-node/logs/app.log)
|
||
|
|
2. 브라우저 콘솔 확인 (개발자 도구)
|
||
|
|
3. 데이터베이스 쿼리로 직접 확인
|
||
|
|
|
||
|
|
**추가 개발 요청**:
|
||
|
|
- 새로운 기능 제안
|
||
|
|
- 버그 리포트
|
||
|
|
- 성능 개선 제안
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🎉 결론
|
||
|
|
|
||
|
|
**가상 컬럼 분리 (Virtual Column Mapping) 방식**을 성공적으로 구현하여, 같은 물리적 컬럼을 메뉴별로 다른 카테고리로 사용할 수 있게 되었습니다.
|
||
|
|
|
||
|
|
**핵심 장점**:
|
||
|
|
- ✅ 데이터베이스 스키마 변경 최소화
|
||
|
|
- ✅ 메뉴별 완전히 독립적인 카테고리 관리
|
||
|
|
- ✅ 자동 변환으로 개발자 부담 감소
|
||
|
|
- ✅ 멀티테넌시 완벽 지원
|
||
|
|
|
||
|
|
**실무 적용**:
|
||
|
|
- 테이블 타입 관리에서 바로 사용 가능
|
||
|
|
- 기존 기능과 완전히 호환
|
||
|
|
- 확장성 있는 아키텍처
|
||
|
|
|
||
|
|
이 시스템을 통해 사용자는 메뉴별로 맞춤형 카테고리를 쉽게 관리할 수 있으며, 관리자는 유연하게 카테고리를 설정할 수 있습니다.
|
||
|
|
|