# 01. 진행관리 이식 상세 매핑

> 원본: `/project/projectMgmtWbsList3.do` (`projectMgmtWbsList3.jsp` 349줄) + 매퍼 `projectMgmtWbsGridList` (project.xml:3854~4280)
> 대상: `app/(main)/COMPANY_16/project/progress/page.tsx` + `backend-node/src/services/projectMgmtService.ts`
> 작성: 2026-05-11 / 사이클: 구조적 검증 1차 (진행관리 메뉴)

## 1. 운영판 식별

wace_plm 컨트롤러에 진행관리 관련 endpoint 3개 동시 존재:

| URL | view | 사용처 |
|---|---|---|
| `/project/projectMgmtList.do` (L321) | `projectMgmtList.jsp` | 옛 화면 (사용 안 함) |
| `/project/projectMgmtList1.do` (L399) | `projectMgmtList1.jsp` | 변종 |
| **`/project/projectMgmtWbsList3.do`** (L3243) | **`projectMgmtWbsList3.jsp`** | **RPS 운영판 화면** ✅ |

> 운영판 화면 캡처에서 컬럼 라벨(`주문유형/품번/품명/S/N/수주수량/E-BOM/M-BOM/발주일/입고율/제조1,2팀/...`)이 일치하는 jsp를 grep으로 역추적해 확정.

## 2. 항목 매핑

### 2.1 검색 폼 — wace 활성 11개 (jsp:222-313)

| # | wace 라벨 | wace name | RPS filter (`ProgressListFilter`) | 입력 위젯 | 상태 |
|---|---|---|---|---|---|
| 1 | 년도 | `Year` | `Year` | `<select>` (sysYear±4) | ✅ |
| 2 | 프로젝트번호 | `project_no` (multi-select2) | `project_nos` | `SmartSelect` (단일, 옵션 API 사용) | 🟡 (다중 → 단일) |
| 3 | 주문유형 | `category_cd` | `category_cd` | `CommCodeSelect groupId="0000167"` | ✅ |
| 4 | 고객사 | `customer_objid` | `customer_objid` | `CustomerSelect` | ✅ |
| 5 | 제품구분 | `product` | `product` | `CommCodeSelect groupId="0000001"` | ✅ |
| 6 | 요청납기일 (from~to) | `contract_start_date` / `contract_end_date` | 동일 | `<Input type="date">` × 2 | ✅ |
| 7 | 국내/해외 | `area_cd` | `area_cd` ('국내'/'해외' 라벨) | `<select>` 정적 | ✅ |
| 8 | 유/무상 | `free_of_charge` | `free_of_charge` ('유상'/'무상' 라벨) | `<select>` 정적 | ✅ |
| 9 | 품번 | `product_item_code` (select2-part) | `search_partObjId` | `PartSelect mode="partNo"` | 🟡 (영업관리 패턴 통일) |
| 10 | 품명 | `product_item_name` (select2-part) | `search_partObjId` (공유) | `PartSelect mode="partName"` | 🟡 (영업관리 패턴 통일) |
| 11 | S/N | `serial_no` | `serial_no` | `<Input>` | ✅ |

**비활성** (JSP `<%-- --%>` 블록): `location` / `setup` / `pm_user_id` — 무시.

### 2.2 그리드 컬럼 — wace 8그룹 18셀 → RPS 평탄화 21셀

DataGrid 중첩 헤더 미지원으로 그룹명을 라벨 prefix(이슈/원가/...)로 표현. wace SQL `projectMgmtWbsGridList` 활성 본문 1:1.

