feat: 메뉴 복사 기능 - 2단계 복사 방식으로 화면 참조 매핑 문제 해결
- 문제: 화면 복사 시 참조되는 화면이 아직 복사되지 않아 screenIdMap에 매핑 정보가 없었음 - 해결: 2단계 복사 방식 도입 1단계: 모든 screen_definitions 먼저 복사하여 screenIdMap 완성 2단계: screen_layouts 복사하면서 완성된 screenIdMap으로 참조 업데이트 - 결과: targetScreenId가 올바르게 새 회사의 화면 ID로 매핑됨 (예: 149 → 517) - 추가: 화면 수집 시 문자열 타입 ID도 올바르게 파싱하도록 개선 - 추가: 참조 화면 발견 및 업데이트 로그 추가 관련 파일: - backend-node/src/services/menuCopyService.ts - db/migrations/1003_add_source_menu_objid_to_menu_info.sql - db/scripts/cleanup_company_11_*.sql
This commit is contained in:
184
db/migrations/README_1003.md
Normal file
184
db/migrations/README_1003.md
Normal file
@@ -0,0 +1,184 @@
|
||||
# 마이그레이션 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 저장
|
||||
|
||||
146
db/migrations/RUN_MIGRATION_1003.md
Normal file
146
db/migrations/RUN_MIGRATION_1003.md
Normal file
@@ -0,0 +1,146 @@
|
||||
# 마이그레이션 1003 실행 가이드
|
||||
|
||||
## ❌ 현재 에러
|
||||
```
|
||||
column "source_menu_objid" does not exist
|
||||
```
|
||||
|
||||
**원인**: `menu_info` 테이블에 `source_menu_objid` 컬럼이 아직 추가되지 않음
|
||||
|
||||
## ✅ 해결 방법
|
||||
|
||||
### 방법 1: psql 직접 실행 (권장)
|
||||
|
||||
```bash
|
||||
# 1. PostgreSQL 접속 정보 확인
|
||||
# - Host: localhost (또는 실제 DB 호스트)
|
||||
# - Port: 5432 (기본값)
|
||||
# - Database: ilshin
|
||||
# - User: postgres
|
||||
|
||||
# 2. 마이그레이션 실행
|
||||
cd /Users/kimjuseok/ERP-node
|
||||
psql -h localhost -U postgres -d ilshin -f db/migrations/1003_add_source_menu_objid_to_menu_info.sql
|
||||
|
||||
# 또는 대화형으로
|
||||
psql -h localhost -U postgres -d ilshin
|
||||
# 그 다음 파일 내용 붙여넣기
|
||||
```
|
||||
|
||||
### 방법 2: DBeaver / pgAdmin에서 실행
|
||||
|
||||
1. DBeaver 또는 pgAdmin 실행
|
||||
2. `ilshin` 데이터베이스 연결
|
||||
3. SQL 편집기 열기
|
||||
4. 아래 SQL 복사하여 실행:
|
||||
|
||||
```sql
|
||||
-- source_menu_objid 컬럼 추가
|
||||
ALTER TABLE menu_info
|
||||
ADD COLUMN IF NOT EXISTS source_menu_objid BIGINT;
|
||||
|
||||
-- 인덱스 생성 (검색 성능 향상)
|
||||
CREATE INDEX IF NOT EXISTS idx_menu_info_source_menu_objid
|
||||
ON menu_info(source_menu_objid);
|
||||
|
||||
-- 복합 인덱스: 회사별 원본 메뉴 검색
|
||||
CREATE INDEX IF NOT EXISTS idx_menu_info_source_company
|
||||
ON menu_info(source_menu_objid, company_code);
|
||||
|
||||
-- 컬럼 설명 추가
|
||||
COMMENT ON COLUMN menu_info.source_menu_objid IS '원본 메뉴 ID (복사된 경우만 값 존재)';
|
||||
|
||||
-- 확인
|
||||
SELECT column_name, data_type, is_nullable
|
||||
FROM information_schema.columns
|
||||
WHERE table_name = 'menu_info'
|
||||
AND column_name = 'source_menu_objid';
|
||||
```
|
||||
|
||||
### 방법 3: Docker를 통한 실행
|
||||
|
||||
Docker Compose 설정 확인 후:
|
||||
|
||||
```bash
|
||||
# Docker Compose에 DB 서비스가 있는 경우
|
||||
docker-compose exec db psql -U postgres -d ilshin -f /path/to/migration.sql
|
||||
|
||||
# 또는 SQL을 직접 실행
|
||||
docker-compose exec db psql -U postgres -d ilshin -c "
|
||||
ALTER TABLE menu_info ADD COLUMN IF NOT EXISTS source_menu_objid BIGINT;
|
||||
CREATE INDEX IF NOT EXISTS idx_menu_info_source_menu_objid ON menu_info(source_menu_objid);
|
||||
CREATE INDEX IF NOT EXISTS idx_menu_info_source_company ON menu_info(source_menu_objid, company_code);
|
||||
"
|
||||
```
|
||||
|
||||
## ✅ 실행 후 확인
|
||||
|
||||
### 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
|
||||
FROM pg_indexes
|
||||
WHERE tablename = 'menu_info'
|
||||
AND indexname LIKE '%source%';
|
||||
```
|
||||
|
||||
**예상 결과**:
|
||||
```
|
||||
indexname
|
||||
---------------------------------
|
||||
idx_menu_info_source_menu_objid
|
||||
idx_menu_info_source_company
|
||||
```
|
||||
|
||||
### 3. 메뉴 복사 재시도
|
||||
마이그레이션 완료 후 프론트엔드에서 메뉴 복사를 다시 실행하세요.
|
||||
|
||||
## 🔍 DB 접속 정보 찾기
|
||||
|
||||
### 환경 변수 확인
|
||||
```bash
|
||||
# .env 파일 확인
|
||||
cat backend-node/.env | grep DB
|
||||
|
||||
# Docker Compose 확인
|
||||
cat docker-compose*.yml | grep -A 10 postgres
|
||||
```
|
||||
|
||||
### 일반적인 접속 정보
|
||||
- **Host**: localhost 또는 127.0.0.1
|
||||
- **Port**: 5432 (기본값)
|
||||
- **Database**: ilshin
|
||||
- **User**: postgres
|
||||
- **Password**: (환경 설정 파일에서 확인)
|
||||
|
||||
## ⚠️ 주의사항
|
||||
|
||||
1. **백업 권장**: 마이그레이션 실행 전 DB 백업 권장
|
||||
2. **권한 확인**: ALTER TABLE 권한이 필요합니다
|
||||
3. **백엔드 재시작 불필요**: 컬럼 추가만으로 즉시 작동합니다
|
||||
|
||||
## 📞 문제 해결
|
||||
|
||||
### "permission denied" 에러
|
||||
→ postgres 사용자 또는 superuser 권한으로 실행 필요
|
||||
|
||||
### "relation does not exist" 에러
|
||||
→ 올바른 데이터베이스(ilshin)에 접속했는지 확인
|
||||
|
||||
### "already exists" 에러
|
||||
→ 이미 실행됨. 무시하고 진행 가능
|
||||
|
||||
Reference in New Issue
Block a user