# 프로젝트관리 이식 GAP 분석 (원본 wace_plm 대비)

> 작성: 2026-05-11 / 작성자: hjjeong
> **개정 2026-05-11**: 운영판 실 화면은 `projectMgmtList.jsp`(옛 화면)가 **아니라** `projectMgmtWbsList3.jsp` + 매퍼 `projectMgmtWbsGridList`인 것이 확인되어 GAP 전면 개정.

---

## 0. 한 문장 요약

운영판 진행관리는 **`/project/projectMgmtWbsList3.do`** endpoint가 반환하는 화면이고, 그리드 SQL은 매퍼 `projectMgmtWbsGridList`(project.xml:3854~4280). 그리드 컬럼은 8그룹/18셀 + 검색폼은 11필드. 의존 테이블 대부분 RPS에 보유 — `project_mgmt`/`contract_mgmt`/`contract_item`/`contract_item_serial`/`customer_mng`/`user_info`/`comm_code`/`attach_file_info`/`sales_registration`/`part_mng`. `pms_wbs_task`/`setup_wbs_task`만 부재(P2 의존, 그리드 표시 컬럼엔 영향 거의 없음). **P1에서 그리드 18셀 전부 실데이터로 채울 수 있음.**

## 0.1 이식 원칙

> JSP/Java/매퍼XML 안의 `/* */`, `<!-- -->`, `//` 주석 블록은 비활성. 활성 코드만 이식.

- 운영 화면(waceplm.esgrin.com) = 진실의 기준.
- wace 컨트롤러에 `projectMgmtList.do`(옛) + `projectMgmtList1.do` + **`projectMgmtWbsList3.do`(운영판)** 셋이 동시 존재 — 메뉴가 가리키는 것이 무엇인지 확인 필수.
- `client_mng`/`supply_mng` → RPS는 `customer_mng`로 통합. CASE WHEN LIKE 'C_%' 분기는 모두 customer_mng 단일 LEFT JOIN으로 변환.
- `CODE_NAME()` 함수 RPS DB에 존재. 다만 영업관리 패턴(`LEFT JOIN comm_code CC_X ON CC_X.code_id=...`)으로 통일.
- 금액 1,234.00 / 수량 1,234 / 모든 숫자 right-align.

---

## 1. 운영판 진행관리 흐름

### 1.1 endpoint

| URL | Controller | view / 결과 |
|---|---|---|
| `/project/projectMgmtWbsList3.do` | `projectMgmtWbsList3` (L3243) | view 반환 + 코드맵(`category_cd`/`customer_cd`/`project_no`/`product_cd`/`status_cd`/`result_cd`/`pm_user_id`) |
| `/project/projectMgmtWbsGridList.do` | (`projectMgmtWbsGridList` 매퍼 호출) | 그리드 JSON |
| `fn_openSaleRegPopup(orderNo)` → `/salesMgmt/salesRegForm.do?orderNo={PROJECT_NO}` | (영업관리 주문서 등록 화면) | 행 클릭 → 영업관리 주문서 등록 폼 오픈. **진행관리 자체 수정 폼 없음.** |

→ 본 이식의 RPS 측 라우트:
- `GET /api/project/progress/list` — 그리드
- 행 클릭 동작은 **P1.5에서 결정** (영업관리 `OrderRegistDialog` 재사용 vs 미연결)

### 1.2 그리드 컬럼 (운영판 그대로)

8그룹 / 18셀 (frozen 1개 포함):

