diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx index e1e4adf44..b5c6177b0 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx @@ -9,8 +9,8 @@ export const pubFacHeadListExport: TableUpperProps[] = [ { id: "addr", title: "위치", widthPercent: 24 }, { id: "efflWqltStndrdNm", title: "지역구분", widthPercent: 15 }, { id: "fctCpc", title: "시설용량(m³/일)", widthPercent: 12 }, - { id: "ruse", title: "재이용\n여부", widthPercent: 8 }, - { id: "rswtrYn", title: "등록\n여부", widthPercent: 6 }, + { id: "ruse", title: "등록\n여부", widthPercent: 8 }, + { id: "rswtrYn", title: "재이용\n여부", widthPercent: 6 }, ]; export const pbnstMngUpHeadListExport: TableUpperProps[] = [ diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx index 0b395d1b3..5660adbff 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx @@ -103,52 +103,26 @@ export const pubFacStateExport: pubFacState = { fclts: null, }, }; -// 재사용시설에 대한 정보 조회 -export const checkWrRegList = async (get: any, set: any) => { - const { pbnst } = get(); - - if (Array.isArray(pbnst.fclts)) { - return pbnst.fclts; - } - - const wrRegList = await getFetch("wr", `/reuseFc/pubFc`); - const fclts = Array.isArray(wrRegList) ? wrRegList : []; - - set((state: pubFacState) => ({ - ...state, - pbnst: { - ...state.pbnst, - fclts, - }, - })); - - return fclts; -}; // 하수처리시설 정보 조회 const hasuListFetch = async ( - get: any, - set: any, + _get: any, + _set: any, page: number = 1, sggOrCity: string, // 해당 지자체의 하수처리시설 조회 searchTxt?: string ) => { - const wrData = await checkWrRegList(get, set); // 재사용시설에 대한 정보 조회 - const wrBscFctCdSet = new Set( - wrData - .map((wrItem: any) => (typeof wrItem === "string" ? wrItem.trim() : "")) - ); - - let url = `/prcsFclt/ruseInfo/reg/${page}/${DEFAULT_LIST_SIZE}/A/${sggOrCity ? sggOrCity : "0"}/0/1/SW`; + let url = `/reuseFc/pbnstRegList/${page}/${DEFAULT_LIST_SIZE}/A/${sggOrCity ? sggOrCity : "0"}/0/1/SW`; if (searchTxt?.trim()) { url += `?swtrmtFcltNm=${encodeURIComponent(searchTxt.trim())}`; } - const fcltRes = await getFetchWithCount(fetchType.COMMON, url); // fo + const fcltRes = await getFetchWithCount("wr", url); const hasuList = fcltRes.data.map((item: any) => { return { ...item, fctCpc: Number(item.fctCpc) || 0, - ruse: item?.bscFctCd && wrBscFctCdSet.has(item.bscFctCd) ? "Y" : "N", + ruse: item?.ruse ?? "N", + rswtrYn: item?.rswtrYn ?? "N", }; }); diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx index c39d3d72b..cb86777e0 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx @@ -76,6 +76,8 @@ export const pubHasuZod = z.object({ tel: z.string().default(""), fctCpc: z.number().default(0), // 시설용량 addr: z.string().nullish(), // 위치 + ruse: z.string().default("N"), // 등록여부 + rswtrYn: z.string().default("N"), // 재이용여부 }); export type pubHasuType = z.infer; diff --git a/apps/wr/docs/작업계획/하수재이용속도개선.md b/apps/wr/docs/작업계획/하수재이용속도개선.md new file mode 100644 index 000000000..1c5171d97 --- /dev/null +++ b/apps/wr/docs/작업계획/하수재이용속도개선.md @@ -0,0 +1,257 @@ +# 하수재이용시설 등록 목록 조회 속도개선 작업계획 + +## 1. 배경 + +- 대상 화면: `frontend/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/page.tsx` +- 대상 스토어: `frontend/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx` +- 연계 백엔드: `D:\iipbs\wr_back_out` + +현재 `재이용시설 등록 > 하수재이용시설 등록` 화면의 목록은 아래 순서로 구성된다. + +1. WR 등록 시설 목록 조회 + - `GET /reuseFc/pubFc` +2. 하수처리시설 목록 조회 + - `GET/POST /prcsFclt/ruseInfo/reg/...` +3. 프론트에서 `bscFctCd` 기준으로 등록 여부를 합성 + +문제는 2번 조회가 운영 `ONSEMIRO_NEW` 의존 경로를 타면서 응답시간이 길어지고, 그 결과 등록 화면 진입과 검색 모두 느려진다는 점이다. + +이번 개선의 기준목록은 `ONSEMIRO_NEW.OM_MS_VW`의 하수처리시설 목록이다. 현재 이 기준정보가 WR(Postgres)에 적재된 테이블은 없으므로, `reuse-service`가 `ONSEMIRO_NEW.OM_MS_VW`를 직접 조회해야 한다. + +--- + +## 2. 현재 구조 확인 결과 + +### 2.1 프론트 + +- `checkWrRegList` + - `GET /reuseFc/pubFc` 호출로 WR 등록 시설 목록을 별도 조회 +- `hasuListFetch` + - `/prcsFclt/ruseInfo/reg/${page}/${DEFAULT_LIST_SIZE}/A/${sggOrCity}/0/1/SW` 호출 + - 검색어가 있으면 `swtrmtFcltNm` query 추가 + - FO 응답과 WR 목록을 프론트에서 합쳐 `ruse: "Y" | "N"` 계산 +- `pubHasuInit`, `pubHasuSearch` + - 페이지 이동, 최초 진입, 검색 시마다 위 로직 반복 + +즉, 현재 등록 화면은 "목록 원천 조회"와 "등록 여부 판정"을 프론트가 나눠서 처리하고 있다. + +### 2.2 백엔드 + +- `wr_back_out`에는 이미 WR 기준 조회용 `pbnstList` API가 존재한다. + - `PublicFcController.getPbnstList` + - `PublicFcService.getPbnstList` + - `public_fc_select.xml#getPbnstList` +- 다만 현재는 `ONSEMIRO_NEW.OM_MS_VW`가 WR(Postgres)에 적재되어 있지 않다. +- 따라서 `ONSEMIRO_NEW.OM_MS_VW`와 `sm_bs_wr.tb_wr_pbnst_ruse_fclt`를 DB 레벨에서 직접 조인하는 방식은 사용할 수 없다. + +하지만 등록 화면은 아직 이 WR 단일 조회 경로를 사용하지 않고, 여전히 `operation-service` 경유 목록 조회를 사용 중이다. + +--- + +## 3. 개선 방향 + +### 3.1 1차 목표 + +현 상황에서 가장 빠르게 체감속도를 높이는 방법은 아래 두 가지를 동시에 적용하는 것이다. + +1. 등록 화면 목록 조회를 `operation-service` 및 `ONSEMIRO_NEW` 실시간 호출 경로에서 분리 +2. 백엔드가 "`OM_MS_VW` 기준 하수처리시설 목록 + WR 등록여부"를 한 번에 내려주도록 변경 + +즉, 프론트의 `WR 목록 조회 + operation-service 목록 조회 + 프론트 merge` 구조를, +`reuse-service 단일 API 1회 호출` 구조로 바꾼다. + +### 3.2 기본 원칙 + +- 기준목록은 `ONSEMIRO_NEW.OM_MS_VW`의 하수처리시설이다. +- 기준정보는 WR 적재본이 아니라 `reuse-service`에서 `ONSEMIRO_NEW.OM_MS_VW`를 직접 조회한다. +- 다만 프론트는 `operation-service`를 호출하지 않고 `reuse-service`만 호출한다. +- 기존 `operation-service`의 하수처리시설 조회 로직은 `D:\iipbs\iipbs_fo`의 구현을 기준으로 `reuse-service`로 이관한다. +- 등록 화면에서 필요한 컬럼만 조회한다. +- 등록 여부 계산은 프론트가 아니라 백엔드 SQL에서 처리한다. +- `ruse`는 "재이용여부"가 아니라 "등록여부"로 사용한다. +- `rswtrYn`는 `reuse-service`에 신규로 만들어지는 API에서 조회되는 값을 재이용여부로 사용한다. +- 검색/페이지 이동 시 불필요한 중복 호출을 줄인다. + +--- + +## 4. 프론트 작업계획 + +### 4.1 대상 파일 + +- `frontend/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx` +- `frontend/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/page.tsx` + +### 4.2 변경 계획 + +1. `hasuListFetch`를 `reuse-service` 단일 목록 API 호출 방식으로 교체 + - 기존 + - `GET /reuseFc/pubFc` + - `GET/POST /prcsFclt/ruseInfo/reg/...` (`operation-service`) + - 프론트 merge + - 변경 + - `GET /reuseFc/...` 신규 또는 확장 API 1회 + +2. `checkWrRegList` 제거 또는 비활성화 + - 등록 여부를 별도 조회하지 않고 백엔드 응답의 `ruse` 사용 + +3. `pubHasuInit` 삭제, `pubHasuSearch`로 통합. + - URL 파라미터만 조합하고 목록 바인딩만 수행 + +4. 검색 입력 최적화 + - 검색 버튼 클릭 기준 유지 시 즉시 반영 + - 필요 시 `swtrmtFcltNm` 입력에 debounce 적용 검토 + - 페이지 이동 시 같은 조건이면 재호출 최소화 + +5. 응답 필드 의미 정리 + - `ruse`: 등록여부 (`sm_bs_wr.tb_wr_pbnst_ruse_fclt` 등록 시 `Y`) + - `rswtrYn`: 기존 `operation-service` 목록 응답과 동일한 재이용여부 + +6. 수정/등록 후 재조회 범위 축소 + - 전체 목록 재초기화 대신 현재 페이지 재조회 + - 선택 행 유지 가능 여부 검토 + +### 4.3 프론트 기대효과 + +- 최초 진입 시 `operation-service` 외부 느린 경로 제거 +- 검색 시 응답시간 단축 +- 프론트 merge 로직 제거로 코드 단순화 +- 등록 여부 계산 일관성 확보 + +--- + +## 5. 백엔드 작업계획 + +### 5.1 대상 파일 + +- `D:\iipbs\wr_back_out\src\main\java\kr\co\mindone\wrout\controller\PublicFcController.java` +- `D:\iipbs\wr_back_out\src\main\java\kr\co\mindone\wrout\service\public_fc\PublicFcService.java` +- `D:\iipbs\wr_back_out\src\main\java\kr\co\mindone\wrout\mapper\wr\PublicFcMapper.java` +- `D:\iipbs\wr_back_out\src\main\resources\postgres\mapper\wr\public_fc_select.xml` + +### 5.2 구현 방향 + +1. 등록 화면 전용 목록 API 추가 + - 목적 + - `OM_MS_VW` 기준 하수처리시설 목록 + - WR 등록 여부(`ruse`) + - 재이용여부(`rswtrYn`) + - 등록 화면에 필요한 최소 컬럼 + - 페이지/검색/행정구역 조건 + - 후보 경로 예시 + - `GET /reuseFc/pbnstRegList/{pageNo}/{pageCnt}/{searchingCd}/{nameCd}` + - 구현 기준 + - `D:\iipbs\iipbs_fo`의 `ruseInfo/reg` 기존 조회 로직과 응답 컬럼을 최대한 그대로 가져온다. + - 프론트가 받는 목록 구조도 기존과 최대한 동일하게 유지한다. + + +2. 조회 원천을 `reuse-service`로 단일화 + - 기준목록은 `reuse-service`에서 `ONSEMIRO_NEW.OM_MS_VW` 조회 + - 등록정보는 `sm_bs_wr.tb_wr_pbnst_ruse_fclt` 조회 + - 두 DB는 다르므로 DB 조인 대신 `reuse-service` 서비스 로직에서 결과를 합성 + - 프론트의 `operation-service` 호출 제거 + +3. SQL을 등록 화면 전용으로 최소화 + - 상세/실적/운영정보까지 한 번에 끌고 오지 않음 + - 등록 화면 좌측 목록에 필요한 컬럼만 select + - 검색 조건 + - 행정구역 + - 시설명 + - 필요 시 시설용량 + +4. 등록여부/재이용여부 계산을 백엔드로 일원화 + - 등록여부 + - 기준: `OM_MS_VW`의 하수처리시설을 조회했을 때 `sm_bs_wr.tb_wr_pbnst_ruse_fclt`에도 등록되어 있으면 `ruse = 'Y'` + - 재이용여부 + - 기존 `operation-service`가 내려주던 `rswtrYn`를 그대로 반환 + - 즉, 현재 목록에서 보이던 재이용여부 표시는 유지하되, `ruse`의 의미만 등록여부로 수정 + - 구현 방식 + - `ONSEMIRO_NEW.OM_MS_VW` 결과에서 시설키 목록 추출 + - WR의 `tb_wr_pbnst_ruse_fclt` 등록정보를 별도 조회 + - `reuse-service`에서 키 기준으로 매핑 후 응답 생성 + - 프론트의 `Set` 비교 제거 + +5. 인덱스/실행계획 점검 + - `ONSEMIRO_NEW.OM_MS_VW` 조회 조건 컬럼 + - 시설코드 + - 행정구역 코드 + - 시설명 + - `tb_wr_pbnst_ruse_fclt`의 연계 키 컬럼 + - `swage_trtmfct_id` + - `pbnst_ruse_fclt_id` + - `LIKE '%검색어%'`가 병목이면 prefix 검색 또는 보조 검색전략 검토 + +6. API 호출 원칙 고정 + - 등록 화면 목록은 `reuse-service`만 호출한다. + - `operation-service`는 호출하지 않는다. + +7. 선택적 캐시 적용 검토 + - 같은 조건 반복 조회가 많으면 짧은 TTL 메모리 캐시 가능 + - 단, 1차는 SQL 단순화와 WR 내부조회 전환이 우선 + +### 5.3 백엔드 기대효과 + +- 등록 목록 조회 시 `operation-service` 및 `ONSEMIRO_NEW` 대기 제거 +- 목록 API 응답 구조 단순화 +- 등록여부/재이용여부 의미 분리 +- 프론트와 백엔드 간 호출 수 감소 + +--- + +## 6. 권장 작업 순서 + +### 단계 1. 백엔드 전용 목록 API 준비 + +- `D:\iipbs\iipbs_fo`의 `ruseInfo/reg` 기존 로직 분석 +- `ONSEMIRO_NEW.OM_MS_VW` 조회 SQL 작성 +- WR 등록정보 조회 SQL 작성 +- 두 결과를 `reuse-service`에서 합성하는 서비스 로직 작성 +- 등록여부(`ruse`) / 재이용여부(`rswtrYn`) 포함 응답 DTO 정의 +- Swagger 및 응답 count 포함 + +### 단계 2. 프론트 등록 화면 연결 + +- `hasuListFetch`를 `reuse-service` 신규 API로 교체 +- `checkWrRegList` 제거 +- 화면 목록 바인딩 점검 + +### 단계 3. 성능 검증 + +- 동일 조건 기준 기존/개선 응답시간 비교 +- 최초 진입, 검색, 페이지 이동 각각 측정 +- 운영데이터와 등록여부 정합성 확인 + +--- + +## 7. 검증 항목 + +1. `하수재이용시설 등록` 화면 최초 진입 시간이 개선되는지 +2. 시설명 검색 시 응답시간이 개선되는지 +3. `sm_bs_wr.tb_wr_pbnst_ruse_fclt` 등록 여부에 따라 `ruse = Y/N`가 정확히 표시되는지 +4. `rswtrYn`가 재이용여부 의미로 올바르게 내려오는지 +5. 특정 지자체 권한(`laeSeCd`) 조건에서 목록이 정상 필터링되는지 +6. 행 선택 후 상세 등록 폼 진입 동작에 영향이 없는지 + +--- + +## 8. 리스크 및 유의사항 + +- `ONSEMIRO_NEW.OM_MS_VW`와 WR 등록정보가 서로 다른 DB에 있으므로 DB 조인은 불가하다. +- 따라서 `reuse-service` 내부에서 2회 조회 후 합성하는 구조가 필요하다. +- `operation-service`는 제거하더라도 `reuse-service`의 `ONSEMIRO_NEW` 직접 조회 성능은 여전히 관리해야 한다. +- 기존 `pbnstList`는 현황 화면 성격이 강하므로, 등록 화면은 별도 API로 분리하는 편이 유지보수에 유리하다. +- 필드 의미 변경은 `ruse`에만 적용되므로, 기존 화면에서 `ruse`를 재이용여부로 해석하는 코드가 남아 있지 않은지 점검이 필요하다. +- `rswtrYn`는 기존 operation-service 응답으로 frontend에서 등록여부로 사용되었으나 재이용여부로 변경한다. +- 상세 진입 시 `pbnstRegClick -> /reuseFc/pubFc/{bscFctCd}` 경로는 별도 검토가 필요하다. 목록 최적화 후에도 상세 로딩 병목이 남을 수 있다. + +--- + +## 9. 결론 + +1차 개선안은 "`reuse-service`가 `OM_MS_VW` 기준 하수처리시설 목록과 WR 등록정보를 각각 조회해 서버에서 합성하고, 등록 화면은 `reuse-service` 단일 API만 호출"하도록 바꾸는 것이다. + +핵심은 다음 2건이다. + +1. 백엔드에서 `iipbs_fo`의 기존 `ruseInfo/reg` 로직을 `reuse-service`로 이관하고, `OM_MS_VW 기준정보 + 등록여부(ruse) + 재이용여부(rswtrYn)`를 한 번에 반환하는 등록 전용 API 추가 +2. 프론트에서 `operation-service` 경로와 merge 로직을 제거하고 `reuse-service`만 호출하도록 변경 + +이 방향이 현재 구조에서 가장 적은 변경으로 가장 큰 체감속도 개선을 낼 수 있다.