# 01. 진행관리 wace 1:1 검증

> 작성: 2026-05-11 / 사이클: 구조적 검증 1차
> 목적: wace 운영판 화면(`projectMgmtWbsList3.jsp`)과 RPS 진행관리(`/COMPANY_16/project/progress`)를 데이터 단위로 1:1 일치 확인 + 갭 검증 + 사용자 시나리오 검증.

## 0. 자격증명

```
RPS    : host=211.115.91.141 port=11134 db=vexplor_rps user=postgres pw=vexplor0909!!
운영DB : host=211.115.91.141 port=11133 db=waceplm     user=postgres pw=waceplm0909!!
```

## 1. 데이터 일치 검증

### 1.1 운영판 화면 첫 행 일치

운영판 `projectMgmtWbsList3` 그리드 첫 행 (사용자 화면 캡처) 기준:
```
PROJECT_NO       = S-기타-260506-001
주문유형         = 판매
제품구분         = 기타
국내/해외        = 국내
접수일           = 2026-05-06
고객사           = 한미반도체주식회사
유/무상          = 유상
품번             = 31011-0012
품명             = CARBON BRUSH SET (HMD V2)
수주수량         = 8
발주일           = 2026-05-06
```

RPS service SQL 검증:
```sql
PGPASSWORD='vexplor0909!!' psql -h 211.115.91.141 -p 11134 -U postgres -d vexplor_rps <<SQL
SELECT
   T.PROJECT_NO
  ,CODE_NAME(T.CATEGORY_CD)         AS CATEGORY_NAME
  ,CODE_NAME(T.PRODUCT)              AS PRODUCT_NAME
  ,CODE_NAME(T.AREA_CD)              AS AREA_NAME
  ,TO_CHAR(T.REGDATE,'YYYY-MM-DD')   AS REG_DATE
  ,C.customer_name                    AS CUSTOMER_NAME
  ,(SELECT CASE WHEN O.paid_type='paid' THEN '유상' WHEN O.paid_type='free' THEN '무상' END
      FROM contract_mgmt O WHERE O.objid=T.CONTRACT_OBJID) AS FREE_OF_CHARGE
  ,T.PART_NO                          AS PRODUCT_ITEM_CODE
  ,T.PART_NAME                        AS PRODUCT_ITEM_NAME
  ,COALESCE(NULLIF(T.QUANTITY,'')::numeric,0) AS CONTRACT_QTY
  ,(SELECT O.order_date FROM contract_mgmt O WHERE O.objid=T.CONTRACT_OBJID) AS ORDER_DATE
FROM project_mgmt T
LEFT JOIN customer_mng C
  ON C.customer_code = CASE WHEN T.CUSTOMER_OBJID LIKE 'C_%' THEN substring(T.CUSTOMER_OBJID,3) ELSE T.CUSTOMER_OBJID END
WHERE T.PROJECT_NO = 'S-기타-260506-001';
SQL
```

기대 결과: 운영판 화면 첫 행과 모든 컬럼 값 100% 일치 — **검증 완료 (2026-05-11)** ✅

### 1.2 정렬 검증 (wace ORDER BY 1:1)

```sql
SELECT PROJECT_NO,
       SUBSTRING(PROJECT_NO, POSITION('-' IN PROJECT_NO)+1) AS sort_key,
       OVERHAUL_ORDER
  FROM project_mgmt
 ORDER BY SUBSTRING(PROJECT_NO, POSITION('-' IN PROJECT_NO)+1) DESC,
          OVERHAUL_ORDER DESC NULLS LAST
 LIMIT 10;
```

운영판 화면과 동일한 행 순서로 출력되는지 확인.

### 1.3 부속 테이블 매칭 검증

```sql
-- contract_item.due_date COALESCE 1순위 확인 (요청납기)
SELECT T.project_no, T.due_date AS pmgmt_due,
       (SELECT CI.due_date FROM contract_item CI
         WHERE CI.contract_objid = T.contract_objid AND CI.part_objid = T.part_objid AND CI.status='ACTIVE'
         ORDER BY CI.objid DESC LIMIT 1) AS ci_due,
       (SELECT CM.due_date FROM contract_mgmt CM WHERE CM.objid = T.contract_objid) AS cm_due
  FROM project_mgmt T WHERE T.project_no = 'S-기타-260506-001';

-- contract_item_serial S/N 집계 검증
SELECT T.project_no,
       (SELECT MIN(CIS.serial_no) FROM contract_item_serial CIS
         WHERE CIS.item_objid::varchar = T.contract_item_objid AND UPPER(CIS.status)='ACTIVE') AS first_sn,
       (SELECT COUNT(*) FROM contract_item_serial CIS
         WHERE CIS.item_objid::varchar = T.contract_item_objid AND UPPER(CIS.status)='ACTIVE') AS sn_cnt
  FROM project_mgmt T WHERE T.project_no = 'R-기타-260410-001';

-- sales_registration 출하일 매칭
SELECT T.project_no, SR.shipping_date, SR.sale_no
  FROM project_mgmt T
  LEFT JOIN sales_registration SR ON SR.project_no = T.project_no
 WHERE SR.sale_no IS NOT NULL
 ORDER BY SR.sale_no DESC LIMIT 10;
```

## 2. 빈 컬럼 진단 (운영판도 동일하게 빈가 확인)

