diff --git a/README.md b/README.md index 35dcf9d..75bcc3c 100644 --- a/README.md +++ b/README.md @@ -1,396 +1,405 @@ -# SPipe - -## 프로젝트 개요 - -웹 브라우저에서 쓰는 상수도 관망 수리해석·관리 플랫폼. -EPANET 2.3.5 엔진으로 관망을 해석하고, GIS·DEM·자산 정보를 한 화면에서 함께 다룬다. - -주요 기능: - -- EPANET INP 관망 불러오기·편집·해석 (Native DLL과 WASM 두 엔진 교차 검증) -- 지도 기반 관망 편집 (절점·관로·밸브·펌프, 꺾임점, 분할·병합) -- 해석 결과 지도·그래프·종단·보고서, 실측 보정 -- 분석 도구: 소화전 모의, 관로 중요도, 급수 구역, VSP, 등치선, 에너지 비용, 자동 보정, 펌프 운전 최적화 -- GIS 연동: SHP·DXF·DGN·MIF·GML·KML·GPKG 불러오기·내보내기, 좌표계 변환, 도형 연산 -- DEM 기반 절점 표고 입력·검증, 유역·하천 분석, 3D 보기 -- 프로젝트 파일(.spipe), 시나리오, 자동 백업 - -## 웹 기반으로 만드는 이유 - -### 기존 운영 방식 - -설치형 관망해석 프로그램(EPANET 등)을 PC마다 설치하고, 관망 파일·GIS 자료·DEM·엑셀 자료를 파일 단위로 주고받으며 작업하는 구조. - -### 기존 문제 - -- PC마다 프로그램 설치·버전 관리 필요 -- 관망 INP, GIS 레이어, 표고 자료, 자산 대장이 서로 다른 프로그램·파일에 분산 -- 같은 관망을 여러 사람이 볼 때 파일 사본이 늘어나고 최신본 확인이 어려움 -- 수리해석 결과를 지도·자산 정보와 함께 보려면 여러 프로그램을 오가야 함 - -### 웹 기반 통합의 필요성 - -사내망 서버 한 곳에 해석 엔진과 GIS 처리를 두고, 사용자는 브라우저로 접속해 같은 기능을 쓴다. -관망 모델(INP)을 기준으로 GIS·DEM·자산 정보를 연결해 하나의 작업 흐름으로 관리한다. - -### 기대 효과 - -- 설치 없이 브라우저 접속만으로 사용 -- 관망·지도·표고·자산 정보를 한 화면에서 확인 -- 해석 결과를 두 엔진으로 교차 검증해 신뢰도 확보 -- 분석 결과를 표준 형식(INP, SHP, GPKG, CSV)으로 내보내 기존 업무와 연계 - -## 핵심 용어 - -| 용어 | 의미 | -|---|---| -| INP | EPANET 관망 입력 파일. SPipe 관망 모델의 원본 형식 | -| 절점 / 링크 | 접합점·배수지·탱크(절점)와 관로·펌프·밸브(링크) | -| EPS | 연장 기간 해석. 시간대별 수요 패턴에 따라 여러 시점을 해석 | -| Native / WASM 엔진 | 서버의 EPANET DLL과 브라우저의 epanet-js. 같은 관망을 둘 다 해석해 결과를 비교 | -| 시나리오 | 원본 관망에서 갈라져 나온 대안 관망 | -| 자산 속성 | INP에 없는 관재질·설치년도·매설깊이·소블록 등 관리 정보 | -| DEM | 수치표고모델. 절점 표고 입력과 유역 분석에 사용 | -| 일괄 해석(Job) | 관로 중요도·소화전 모의처럼 해석을 여러 번 반복하는 서버 작업 | -| .spipe | 관망·시나리오·GIS 레이어·스타일·보정 자료를 묶은 프로젝트 파일 | - -## 처리 흐름 - -``` -INP 불러오기 또는 GIS 레이어로 관망 만들기 - ↓ -지도에서 관망 편집 · 자산 속성 · DEM 표고 입력 - ↓ -수리해석 (Native DLL + WASM 동시 실행, 결과 비교) - ↓ -결과 확인 (지도 · 그래프 · 종단 · 보고서 · 실측 보정) - ↓ -분석 도구로 검토 (중요도 · 급수 구역 · 소화전 · 최적화 ...) - ↓ -INP · SHP · 엑셀 · .spipe 로 저장·공유 -``` - -핵심 원칙: - -- 관망 모델의 원본은 INP 구조이며, 편집은 모두 INP로 다시 생성 가능한 형태로 저장 -- INP에 없는 정보(자산 속성, 화면 설정)는 별도 저장소에 두고 요소 ID로만 연결 -- 해석 결과는 엔진 출력이 원본이며, 화면은 단위 변환만 수행 -- 모든 편집은 실행 취소(Ctrl+Z) 가능 - -이 문서는 저장소의 시작점입니다. 상세 설계와 점검 기록은 별도 문서에 두고, 여기에는 실행·검증·배포 순서와 문서 선택 기준을 정리합니다. - ---- - -## 1. 빠른 시작 - -### 로컬 실행 (Windows) - -필요 조건: - -- Node.js 24.x (검증 버전 24.14.1) -- Python 3.12 64비트 -- EPANET 2.3.5 (`64bit/epanet2.dll` 포함) - -```powershell -npm install -py -3.12 -m venv .venv -.\.venv\Scripts\python.exe -m pip install -r backend\requirements.txt pytest httpx -``` - -가장 간단한 실행 방법은 `start-spipe.bat` 더블클릭입니다. 해석 API(8000)와 웹 개발 서버(5173)를 함께 띄우고 브라우저를 엽니다. 종료는 `stop-spipe.bat`. - -수동 실행: - -```powershell -npm run api -``` - -```powershell -npm run dev -``` - -접속 주소: - -- Web: http://127.0.0.1:5173 -- 해석 API: http://127.0.0.1:8000 -- API 상태 확인: http://127.0.0.1:8000/api/health - -지도 서비스 키 설정 (`.env.example`을 `.env.local`로 복사해 값 입력. 없으면 배경지도·주소 검색만 동작하지 않음): - -```powershell -Copy-Item .env.example .env.local -``` - -개발 서버는 `127.0.0.1`에만 바인딩됩니다. 사내망에 공개할 때는 아래 "8. 사내 서버 배포"를 따릅니다. - -### 로컬 검증 - -```powershell -npm run typecheck -``` - -```powershell -npm test -``` - -```powershell -npm run test:api -``` - -```powershell -npm run build -``` - -- `npm test`: 모델·단위·비교 로직, 편집·분석 도구 회귀 테스트 (Node 테스트) -- `npm run test:api`: FastAPI·EPANET DLL·GIS·DEM 테스트 (pytest) - -CI는 `.github/workflows/ci.yml` (windows-latest). - -## 2. 서비스 구조 - -``` -브라우저 - │ - ▼ -Web (React + Vite) 지도·편집·결과 화면, WASM 해석(Web Worker) - │ /api 프록시 - ▼ -해석 API (FastAPI) EPANET DLL(ctypes) 해석, 일괄 해석, GIS·DEM 처리 - ├─▶ 64bit/epanet2.dll EPANET 2.3.5 엔진 (프로세스 풀) - ├─▶ GDAL (pyogrio, rasterio) 벡터·래스터 입출력 - └─▶ data/dem 업로드한 DEM 보관 - -외부 연동(브라우저에서 직접 호출): 브이월드 배경지도 · 카카오 주소 검색 · Open-Meteo 표고(90m) · OpenStreetMap 건물 -``` - -| 구성요소 | 책임 | 기본 포트 | -|---|---|---| -| `src/` Web | 관망 편집, 결과 표시, WASM 해석, 엔진 결과 비교 | 5173 개발 / 8080 사내 | -| `backend/` 해석 API | 해석, 일괄 분석 Job, GIS 변환·연산, DEM | 8000 (내부 전용) | -| `64bit/epanet2.dll` | EPANET 2.3.5 엔진 | - | -| `data/dem/` | 서버 DEM 보관 (최근 8개) | - | - -## 3. 데이터와 원본 원칙 - -관망의 원본은 **INP 구조**입니다. 화면 편집은 내부 모델(`src/inpModel.ts`)을 바꾸고, 해석·저장 시 항상 INP로 다시 생성합니다. - -INP로 저장되는 것: - -- 절점·관로·펌프·밸브, 패턴·곡선·컨트롤·규칙, 해석 옵션 -- 다중 수요, 이미터, 수질·수원, 탱크 혼합, 에너지, 초기 상태, 반응 계수, 지도 라벨 -- 관로 꺾임점(`[VERTICES]`) — 이름 변경·삭제·분할·방향 전환을 따라감 - -INP 밖에 별도로 두는 것: - -- 자산 속성(관재질·설치년도·매설깊이·소블록 등): 요소 ID로 연결, `.spipe`에 함께 저장 -- 화면 설정(레이어 스타일·범례·라벨): `.spipe`에 저장 -- DEM 원본: 서버 `data/dem`에 보관, 브라우저에는 식별자만 보관 - -원칙: - -- 해석 결과는 엔진 출력을 그대로 쓰고, 화면은 표시 단위 변환만 수행 -- 재생성한 INP가 원본 INP와 같은 해석 결과를 내는지 회귀 테스트로 확인 -- 실무 관망 원본 파일(INP)은 저장소에 커밋하지 않음 - -## 4. 해석 흐름 - -1. 사용자가 해석 실행을 누르면 현재 모델로 INP를 생성합니다. -2. 같은 INP를 서버(Native DLL)와 브라우저(WASM)에서 동시에 해석합니다. -3. 두 결과를 시간대별·요소별로 비교해 허용오차 안에서 일치하는지 표시합니다 (`src/comparisonEngine.ts`). -4. EPANET 경고 코드(1~6)와 비정상 압력을 별도로 점검해 표시합니다 (`src/convergence.ts`). -5. 분석 탭의 일괄 해석(관로 중요도, 소화전, 보정 등)은 서버 Job으로 실행합니다 (`backend/jobs.py`). - -관련 구현 위치: - -- INP 파싱·생성: `src/inpModel.ts`, `src/inpExtras.ts` -- 서버 해석: `backend/main.py`, `backend/epanet.py` -- 일괄 해석 프레임워크: `backend/batch.py`, `backend/jobs.py` -- WASM 해석: `src/worker.ts` - -## 5. 주요 기능 사용 가이드 - -### 관망 편집 - -상단 [편집] 모드에서 절점·관로를 추가하고 지도에서 끌어 옮깁니다. 관로를 선택하면 꺾임점 핸들이 나타나며, 주황 점을 끌면 이동, 흰 점을 끌면 추가, 더블클릭하면 삭제됩니다. 속성창 아래 "추가 속성"에서 다중 수요·이미터·수질·탱크 혼합·펌프 에너지를 편집합니다. - -### 결과 확인 - -[결과] 창에서 표·시계열·누적 빈도·종단(시간별)·실측 보정을 확인합니다. 표의 행을 누르면 지도가 해당 요소로 이동합니다. - -### 분석 탭 - -| 분석 | 내용 | -|---|---| -| 소화전 모의 | 시간대별 소화 유량 추가 해석, 확보 가능 유량 | -| 관로 중요도 | 관로를 하나씩 닫아 영향 절점·수요 순위 | -| 급수 구역 | 배수지별 공급 비율 추적 | -| 흐름 방향 | 역류·무흐름 관로 | -| VSP | 목표 압력용 시간별 펌프 회전수 | -| 등치선 | 압력·동수두·표고 등치선 | -| 에너지 비용 | 펌프별 가동률·효율·원단위·전력비 | -| 관로 통계 | 관경·재질·설치 연대별 집계 | -| 자동 보정 (시험) | 실측값으로 그룹별 C값 배율·관벽 계수 추정 | -| 펌프 운전 최적화 (시험) | 압력·탱크 조건을 지키는 저비용 운전 일정 | -| 편집 도구 | 이동·회전·2점 보정, 분할, 절점 병합, 관로 점검, 추적 | -| 지형(DEM) | DEM 표고 입력·검증, 인터넷 90m 표고, TIN, 유역·하천, 3D | -| GIS 도구 | 레이어 좌표계·내보내기, 도형 연산, 밸브·계량기·소블록 반영 | - -### 저장과 백업 - -프로젝트 메뉴에서 `.spipe`로 저장하면 관망·시나리오·레이어·보정 자료가 한 파일에 담깁니다. 수정 중에는 10분마다 브라우저에 자동 백업되며(최근 30개), 프로젝트 메뉴 > 백업 기록에서 복원합니다. - -## 6. API - -브라우저는 Web 서버의 `/api` 프록시를 통해 해석 API를 호출합니다. 해석 API 포트는 외부에 공개하지 않습니다. - -| 메서드 | 경로 | 설명 | -|---|---|---| -| GET | `/api/health` | 상태 확인 | -| POST | `/api/analyze` | multipart `file`(.inp) → 전체 EPS 해석 결과 JSON (`?format=columnar` 압축 형식) | -| POST | `/api/jobs/{name}` | 일괄 해석: `fireflow`, `criticality`, `servicearea`, `vsp`, `energy`, `calibrate`, `pumpschedule` | -| POST | `/api/gis/vector` | GDAL 벡터 파일 → WGS84 GeoJSON | -| POST | `/api/gis/export` | 레이어 → SHP·GPKG·DXF·GeoJSON·KML (좌표계 지정) | -| POST | `/api/gis/op` | 버퍼·병합·잘라내기·차이·보로노이·격자 | -| POST | `/api/gis/reproject` | 레이어 좌표계 다시 지정 | -| POST | `/api/dem` | DEM 업로드 (GeoTIFF·ASC·IMG, zip) | -| GET | `/api/dem/{id}/preview.png` | DEM 음영 미리보기 | -| GET | `/api/dem/{id}/terrain/{z}/{x}/{y}.png` | 3D 지형 타일 (terrarium) | -| POST | `/api/dem/{id}/sample` | 지점 표고 (쌍선형 보간) | -| POST | `/api/dem/{id}/hydro` | 하천선 추출 / 유역 | -| POST | `/api/dem/from-points` | 점 표고로 DEM 생성 (TIN) | - -해석 결과의 필드 정의는 `src/types.ts`의 `SimulationResult`를 기준으로 합니다. 오류는 `{"detail": "..."}` 형식입니다. - -| 상태 | 의미 | -|---|---| -| 400 | 입력 형식 오류 (확장자, 파라미터, 좌표계) | -| 413 | 업로드 한도 또는 해석 규모 상한 초과 | -| 500 | EPANET 입력·해석 오류 | -| 504 | 해석 시간 초과 | - -## 7. 환경변수와 비밀값 - -| 변수 | 기본값 | 의미 | -|---|---|---| -| `SPIPE_MAX_UPLOAD_MB` | 20 | INP·GIS 업로드 한도. nginx `client_max_body_size`와 맞출 것 | -| `SPIPE_MAX_DEM_MB` | 300 | DEM 업로드 한도. nginx `location /api/dem`과 맞출 것 | -| `SPIPE_ANALYZE_TIMEOUT_S` | 120 | 해석 1건 시간 제한 | -| `SPIPE_JOB_TIMEOUT_S` | 900 | 일괄 해석 1건 시간 제한 | -| `SPIPE_MAX_PERIODS` | 10000 | 수리 스텝 수 상한 | -| `SPIPE_MAX_RESULT_CELLS` | 50000000 | (노드+링크) × 스텝 상한 | -| `SPIPE_WORKERS` | min(4, CPU-1) | 해석 프로세스 수 | -| `SPIPE_DEM_DIR` | `data/dem` | DEM 보관 폴더 | -| `SPIPE_DEM_KEEP` | 8 | 보관할 DEM 개수 | -| `EPANET_LIBRARY_PATH` | `64bit/epanet2.dll` | EPANET 라이브러리 경로 | - -비밀값 원칙: - -- API 키·토큰은 저장소에 커밋하지 않습니다. -- 지도 서비스 키는 `.env.local`(커밋 제외)에 넣습니다. `.env.example`을 복사해 채우고 다시 빌드합니다. - - `VITE_VWORLD_API_KEY`: 브이월드 배경지도 - - `VITE_KAKAO_JS_KEY`: 카카오 주소 검색 (콘솔의 JavaScript SDK 도메인에 접속 주소 등록 필요) -- 이 키들은 빌드된 화면 코드에 포함되어 브라우저에 노출되므로, 각 콘솔에서 사용 도메인을 제한합니다. -- 이전 커밋 기록에는 키가 남아 있습니다. 저장소를 공개하려면 키를 재발급합니다. -- 실무 관망 INP, HWP·PDF 보고서, 화면 캡처는 커밋하지 않습니다 (`.gitignore` 참고). - -## 8. 사내 서버 배포 - -### Windows 서버 PC (현재 운영 방식) - -현재 배포본은 데모 v2 (2026-10-30, 이전 배포 데모 v1 2026-10-15)입니다. 변경 내역은 `docs/SPipe_패치내역_v2_2026-10-30.txt`를 확인하고, (시험)으로 표시된 기능은 기존 방식과 결과를 비교해 사용합니다. - -저장소의 파일(또는 배포용 압축 파일 `SPipe_server_*.zip`)을 서버 PC의 SPipe 폴더에 덮어쓰고 다음 순서로 실행합니다. 기존 `.venv`, `node_modules`, `data`와 `.env.local`은 유지합니다. 최초 설치 절차는 `SERVER_SETUP.md`를 따릅니다. - -1. 새 라이브러리 설치 (데모 v2에서 scipy, rasterio 등이 추가되어 반드시 실행) - -```powershell -.\.venv\Scripts\python.exe -m pip install -r backend\requirements.txt -``` - -2. 화면을 다시 빌드하면서 서버 실행 (`-Rebuild` 없이 실행하면 예전 화면이 남음) - -```powershell -powershell -ExecutionPolicy Bypass -File .\start-lan.ps1 -Rebuild -``` - -- 웹 화면: `http://<서버 IP>:8080` (사내망 공개) -- 해석 API: `127.0.0.1:8000` (서버 내부 전용, 웹 서버가 `/api`만 전달) -- 코드 갱신 후에는 반드시 `-Rebuild`로 화면을 다시 빌드합니다. - -### Docker (nginx + API) - -```bash -docker compose up -d --build -``` - -- 구성: `compose.yaml`, `deploy/Dockerfile`, `deploy/nginx.conf` -- DEM 보관 폴더는 컨테이너의 `/app/data/dem` (필요하면 볼륨으로 유지) -- 업로드 한도를 바꿀 때는 환경변수와 nginx 설정을 함께 바꿉니다. - -배포 전 확인: - -```powershell -git status -``` - -```powershell -npm run typecheck -``` - -```powershell -npm test -``` - -```powershell -npm run test:api -``` - -```powershell -npm run build -``` - -## 9. 문제 해결 순서 - -1. 브라우저 주소가 `127.0.0.1:5173`(개발)인지 `<서버 IP>:8080`(사내)인지 확인합니다. -2. `/api/health`가 `{"status":"ok"}`를 돌려주는지 확인합니다. 아니면 해석 API가 꺼진 상태입니다. -3. 해석 오류는 메시지의 `Error 2xx` 줄(EPANET 입력 오류)을 먼저 확인합니다. -4. 지도가 엉뚱한 곳에 그려지면 상단 좌표계 설정과 GIS 레이어의 원본 좌표계를 확인합니다. -5. 새 기능이 화면에 안 보이면 `start-lan.ps1 -Rebuild`로 다시 빌드했는지 확인합니다. -6. DEM·GIS 기능이 서버 오류를 내면 `pip install -r backend\requirements.txt`를 다시 실행했는지 확인합니다. -7. 인터넷 표고(90m)·OSM 건물·배경지도만 실패하면 사용자 PC의 외부 인터넷 차단 여부를 확인합니다. - -자료가 이상하다고 관망 파일이나 백업을 지우지 않습니다. 먼저 프로젝트 메뉴 > 백업 기록과 실행 취소로 되돌릴 수 있는지 확인합니다. - -## 10. 상세 문서 목차 - -- `SERVER_SETUP.md`: 다른 Windows PC를 사내 서버로 설치하는 절차 -- `deploy/README.md`: Docker·nginx 배포 -- `docs/SPipe_패치내역_v2_2026-10-30.txt`: 데모 v2 변경 내역 (공지·첨부용) -- `public/EXAMPLE_NETWORKS.md`: 예제 관망 설명 -- `_worklog.md`: 배포본 등록·변경 작업 기록 - -## 11. 저장소 구조 - -``` -src/ React 웹 앱 - App.tsx 상태와 화면 조립 - inpModel.ts INP 파싱·생성, 편집 함수 - inpExtras.ts 다중 수요·수질·에너지 등 구조화 섹션 - worker.ts WASM 해석 (Web Worker) - Map.tsx 지도 표시·편집 (MapLibre) - *Section.tsx 분석 탭 화면 (편집 도구, DEM, GIS, 최적화 ...) - *Tools.ts 분석·편집·GIS 순수 로직 (Node 테스트 대상) -backend/ FastAPI 해석 API - main.py API 진입점 - epanet.py EPANET DLL ctypes 바인딩 - batch.py, jobs.py 일괄 해석 프레임워크와 분석 Job - gisio.py, gisops.py GIS 입출력·연산 (GDAL) - dem.py DEM 보관·표고·지형 타일·유역 - blocksys/ 블록 분할 CLI - tests/ pytest -64bit/ EPANET 2.3.5 DLL -public/ 예제 관망 (Net1~3, 한글 CP949, 합성망) -tests/ Node 회귀 테스트 -deploy/ Dockerfile, nginx.conf -data/ 서버 실행 중 생성 (DEM 보관, 커밋 제외) -``` +# SPipe + +## 프로젝트 개요 + +웹 브라우저에서 쓰는 상수도 관망 수리해석·관리 플랫폼. +EPANET 2.3.5 엔진으로 관망을 해석하고, GIS·DEM·자산 정보를 한 화면에서 함께 다룬다. + +주요 기능: + +- EPANET INP 관망 불러오기·편집·해석 (Native DLL과 WASM 두 엔진 교차 검증) +- 지도 기반 관망 편집 (절점·관로·밸브·펌프, 꺾임점, 분할·병합) +- 해석 결과 지도·그래프·종단·보고서, 실측 보정 +- 분석 도구: 소화전 모의, 관로 중요도, 급수 구역, VSP, 등치선, 에너지 비용, 자동 보정, 펌프 운전 최적화 +- GIS 연동: SHP·DXF·DGN·MIF·GML·KML·GPKG 불러오기·내보내기, 좌표계 변환, 도형 연산 +- DEM 기반 절점 표고 입력·검증, 유역·하천 분석, 3D 보기 +- 프로젝트 파일(.spipe), 시나리오, 자동 백업 + +## 웹 기반으로 만드는 이유 + +### 기존 운영 방식 + +설치형 관망해석 프로그램(EPANET 등)을 PC마다 설치하고, 관망 파일·GIS 자료·DEM·엑셀 자료를 파일 단위로 주고받으며 작업하는 구조. + +### 기존 문제 + +- PC마다 프로그램 설치·버전 관리 필요 +- 관망 INP, GIS 레이어, 표고 자료, 자산 대장이 서로 다른 프로그램·파일에 분산 +- 같은 관망을 여러 사람이 볼 때 파일 사본이 늘어나고 최신본 확인이 어려움 +- 수리해석 결과를 지도·자산 정보와 함께 보려면 여러 프로그램을 오가야 함 + +### 웹 기반 통합의 필요성 + +사내망 서버 한 곳에 해석 엔진과 GIS 처리를 두고, 사용자는 브라우저로 접속해 같은 기능을 쓴다. +관망 모델(INP)을 기준으로 GIS·DEM·자산 정보를 연결해 하나의 작업 흐름으로 관리한다. + +### 기대 효과 + +- 설치 없이 브라우저 접속만으로 사용 +- 관망·지도·표고·자산 정보를 한 화면에서 확인 +- 해석 결과를 두 엔진으로 교차 검증해 신뢰도 확보 +- 분석 결과를 표준 형식(INP, SHP, GPKG, CSV)으로 내보내 기존 업무와 연계 + +## 핵심 용어 + +| 용어 | 의미 | +|---|---| +| INP | EPANET 관망 입력 파일. SPipe 관망 모델의 원본 형식 | +| 절점 / 링크 | 접합점·배수지·탱크(절점)와 관로·펌프·밸브(링크) | +| EPS | 연장 기간 해석. 시간대별 수요 패턴에 따라 여러 시점을 해석 | +| Native / WASM 엔진 | 서버의 EPANET DLL과 브라우저의 epanet-js. 같은 관망을 둘 다 해석해 결과를 비교 | +| 시나리오 | 원본 관망에서 갈라져 나온 대안 관망 | +| 자산 속성 | INP에 없는 관재질·설치년도·매설깊이·소블록 등 관리 정보 | +| DEM | 수치표고모델. 절점 표고 입력과 유역 분석에 사용 | +| 일괄 해석(Job) | 관로 중요도·소화전 모의처럼 해석을 여러 번 반복하는 서버 작업 | +| .spipe | 관망·시나리오·GIS 레이어·스타일·보정 자료를 묶은 프로젝트 파일 | + +## 처리 흐름 + +``` +INP 불러오기 또는 GIS 레이어로 관망 만들기 + ↓ +지도에서 관망 편집 · 자산 속성 · DEM 표고 입력 + ↓ +수리해석 (Native DLL + WASM 동시 실행, 결과 비교) + ↓ +결과 확인 (지도 · 그래프 · 종단 · 보고서 · 실측 보정) + ↓ +분석 도구로 검토 (중요도 · 급수 구역 · 소화전 · 최적화 ...) + ↓ +INP · SHP · 엑셀 · .spipe 로 저장·공유 +``` + +핵심 원칙: + +- 관망 모델의 원본은 INP 구조이며, 편집은 모두 INP로 다시 생성 가능한 형태로 저장 +- INP에 없는 정보(자산 속성, 화면 설정)는 별도 저장소에 두고 요소 ID로만 연결 +- 해석 결과는 엔진 출력이 원본이며, 화면은 단위 변환만 수행 +- 모든 편집은 실행 취소(Ctrl+Z) 가능 + +이 문서는 저장소의 시작점입니다. 상세 설계와 점검 기록은 별도 문서에 두고, 여기에는 실행·검증·배포 순서와 문서 선택 기준을 정리합니다. + +--- + +## 1. 빠른 시작 + +### 로컬 실행 (Windows) + +필요 조건: + +- Node.js 24.x (검증 버전 24.14.1) +- Python 3.12 64비트 +- EPANET 2.3.5 (`64bit/epanet2.dll` 포함) + +```powershell +npm install +py -3.12 -m venv .venv +.\.venv\Scripts\python.exe -m pip install -r backend\requirements.txt pytest httpx +``` + +가장 간단한 실행 방법은 `start-spipe.bat` 더블클릭입니다. 해석 API(8000)와 웹 개발 서버(5173)를 함께 띄우고 브라우저를 엽니다. 종료는 `stop-spipe.bat`. + +수동 실행: + +```powershell +npm run api +``` + +```powershell +npm run dev +``` + +접속 주소: + +- Web: http://127.0.0.1:5173 +- 해석 API: http://127.0.0.1:8000 +- API 상태 확인: http://127.0.0.1:8000/api/health + +지도 서비스 키 설정 (`.env.example`을 `.env.local`로 복사해 값 입력. 없으면 배경지도·주소 검색만 동작하지 않음): + +```powershell +Copy-Item .env.example .env.local +``` + +개발 서버는 `127.0.0.1`에만 바인딩됩니다. 사내망에 공개할 때는 아래 "8. 사내 서버 배포"를 따릅니다. + +### 로컬 검증 + +```powershell +npm run typecheck +``` + +```powershell +npm test +``` + +```powershell +npm run test:api +``` + +```powershell +npm run build +``` + +- `npm test`: 모델·단위·비교 로직, 편집·분석 도구 회귀 테스트 (Node 테스트) +- `npm run test:api`: FastAPI·EPANET DLL·GIS·DEM 테스트 (pytest) + +CI는 `.github/workflows/ci.yml` (windows-latest). + +## 2. 서비스 구조 + +``` +브라우저 + │ + ▼ +Web (React + Vite) 지도·편집·결과 화면, WASM 해석(Web Worker) + │ /api 프록시 + ▼ +해석 API (FastAPI) EPANET DLL(ctypes) 해석, 일괄 해석, GIS·DEM 처리 + ├─▶ 64bit/epanet2.dll EPANET 2.3.5 엔진 (프로세스 풀) + ├─▶ GDAL (pyogrio, rasterio) 벡터·래스터 입출력 + └─▶ data/dem 업로드한 DEM 보관 + +외부 연동(브라우저에서 직접 호출): 브이월드 배경지도 · 카카오 주소 검색 · Open-Meteo 표고(90m) · OpenStreetMap 건물 +``` + +| 구성요소 | 책임 | 기본 포트 | +|---|---|---| +| `src/` Web | 관망 편집, 결과 표시, WASM 해석, 엔진 결과 비교 | 5173 개발 / 8080 사내 | +| `backend/` 해석 API | 해석, 일괄 분석 Job, GIS 변환·연산, DEM | 8000 (내부 전용) | +| `64bit/epanet2.dll` | EPANET 2.3.5 엔진 | - | +| `data/dem/` | 서버 DEM 보관 (최근 8개) | - | + +## 3. 데이터와 원본 원칙 + +관망의 원본은 **INP 구조**입니다. 화면 편집은 내부 모델(`src/inpModel.ts`)을 바꾸고, 해석·저장 시 항상 INP로 다시 생성합니다. + +INP로 저장되는 것: + +- 절점·관로·펌프·밸브, 패턴·곡선·컨트롤·규칙, 해석 옵션 +- 다중 수요, 이미터, 수질·수원, 탱크 혼합, 에너지, 초기 상태, 반응 계수, 지도 라벨 +- 관로 꺾임점(`[VERTICES]`) — 이름 변경·삭제·분할·방향 전환을 따라감 + +INP 밖에 별도로 두는 것: + +- 자산 속성(관재질·설치년도·매설깊이·소블록 등): 요소 ID로 연결, `.spipe`에 함께 저장 +- 화면 설정(레이어 스타일·범례·라벨): `.spipe`에 저장 +- DEM 원본: 서버 `data/dem`에 보관, 브라우저에는 식별자만 보관 + +원칙: + +- 해석 결과는 엔진 출력을 그대로 쓰고, 화면은 표시 단위 변환만 수행 +- 재생성한 INP가 원본 INP와 같은 해석 결과를 내는지 회귀 테스트로 확인 +- 실무 관망 원본 파일(INP)은 저장소에 커밋하지 않음 + +## 4. 해석 흐름 + +1. 사용자가 해석 실행을 누르면 현재 모델로 INP를 생성합니다. +2. 같은 INP를 서버(Native DLL)와 브라우저(WASM)에서 동시에 해석합니다. +3. 두 결과를 시간대별·요소별로 비교해 허용오차 안에서 일치하는지 표시합니다 (`src/comparisonEngine.ts`). +4. EPANET 경고 코드(1~6)와 비정상 압력을 별도로 점검해 표시합니다 (`src/convergence.ts`). +5. 분석 탭의 일괄 해석(관로 중요도, 소화전, 보정 등)은 서버 Job으로 실행합니다 (`backend/jobs.py`). + +관련 구현 위치: + +- INP 파싱·생성: `src/inpModel.ts`, `src/inpExtras.ts` +- 서버 해석: `backend/main.py`, `backend/epanet.py` +- 일괄 해석 프레임워크: `backend/batch.py`, `backend/jobs.py` +- WASM 해석: `src/worker.ts` + +## 5. 주요 기능 사용 가이드 + +### 관망 편집 + +상단 [편집] 모드에서 절점·관로를 추가하고 지도에서 끌어 옮깁니다. 관로를 선택하면 꺾임점 핸들이 나타나며, 주황 점을 끌면 이동, 흰 점을 끌면 추가, 더블클릭하면 삭제됩니다. 속성창 아래 "추가 속성"에서 다중 수요·이미터·수질·탱크 혼합·펌프 에너지를 편집합니다. + +### 결과 확인 + +[결과] 창에서 표·시계열·누적 빈도·종단(시간별)·실측 보정을 확인합니다. 표의 행을 누르면 지도가 해당 요소로 이동합니다. + +### 분석 탭 + +| 분석 | 내용 | +|---|---| +| 소화전 모의 | 시간대별 소화 유량 추가 해석, 확보 가능 유량 | +| 관로 중요도 | 관로를 하나씩 닫아 영향 절점·수요 순위 | +| 급수 구역 | 배수지별 공급 비율 추적 | +| 흐름 방향 | 역류·무흐름 관로 | +| VSP | 목표 압력용 시간별 펌프 회전수 | +| 등치선 | 압력·동수두·표고 등치선 | +| 에너지 비용 | 펌프별 가동률·효율·원단위·전력비 | +| 관로 통계 | 관경·재질·설치 연대별 집계 | +| 자동 보정 (시험) | 실측값으로 그룹별 C값 배율·관벽 계수 추정 | +| 펌프 운전 최적화 (시험) | 압력·탱크 조건을 지키는 저비용 운전 일정 | +| 편집 도구 | 이동·회전·2점 보정, 분할, 절점 병합, 관로 점검, 추적 | +| 지형(DEM) | DEM 표고 입력·검증, 인터넷 90m 표고, TIN, 유역·하천, 3D | +| GIS 도구 | 레이어 좌표계·내보내기, 도형 연산, 밸브·계량기·소블록 반영 | + +### 저장과 백업 + +프로젝트 메뉴에서 `.spipe`로 저장하면 관망·시나리오·레이어·보정 자료가 한 파일에 담깁니다. 수정 중에는 10분마다 브라우저에 자동 백업되며(최근 30개), 프로젝트 메뉴 > 백업 기록에서 복원합니다. + +## 6. API + +브라우저는 Web 서버의 `/api` 프록시를 통해 해석 API를 호출합니다. 해석 API 포트는 외부에 공개하지 않습니다. + +| 메서드 | 경로 | 설명 | +|---|---|---| +| GET | `/api/health` | 상태 확인 | +| POST | `/api/analyze` | multipart `file`(.inp) → 전체 EPS 해석 결과 JSON (`?format=columnar` 압축 형식) | +| POST | `/api/jobs/{name}` | 일괄 해석: `fireflow`, `criticality`, `servicearea`, `vsp`, `energy`, `calibrate`, `pumpschedule` | +| POST | `/api/gis/vector` | GDAL 벡터 파일 → WGS84 GeoJSON | +| POST | `/api/gis/export` | 레이어 → SHP·GPKG·DXF·GeoJSON·KML (좌표계 지정) | +| POST | `/api/gis/op` | 버퍼·병합·잘라내기·차이·보로노이·격자 | +| POST | `/api/gis/reproject` | 레이어 좌표계 다시 지정 | +| POST | `/api/dem` | DEM 업로드 (GeoTIFF·ASC·IMG, zip) | +| GET | `/api/dem/{id}/preview.png` | DEM 음영 미리보기 | +| GET | `/api/dem/{id}/terrain/{z}/{x}/{y}.png` | 3D 지형 타일 (terrarium) | +| POST | `/api/dem/{id}/sample` | 지점 표고 (쌍선형 보간) | +| POST | `/api/dem/{id}/hydro` | 하천선 추출 / 유역 | +| POST | `/api/dem/from-points` | 점 표고로 DEM 생성 (TIN) | + +해석 결과의 필드 정의는 `src/types.ts`의 `SimulationResult`를 기준으로 합니다. 오류는 `{"detail": "..."}` 형식입니다. + +| 상태 | 의미 | +|---|---| +| 400 | 입력 형식 오류 (확장자, 파라미터, 좌표계) | +| 413 | 업로드 한도 또는 해석 규모 상한 초과 | +| 500 | EPANET 입력·해석 오류 | +| 504 | 해석 시간 초과 | + +## 7. 환경변수와 비밀값 + +| 변수 | 기본값 | 의미 | +|---|---|---| +| `SPIPE_MAX_UPLOAD_MB` | 20 | INP·GIS 업로드 한도. nginx `client_max_body_size`와 맞출 것 | +| `SPIPE_MAX_DEM_MB` | 300 | DEM 업로드 한도. nginx `location /api/dem`과 맞출 것 | +| `SPIPE_ANALYZE_TIMEOUT_S` | 120 | 해석 1건 시간 제한 | +| `SPIPE_JOB_TIMEOUT_S` | 900 | 일괄 해석 1건 시간 제한 | +| `SPIPE_MAX_PERIODS` | 10000 | 수리 스텝 수 상한 | +| `SPIPE_MAX_RESULT_CELLS` | 50000000 | (노드+링크) × 스텝 상한 | +| `SPIPE_WORKERS` | min(4, CPU-1) | 해석 프로세스 수 | +| `SPIPE_DEM_DIR` | `data/dem` | DEM 보관 폴더 | +| `SPIPE_DEM_KEEP` | 8 | 보관할 DEM 개수 | +| `SPIPE_BASE_DEM_DIR` | `data/base_dem` | 서버 기본 DEM 폴더 (정리되지 않음) | +| `EPANET_LIBRARY_PATH` | `64bit/epanet2.dll` | EPANET 라이브러리 경로 | + +비밀값 원칙: + +- API 키·토큰은 저장소에 커밋하지 않습니다. +- 지도 서비스 키는 `.env.local`(커밋 제외)에 넣습니다. `.env.example`을 복사해 채우고 다시 빌드합니다. + - `VITE_VWORLD_API_KEY`: 브이월드 배경지도 + - `VITE_KAKAO_JS_KEY`: 카카오 주소 검색 (콘솔의 JavaScript SDK 도메인에 접속 주소 등록 필요) +- 이 키들은 빌드된 화면 코드에 포함되어 브라우저에 노출되므로, 각 콘솔에서 사용 도메인을 제한합니다. +- 이전 커밋 기록에는 키가 남아 있습니다. 저장소를 공개하려면 키를 재발급합니다. +- 실무 관망 INP, HWP·PDF 보고서, 화면 캡처는 커밋하지 않습니다 (`.gitignore` 참고). + +## 8. 사내 서버 배포 + +### Windows 서버 PC (현재 운영 방식) + +현재 배포본은 데모 v2 (2026-10-30, 이전 배포 데모 v1 2026-10-15)입니다. 변경 내역은 `docs/SPipe_패치내역_v2_2026-10-30.txt`를 확인하고, (시험)으로 표시된 기능은 기존 방식과 결과를 비교해 사용합니다. + +저장소의 파일(또는 배포용 압축 파일 `SPipe_server_*.zip`)을 서버 PC의 SPipe 폴더에 덮어쓰고 다음 순서로 실행합니다. 기존 `.venv`, `node_modules`, `data`와 `.env.local`은 유지합니다. 최초 설치 절차는 `SERVER_SETUP.md`를 따릅니다. + +1. 새 라이브러리 설치 (데모 v2에서 scipy, rasterio 등이 추가되어 반드시 실행) + +```powershell +.\.venv\Scripts\python.exe -m pip install -r backend\requirements.txt +``` + +2. 화면을 다시 빌드하면서 서버 실행 (`-Rebuild` 없이 실행하면 예전 화면이 남음) + +```powershell +powershell -ExecutionPolicy Bypass -File .\start-lan.ps1 -Rebuild +``` + +- 웹 화면: `http://<서버 IP>:8080` (사내망 공개) +- 해석 API: `127.0.0.1:8000` (서버 내부 전용, 웹 서버가 `/api`만 전달) +- 코드 갱신 후에는 반드시 `-Rebuild`로 화면을 다시 빌드합니다. + +서버 기본 DEM 등록 (선택, 최초 1회): 국토지리정보원 DEM 등을 서버에 한 번 등록해 두면 사용자가 파일을 올리지 않고 분석 → 지형(DEM)의 "서버 DEM" 버튼으로 바로 씁니다. DEM 파일은 저장소·배포 압축에 들어 있지 않으므로 서버마다 등록합니다. + +```powershell +.\.venv\Scripts\python.exe -m backend.dem register "C:\경로\한반도.zip" korea-90m "국토지리정보원 DEM 90m (비영리·변경금지)" +``` + +이름(두 번째 값)은 영문 소문자·숫자·`-`·`_`만 씁니다. 자료의 이용 조건(국토지리정보원 90m는 CC BY-NC-ND)을 확인하고 등록하세요. + +### Docker (nginx + API) + +```bash +docker compose up -d --build +``` + +- 구성: `compose.yaml`, `deploy/Dockerfile`, `deploy/nginx.conf` +- DEM 보관 폴더는 컨테이너의 `/app/data/dem` (필요하면 볼륨으로 유지) +- 업로드 한도를 바꿀 때는 환경변수와 nginx 설정을 함께 바꿉니다. + +배포 전 확인: + +```powershell +git status +``` + +```powershell +npm run typecheck +``` + +```powershell +npm test +``` + +```powershell +npm run test:api +``` + +```powershell +npm run build +``` + +## 9. 문제 해결 순서 + +1. 브라우저 주소가 `127.0.0.1:5173`(개발)인지 `<서버 IP>:8080`(사내)인지 확인합니다. +2. `/api/health`가 `{"status":"ok"}`를 돌려주는지 확인합니다. 아니면 해석 API가 꺼진 상태입니다. +3. 해석 오류는 메시지의 `Error 2xx` 줄(EPANET 입력 오류)을 먼저 확인합니다. +4. 지도가 엉뚱한 곳에 그려지면 상단 좌표계 설정과 GIS 레이어의 원본 좌표계를 확인합니다. +5. 새 기능이 화면에 안 보이면 `start-lan.ps1 -Rebuild`로 다시 빌드했는지 확인합니다. +6. DEM·GIS 기능이 서버 오류를 내면 `pip install -r backend\requirements.txt`를 다시 실행했는지 확인합니다. +7. 인터넷 표고(90m)·OSM 건물·배경지도만 실패하면 사용자 PC의 외부 인터넷 차단 여부를 확인합니다. + +자료가 이상하다고 관망 파일이나 백업을 지우지 않습니다. 먼저 프로젝트 메뉴 > 백업 기록과 실행 취소로 되돌릴 수 있는지 확인합니다. + +## 10. 상세 문서 목차 + +- `SERVER_SETUP.md`: 다른 Windows PC를 사내 서버로 설치하는 절차 +- `deploy/README.md`: Docker·nginx 배포 +- `docs/SPipe_패치내역_v2_2026-10-30.txt`: 데모 v2 변경 내역 (공지·첨부용) +- `public/EXAMPLE_NETWORKS.md`: 예제 관망 설명 +- `_worklog.md`: 배포본 등록·변경 작업 기록 + +## 11. 저장소 구조 + +``` +src/ React 웹 앱 + App.tsx 상태와 화면 조립 + inpModel.ts INP 파싱·생성, 편집 함수 + inpExtras.ts 다중 수요·수질·에너지 등 구조화 섹션 + worker.ts WASM 해석 (Web Worker) + Map.tsx 지도 표시·편집 (MapLibre) + *Section.tsx 분석 탭 화면 (편집 도구, DEM, GIS, 최적화 ...) + *Tools.ts 분석·편집·GIS 순수 로직 (Node 테스트 대상) +backend/ FastAPI 해석 API + main.py API 진입점 + epanet.py EPANET DLL ctypes 바인딩 + batch.py, jobs.py 일괄 해석 프레임워크와 분석 Job + gisio.py, gisops.py GIS 입출력·연산 (GDAL) + dem.py DEM 보관·표고·지형 타일·유역 + blocksys/ 블록 분할 CLI + tests/ pytest +64bit/ EPANET 2.3.5 DLL +public/ 예제 관망 (Net1~3, 한글 CP949, 합성망) +tests/ Node 회귀 테스트 +deploy/ Dockerfile, nginx.conf +data/ 서버 실행 중 생성 (DEM 보관, 커밋 제외) +``` diff --git a/_worklog.md b/_worklog.md index 1e03b49..288ffa4 100644 --- a/_worklog.md +++ b/_worklog.md @@ -1,19 +1,28 @@ -# SPipe 작업 기록 - -## 2026-10-30 데모 v2 배포본 등록 - -- 원본: `SPipe_server_2026-10-30.zip` (파일 181개). 압축은 저장소에 올리지 않고 풀어서 등록 -- 변경 내역: `docs/SPipe_패치내역_v2_2026-10-30.txt` (이전 배포 데모 v1, 2026-10-15) -- 등록 제외 - - `backend/temp.bin`, `backend/temp.inp`: 해석 중 생기는 임시 파일 - - `.env.local`, 배포 전달 메모: 브이월드·카카오 API 키 포함 - - 실데이터(상리 INP), HWP, 화면 캡처, 테스트 DEM: 배포본에 포함되지 않음 -- README: 원본 README에 데모 v2 서버 업데이트 순서를 추가하고, 저장소에 없는 문서 목차를 정리 -- 서버 반영: 기존 폴더에 덮어쓰기(`.venv`·`node_modules`·`data`·`.env.local` 유지) → `pip install -r backend\requirements.txt` → `start-lan.ps1 -Rebuild` -- 남은 일: 서버 PC IP 확정 시 카카오 JavaScript SDK 도메인에 `http://<서버 IP>:8080` 추가 - -## 2026-10-30 예전 프로그램 이름 표기 정리 - -- 실행 파일 이름을 `start-spipe.bat`, `stop-spipe.bat`로 변경 (README·실행 안내 문구 함께 수정) -- README, `public/EXAMPLE_NETWORKS.md`, 코드 주석, CSS 머리말, 시험 임시 폴더 접두어의 예전 이름을 SPipe 또는 "상용 관망 프로그램"으로 변경 -- 그대로 둔 것: 브라우저 저장 키, 세션 DB 이름, 복사·붙여넣기 표시의 예전 접두어. 바꾸면 사용자의 저장된 설정·세션이 초기화되므로 이전(마이그레이션) 방식을 정한 뒤 변경 +# SPipe 작업 기록 + +## 2026-10-30 데모 v2 배포본 등록 + +- 원본: `SPipe_server_2026-10-30.zip` (파일 181개). 압축은 저장소에 올리지 않고 풀어서 등록 +- 변경 내역: `docs/SPipe_패치내역_v2_2026-10-30.txt` (이전 배포 데모 v1, 2026-10-15) +- 등록 제외 + - `backend/temp.bin`, `backend/temp.inp`: 해석 중 생기는 임시 파일 + - `.env.local`, 배포 전달 메모: 브이월드·카카오 API 키 포함 + - 실데이터(상리 INP), HWP, 화면 캡처, 테스트 DEM: 배포본에 포함되지 않음 +- README: 원본 README에 데모 v2 서버 업데이트 순서를 추가하고, 저장소에 없는 문서 목차를 정리 +- 서버 반영: 기존 폴더에 덮어쓰기(`.venv`·`node_modules`·`data`·`.env.local` 유지) → `pip install -r backend\requirements.txt` → `start-lan.ps1 -Rebuild` +- 남은 일: 서버 PC IP 확정 시 카카오 JavaScript SDK 도메인에 `http://<서버 IP>:8080` 추가 + +## 2026-10-30 예전 프로그램 이름 표기 정리 + +- 실행 파일 이름을 `start-spipe.bat`, `stop-spipe.bat`로 변경 (README·실행 안내 문구 함께 수정) +- README, `public/EXAMPLE_NETWORKS.md`, 코드 주석, CSS 머리말, 시험 임시 폴더 접두어의 예전 이름을 SPipe 또는 "상용 관망 프로그램"으로 변경 +- 그대로 둔 것: 브라우저 저장 키, 세션 DB 이름, 복사·붙여넣기 표시의 예전 접두어. 바꾸면 사용자의 저장된 설정·세션이 초기화되므로 이전(마이그레이션) 방식을 정한 뒤 변경 + +## 2026-11-06 도면 출력 추가 + +- 변경 내역: `docs/SPipe_패치내역_도면출력_2026-11-06.txt` (이전 배포 데모 v2, 2026-10-30) +- 기준: 데모 v2 이후 개발 PC에서 추가한 변경만 옮김. 이 저장소의 이름 변경(`start-spipe.bat` 등)과 README 정리는 그대로 유지 +- 주요 내용: 수리 종단면도·관망도(색인도 + 부분도, 수압표) 도면 출력, 범례 양식·색상 선택, DXF(AutoCAD 2018), 서버 기본 DEM, DEM 등고선, 속성 테이블 범위 선택, WNTR 교차 검증 시험 +- 새 라이브러리: Python `ezdxf`(DXF), npm `maplibre-contour`(등고선). 서버 반영 시 `pip install -r backend\requirements.txt`와 `npm install` 후 `start-lan.ps1 -Rebuild` +- 확인: `npm run typecheck`, `npm test`(109개), `npm run test:api`(75개), `npm run build` 통과 +- 그대로 둔 것: 브라우저 저장 키의 예전 접두어(`gispipe_`). 새 도면 설정 키는 `spipe_` 접두어 사용 diff --git a/backend/dem.py b/backend/dem.py index 2cbe982..896b48b 100644 --- a/backend/dem.py +++ b/backend/dem.py @@ -27,12 +27,24 @@ from .batch import BatchError DEM_DIR = Path(os.environ.get("SPIPE_DEM_DIR", Path(__file__).resolve().parents[1] / "data" / "dem")) DEM_KEEP = int(os.environ.get("SPIPE_DEM_KEEP", "8")) +# Server-provided DEMs (e.g. the national 90 m DEM), registered once with +# `python -m backend.dem register