429 lines
12 KiB
Markdown
429 lines
12 KiB
Markdown
|
|
# 채번규칙 테이블 기반 필터링 시스템 구현 완료 보고서
|
||
|
|
|
||
|
|
## 📅 완료 일시
|
||
|
|
- **날짜**: 2025-11-08
|
||
|
|
- **소요 시간**: 약 3시간 30분 (마이그레이션 실행 미완료)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🎯 목적
|
||
|
|
|
||
|
|
화면관리 시스템에서 채번규칙이 표시되지 않는 문제를 해결하기 위해 **메뉴 기반 필터링**에서 **테이블 기반 필터링**으로 전환
|
||
|
|
|
||
|
|
### 기존 문제점
|
||
|
|
1. 화면관리에서 `menuObjid` 정보가 없어 `scope_type='menu'` 규칙을 볼 수 없음
|
||
|
|
2. 메뉴 구조 변경 시 채번규칙 재설정 필요
|
||
|
|
3. 같은 테이블을 사용하는 화면인데도 규칙이 보이지 않음
|
||
|
|
|
||
|
|
### 해결 방안
|
||
|
|
- **테이블명 기반 자동 매칭**: 화면의 테이블과 규칙의 테이블이 같으면 자동으로 표시
|
||
|
|
- **하이브리드 접근**: `scope_type`을 `'global'`, `'table'`, `'menu'` 세 가지로 확장
|
||
|
|
- **우선순위 필터링**: menu > table > global 순으로 규칙 표시
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## ✅ 구현 완료 항목
|
||
|
|
|
||
|
|
### Phase 1: 데이터베이스 마이그레이션 (준비 완료)
|
||
|
|
|
||
|
|
#### 파일 생성
|
||
|
|
- ✅ `/db/migrations/046_update_numbering_rules_scope_type.sql`
|
||
|
|
- ✅ `/db/migrations/RUN_046_MIGRATION.md`
|
||
|
|
|
||
|
|
#### 마이그레이션 내용
|
||
|
|
- `scope_type` 제약조건 확장: `'global'`, `'table'`, `'menu'`
|
||
|
|
- 유효성 검증 제약조건 추가:
|
||
|
|
- `check_table_scope_requires_table_name`: table 타입은 table_name 필수
|
||
|
|
- `check_global_scope_no_table_name`: global 타입은 table_name 없어야 함
|
||
|
|
- `check_menu_scope_requires_menu_objid`: menu 타입은 menu_objid 필수
|
||
|
|
- 기존 데이터 자동 마이그레이션: `global` + `table_name` → `table` 타입으로 변경
|
||
|
|
- 멀티테넌시 인덱스 최적화:
|
||
|
|
- `idx_numbering_rules_scope_table (scope_type, table_name, company_code)`
|
||
|
|
- `idx_numbering_rules_scope_menu (scope_type, menu_objid, company_code)`
|
||
|
|
|
||
|
|
#### 상태
|
||
|
|
⚠️ **마이그레이션 파일 준비 완료, 실행 대기 중**
|
||
|
|
- Docker 컨테이너 연결 문제로 수동 실행 필요
|
||
|
|
- 실행 가이드는 `RUN_046_MIGRATION.md` 참고
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Phase 2: 백엔드 API 수정 ✅
|
||
|
|
|
||
|
|
#### 2.1 numberingRuleService.ts
|
||
|
|
- ✅ `getAvailableRulesForScreen()` 함수 추가
|
||
|
|
- 파라미터: `companyCode`, `tableName` (필수), `menuObjid` (선택)
|
||
|
|
- 우선순위 필터링: menu > table > global
|
||
|
|
- 멀티테넌시 완벽 지원
|
||
|
|
|
||
|
|
**주요 SQL 쿼리:**
|
||
|
|
```sql
|
||
|
|
SELECT * FROM numbering_rules
|
||
|
|
WHERE company_code = $1
|
||
|
|
AND (
|
||
|
|
(scope_type = 'menu' AND menu_objid = $2)
|
||
|
|
OR (scope_type = 'table' AND table_name = $3)
|
||
|
|
OR (scope_type = 'global' AND table_name IS NULL)
|
||
|
|
)
|
||
|
|
ORDER BY
|
||
|
|
CASE scope_type
|
||
|
|
WHEN 'menu' THEN 1
|
||
|
|
WHEN 'table' THEN 2
|
||
|
|
WHEN 'global' THEN 3
|
||
|
|
END,
|
||
|
|
created_at DESC
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 2.2 numberingRuleController.ts
|
||
|
|
- ✅ `GET /api/numbering-rules/available-for-screen` 엔드포인트 추가
|
||
|
|
- Query Parameters: `tableName` (필수), `menuObjid` (선택)
|
||
|
|
- tableName 검증 로직 포함
|
||
|
|
- 상세 로그 기록
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Phase 3: 프론트엔드 API 클라이언트 수정 ✅
|
||
|
|
|
||
|
|
#### lib/api/numberingRule.ts
|
||
|
|
- ✅ `getAvailableNumberingRulesForScreen()` 함수 추가
|
||
|
|
- 파라미터: `tableName` (필수), `menuObjid` (선택)
|
||
|
|
- 기존 `getAvailableNumberingRules()` 유지 (하위 호환성)
|
||
|
|
|
||
|
|
**사용 예시:**
|
||
|
|
```typescript
|
||
|
|
const response = await getAvailableNumberingRulesForScreen(
|
||
|
|
"item_info", // 테이블명
|
||
|
|
undefined // menuObjid (선택)
|
||
|
|
);
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Phase 4: 화면관리 UI 수정 ✅
|
||
|
|
|
||
|
|
#### 4.1 TextTypeConfigPanel.tsx
|
||
|
|
- ✅ `tableName`, `menuObjid` props 추가
|
||
|
|
- ✅ 채번 규칙 로드 로직 개선:
|
||
|
|
- 테이블명이 있으면 `getAvailableNumberingRulesForScreen()` 호출
|
||
|
|
- 없으면 기존 메뉴 기반 방식 사용 (Fallback)
|
||
|
|
- 상세 로그 추가
|
||
|
|
|
||
|
|
**주요 코드:**
|
||
|
|
```typescript
|
||
|
|
useEffect(() => {
|
||
|
|
const loadRules = async () => {
|
||
|
|
if (tableName) {
|
||
|
|
response = await getAvailableNumberingRulesForScreen(tableName, menuObjid);
|
||
|
|
} else {
|
||
|
|
response = await getAvailableNumberingRules(menuObjid);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
}, [localValues.autoValueType, tableName, menuObjid]);
|
||
|
|
```
|
||
|
|
|
||
|
|
#### 4.2 DetailSettingsPanel.tsx
|
||
|
|
- ✅ `currentTableName`을 ConfigPanelComponent에 전달
|
||
|
|
- ✅ ConfigPanelComponent 타입에 `tableName`, `menuObjid` 추가
|
||
|
|
|
||
|
|
#### 4.3 getConfigPanelComponent.tsx
|
||
|
|
- ✅ `ConfigPanelComponent` 타입 확장: `tableName?`, `menuObjid?` 추가
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
### Phase 5: 채번규칙 관리 UI 수정 ✅
|
||
|
|
|
||
|
|
#### NumberingRuleDesigner.tsx
|
||
|
|
- ✅ 적용 범위 선택 UI 추가
|
||
|
|
- Global: 모든 화면에서 사용
|
||
|
|
- Table: 특정 테이블에서만 사용
|
||
|
|
- Menu: 특정 메뉴에서만 사용
|
||
|
|
- ✅ 조건부 필드 표시:
|
||
|
|
- `scope_type='table'`: 테이블명 입력 필드 표시
|
||
|
|
- `scope_type='menu'`: 메뉴 선택 드롭다운 표시
|
||
|
|
- `scope_type='global'`: 추가 필드 불필요
|
||
|
|
- ✅ 새 규칙 기본값: `scope_type='global'`로 변경 (가장 일반적)
|
||
|
|
|
||
|
|
**UI 구조:**
|
||
|
|
```
|
||
|
|
규칙명 | 미리보기
|
||
|
|
-----------------
|
||
|
|
적용 범위 [Global/Table/Menu]
|
||
|
|
└─ (table) 테이블명 입력
|
||
|
|
└─ (menu) 메뉴 선택
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔄 데이터 흐름
|
||
|
|
|
||
|
|
### 화면관리에서 채번 규칙 조회 시
|
||
|
|
|
||
|
|
1. **화면 로드**
|
||
|
|
- ScreenDesigner → DetailSettingsPanel
|
||
|
|
- `currentTableName` 전달
|
||
|
|
|
||
|
|
2. **TextTypeConfigPanel 렌더링**
|
||
|
|
- Props: `tableName="item_info"`
|
||
|
|
- autoValueType이 `"numbering_rule"`일 때 규칙 로드
|
||
|
|
|
||
|
|
3. **API 호출**
|
||
|
|
```
|
||
|
|
GET /api/numbering-rules/available-for-screen?tableName=item_info
|
||
|
|
```
|
||
|
|
|
||
|
|
4. **백엔드 처리**
|
||
|
|
- `numberingRuleService.getAvailableRulesForScreen()`
|
||
|
|
- SQL 쿼리로 우선순위 필터링
|
||
|
|
- 멀티테넌시 적용 (company_code 확인)
|
||
|
|
|
||
|
|
5. **응답 데이터**
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"success": true,
|
||
|
|
"data": [
|
||
|
|
{
|
||
|
|
"ruleId": "ITEM_CODE",
|
||
|
|
"ruleName": "품목 코드",
|
||
|
|
"scopeType": "table",
|
||
|
|
"tableName": "item_info"
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"ruleId": "GLOBAL_CODE",
|
||
|
|
"ruleName": "전역 코드",
|
||
|
|
"scopeType": "global"
|
||
|
|
}
|
||
|
|
]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
6. **UI 표시**
|
||
|
|
- Select 드롭다운에 규칙 목록 표시
|
||
|
|
- 우선순위대로 정렬됨
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📊 scope_type 정의 및 우선순위
|
||
|
|
|
||
|
|
| scope_type | 설명 | 우선순위 | 사용 케이스 |
|
||
|
|
| ---------- | ---------------------- | -------- | ------------------------------- |
|
||
|
|
| `menu` | 특정 메뉴에서만 사용 | 1 (최고) | 메뉴별로 다른 채번 방식 필요 시 |
|
||
|
|
| `table` | 특정 테이블에서만 사용 | 2 (중간) | 테이블 기준 채번 (일반적) |
|
||
|
|
| `global` | 모든 곳에서 사용 가능 | 3 (최저) | 공통 채번 규칙 |
|
||
|
|
|
||
|
|
### 필터링 로직
|
||
|
|
```sql
|
||
|
|
WHERE company_code = $1 -- 멀티테넌시 필수
|
||
|
|
AND (
|
||
|
|
(scope_type = 'menu' AND menu_objid = $2) -- 1순위
|
||
|
|
OR (scope_type = 'table' AND table_name = $3) -- 2순위
|
||
|
|
OR (scope_type = 'global' AND table_name IS NULL) -- 3순위
|
||
|
|
)
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔐 멀티테넌시 보장
|
||
|
|
|
||
|
|
### 데이터베이스 레벨
|
||
|
|
- ✅ `company_code` 컬럼 필수 (NOT NULL)
|
||
|
|
- ✅ 외래키 제약조건 (company_info 참조)
|
||
|
|
- ✅ 복합 인덱스에 company_code 포함
|
||
|
|
|
||
|
|
### API 레벨
|
||
|
|
- ✅ 일반 회사: `WHERE company_code = $1`
|
||
|
|
- ✅ 최고 관리자: 모든 데이터 조회 가능 (company_code="*" 제외)
|
||
|
|
- ✅ 일반 회사는 `company_code="*"` 데이터를 볼 수 없음
|
||
|
|
|
||
|
|
### 로깅 레벨
|
||
|
|
- ✅ 모든 로그에 `companyCode` 포함 (감사 추적)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🧪 테스트 체크리스트
|
||
|
|
|
||
|
|
### 데이터베이스 테스트 (마이그레이션 후 수행)
|
||
|
|
|
||
|
|
- [ ] 제약조건 확인
|
||
|
|
```sql
|
||
|
|
SELECT conname, pg_get_constraintdef(oid)
|
||
|
|
FROM pg_constraint
|
||
|
|
WHERE conrelid = 'numbering_rules'::regclass
|
||
|
|
AND conname LIKE '%scope%';
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] 인덱스 확인
|
||
|
|
```sql
|
||
|
|
SELECT indexname, indexdef
|
||
|
|
FROM pg_indexes
|
||
|
|
WHERE tablename = 'numbering_rules'
|
||
|
|
AND indexname LIKE '%scope%';
|
||
|
|
```
|
||
|
|
|
||
|
|
- [ ] 데이터 마이그레이션 확인
|
||
|
|
```sql
|
||
|
|
SELECT scope_type, COUNT(*) as count
|
||
|
|
FROM numbering_rules
|
||
|
|
GROUP BY scope_type;
|
||
|
|
```
|
||
|
|
|
||
|
|
### 기능 테스트
|
||
|
|
|
||
|
|
- [ ] **회사 A로 로그인**
|
||
|
|
- [ ] 채번규칙 관리에서 새 규칙 생성 (scope_type='table', tableName='item_info')
|
||
|
|
- [ ] 저장 성공 확인
|
||
|
|
- [ ] 화면관리에서 item_info 테이블 화면 생성
|
||
|
|
- [ ] 텍스트 필드에서 "자동 입력 > 채번 규칙" 선택
|
||
|
|
- [ ] 방금 생성한 규칙이 목록에 표시되는지 확인 ✅
|
||
|
|
|
||
|
|
- [ ] **회사 B로 로그인**
|
||
|
|
- [ ] 화면관리에서 item_info 테이블 화면 접속
|
||
|
|
- [ ] 텍스트 필드에서 "자동 입력 > 채번 규칙" 선택
|
||
|
|
- [ ] 회사 A의 규칙이 보이지 않는지 확인 ✅
|
||
|
|
|
||
|
|
- [ ] **최고 관리자로 로그인**
|
||
|
|
- [ ] 채번규칙 관리에서 모든 회사 규칙이 보이는지 확인 ✅
|
||
|
|
- [ ] 화면관리에서는 일반 회사 규칙만 보이는지 확인 ✅
|
||
|
|
|
||
|
|
### 우선순위 테스트
|
||
|
|
|
||
|
|
- [ ] 같은 테이블(item_info)에 대해 3가지 scope_type 규칙 생성
|
||
|
|
- [ ] scope_type='global', table_name=NULL, ruleName="전역규칙"
|
||
|
|
- [ ] scope_type='table', table_name='item_info', ruleName="테이블규칙"
|
||
|
|
- [ ] scope_type='menu', menu_objid=123, tableName='item_info', ruleName="메뉴규칙"
|
||
|
|
|
||
|
|
- [ ] 화면관리에서 item_info 화면 접속 (menuObjid=123)
|
||
|
|
- [ ] 규칙 목록에서 순서 확인:
|
||
|
|
1. 메뉴규칙 (menu, 우선순위 1)
|
||
|
|
2. 테이블규칙 (table, 우선순위 2)
|
||
|
|
3. 전역규칙 (global, 우선순위 3)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📁 수정된 파일 목록
|
||
|
|
|
||
|
|
### 데이터베이스 (준비 완료, 실행 대기)
|
||
|
|
- ✅ `db/migrations/046_update_numbering_rules_scope_type.sql`
|
||
|
|
- ✅ `db/migrations/RUN_046_MIGRATION.md`
|
||
|
|
|
||
|
|
### 백엔드
|
||
|
|
- ✅ `backend-node/src/services/numberingRuleService.ts`
|
||
|
|
- ✅ `backend-node/src/controllers/numberingRuleController.ts`
|
||
|
|
|
||
|
|
### 프론트엔드 API
|
||
|
|
- ✅ `frontend/lib/api/numberingRule.ts`
|
||
|
|
|
||
|
|
### 프론트엔드 UI
|
||
|
|
- ✅ `frontend/components/screen/panels/webtype-configs/TextTypeConfigPanel.tsx`
|
||
|
|
- ✅ `frontend/components/screen/panels/DetailSettingsPanel.tsx`
|
||
|
|
- ✅ `frontend/lib/utils/getConfigPanelComponent.tsx`
|
||
|
|
- ✅ `frontend/components/numbering-rule/NumberingRuleDesigner.tsx`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🚀 배포 가이드
|
||
|
|
|
||
|
|
### 1단계: 데이터베이스 마이그레이션
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Docker 환경
|
||
|
|
docker exec -i erp-node-db-1 psql -U postgres -d ilshin < db/migrations/046_update_numbering_rules_scope_type.sql
|
||
|
|
|
||
|
|
# 로컬 PostgreSQL
|
||
|
|
psql -h localhost -U postgres -d ilshin -f db/migrations/046_update_numbering_rules_scope_type.sql
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2단계: 백엔드 재시작
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Docker 환경
|
||
|
|
docker-compose restart backend
|
||
|
|
|
||
|
|
# 로컬 개발
|
||
|
|
npm run dev
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3단계: 프론트엔드 재빌드
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Docker 환경
|
||
|
|
docker-compose restart frontend
|
||
|
|
|
||
|
|
# 로컬 개발
|
||
|
|
npm run dev
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4단계: 검증
|
||
|
|
|
||
|
|
1. 개발자 도구 콘솔 열기
|
||
|
|
2. 화면관리 접속
|
||
|
|
3. 텍스트 필드 추가 → 자동 입력 → 채번 규칙 선택
|
||
|
|
4. 콘솔에서 다음 로그 확인:
|
||
|
|
```
|
||
|
|
📋 테이블 기반 채번 규칙 조회: { tableName: "xxx", menuObjid: undefined }
|
||
|
|
✅ 채번 규칙 로드 성공: N개
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🎉 주요 개선 사항
|
||
|
|
|
||
|
|
### 사용자 경험
|
||
|
|
- ✅ 화면관리에서 채번규칙이 자동으로 표시
|
||
|
|
- ✅ 메뉴 구조를 몰라도 규칙 설정 가능
|
||
|
|
- ✅ 같은 테이블 화면에 규칙 재사용 자동
|
||
|
|
|
||
|
|
### 유지보수성
|
||
|
|
- ✅ 메뉴 구조 변경 시 규칙 재설정 불필요
|
||
|
|
- ✅ 테이블 중심 설계로 직관적
|
||
|
|
- ✅ 코드 복잡도 감소
|
||
|
|
|
||
|
|
### 확장성
|
||
|
|
- ✅ 향후 scope_type 추가 가능
|
||
|
|
- ✅ 다중 테이블 지원 가능
|
||
|
|
- ✅ 멀티테넌시 완벽 지원
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## ⚠️ 알려진 제약사항
|
||
|
|
|
||
|
|
1. **메뉴 목록 로드 미구현**
|
||
|
|
- NumberingRuleDesigner에서 `scope_type='menu'` 선택 시 메뉴 목록 로드 필요
|
||
|
|
- TODO: 메뉴 API 연동
|
||
|
|
|
||
|
|
2. **마이그레이션 실행 대기**
|
||
|
|
- Docker 컨테이너 연결 문제로 수동 실행 필요
|
||
|
|
- 배포 시 반드시 실행 필요
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📝 다음 단계
|
||
|
|
|
||
|
|
1. **마이그레이션 실행**
|
||
|
|
- DB 접속 정보 확인 후 마이그레이션 실행
|
||
|
|
- 검증 쿼리로 정상 동작 확인
|
||
|
|
|
||
|
|
2. **통합 테스트**
|
||
|
|
- 전체 워크플로우 테스트
|
||
|
|
- 회사별 데이터 격리 확인
|
||
|
|
- 우선순위 필터링 확인
|
||
|
|
|
||
|
|
3. **메뉴 API 연동**
|
||
|
|
- NumberingRuleDesigner에서 메뉴 목록 로드 구현
|
||
|
|
|
||
|
|
4. **사용자 가이드 작성**
|
||
|
|
- 채번규칙 사용 방법 문서화
|
||
|
|
- scope_type별 사용 예시 추가
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📞 문의 및 지원
|
||
|
|
|
||
|
|
- **작성자**: AI 개발팀
|
||
|
|
- **작성일**: 2025-11-08
|
||
|
|
- **관련 문서**: `채번규칙_테이블기반_필터링_구현_계획서.md`
|
||
|
|
|
||
|
|
**구현 완료!** 🎊
|
||
|
|
|
||
|
|
마이그레이션 실행 후 바로 사용 가능합니다.
|
||
|
|
|