```sql
-- vexplor_rps
SELECT count(*) AS total,
       count(NULLIF(project_name,''))      AS project_name,
       count(NULLIF(setup,''))             AS setup,
       count(NULLIF(facility,''))          AS facility,
       count(NULLIF(pm_user_id,''))        AS pm_user_id,
       count(NULLIF(manufacture_plant,'')) AS manufacture_plant,
       count(NULLIF(req_del_date,''))      AS req_del_date,
       count(NULLIF(ebom_status,''))       AS ebom_status,
       count(NULLIF(mbom_status,''))       AS mbom_status,
       count(NULLIF(receiving_rate,''))    AS receiving_rate
  FROM project_mgmt;
```

기대: 대부분 0건 — **2026-05-11 검증 완료**. `category_cd`/`customer_objid`/`product`/`contract_no`/`contract_result`/`part_no`/`part_name`/`quantity`/`contract_item_objid`/`area_cd`/`writer`/`regdate`만 채워짐. 운영DB(11133/`waceplm`) 89건도 동일 — 코드/이식 정상.

## 3. 검색 필터 시나리오

| 시나리오 | 입력 | 기대 결과 | SQL 단편 |
|---|---|---|---|
| Year | `Year=2026` | 2026년 등록건만 | `TO_CHAR(REGDATE,'YYYY') = '2026'` |
| 프로젝트번호 | `project_nos=507449280` (단일 OBJID) | 1건 | `OBJID IN ('507449280')` |
| 주문유형 | `category_cd=0001792` (판매) | 판매건만 | `CATEGORY_CD = '0001792'` |
| 고객사 | `customer_objid=C_0000003094` | 한미반도체분 47건 | `CUSTOMER_OBJID = 'C_0000003094'` |
| 국내/해외 | `area_cd=국내` | `CODE_NAME(area_cd)='국내'` 매칭 | `CODE_NAME(AREA_CD) = '국내'` |
| 유/무상 | `free_of_charge=유상` | contract_mgmt.paid_type='paid'인 행 | `(... paid_type 매핑) = '유상'` |
| 품번 | `search_partObjId=1626888159` | 특정 part_objid 매칭건 | `T.PART_OBJID = '1626888159'` |
| S/N | `serial_no=M080` | contract_item_serial 매칭 | `EXISTS (... CIS.serial_no LIKE '%M080%')` |
| 요청납기 from~to | `2026-04-01` ~ `2026-05-31` | COALESCE 3단 매칭 | `TO_DATE(COALESCE(CI.due_date, T.DUE_DATE, CM.due_date),'YYYY-MM-DD') BETWEEN ...` |

각 시나리오는 `GET /api/project/progress/list?...` 로 직접 호출 또는 화면에서 검색 후 응답 행 수 / 첫 행 데이터 확인.

## 4. P1.5 PROJECT_NO 셀 클릭 → 프로젝트 정보 다이얼로그 검증

### 4.1 시나리오

1. `/COMPANY_16/project/progress` 진입 → 그리드 90건
2. **PROJECT_NO 컬럼 셀만 클릭** (wace `cellClick`과 동일). 다른 컬럼 셀 클릭은 행 선택만.
3. `ProjectInfoDialog` 오픈 — 같은 탭 내 다이얼로그 (새 창 X)
4. 다이얼로그 내용 확인:
   - 프로젝트번호 / 영업번호 / 주문유형 / 제품구분 / 국내해외 / 고객사 / 유무상 / 품번 / 품명 / S/N / 수주수량 / 접수일 / 요청납기 / 발주일 / 프로젝트명 / 작성자
   - 모두 read-only (편집 불가)
   - 빈 값은 `-` 로 표시
5. 닫기 버튼으로 다이얼로그 닫힘

### 4.2 별도 API 호출 없음

list SQL 응답(`ProgressRow`)에 표시 필요 데이터가 모두 포함돼 있어 다이얼로그 오픈 시 추가 fetch 없음. 네트워크 검증:
- DevTools Network 패널 → 셀 클릭 시 추가 `/api/...` 호출 0건 확인

### 4.3 wace 운영판과의 차이

| 항목 | wace | RPS |
|---|---|---|
| 클릭 대상 | PROJECT_NO 셀 (cellClick) | 동일 |
| 화면 형식 | 새 창 (`fn_centerPopup` 1000×550) | 같은 탭 내 Dialog |
| 모드 | `saleNo="detail"` (판매등록 폼 detail 모드) | 프로젝트 정보 read-only |
| 데이터 | `salesRegForm.do?orderNo=...` 서버 렌더 | list row 객체 직접 사용 (추가 API 호출 없음) |

RPS는 SPA 패턴 + 진행관리 본연의 목적이 "프로젝트 상황 모니터링"이라 정보 표시에 집중. 판매 등록은 영업관리 판매관리 메뉴에서 처리.

## 5. 미구현 / 알려진 갭

| 항목 | 메모 | 후속 |
|---|---|---|
| 다중 프로젝트번호 검색 | wace multi-select2 → RPS 단일 `SmartSelect` | P1.5+ |
| 진척율 / 이슈 / 원가 / 출고 컬럼 데이터 | 그리드 표시엔 안 들어가지만 service SQL 자리는 0/NULL | P2(WBS) |
| `getById` / `updateProject` 라우트 | 옛 jsp 기반 — 행 클릭 라우팅 통일 후 미사용 | 정리 검토 |

## 6. 회귀 방지 — 영업관리에 영향 없음

P1.5 초기 시도(판매관리 페이지 라우팅)는 사용자 의도와 어긋나 폐기. 영업관리에 추가했던 변경(`SaleListFilter.project_no` / `useSearchParams` 자동 선택 / 검색폼 `project_no` 필드)을 모두 롤백해 **영업관리에 변경 영향 없음**. 진행관리 P1.5는 진행관리 페이지 + 신규 `ProjectInfoDialog` 컴포넌트만으로 완결됨.