| # | wace title | wace field | RPS GRID_COLUMNS key | SQL 출처 | 상태 |
|---|---|---|---|---|---|
| 1 | 프로젝트번호 (frozen) | `PROJECT_NO` | `project_no` | `project_mgmt.project_no` | ✅ |
| 2 | 주문유형 | `CATEGORY_NAME` | `category_name` | `CODE_NAME(category_cd)` | ✅ |
| 3 | 제품구분 | `PRODUCT_NAME` | `product_name` | `CODE_NAME(product)` | ✅ |
| 4 | 국내/해외 | `AREA_NAME` | `area_name` | `CODE_NAME(area_cd)` | ✅ |
| 5 | 접수일 | `REG_DATE` | `reg_date` | `TO_CHAR(regdate,'YYYY-MM-DD')` | ✅ |
| 6 | 고객사 | `CUSTOMER_NAME` | `customer_name` | `customer_mng` LEFT JOIN | ✅ (RPS 매핑) |
| 7 | 유/무상 | `FREE_OF_CHARGE` | `free_of_charge` | `contract_mgmt.paid_type` → '유상'/'무상' | ✅ |
| 8 | 품번 | `PRODUCT_ITEM_CODE` | `product_item_code` | `project_mgmt.part_no` | ✅ |
| 9 | 품명 | `PRODUCT_ITEM_NAME` | `product_item_name` | `project_mgmt.part_name` | ✅ |
| 10 | S/N | `SERIAL_NO` | `serial_no` | `contract_item_serial` 집계 | ✅ |
| 11 | 수주수량 | `CONTRACT_QTY` | `contract_qty` | `project_mgmt.quantity::numeric` | ✅ |
| 12 | 요청납기 | `REQ_DEL_DATE` | `req_del_date` | COALESCE(`contract_item.due_date`, `project_mgmt.due_date`, `contract_mgmt.due_date`) | ✅ |
| 13 | E-BOM | `EBOM_STATUS` | `ebom_status` | `project_mgmt.ebom_status` | ✅ (운영도 대부분 빈값) |
| 14 | M-BOM | `MBOM_STATUS` | `mbom_status` | `project_mgmt.mbom_status` | ✅ |
| 15 | 발주일 | `ORDER_DATE` | `order_date` | `contract_mgmt.order_date` 스칼라 서브쿼리 | ✅ |
| 16 | 입고율 | `RECEIVING_RATE` | `receiving_rate` | `project_mgmt.receiving_rate` | ✅ |
| 17 | 제조1,2팀 | `PRODUCTION_TEAM_12` | `production_team_12` | `project_mgmt.production_team_12` | ✅ |
| 18 | 제조3팀 | `PRODUCTION_TEAM_3` | `production_team_3` | `project_mgmt.production_team_3` | ✅ |
| 19 | 조립 | `ASSEMBLY` | `assembly` | wace SQL에 없음 → NULL | ✅ (운영도 빈값) |
| 20 | 검증 | `VERIFICATION` | `verification` | wace SQL에 없음 → NULL | ✅ |
| 21 | 출하일 | `SHIPMENT_DATE` | `shipment_date` | `sales_registration.shipping_date` (project_no 매칭, MAX sale_no) | ✅ |

### 2.3 ORDER BY

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

→ "주문유형-제품구분-YYMMDD-NNN" 패턴에서 첫 `-` 이후 부분 내림차순 = 사실상 (제품구분 → YYMMDD → NNN) 역순.

### 2.4 액션

| 동작 | wace | RPS |
|---|---|---|
| 조회 | `btnSearch` → `/projectMgmtWbsGridList.do` | `GET /api/project/progress/list` |
| 프로젝트번호 옵션 | `code_map.project_no = common.getCusProjectNoList` | `GET /api/project/progress/project-no-options` |
| **PROJECT_NO 셀 클릭** (cellClick) | `fn_openSaleRegPopup(PROJECT_NO, "detail")` → `/salesMgmt/salesRegForm.do?orderNo={PROJECT_NO}&saleNo=detail` 새 창(read-only 상세 모드) | `ProjectInfoDialog` (같은 탭 다이얼로그) — 그리드 row 객체 그대로 read-only 표시 |