| # | dataField | 라벨 | 의존 | P1 채움 |
|---|---|---|---|---|
| 1 | **PROJECT_NO** (frozen) | 프로젝트번호 | project_mgmt | ✅ |
| 2 | CATEGORY_NAME | 주문유형 | comm_code(0000167) | ✅ |
| 3 | PRODUCT_NAME | 제품구분 | comm_code(0000001) | ✅ |
| 4 | AREA_NAME | 국내/해외 | comm_code(area_cd) | ✅ |
| 5 | REG_DATE | 접수일 | TO_CHAR(regdate,'YYYY-MM-DD') | ✅ |
| 6 | CUSTOMER_NAME | 고객사 | customer_mng | ✅ |
| 7 | FREE_OF_CHARGE | 유/무상 | contract_mgmt.paid_type → '유상'/'무상' | ✅ |
| 8 | PRODUCT_ITEM_CODE | 품번 | project_mgmt.part_no | ✅ |
| 9 | PRODUCT_ITEM_NAME | 품명 | project_mgmt.part_name | ✅ |
| 10 | SERIAL_NO | S/N | contract_item_serial (CIS.item_objid=T.contract_item_objid) | ✅ |
| 11 | CONTRACT_QTY | 수주수량 | project_mgmt.quantity | ✅ |
| 12 | REQ_DEL_DATE | 요청납기 | COALESCE(contract_item.due_date, project_mgmt.due_date, contract_mgmt.due_date) | ✅ |
| 13 | EBOM_STATUS | E-BOM | project_mgmt.ebom_status | ✅ (대부분 빈값, 운영DB도 빈값) |
| 14 | MBOM_STATUS | M-BOM | project_mgmt.mbom_status | ✅ (대부분 빈값) |
| 15 | ORDER_DATE | 발주일 | contract_mgmt.order_date | ✅ |
| 16 | RECEIVING_RATE | 입고율 | project_mgmt.receiving_rate | ✅ |
| 17 | PRODUCTION_TEAM_12 | 제조1,2팀 | project_mgmt.production_team_12 | ✅ |
| 18 | PRODUCTION_TEAM_3 | 제조3팀 | project_mgmt.production_team_3 | ✅ |
| 19 | ASSEMBLY | 조립 | (wace SQL에 없음 — 빈값) | (빈값) |
| 20 | VERIFICATION | 검증 | (wace SQL에 없음 — 빈값) | (빈값) |
| 21 | SHIPMENT_DATE | 출하일 | sales_registration.shipping_date (project_no 매칭) | ✅ |

→ **18셀 모두 P1에서 채움 가능** (장비 조립/검증 2개는 wace 원본도 빈값). PMS_WBS_TASK 의존 컬럼들은 그리드 표시에 없음.

### 1.3 검색 폼 (11필드)

| # | name | 라벨 | 입력 | 매핑 |
|---|---|---|---|---|
| 1 | Year | 년도 | select(sysYear±4) | TO_CHAR(REGDATE,'YYYY') |
| 2 | project_nos | 프로젝트번호 | multi-select | OBJID IN (쉼표 split) |
| 3 | category_cd | 주문유형 | select(0000167) | T.CATEGORY_CD |
| 4 | customer_objid | 고객사 | select | T.CUSTOMER_OBJID |
| 5 | product | 제품구분 | select(0000001) | T.PRODUCT |
| 6 | contract_start_date / contract_end_date | 요청납기일 | date range | COALESCE(contract_item.due_date, project_mgmt.due_date, contract_mgmt.due_date) |
| 7 | area_cd | 국내/해외 | select(국내/해외 라벨) | CODE_NAME(AREA_CD) = '국내'/'해외' |
| 8 | free_of_charge | 유/무상 | select(유상/무상 라벨) | contract_mgmt.paid_type 매핑 비교 |
| 9 | product_item_code | 품번 | autocomplete | T.PART_NO ILIKE '%?%' |
| 10 | product_item_name | 품명 | autocomplete | T.PART_NAME ILIKE '%?%' |
| 11 | serial_no | S/N | text | EXISTS contract_item_serial ILIKE |

비활성(주석블록): location / setup / pm_user_id — 무시.

### 1.4 ORDER BY

