15 KiB
지반침하 상세정보·하수관로 목록 엑셀 다운로드 작업계획
- 작성일: 2026-10-22
- 요구사항: SFR-010-010
- 상태: 사용자 승인 후 구현 완료. 타입·XLSX 검증 완료, 실제 브라우저 클릭 검증은 미완료.
- 작업 목적: 지도 우측 지반침하 상세정보에서 발생정보와 해당 반경 내 하수관로 목록을 하나의 XLSX 파일로 내려받는다.
- 범위: FE만 수정한다. 공통 유틸은 사용자 지정 경로인
apps/sn/src/shared/util에 둔다.
1. 요구사항 및 원본 확인
| 근거 | 직접 확인한 내용 |
|---|---|
| 사용자 요청 | 우측 상세정보에 엑셀 다운로드 추가. 상세 상단을 첫 시트, 하수관로 목록을 둘째 시트로 구성. 다른 화면을 참조해 공통화하고 승인 후 구현 |
COMMON_DOCS_ROOT/기준문서/요구사항정의서.xlsx |
3. (기능)요구사항정의 및 추적표 시트 82행, SFR-010-010, 싱크홀 발생 정보 지도 서비스. 지반침하 용어 변경, 연계 정보 지도 표출, 기본 반경 100m 및 사용자 입력 반경, 좌표 없는 자료의 목록 표출 근거 확인 |
COMMON_DOCS_ROOT/기준문서/화면설계서.pptx |
슬라이드 7, 화면 ID SN_MN010101, 하수관망도 > 지반침하정보. 발생정보 상세, 반경 내 관로 추출, 관로 행 클릭 강조, 발생이력 목록 다운로드 확인 |
| 기존 작업카드 | 같은 폴더의 001-fe-SFR-010-010-지반침하정보-작업카드.md 확인. 현재 경로와 실제 구현을 기준으로 추가 계획 작성 |
원본에는 우측 상세정보를 두 시트로 내려받는 구체적 구성이 없으므로 이번 사용자 요청을 추가 요구사항으로 삼는다. 원본의 피해 인원 항목을 새로 추가하지 않고 현재 상세 상단에 표시되는 9개 항목을 내보낸다.
원본 파일 정보: 화면설계서 10,736,400바이트 / 수정일 2026-08-13, 요구사항정의서 124,187바이트 / 수정일 2026-08-06.
2. 현재 구현과 참조 결과
| 파일 | 확인 결과 / 활용 방향 |
|---|---|
app/(map-layout)/map/components/sinkhole/sinkhole-detail-panel.tsx |
detail, nearbyPipes, radiusMeters를 받아 발생정보 9개 항목과 관로 5개 열을 표시한다. 다운로드 버튼은 없다. 복구상태와 관로 용도는 공통코드 표시명 사용 |
app/(map-layout)/map/components/sinkhole/sinkhole-popup-page.tsx |
기존 지반침하 목록 다운로드는 적용조건 전체를 페이지 순회하여 수집하고 한글 헤더, 로딩 및 오류 안내를 적용한다. 해당 목록 기능은 유지 |
src/shared/lib/download-excel.ts |
xlsx 동적 import, 한글 헤더, 열 너비, 시트명 정리, 압축 저장 참조. sheetNameArray는 현재 첫 이름만 사용하며 동일 구조 데이터의 대량 분할용이므로 이종 데이터 두 시트를 직접 표현하기 어렵다 |
app/(map-layout)/map/components/aged-pipe-status-by-ctpv/aged-pipe-status-by-ctpv-export.ts |
aoa_to_sheet, 병합, 열 너비, 자동필터, book_append_sheet, XLSX 저장 방식 참조 |
app/(map-layout)/map/ui/map-page-client.tsx |
활성 지반침하 상세 탭의 상세와 관로 배열을 패널에 전달한다. 기존 조회 실패도 빈 배열이 되므로 관로 0건과 조회 실패를 현재 props만으로 구분할 수 없다 |
백엔드는 읽기 전용으로 현행 제약만 확인했다. SinkholeQueryService.getNearbyPipes, getNearbyPipesByPoint 모두 관로 조회 상한이 200건이다. 호출 인자로 전체 건수나 페이지를 요청할 수 없다.
3. 결과 파일과 UI 제안
- 버튼: 사용자 최종 후속 요청에 따라 하수관로 목록의
침하발생 반경내 관로정보제목과 같은 헤더 행의 오른쪽에 배치한다. 하수처리구역 상세의보수이력과 동일한 Button 기본 크기와 색상·여백 클래스를 사용한다. 좁은 패널에서는 제목 줄바꿈을 허용하고 버튼 크기를 유지한다. - 파일명:
지반침하정보_사고번호_YYYY-MM-DD.xlsx. 파일명에 쓸 수 없는 문자는 정리하고 날짜는 사용자 로컬 날짜를 사용한다. - 두 시트의 순서는 고정한다.
| 순서 / 시트명 | 구성 |
|---|---|
1 / 지반침하정보 |
항목, 내용의 세로 표. 사고번호, 발생일자, 주소, 발생규모폭, 발생규모연장, 발생규모깊이, 상세발생원인, 복구상태, 복구완료일자 순으로 현재 상세와 동일한 표시값 사용 |
2 / 하수관로목록 |
상단에 사고번호와 조회 반경(m)을 표시하고, NO, 관로 ID, 용도, 경과년도(년), 거리(m) 열로 관로 목록 구성. 조회 순서를 유지하고 자동필터는 목록 헤더부터 적용 |
- 첫 시트는 현재
summaryTableData와summaryHeadList를 재사용해 화면과 엑셀의 값·항목 순서가 달라지지 않게 한다. - 관로 용도는 현재 화면의 공통코드명 변환 함수를 재사용한다. 코드명 미확보 시 화면과 동일하게 원래 코드를 사용한다.
- 관로 ID와 사고번호는 문자열로 보존한다. 숫자형 경과년도·거리는 숫자로 저장하며 헤더에 단위를 표기한다. 결측값은
-로 처리하고 0은 유지한다. - 관로가 정상 조회되어 0건이면 둘째 시트에 헤더와
반경 내 하수관로 정보가 없습니다.안내를 넣어 두 시트를 모두 생성한다. - 좌표가 없는 상세도 첫 시트는 다운로드할 수 있게 하고, 둘째 시트에는 좌표 부재로 관로를 조회할 수 없다는 안내를 넣는다.
- 다운로드 중에는 버튼을 비활성화하고 진행 상태를 표시한다. 실패하면 안내 후 버튼을 복구한다.
4. 공통화 설계
신규 공통 유틸
경로: apps/sn/src/shared/util/download-excel-workbook.ts
downloadExcelWorkbook({ fileName, sheets }) 형태로 서로 다른 구조의 시트를 순서대로 받는다. 각 시트는 시트명, 명시적 셀 행 배열, 열 너비, 선택적인 자동필터 범위·병합 범위를 전달한다. 셀 값은 문자열·숫자·불리언·null로 제한하고 업무 데이터나 API 호출은 유틸에 넣지 않는다.
공통 책임은 XLSX 동적 import, 워크북/시트 생성, 시트명 금지문자·31자 제한·중복 이름 정리, 열 너비 설정, 자동필터 및 병합 적용, 파일 확장자·파일명 정리, 브라우저 저장이다. 문자열을 수식으로 전환하지 않는다. 빈 데이터에서도 전달된 헤더·안내 행을 저장할 수 있어야 한다.
기존 src/shared/lib/download-excel.ts의 공개 인터페이스와 호출부는 이번에 변경하지 않는다. 두 함수의 목적이 달라 기존 목록 다운로드 전체를 이관하는 작업은 제외하고 새 기능에서 공통 유틸을 사용한다. 다른 화면도 이종 시트가 필요할 때 같은 유틸을 사용할 수 있다.
지반침하 전용 변환
경로: app/(map-layout)/map/components/sinkhole/sinkhole-detail-excel.ts
화면에서 전달한 발생정보 표시값, 관로 표시값, 사고번호, 반경을 XLSX 시트 명세로 변환한다. 지반침하 항목명과 빈 목록·좌표 부재 안내는 이 파일에서 관리하여 공통 유틸과 분리한다.
5. 데이터 범위와 오류 처리
- 이번 다운로드 대상은 선택한 사고의 현재 적용 반경에 대해 기존 API가 제공하는 관로 목록이다. 전체 사고 목록이나 전체 하수관로를 내보내는 기능이 아니다.
- 기존 관로 API가 최대 200건을 반환하므로 FE만으로 200건 초과 전체를 보장할 수 없다. 둘째 시트에
기존 반경 조회 기준, 최대 200건을 표시한다. 200건 초과 전체 추출은 백엔드 계약 보완이 필요한 별도 범위다. - 기존 패널 props의 빈 배열은 조회 실패와 0건을 구분하지 못한다. 이를 숨기지 않도록 다운로드 클릭 시 기존 조회 API로 선택 사고·반경의 관로 목록을 다시 확인한다. 새 API는 만들지 않는다.
- 유효한 상세 x/y가 있으면 기존
nearbyPipesByPoint, 없으면 좌표 조회 가능 상태를 확인한 뒤 기존 사고번호별nearbyPipes를 사용한다. 좌표 부재 상태는 조회를 생략하고 해당 사유를 시트에 남긴다. - 요청 실패·비정상 응답은 0건으로 바꾸지 않고 다운로드를 중단해 안내한다. 정상 응답의 빈
items만 0건으로 처리한다. - 클릭 시 활성 상세, 반경, 코드명 정보를 고정하여 비동기 요청 도중 다른 사고로 이동해도 서로 다른 사고 정보가 섞이지 않게 한다.
- 재조회 중 데이터가 변경될 수 있으므로 두 번째 시트는 다운로드 시점의 같은 사고·반경 조회 결과다. 지도·화면의 상태를 다운로드 때문에 갱신하지 않는다.
6. 수정 예정 파일
| 파일 | 변경 내용 |
|---|---|
src/shared/util/download-excel-workbook.ts |
신규. 업무에 독립적인 다중 시트 XLSX 생성/저장 |
app/(map-layout)/map/components/sinkhole/sinkhole-detail-excel.ts |
신규. 발생정보/관로 두 시트 구성 및 기존 API 재조회 처리를 담당. API 호출은 공통 유틸에 포함하지 않음 |
app/(map-layout)/map/components/sinkhole/sinkhole-detail-panel.tsx |
버튼, 진행/오류 처리, 기존 표시값 전달 |
| 이 작업계획 문서 | 승인 및 구현 후 검증 결과 기록 |
백엔드, 의존성, 공용 패키지 및 다른 페이지의 코드는 변경하지 않는다. 기존에 수정 중인 파일은 덮어쓰지 않는다. 메인 지도 상태 변경은 현재 계획에서 제외한다.
7. 구현 절차
- 공통 워크북 유틸을 작성한다. 업무 데이터와 분리해 서로 다른 행 구조를 가진 시트를 하나의 파일로 생성할 수 있게 한다.
- 지반침하 전용 변환·조회 함수를 작성한다. 클릭 시 사고와 반경을 고정하고 기존 API 응답을 검증한 뒤 발생정보와 관로 시트 명세를 만든다.
- 우측 상세에 다운로드 버튼을 연결한다. 현재 표시값을 재사용하고 진행 중 중복 실행과 오류 안내를 처리한다.
- 아래 검증을 수행하고 결과를 기록한다. 파일 자체와 실제 다운로드 흐름이 요구사항에 맞는지 확인한 뒤 완료 보고한다.
8. 검증 및 완료 기준
git diff --check,pnpm --filter sn run typecheck로 변경 오류를 확인한다.- 사용자의 개발 서버가 실행 중이면 종료·재시작 및
next build를 하지 않는다. 실제 앱 포트와 실행 상태를 확인한 뒤 가능한 환경에서 UI를 검증한다. - 실제 XLSX 파일을 다시 읽어 시트가 정확히 두 개이고 순서·이름·9개 발생정보 항목·관로 5개 열·행 수·값이 맞는지 확인한다.
- 정상 관로 여러 건, 정상 0건, 좌표 없음, API 실패, 비정상 응답, 코드명/원코드 대체, 결측값과 0, 숫자형 ID의 문자열 보존, 중복 클릭을 확인한다.
- 반경 변경 후 다운로드와 활성 사고 탭 전환 중 다운로드에서 사고·반경이 섞이지 않는지 확인한다.
- 한글·긴 주소·발생원인의 열 너비와 줄바꿈, 필터 위치, 파일명과 날짜를 확인한다. XLSX 라이브러리에서 지원하지 않는 장식 스타일을 완료 조건으로 약속하지 않는다.
- 기존 관로 행 클릭·지도 강조·닫기·다른 상세 탭과 기존 지반침하 목록 다운로드가 유지되는지 확인한다.
- 검증용 파일/스크립트는 결과 기록 후 정리하며 사용자 원본과 다른 작업자의 파일은 건드리지 않는다.
9. 영향 범위·롤백·잔여 제약
- 영향: 지반침하 우측 상세의 다운로드 기능과 신규 FE 공통 유틸에 한정한다. 기존 조회·지도·목록 다운로드 계약은 유지한다.
- 롤백: 패널의 이번 버튼/핸들러/import 변경만 되돌리고 신규 전용 함수와 신규 공통 유틸을 제거한다. 기존 타 작업 변경은 보존한다.
- 잔여 제약: 최대 200건 API 상한, 다운로드 시점 재조회와 기존 화면 사이의 데이터 갱신 차이, 대량 XLSX 생성의 브라우저 메모리 사용. 전체 관로 추출이나 서버 생성 방식은 별도 요청/승인 범위다.
10. 승인 및 구현 결과
- 사용자 승인: 이 작업계획대로 코드 수정 요청을 받아 구현했다.
- 신규 공통 유틸
src/shared/util/download-excel-workbook.ts:buildExcelWorkbook으로 시트 생성과 다운로드를 분리하고downloadExcelWorkbook으로 브라우저 저장을 제공한다. 동적 XLSX 로딩, 시트 순서, 이름 중복/금지문자/길이 정리, 파일명 정리, 열 너비·필터·병합을 지원한다. - 신규
sinkhole-detail-excel.ts: 발생정보 9개 항목과 관로 5개 열을 두 시트로 구성한다. API 재조회 실패와 비정상 응답은 다운로드를 중단하고, 정상 0건·좌표 부재는 별도 안내를 내보낸다. 사고·반경·표시 행은 재조회 전에 복사해 고정한다. - 수정
sinkhole-detail-panel.tsx: 하수관로 목록 제목 오른쪽에 버튼을 배치했다. 사용자 후속 요청에 따라 하수처리구역 상세의 보수이력 버튼과 같은 기본 크기·색상·여백을 적용했다. 진행 상태를 state로 표시하고 ref로 즉시 중복 실행을 막으며 오류 후 상태를 복구한다. - 기존 목록 다운로드, 메인 지도, 백엔드, 의존성 및 타 페이지는 수정하지 않았다. 공통 유틸 우선 검토 기준문서 추가는 별도 제안 단계이므로 이번 구현 범위에 포함하지 않았다.
검증 결과
| 항목 | 결과 / 한계 |
|---|---|
pnpm --filter sn run typecheck |
통과 |
git diff --check |
통과 |
| XLSX 실제 직렬화 후 재읽기 | 두 시트 이름·순서, 첫 시트 9개 항목, 둘째 시트 5개 열, 필터 범위, 관로 순서 확인 |
| 데이터 형식 | 문자열 관로 ID 00123의 앞자리 0 보존, 용도명/원코드 대체, 경과년도·거리의 숫자 0과 결측 - 확인 |
| 예외 / 빈 목록 | 정상 0건 안내, 좌표 부재 시 API 요청 생략 및 안내, 요청 실패·비정상 응답 시 저장 중단 확인 |
| 비동기 데이터 고정 | 조회 중 호출자의 사고번호·반경·요약 행을 바꿔도 파일에는 클릭 시 데이터 유지 확인 |
| 공통 유틸 | 금지문자, 대소문자 중복, 31자 제한, 빈 시트, 수식처럼 보이는 문자열의 일반 문자열 저장 확인 |
| API 분기 / 파일명 | 좌표 기준 및 사고번호 기준 요청, 사고번호 URL 인코딩, 파일명 금지문자 정리 확인 |
| 개발 서버 | 기존 3002 포트 서버 유지, /map HTTP 200 확인. 빌드·재시작하지 않음 |
| 브라우저 / 실제 API | 연결된 브라우저가 없어 실제 버튼 클릭·다운로드·지도 회귀 및 실제 API 응답 검증은 미완료. 위 데이터/예외 검증은 요청·저장 함수를 대체한 메모리 기반 검증이며 XLSX 직렬화/재읽기는 실제 라이브러리 사용 |
| 시각 서식 | 열 너비·병합 설정 확인. 줄바꿈 스타일은 라이브러리에 전달하되 무료 SheetJS의 지원 및 Excel 실제 화면은 미검증 |
검증 코드는 셸 표준입력으로 실행했고 디스크에 테스트 파일·XLSX를 남기지 않았다. 롤백과 최대 200건 제약은 9절을 따른다.