행 클릭은 **PROJECT_NO 컬럼 셀에만** 걸림 (wace `cellClick`). 행 전체 클릭은 그냥 행 선택만. wace의 "detail" 모드 새 창은 RPS에서는 같은 탭 내 `ProjectInfoDialog`로 매핑 — 별도 API 호출 없이 list 응답(`ProgressRow`)을 그대로 다이얼로그에 전달해 read-only 표시. 표시 항목: 프로젝트번호 / 영업번호 / 주문유형 / 제품구분 / 국내해외 / 고객사 / 유무상 / 품번 / 품명 / S/N / 수주수량 / 접수일 / 요청납기 / 발주일 / 프로젝트명 / 작성자.

## 3. RPS 매핑 변경 사항

| wace 분기 | RPS 매핑 | 이유 |
|---|---|---|
| `CASE WHEN customer_objid LIKE 'C_%' THEN client_mng ELSE supply_mng END` | `LEFT JOIN customer_mng ON customer_code = substring/통합` | RPS는 `customer_mng` 단일 마스터 (영업관리 G1 자산) |
| `product_item_code` / `product_item_name` LIKE 텍스트 검색 | `search_partObjId` 단일 part_objid 매칭 | 영업관리 패턴 통일 + RPS의 PartSelect 컴포넌트 재사용 |
| `CODE_NAME(...)` 함수 호출 | 동일 (RPS DB 함수 보유) | 영업관리는 LEFT JOIN 패턴이지만 진행관리는 함수 호출 12회로 가독성 우선 |

## 4. 의존 테이블 (활성 SQL 기준 20개 중 RPS 보유 12개)

✅ `project_mgmt`(메인) / `contract_mgmt` / `contract_item` / `contract_item_serial` / `customer_mng` / `user_info` / `comm_code` + `CODE_NAME()` 함수 / `attach_file_info` / `sales_registration` / `part_mng`

❌ `pms_wbs_task` / `setup_wbs_task` / `assembly_wbs_task` / `bom_part_qty` / `part_bom_report` / `planning_issue` / `release_mgmt` / `input_cost_goal` / `expense_master/detail` / `work_diary`

→ 부재한 테이블이 의존하는 SQL 항목들(진척율 / 이슈 카운트 / 투입원가 / 출고)은 wace JSP 그리드 컬럼 정의에 **노출되지 않음** (8그룹 18셀에 포함 X). 따라서 그리드 표시 데이터엔 영향 없음. backend SQL은 `0` / `NULL` 자리만 유지 후 P2(WBS) 이식에서 채움.

## 5. 미구현 / P1.5+ 보류

| 항목 | 메모 |
|---|---|
| 다중 프로젝트번호 선택 | wace는 multi-select2. RPS는 단일(`SmartSelect`). 다중 모드는 P1.5에서 보강 가능 |
| 진척율 / 이슈 / 원가 / 출고 컬럼 채움 | 그리드 표시 컬럼엔 없으므로 영향 없음. 그러나 service SQL의 `0` 자리들은 P2에서 활성화 |
| `getById` / `updateProject` 라우트 | 옛 jsp(projectMgmtList) 기반 자리. 행 클릭이 `ProjectInfoDialog` (list row 직접 사용)로 통일됐으므로 미사용 — 삭제 검토 가능 |
| 엑셀 다운로드 | wace에 없음 — 본 PR 제외 |

## 6. 관련 파일

- backend: [services/projectMgmtService.ts](../../backend-node/src/services/projectMgmtService.ts) · [controllers/projectMgmtController.ts](../../backend-node/src/controllers/projectMgmtController.ts) · [routes/projectMgmtRoutes.ts](../../backend-node/src/routes/projectMgmtRoutes.ts)
- frontend: [app/(main)/COMPANY_16/project/progress/page.tsx](../../frontend/app/(main)/COMPANY_16/project/progress/page.tsx) · [components/project/ProjectInfoDialog.tsx](../../frontend/components/project/ProjectInfoDialog.tsx) · [lib/api/projectMgmt.ts](../../frontend/lib/api/projectMgmt.ts)
- 검증: [01-progress-verify.md](./01-progress-verify.md)