```sql
ORDER BY SUBSTRING(PROJECT_NO,POSITION('-' IN PROJECT_NO)+1) DESC,
         OVERHAUL_ORDER DESC NULLS LAST
```

### 1.5 행 클릭 동작

`fn_openSaleRegPopup(PROJECT_NO)` → `/salesMgmt/salesRegForm.do?orderNo={PROJECT_NO}` (영업관리 주문서 등록 폼). **진행관리 자체 수정 폼 없음.** RPS 이식 시 P1.5 별도 결정.

---

## 2. RPS DB 보유 매트릭스 (개정)

| 테이블 | 보유 | 진행관리에서의 용도 | P1 |
|---|---|---|---|
| project_mgmt | ✅ | 메인 (90건) | ✅ |
| contract_mgmt | ✅ | paid_type / order_date / due_date / pm_user_id | ✅ |
| **contract_item** | ✅ | 요청납기 COALESCE 1순위 | ✅ |
| **contract_item_serial** | ✅ | S/N 집계 | ✅ |
| **sales_registration** | ✅ | 출하일 COALESCE | ✅ |
| customer_mng | ✅ | 고객사명 (wace의 client_mng/supply_mng 분기 흡수) | ✅ |
| user_info | ✅ | PM명 / writer명 / chg_user 등 | ✅ |
| comm_code + CODE_NAME() | ✅ | 카테고리/제품/지역/통화 등 라벨 | ✅ |
| attach_file_info | ✅ | contractMgmt01/02 카운트 (CU01_CNT/CU02_CNT) | ✅ |
| part_mng | ✅ | (이번 P1에서는 직접 사용 안 함 — project_mgmt.part_no/part_name 직접 사용) | — |
| purchase_order_master | ✅ | (이번 P1에서는 사용 안 함 — P2의 투입원가 컬럼에서만 사용) | — |
| pms_wbs_task | ❌ | 진척율/연체 카운트 — 그리드 표시 컬럼엔 없음 | (P2) |
| setup_wbs_task | ❌ | 셋업 진척율 — 그리드 표시 컬럼엔 없음 | (P2) |
| client_mng / supply_mng | ➖ | wace 전용 (customer_mng로 흡수) | — |

→ **P1에서 18셀 전부 실데이터 채울 수 있음.**

---

## 3. GAP 매트릭스 (개정)

| # | 우선 | 항목 | 권장 작업 |
|---|---|---|---|
| **PRJ-1** | 🔴 | 진행관리 메뉴 자체 부재 → 운영판 화면 1:1 이식 | **본 PR (P1)** — 18셀 + 검색 11필드 |
| **PRJ-2** | 🟠 | 행 클릭 → 영업관리 주문서 등록 폼 오픈 (`fn_openSaleRegPopup`) | **P1.5** — `OrderRegistDialog` 재사용 vs 미연결. 사용자 결정 |
| **PRJ-3** | 🟠 | 다중 선택 프로젝트번호 검색 (multi-select) | **본 PR** — frontend SmartSelect multi 모드, backend는 `project_nos` 쉼표 split |
| **PRJ-4** | 🟡 | 검색 코드맵 옵션 (`project_no` 다중 옵션 리스트) | wace는 코드맵에서 동적 생성. RPS는 grid 데이터 기반 옵션 또는 별도 API. **P1 보수적 처리**: 사용자가 OBJID 또는 PROJECT_NO 직접 입력 |
| **PRJ-5** | 🟢 | 엑셀 다운로드 | wace에 없음 — 본 PR 제외 |
| **PRJ-6** | 🟢 | 진척율(PMS_WBS_TASK 의존) — 그리드 표시 컬럼엔 영향 없으나 SQL은 계산 | **P2 (WBS 메뉴 이식 후)**. 본 P1은 진척율 컬럼 자체가 그리드에 없으므로 미반영 |
| **PRJ-7** | 🟢 | 설계/생산 ASSEMBLY/VERIFICATION 컬럼 (운영판 빈값) | 자리만, 빈값 |

