# 마이그레이션 1003: source_menu_objid 추가

## 📋 개요

메뉴 복사 기능 개선을 위해 `menu_info` 테이블에 `source_menu_objid` 컬럼을 추가합니다.

## 🎯 목적

### 이전 방식의 문제점
- 메뉴 이름으로만 기존 복사본 판단
- 같은 이름의 다른 메뉴도 삭제될 위험
- 수동으로 만든 메뉴와 복사된 메뉴 구분 불가

### 개선 후
- 원본 메뉴 ID로 정확히 추적
- 같은 원본에서 복사된 메뉴만 덮어쓰기
- 수동 메뉴와 복사 메뉴 명확히 구분

## 🗄️ 스키마 변경

### 추가되는 컬럼
```sql
ALTER TABLE menu_info 
ADD COLUMN source_menu_objid BIGINT;
```

### 인덱스
```sql
-- 단일 인덱스
CREATE INDEX idx_menu_info_source_menu_objid 
ON menu_info(source_menu_objid);

-- 복합 인덱스 (회사별 검색 최적화)
CREATE INDEX idx_menu_info_source_company 
ON menu_info(source_menu_objid, company_code);
```

## 📊 데이터 구조

### 복사된 메뉴의 source_menu_objid 값

| 메뉴 레벨 | source_menu_objid | 설명 |
|-----------|-------------------|------|
| 최상위 메뉴 | 원본 메뉴의 objid | 예: 1762407678882 |
| 하위 메뉴 | NULL | 최상위 메뉴만 추적 |
| 수동 생성 메뉴 | NULL | 복사가 아님 |

### 예시

#### 원본 (COMPANY_7)
```
- 사용자 (objid: 1762407678882)
  └─ 영업관리 (objid: 1762421877772)
     └─ 거래처관리 (objid: 1762421920304)
```

#### 복사본 (COMPANY_11)
```
- 사용자 (objid: 1763688215729, source_menu_objid: 1762407678882) ← 추적
  └─ 영업관리 (objid: 1763688215739, source_menu_objid: NULL)
     └─ 거래처관리 (objid: 1763688215743, source_menu_objid: NULL)
```

## 🚀 실행 방법

### 로컬 PostgreSQL
```bash
psql -U postgres -d ilshin -f db/migrations/1003_add_source_menu_objid_to_menu_info.sql
```

### Docker 환경
```bash
# 백엔드 컨테이너를 통해 실행
docker exec -i pms-backend-mac bash -c "PGPASSWORD=your_password psql -U postgres -d ilshin" < db/migrations/1003_add_source_menu_objid_to_menu_info.sql
```

### DBeaver / pgAdmin
1. `db/migrations/1003_add_source_menu_objid_to_menu_info.sql` 파일 열기
2. 전체 스크립트 실행

## ✅ 확인 방법

### 1. 컬럼 추가 확인
```sql
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_name = 'menu_info' 
  AND column_name = 'source_menu_objid';
```

**예상 결과**:
```
column_name        | data_type | is_nullable
-------------------|-----------|-------------
source_menu_objid  | bigint    | YES
```

### 2. 인덱스 생성 확인
```sql
SELECT indexname, indexdef
FROM pg_indexes
WHERE tablename = 'menu_info' 
  AND indexname LIKE '%source%';
```

**예상 결과**:
```
indexname                        | indexdef
---------------------------------|----------------------------------
idx_menu_info_source_menu_objid  | CREATE INDEX ...
idx_menu_info_source_company     | CREATE INDEX ...
```

### 3. 기존 데이터 확인
```sql
-- 모든 메뉴의 source_menu_objid는 NULL이어야 함 (기존 데이터)
SELECT 
  COUNT(*) as total,
  COUNT(source_menu_objid) as with_source
FROM menu_info;
```

**예상 결과**:
```
total | with_source
------|-------------
 114  | 0
```

## 🔄 롤백 (필요 시)

```sql
-- 인덱스 삭제
DROP INDEX IF EXISTS idx_menu_info_source_menu_objid;
DROP INDEX IF EXISTS idx_menu_info_source_company;

-- 컬럼 삭제
ALTER TABLE menu_info DROP COLUMN IF EXISTS source_menu_objid;
```

## 📝 주의사항

1. **기존 메뉴는 영향 없음**: 컬럼이 NULL 허용이므로 기존 데이터는 그대로 유지됩니다.
2. **복사 기능만 영향**: 메뉴 복사 시에만 `source_menu_objid`가 설정됩니다.
3. **백엔드 재시작 필요**: 마이그레이션 후 백엔드를 재시작해야 새 로직이 적용됩니다.

## 🧪 테스트 시나리오

### 1. 첫 복사 (source_menu_objid 설정)
```
원본: 사용자 (objid: 1762407678882, COMPANY_7)
복사: 사용자 (objid: 1763688215729, COMPANY_11)
      source_menu_objid: 1762407678882 ✅
```

### 2. 재복사 (정확한 덮어쓰기)
```
복사 전 조회:
  SELECT objid FROM menu_info 
  WHERE source_menu_objid = 1762407678882 
    AND company_code = 'COMPANY_11'
  → 1763688215729 발견

동작:
  1. objid=1763688215729의 메뉴 트리 전체 삭제
  2. 새로 복사 (source_menu_objid: 1762407678882)
```

### 3. 다른 메뉴는 영향 없음
```
수동 메뉴: 관리자 (objid: 1234567890, COMPANY_11)
           source_menu_objid: NULL ✅

"사용자" 메뉴 재복사 시:
  → 관리자 메뉴는 그대로 유지 ✅
```

## 📚 관련 파일

- **마이그레이션**: `db/migrations/1003_add_source_menu_objid_to_menu_info.sql`
- **백엔드 서비스**: `backend-node/src/services/menuCopyService.ts`
  - `deleteExistingCopy()`: source_menu_objid로 기존 복사본 찾기
  - `copyMenus()`: 복사 시 source_menu_objid 저장