---

## 4. P1 스코프 — 본 GAP 결정사항

### 4.1 백엔드 갱신 (`backend-node/src/`)

| 파일 | 동작 |
|---|---|
| `services/projectMgmtService.ts` | **전면 교체** — `listProgress` SQL을 `projectMgmtWbsGridList` 1:1로 재작성. `getById`/`updateProject`는 P1.5에서 결정될 때까지 일단 유지 (사용 안 됨) |
| `controllers/projectMgmtController.ts` | 현행 유지 |
| `routes/projectMgmtRoutes.ts` | 현행 유지 (`GET /list` + 향후 추가 endpoint 자리) |
| `app.ts` | 현행 유지 (이미 마운트됨) |

### 4.2 프론트엔드 갱신 (`frontend/`)

| 파일 | 동작 |
|---|---|
| `app/(main)/COMPANY_16/project/progress/page.tsx` | **전면 교체** — 검색폼 11필드(2행) + 그리드 18셀(8그룹 평탄화) |
| `components/project/ProjectProgressEditDialog.tsx` | **폐기** (옛 jsp 기반). 행 클릭은 P1.5에서 결정 |
| `lib/api/projectMgmt.ts` | 검색 타입/결과 행 타입 갱신 |
| `components/layout/AdminPageRenderer.tsx` | 현행 유지 |

### 4.3 검색 옵션 컴포넌트 매핑

| 검색 필드 | RPS 컴포넌트 |
|---|---|
| Year | `<select>` (native, sysYear±4 동적) |
| project_nos | `<Input>` (쉼표 직렬화 텍스트) — 다중 SmartSelect는 P1.5에서 보강 가능 |
| category_cd / product | `<CommCodeSelect groupId="0000167"/"0000001">` |
| customer_objid | `<CustomerSelect>` |
| 요청납기 범위 | `<Input type="date">` × 2 |
| area_cd | `<select>` 정적 옵션 ('국내'/'해외') |
| free_of_charge | `<select>` 정적 옵션 ('유상'/'무상') |
| product_item_code / product_item_name | `<Input>` (자동완성은 P1.5 보강) |
| serial_no | `<Input>` |

### 4.4 본 PR에서 **하지 않을 것**
- WBS관리 메뉴(별도 PR P2)
- PMS_WBS_TASK / SETUP_WBS_TASK 의존 컬럼 (그리드 표시 컬럼엔 없으므로 영향 없음)
- 행 클릭 → 영업관리 주문서 등록 폼 라우팅 (P1.5 별도)
- 다중 select / 품번품명 자동완성 (P1.5 보강)
- 엑셀 / 결재 (운영판 없음)

---

## 5. 사용자 결정 사항 (2026-05-11)

| # | 항목 | 결정 |
|---|---|---|
| 1 | URL 경로 | `/COMPANY_16/project/progress` |
| 2 | 차종/OEM 마일스톤 | 영구 제외 |
| 3 | 운영판 1:1 재작성 범위 | **그리드 + 검색폼 모두 운영판(projectMgmtWbsList3) 기준 재작성** |
| 4 | 행 클릭 다이얼로그 | P1.5 — `OrderRegistDialog` 재사용 검토. P1에서는 미연결 |
| 5 | 진척율(WBS) 컬럼 | P2에서 — 그리드 표시 컬럼엔 없으므로 P1 영향 없음 |

---

## 6. 다음 단계

1. P1 운영판 1:1 재작성 → 사용자 동작 확인 (그리드 18셀이 실데이터로 채워지는지)
2. P1.5: 행 클릭 동작 결정 (영업관리 OrderRegistDialog 재사용 / 미연결 / 신규 다이얼로그)
3. P2: WBS관리 메뉴(`/COMPANY_16/project/wbs-template`) — PMS_WBS_* 운영DB DDL 추출 + 02-wbs.md
