chore(요구): 요구서 345 — D 예정노선 · E 안정성평가 요구서 · 분석 넷(등록권한공유 · 틀노선추천 · 내보내기양식 · 안정성평가제안)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-25 18:43:02 +09:00
co-authored by Claude Opus 5.5
parent d8d68605b9
commit 9c86243d1e
5 changed files with 828 additions and 0 deletions
@@ -0,0 +1,184 @@
# 345-A 분석 — 프로젝트 등록 · 권한 · 공유 (D 예정노선 · E 안정성평가)
근거 원문 = `docs/raw/요구_1025/사용자요구_1025.md:56-96` (요구 345)
역할 이름 = 예정노선을 만드는 사용자는 「산림청」(사용자 정정 · 판정은 메일 `*.go.kr`)
---
## ① 결론 다섯 줄
1. 프로젝트 생성은 B01 프로젝트 구역의 [+] 세 자리(역할별)에서 B02 한 화면 · API `POST /api/b02/project` 한 길뿐임. `projects` 표에 종류/그룹 칸이 없고 임도 전용 값이 강제됨(`road_type` 은 `main|fire|work` 만 · 사업연도는 정수 하나).
2. 역할은 `SYSTEM_ADMIN`·`ADMIN`·`USER` 셋뿐임. 「산림청」 역할과 `go.kr` 판정은 없음. 다만 세션에 email 이 이미 실려 있어 도메인 판정은 DB 칸 없이 한 줄로 됨(가입 때 OTP 로 메일 확인을 거치므로 믿을 만함).
3. 회사 밖 공유와 보기 전용 판정이 없음. 프로젝트 접근 판정은 `require_project_access` 한 곳(같은 회사만 통과)이고 같은 회사 안에서는 B03~B09 쓰기 때 참여자 여부도 안 봄. 그래서 D 업체 공유는 이 한 곳에 「공유 행이 있으면 GET 만 통과」 한 갈래를 더하면 끝남.
4. 메일은 공용 `send_email`(SMTP · HTML · 재시도)이 있어 완료 메일에 그대로 씀. 첨부가 안 되므로 노선 · 좌표 파일은 링크로 보내거나 함수에 첨부 인자를 더해야 함. 앱 안 알림함 표는 없음.
5. 복제 도구 `tools_clone_project.py` 는 CLI 전용이라 서버에서 import 할 수 없음(모듈 맨 위 argparse · robocopy · 원본 사용자 폴더에 복사). 다만 표 차례와 id 다시 잇기 규칙은 E 「생성 시점 복사」에 그대로 쓸 만함 — 본체를 공용 함수로 떼어 내야 함. D→임도는 노선 CSV 한 벌만 B03 입력에 넣으면 되므로 복제가 필요 없음(임시 보관함 attach 길을 본보기로 씀). 「원본 바뀜」 감지 칸은 없어 지문 칸을 새로 둠.
---
## ② 항목별 현황 (근거 파일:줄)
### 1. 프로젝트 생성 진입점
- [+] 버튼 — `B01_Dashboard/B01_Dashboard_UI_Page.ts:263`(시스템관리자) · `:297`(회사관리자) · `:310`(일반 사용자). 셋 다 `navigateTo(ROUTES.B02_PROJ_REGISTER)` 임. 모달이나 고르기 화면 없이 곧장 B02 로 감.
- 등록 화면 칸 — `B02_ProjRegister/B02_ProjRegister_UI_Page.ts`
- 칸: 프로젝트명 :44-48 · 사업지역 :49-53 · 임도종류 3종(select) :57-64 · 사업연도(단일 숫자 · 기본 올해 · 2000~올해+5) :65-72 · 노선 시작/종료 누가거리 :75-86 · 비고 :87-91
- 도면 표제란 칸: 시행청 :95 · 설계일자 :98 · 과업책임자·분야별책임자·설계자 :100-105(회사 구성원 목록 :109-126)
- 배치 :281-297 · 보내기 :233-256 · 성공하면 현재 프로젝트를 기억하고 B03 으로 감 :270-272
- 프로젝트명 자동입력 — `B02_ProjRegister/B02_ProjRegister_UI_Name.ts:18-96`. 조각 셋(year · region · type)을 글자마다 주인을 기억하며 조합함. 사용자가 손댄 뒤에는 그 조각 구간만 갈아 끼움. 화면 연결은 `B02_ProjRegister_UI_Page.ts:131-168`. 조각 값이 문자열이라 D 는 year 자리에 「2026~2030」 을 넣으면 그대로 씀.
- 저장 API — `B02_ProjRegister/B02_ProjRegister_Router.py:16-71` `POST /api/b02/project`
- `require_company` 로 막음 :20 · 시작 < 종료 검사 :43-48 · 담당자는 같은 회사만 :50
- 저장소 `B02_ProjRegister_Repository.py:55-154`: UUID 를 새로 받음 :70 · storage 경로 :25-31 · INSERT :79-116 · 만든 사람을 참여자로 넣음 :118-121 · 단계 7개 시드 :123(`common_util/common_util_workflow_state.py:12-41`) · 감사 기록 :125-132 · 폴더 · workflow.json · manifest · M02 양식 복사 :34-52
- 요청 스키마 `B02_ProjRegister_Schema.py:15` road_type 정규식 `^(main|fire|work)$` · `:16` project_year 정수 하나
- projects 표 — `db_management/001_create_schema.sql:177-193`
- 칸: id · user_id · company_id(NOT NULL) · name · region · road_type · project_year INT · estimated_length_m · memo · status · crs_epsg · storage_path
- 뒤에 더해진 칸: `011_title_block.sql:19-23` · `012_title_block_inputs.sql:13-15` · `013_company_assets.sql:15-18` · `015_route_range.sql:12-16`(route_start_m · route_end_m)
- 외래키 user · company RESTRICT :498-502
- 종류/그룹 칸 — **없음**. `road_type` 은 임도 종류이고 B05 법정 기준이 읽음(`B05_Profile/B05_Profile_PageSettings.py:54-61` · `B05_Profile_Router_Replan.py:175` · `B05_Profile_Router_Lifecycle.py:175`).
- 이관 규칙 — 마이그레이션은 손으로 돌림(자동 실행기 없음) · 다음 번호는 `020` · 「4환경 공유 DB」 라 칸 추가만 하고 지우지 않음(`013_company_assets.sql:11` · `014_company_logo.sql:14`).
### 2. 사용자 · 역할 · 회사
- 역할 — `users.role ENUM('SYSTEM_ADMIN','ADMIN','USER')` `004_dashboard.sql:14-15`. 옛 값 MASTER/MEMBER 는 `_role()` 이 바꿔 읽음 `B01_Dashboard/B01_Dashboard_Repository.py:19-20`. 화면 타입은 `B01_Dashboard_Api_Fetch.ts:12` · 표시 이름은 `B01_Dashboard_UI_Common.ts:21-24`.
- 시스템관리자 판정 — `.env` 의 관리자 메일 계정과 그 회사 소속 전원을 서버 기동 때 SYSTEM_ADMIN 으로 맞춤 `main.py:238-250` · 회사에 붙을 때 역할 `B01_Dashboard_Repository.py:23-44`.
- 「산림청」 역할 · `go.kr` 판정 — **없음**(코드 전체 검색 0건). 가입 메일은 EmailStr 형식 검사만 함 `A07_Register/A07_Register_Schema.py:7`. 가입 · 로그인 때 OTP 로 메일을 확인하므로 도메인은 믿을 만함.
- 세션 정보 — `common_util/common_util_auth.py:128-136` 에 email · role · company_id · is_master 가 실림 → 도메인 판정에 DB 조회가 더 필요 없음.
- 회사 표 — `001_create_schema.sql:51-68`(name UNIQUE · business_registration_number UNIQUE · company_code NOT NULL · status · subscription_status) · 회사를 만들 때 사업자번호가 필수 `B01_Dashboard/B01_Dashboard_Schema.py:31-35`.
- 사용자-회사 관계 — `users.company_id` 하나(`001:37`) · 가입 직후 `NO_COMPANY`(`003_register_split.sql:14-16`) · 가입 신청 `join_requests`(`001:103-113`) · 팀원 붙이기 `B01_Dashboard_Repository_Members.py:55-84`.
- 프로젝트 권한 구조
- 목록: 회사 소속이면 회사 프로젝트 전부 `B01_Dashboard_Router.py:141-150`(`list_company_projects` `B01_Dashboard_Repository.py:209-225`) · 시스템관리자는 전부 `B01_Dashboard_Router.py:580-585`
- 수정 · 삭제: `_can_edit_project` `B01_Dashboard_Router.py:85-93`(시스템관리자는 전부 · 회사관리자는 같은 회사 · 일반은 같은 회사이면서 참여자일 때) · 화면 쪽 짝 `B01_Dashboard_UI_Helper.ts:3-13`
- 참여자 표 `project_members` `016_project_members.sql:12-22` · 같은 회사 사람만 `B01_Dashboard_Repository_Members.py:117-128`
- B03~B09 API: `main.py:454-458` `protected_with_company` → `require_project_access` `common_util/common_util_auth.py:173-203`(프로젝트 company_id 가 세션 회사와 같아야 함 · 시스템관리자는 통과) — 참여자 여부와 읽기/쓰기를 가리지 않음
- 화면 길 가드: `A00_Common/router.ts:206-222`(회사가 없으면 B01 로 · 시스템관리자는 예외)
- `projects.company_id` 가 NOT NULL 이라(`001:180`) 「산림청」 사용자도 기관 「회사」에 붙어 있어야 프로젝트를 만들 수 있음.
### 3. 프로젝트 공유
- 회사 밖 공유 표 · API — **없음**(`project_shares` 같은 것 0건). 코드의 「공유」는 회사 안 도면 자산(로고 · 서명, `013_company_assets.sql`)을 뜻함.
- 보기 전용 판정 — **없음**. 화면의 viewOnly 는 B07 미리보기 CAD 같은 부품 수준뿐임(`B07_DesignDetail/B07_DesignDetail_UI_PlanManage.ts:192`). B07 읽기 전용 깃발은 늘 거짓(`B07_DesignDetail_UI_Page.ts:86`).
- 앱 안 알림함 표 — 없음.
### 4. 메일 보내기
- 공용 함수 — `common_util/common_util_email.py:25-64`: smtplib · HTML 본문 · 재시도(지수 대기) · `send_email`(await) / `send_email_background`. **첨부 없음**(`add_alternative` 만 씀 :31).
- 설정 — `config/config_system.py:259-271`(SMTP 칸 · 실제 값은 `.env`).
- 쓰는 곳 — 가입 · 로그인 OTP(`A07_Register_Router.py:66` · `A06_Login_Router.py:54`) · 팀원 초대(`B01_Dashboard_Router.py:286-308`, 본문 escape 본보기) · 분석 완료 메일(`B03_FileInput/B03_FileInput_Email.py:112-337`, HTML 틀 `_email_shell` :39).
- 템플릿 — `common_util/common_util_email_templates.py:6-70`.
### 5. storage 폴더 구조 · 복제 도구
- 경로 규칙 — `storage/{company_id}/{user_id}/{project_uuid}`(`B02_ProjRegister_Repository.py:25-31`). DB 의 `storage_path` 는 상대 경로이고 해석은 `common_util/common_util_storage.py:103-122`. 해석할 때마다 B 단계 폴더를 만들어 줌 :121.
- 단계 폴더 허용 목록 — `config/config_system.py:205-215`(B03~B09 만) · 레이아웃 `common_util_storage.py:12-22`.
- 실측(한 프로젝트 `storage/1/3/dad81824…`) — B03 1.6G · B04 1.3G(processed 1.1G) · B05 18M · B06 1.8M · initial_snapshot 98M · templates 11M · _derived 4M → 통째로 복사하면 약 3GB.
- 지울 때 안전 규칙 — 4 마디 · 마지막 마디가 프로젝트 id 여야 함 `common_util_storage.py:78-100`.
- 복제 도구 `db_management/tools_clone_project.py`
- DB(:10-12 · :167-325): projects · project_members · input_files · processed_point_cloud · surface_models · terrain_layers · routes · route_points · route_statistics · longitudinal_sections · cross_sections · project_workflow_stages. 자동증가 id 는 새로 받고 외래키를 새 id 로 다시 이음 · 단계 params 안의 input_file_id · surface_model_id 도 고침 :314-324
- 파일: 폴더 통째 robocopy `/E /MT:8` :76-96 · 파일을 먼저 복사하고 DB 는 한 트랜잭션 :232-326
- 치환: json 안 옛 UUID → 새 UUID :99-110 · `initial_snapshot/db.json` 의 surface_model_id :112-123
- 한계: ① 모듈 맨 위에서 argparse 를 돌려(:59) import 할 수 없음 ② 새 폴더가 원본과 같은 회사/사용자 폴더(:229-230) ③ robocopy 는 Windows 전용 ④ projects 행은 이름만 바꾸고 company_id · user_id 는 원본 그대로(:238-243) ⑤ 감사 기록 · manifest 갱신 없음 ⑥ structures · quantity_items · outputs DB 표는 안 뜸(정본이 파일이라 지금은 문제없음)
- 백업 도구 `db_management/tools_project_backup.py:28-` TABLES — 표 목록과 부모-자식 차례의 두 번째 출처.
- 초기값 스냅샷 `common_util/common_util_initial_snapshot.py:41-56` — 정본 파일 자리 목록(B05 route · B06 종횡단 · B04 drainage) → E 가 「B06까지」만 가볍게 뜰 때 쓸 파일 목록 후보.
- E 재활용 판정 — 표 목록 · id 다시 잇기 · UUID 치환은 그대로 씀. 본체만 `common_util` 함수로 떼고 새 주인 · 새 회사 · 새 폴더(`storage/{새 회사}/{새 사용자}/{새 id}`) 를 받게 고침. D→임도 연결 복사에는 쓰지 않음(노선 한 벌뿐이라).
### 6. B03_FileInput
- 받는 확장자 — `config/config_frontend.ts:52-67`(.csv .shp .shx .dbf .cpg .las .laz .tif .tfw .prj .dxf) · 카드는 최대 10장 :40.
- 업로드 검사 — `B03_FileInput/B03_FileInput_Router.py:136-200`: 노선 .shp/.csv 를 정확히 1개 :182-190 · LAS 1개 이상(las_free 가 아닐 때) :172-179. 필수 목록은 `B03_FileInput_Router_Helpers.py:104-156`(prj · tfw + 노선 + las · shp 이면 shx · dbf · route_prj).
- 노선 CSV 칸 — `route_name, sequence, x, y, z, crs_epsg` `B03_FileInput_Engine_Analyze.py:395` · 검증 :418-501(노선 하나 · sequence 는 1부터 이어짐 · EPSG 한 값 · 2점 이상).
- shapefile 판독 — `B03_FileInput_Engine_Shapefile.py:155-258`.
- 저장 자리 — `{project}/B03_FileInput/input/{확장자}/…`(실측 폴더 las · prj · shp · tfw · tif) · DB `input_files`(상대 경로 `B03_FileInput_Router.py:235-248`) · `B03_FileInput/metadata.json` :275-276.
- 설계가 읽는 자리 — `find_planned_route_file` `common_util/common_util_route_geometry.py:200-214`(input 아래 *.shp 우선 → *.csv · 가장 최근 것) → `load_design_route` :266 → 자동 체인 `B03_FileInput_Service_Chain.py:157-248`(route_start_m · route_end_m 범위로 먼저 자름 :219-225).
- 다른 출처를 꽂을 자리(본보기) — 임시 보관함 attach
- 화면: `B03_FileInput_UI_Page.ts:63` `createTempPicker` · 흐름 `B03_FileInput_UI_Page_Flow.ts:120-140`
- 서버: `B03_FileInput_Router_Temp.py:361-434` `POST /api/projects/{id}/temp-uploads/{batch}/attach` — 분석 중이면 막음 → 옛 결과 지우기 확인 → 파일 이동 → input_files 등록 → WF1 · 자동 체인
- 예정노선 가져오기는 이 흐름에서 「노선 카드만」 채움. 지형(LAS · prj · tfw)은 여전히 업체가 올림(las_free 이면 도엽 기반).
- 줄 수 주의 — `B03_FileInput_UI_Page.ts` 가 692줄이라 새 코드는 새 파일로 둠(700줄 제한).
### 7. 페이지 라우팅 · 메뉴
- 화면 주소 상수 — `config/config_frontend.ts:94-123` ROUTES · 보호 목록 :132-147.
- 지연 로더 표 — `A00_Common/router.ts:27-75` · 워크플로 가드(로그인 + 회사) :192-222 · 현재 프로젝트 화면 :108-117 · 꼬리말 없음 `A00_Common/main.ts:34-48`.
- 초안 길(파일 하나로 길 추가) — `router.ts:77-98` 이 `../*/draft/*_Route.ts` 를 glob 함 · `DraftRoute{path, workflow, project, footerless, load}` · 본보기 `B09_Estimation/draft/B09_Draft_Print_Route.ts:9-15`. 폴더 이름이 `D01_*` 여도 이 패턴에 걸림(정식 길은 ROUTES 에 넣음).
- 백엔드 — `main.py:26-84` import · `:445-519` include_router(B 페이지는 `protected_with_company` :454-458). 초안 라우터 자동 끼움은 B09 안에만 있음 `B09_Estimation_Router.py:382-404`.
- vite — `vite.config.ts:19-65`. root 가 A00_Common 이고 페이지 폴더는 import 로 닿으므로 폴더를 따로 등록하지 않음.
- 대시보드 단계 배지 — `B01_Dashboard_UI_Projects.ts:56-68` · `WORKFLOW_STEP_ROUTES` `A00_Common/b_workflow_nav.ts:30-38` · 단계 이름 `A00_Common/b_page_scaffold.ts:139-149` — B 단계 7개로 고정되어 있음.
- 새 D0x · E0x 를 붙일 때 손댈 곳 — `config_frontend.ts` ROUTES · PROTECTED_ROUTES / `router.ts` routeTable · workflowRoutes · PROJECT_ROUTES / `main.ts` FOOTERLESS / `main.py` import · include_router / `config_system.py:205` PROJECT_STORAGE_STAGE_DIRS / `common_util_storage.py:12` 레이아웃 / `common_util_workflow_state.py:12` STAGE_KEYS(종류별) / `b_workflow_nav.ts:30` · `b_page_scaffold.ts:139` 단계표 / `ui_template/ui_template_locale_*.ts` 문구 / `B01_Dashboard_UI_Projects.ts` 종류 열 · 클릭 행선지.
- 고르기 카드 부품 — 그림 + 제목 카드 공용 부품은 없음 · 모달은 `ui_template/ui_template_modal.ts:28` `openModal` 을 씀.
### 8. 원본 바뀜 감지
- `projects.updated_at`(ON UPDATE, `001:190`) — 행을 고칠 때만 움직이고 파일 정본이 바뀔 때는 안 움직임 → 쓸 수 없음.
- `project_versions` 표(`001:196-204`) — 있으나 코드에서 안 씀(백업 도구만 언급).
- 재사용할 지문 부품 — `derived_key`(json 조각의 sha1) · `file_stamp`(mtime:크기) `common_util/common_util_derived_store.py:21-34`.
- B03 업로드 지문(크기 + 앞 · 중간 · 끝 8MB) `B03_FileInput_Fingerprint.ts:1-30` · 서버 대조 `B03_FileInput_Router_Helpers.py:165-191` · `input_files.metadata.fingerprint`.
- 판번호 본보기 — 구조물 정본 `revision` / `base_revision` `B05_Profile/B05_Profile_Structures_Schema.py:193 · 270-283`.
- B05 추천 저장본 fingerprint `B05_Profile/B05_Profile_Engine_RouteInitial_Store.py:71-117`.
- 「원본 바뀜 → 연결본에 알림」 용 칸은 없음.
---
## ③ 새로 만들 것 목록
### DB (마이그레이션 `020_project_groups.sql` · 추가만)
- `projects` 칸 추가
- `project_kind VARCHAR(20) NOT NULL DEFAULT 'ROAD'` — ROAD(임도) · PLAN(예정노선) · EROSION(사방 · 자리만) · STABILITY(안정성평가). 기존 행은 ROAD
- `project_year_end INT NULL` — 예정노선 사업연도 범위의 끝(시작은 기존 `project_year`)
- `source_project_id CHAR(36) NULL` · `source_copied_at DATETIME NULL` · `source_fingerprint CHAR(40) NULL` — E 원본 / 임도의 D 연결 원본 · 복사 시점 · 복사 때 지문
- `plan_route_years` (예정노선 연도별 구간) — `project_id` · `year` · `start_x/y` · `end_x/y` · `route_json`(분석 결과 노선) · `fingerprint` · `confirmed_at` · PK(project_id, year). 직전 연도의 종점 = 다음 연도의 시점은 저장할 때 서버가 맞춤
- `plan_route_assignees` (연도별 지정 업체) — `id` · `project_id` · `year` · `company_id NULL`(아이슬로 등록 회사) · `company_name` · `email`(수기) · `notified_at` · `linked_project_id NULL`(등록 회사가 연결한 임도 프로젝트)
- (선택) `project_links` 를 따로 두지 않고 위 `source_*` 칸 + `plan_route_assignees.linked_project_id` 로 끝냄
### API
- `POST /api/b02/project` 를 넓힘 — `project_kind` 를 받음 · PLAN 은 「산림청 / 시스템관리자」만 · STABILITY 는 `source_project_id` 필수(같은 회사 + stage 3 SECTION COMPLETE)
- 판정 함수 `common_util_auth.py` 에 `is_forest_service(session)` = 시스템관리자 또는 `email.lower().endswith(".go.kr")`
- `require_project_access` 한 곳에 갈래 추가 — 다른 회사여도 `plan_route_assignees` 에 그 회사가 있으면 GET 만 통과 · 그 밖 메서드는 403
- `GET /api/dashboard/plan-routes/assigned` — 우리 회사에 지정된 예정노선(연도 · 노선 · 연결 상태 · 업데이트 있음 깃발)
- `PUT /api/d0x/{id}/assignees` (업체 지정) · `POST /api/d0x/{id}/finalize` (확정 → 메일 + 등록 회사 목록에 뜸)
- `POST /api/projects/{임도 id}/plan-route/import` — 예정노선 연도 노선을 B03 입력 CSV(`route_name,sequence,x,y,z,crs_epsg`)로 쓰고 input_files 행 등록 · `source_*` 채움(B03 attach 흐름과 같은 옛 결과 지우기 확인을 거침)
- `POST /api/dashboard/plan-routes/{assignee id}/link` — 새 임도 프로젝트 만들기 또는 기존 것에 연결(둘 다 위 import 를 부름)
- E 생성 안 — 공용 복사 함수 `common_util/common_util_project_copy.py`(복제 도구 본체를 옮김 · CLI 는 이것을 부르는 껍데기로 남김)
- 메일 — `send_email` 을 그대로 씀(첨부를 하려면 `attachments` 인자 추가)
### 화면
- B01 [+] 세 자리 → 고르기 모달(예정노선 · 임도설계 · 사방설계 · 안정성평가 네 카드, 그림 + 제목) · 산림청이 아니면 예정노선 카드를 흐리게 · 사방은 「준비 중」
- 등록 화면 — 임도는 지금 B02 그대로 · 예정노선 등록(사업연도 범위 · 사업지역 · 종류 「노선 계획」 하나 · 프로젝트명은 B02 이름 조합기를 다시 씀 · 노선 시작/종료 누가거리 · 도면 칸 없음) · 안정성평가 등록(대상 임도 프로젝트 고르기 = B06 완료만)
- B01 프로젝트 표에 종류 열 · 행을 누르면 종류별 첫 화면으로 · 「받은 예정노선」 구역(보기 · 연결 · 업데이트 있음 배지)
- B03 노선 카드 옆 [예정노선에서 가져오기] — `B03_FileInput_UI_TempPicker.ts` 를 본보기로 새 파일
- D01_* · E01_* 페이지 폴더(라우팅 등록은 ② 7항 목록)
---
## ④ 정할 거리
1. **「산림청」 판정 범위** — 갈래 ㉮ 메일 `*.go.kr` 만(지자체 · 다른 부처도 들어옴) ㉯ 산림청 메일(`forest.go.kr`)만 ㉰ 시스템관리자가 계정에 깃발을 켬. → 권함: ㉮(사용자 원문 그대로 · DB 칸 없음) · 이름만 「산림청」. 산림조합처럼 `go.kr` 이 아닌 발주처가 생기면 ㉰ 를 덧붙임.
2. **산림청 사용자의 「회사」** — `projects.company_id` NOT NULL · 회사를 만들 때 사업자번호가 필수임. 갈래 ㉮ 기관을 회사로 등록(고유번호를 사업자번호 칸에) ㉯ company_id NULL 허용. → 권함: ㉮(스키마 · 권한 코드를 그대로 씀).
3. **종류 칸 자리** — ㉮ `projects.project_kind` 새 칸 ㉯ `road_type` 에 값을 섞음. → 권함: ㉮(road_type 은 B05 법정 기준이 읽음 · 섞으면 깨짐).
4. **사업연도 범위** — ㉮ `project_year`(시작) + `project_year_end` 새 칸 ㉯ 문자열 하나. → 권함: ㉮.
5. **예정노선을 보기만 하는 사람의 범위** — ㉮ 지정된 등록 회사의 구성원 전부 ㉯ 그 회사 관리자만. → 권함: ㉮(지금 회사 프로젝트 목록 규칙과 같음).
6. **완료 메일 내용** — ㉮ 노선 · 좌표 파일 첨부(`send_email` 에 첨부 인자 추가) ㉯ 내려받기 링크만(수기 업체는 로그인이 없어 열쇠 붙은 링크가 필요). → 권함: ㉮ 첨부(수기 업체도 바로 받음 · 링크용 열쇠 관리가 필요 없음).
7. **D→임도 「복사」 범위** — ㉮ 그 연도 노선 CSV 한 벌만 B03 입력에 넣음 ㉯ D 가 받은 수치지형도까지 복사. → 권함: ㉮(원문 「좌표값과 노선데이터」 · 지형은 업체가 올림).
8. **「업데이트 있음」 판정** — ㉮ 연도 구간마다 노선 지문(`derived_key`)을 두고 연결 때 지문과 비교 ㉯ 확정 횟수 판번호. → 권함: ㉮(내용이 같으면 알림 없음 · 부품이 이미 있음).
9. **E 복사 범위** — ㉮ 폴더 통째(약 3GB · 복제 도구 그대로) ㉯ B03 원본 LAS(1.6G) · B07~B09 를 빼고 B04 모델 · B05 · B06 · initial_snapshot + DB 표만. → 권함: ㉯(원문 「자원이 많이 듦」 · 안정성 평가는 지표면 · 노선 · 횡단만 읽음). 단, 무엇을 읽을지는 E 로직이 정해지기 전이라 E 분석과 함께 확정함.
10. **E 대상 프로젝트 범위** — ㉮ 같은 회사 프로젝트 ㉯ 내가 참여자인 것만. → 권함: ㉮(지금 접근 규칙과 같음).
11. **공유 보기 전용 막는 자리** — ㉮ `require_project_access` 한 곳에서 「공유 회사는 GET 만」 ㉯ 라우터마다. → 권함: ㉮(모든 B · D 길이 지나는 한 점).
12. **D 단계 · 폴더 이름** — ㉮ `D01_PlanBase`(1단계 기준 지정) · `D02_PlanAnalysis`(2단계 분석) · `D03_PlanConfirm`(확정 · 업체 · 내보내기) ㉯ 한 폴더에 다 둠. → 권함: ㉮(원문 1~4절과 짝 · DXX_XXX 형식).
---
## ⑤ 계획 걸음 후보 (무엇 · 어디 · 무엇으로 확인)
1. 종류 칸 · 연도 끝 · 원본 칸 추가 — `db_management/020_project_groups.sql` — 랩탑 DB 에 적용 후 `SHOW COLUMNS FROM projects` · 기존 행이 ROAD 인지.
2. 「산림청」 판정 함수 — `common_util/common_util_auth.py` — 새 지킴 시험(go.kr · 대문자 · 하위 도메인 · 아닌 메일).
3. B02 API 가 `project_kind` 를 받고 PLAN · STABILITY 를 검사 — `B02_ProjRegister_Router.py` · `_Schema.py` · `_Repository.py` — 시험: 일반 사용자가 PLAN 을 만들면 403 · STABILITY 원본이 B06 미완료면 400.
4. 종류별 단계 시드 · 폴더 허용 목록 — `common_util_workflow_state.py` · `config_system.py:205` · `common_util_storage.py:12` — 시험: PLAN 프로젝트에 D 단계 행 · D 폴더가 생김.
5. [+] 고르기 모달 · 네 카드 — `B01_Dashboard/` 새 파일 + `B01_Dashboard_UI_Page.ts:263·297·310` — ORCA 로 세 역할 각각 모달 · 카드 상태 확인.
6. 예정노선 등록 화면 — 새 `D01_*` 폴더(이름 조합기 `B02_ProjRegister_UI_Name.ts` 를 다시 씀) + 라우팅 등록 — ORCA 로 등록 → DB 행 · 이름 자동입력 확인.
7. 공유 표 · 보기 전용 판정 — `020` 에 `plan_route_assignees` · `require_project_access` 한 갈래 — 시험: 공유 회사 GET 200 · PUT 403 · 미지정 회사 403.
8. 받은 예정노선 구역 · 종류 열 — `B01_Dashboard_Router.py` 새 GET + 화면 — ORCA 로 지정 회사 계정에서 보임 · 지정 안 된 회사에서 안 보임.
9. 노선 가져오기 → B03 입력 CSV — 새 `B03_FileInput_Router_PlanImport.py` + 새 화면 파일 — 시험: 쓴 CSV 가 `analyze_planned_route_csv` 를 통과 · input_files 행 · `source_*` 칸.
10. 업데이트 있음 깃발 — 지문 비교(`derived_key`) — 시험: D 노선을 고치면 깃발이 켜지고 같은 값으로 되돌리면 꺼짐.
11. 완료 메일 — `common_util_email.py` 첨부 인자 + 템플릿 — 시험: EMAIL_NOTIFICATION_ENABLED 를 끈 상태에서 메시지 조립 · 첨부 이름 확인.
12. 공용 복사 함수 · E 생성 — `common_util/common_util_project_copy.py`(복제 도구 본체를 옮기고 CLI 는 껍데기) — 시험: 임시 storage 사본(`resources/tester/helper_temp_storage.py`)에서 복사 → 새 id 표 · 파일 안 UUID 치환 · 원본 그대로.
@@ -0,0 +1,172 @@
# 345-B 분석 — D 예정노선 페이지 틀 · 지도 · 수치지형도 · 노선 추천 · 측점 · 횡단 · 3D
- 원문: `docs/raw/요구_1025/사용자요구_1025.md:56-96` (요구 345 D-2 · D-3)
- 원칙: B 그룹 임도설계 코드 재활용. 아래 표기 — **[그대로]** = B 함수를 손대지 않고 부름 · **[인자]** = B 함수에 선택 인자 하나 더함(B 호출은 그대로) · **[이동]** = 파일 자리만 공용으로 옮김 · **[새로]** = B 에 없어 새로 만듦
- 경로는 저장소 뿌리 기준
## ① 결론 다섯 줄
1. **틀** — B05~B09 틀(`createWorkflowLayout` + 패널 손잡이 + 단계 막대)은 단계 목록 · 경로를 인자로 받아 D 페이지가 [그대로] 씀. 새 페이지는 `D0x_*/draft/*_Route.ts` 한 파일로 길이 붙음(정적 경로표 손 안 댐). B 에 묶인 곳은 아이콘 7개 · [<][>] 경로표 · 도움말 이름 규칙 세 줄뿐임.
2. **지도** — 카카오맵 끌기 표지 · 누름 · 선 그리기는 B08 `editMap` 에 이미 있음 → D02 가 [그대로] 부름(키 길도 project_id 만 봄). 좌표 입력칸 · WGS84↔TM 점 변환 공용 함수는 B 에 없음 → [새로](pyproj 한 줄짜리).
3. **수치지형도** — VWorld 1:5,000 도엽 zip → 레이어 병합 → 등고선 1 m DEM 이 모두 경로 인자 함수라, 업로드 없이 D 지점만으로 [그대로] 돎. 「더 받기」는 `prune_sheets` 만 안 부르면 합집합으로 늘어남. 단, 지점 사이 도엽 메우기는 [새로]이고, 긴 다년 노선은 메모리 · 비용면 한도(4M 칸) 때문에 DEM 을 연도 구간별로 만들어야 함.
4. **노선 추천** — 엔진 `generate_initial_route(점 목록, Terrain, 계류, …)` 는 DB · 세션 · 파일이 없는 순수 함수이고 시점 · 종점을 옮기지 않음 → 연도 구간마다 한 번씩 불러 이으면 연도 경계가 정확히 맞물림. 경유점 강제 통과 기능은 없음(구간 나눔으로 대신함). 프로젝트 묶임은 라우터 · 로더에만 있어서, D 라우터가 얇게 감싸고 B 쪽은 지형 로더에 [인자] 둘만 더함.
5. **측점 · 횡단 · 3D** — `buildStations` · `sectionsGround`(B05/logic), `drawStationTicks` · `stationAtScreen`, `buildCrossSvg(design=null)`, `createRouteViewer`+`renderRoute`(코리도 안 부름)로 설계 단면 없이 지반선 횡단 · 3D 가 됨. 지형 API(미리보기 · 격자 · 등고선 · 위성 지도)는 project_id + `surface_models` 행으로 찾음 → D 프로젝트가 `projects` 표에 있고 지형을 `B04_PreProcess/` 배치로 두면 [그대로] 씀.
## ② 항목별 현황
### 1. 페이지 틀
- 틀 본체: `createWorkflowLayout(options)` `ui_template/ui_template_workflow_layout.ts:198-258` — `steps` · `routes` · `stages` · `leftPanel` · `mainContent` · `onStepClick` 을 인자로 받음(옵션 정의 `:22-37`).
- 좌측 제목 패널 · 진행 패널 = `createWorkflowOverlays` `ui_template/ui_template_overlay.ts:248-286`
- 단계 막대 = `createStepBar` `ui_template_workflow_layout.ts:65-190` (🏠 단추 `:79-94`)
- [<][>] = `ui-step-nav` 이벤트 → 이웃 단계 단추 누름 `ui_template_workflow_layout.ts:239-245`
- 우 · 상 · 하 패널은 틀 밖에서 페이지마다 `createWorkflowPanelHandle` `ui_template/ui_template_overlay.ts:38` 로 붙임(우 배수 `B05_Profile/B05_Profile_UI_Drainage_Chrome.ts:59` · 하 종단 `A00_Common/design/design_profile_frame.ts:21` · 상 평면 `A00_Common/design/design_plan_peek.ts:30`). 우측 묶음 패널 = `createSidePanels` `ui_template/ui_template_side_panels.ts:69`.
- 페이지 쓰는 법 본보기: B08 `B08_Quantity/B08_Quantity_UI_Page.ts:160-178` · B09 `B09_Estimation/B09_Estimation_UI_Shell.ts:350-362`(B09 는 [>] 를 덮어씀 `:369-384`).
- B 에 묶인 곳(D 가 쓰려면 손볼 곳):
- 아이콘 7개 고정 `ui_template_workflow_layout.ts:63` · `:211` 에서 옵션 없이 박아 넣음 → [인자] `icons?`
- [<][>] 경로표가 B05~B09 뿐 `ui_template/ui_template_help.ts:27-33` · 도움말 이름 `#/b0N` `:35-38` · 서버 `^B0[2-9]$` `common_util/common_util_help_router.py:17` → D 경로 한 줄씩
- 틀이 B01 API 를 import `ui_template_workflow_layout.ts:8`(역할 확인용 · D 에도 무해)
- 프로젝트 이름 표가 B workflow-state 를 읽음 `ui_template/ui_template_overlay.ts:148-164` → 345-A 의 종류별 단계 시드가 들어오면 그대로 맞음
- 단계 목록은 세 곳에 하드코딩: 경로 `A00_Common/b_workflow_nav.ts:30-38` · 이름 `A00_Common/b_page_scaffold.ts:139-149` · 서버 `common_util/common_util_workflow_state.py:12-20`. D 는 같은 꼴의 D 목록을 따로 둠(B 목록은 안 건드림).
- B05/B06 한 페이지 틀(`A00_Common/design/design_page.ts` · `design_panel.ts` · `design_dock.ts`)은 B06 저장소를 import 하고 보기가 `"profile" | "cross"` 둘로 고정(`design_dock.ts:15`) → D 는 이 묶음이 아니라 위 공용 틀을 씀.
- 새 페이지 하나 붙일 때 손댈 곳:
- 화면 길: `D0x_*/draft/D0x_*_Route.ts` 에 `ROUTE` 선언만 — 라우터가 `../*/draft/*_Route.ts` 를 자동으로 줍음 `A00_Common/router.ts:79-95` (본보기 `B09_Estimation/draft/B09_Draft_Print_Route.ts:9-15`)
- 우클릭 막기 · 돋보기가 `b|m` 경로만 봄 `ui_template/ui_template_native_menu.ts:11` · `ui_template/ui_template_loupe.ts:37` → `d` 한 글자 더함
- 글자: `ui_template/ui_template_locale_d1.ts` 새 파일 + `ui_template/ui_template_locale.ts:22-30,58-68` 에 펼침
- 서버: `main.py:26-84` import + `:445-519` `include_router(…, dependencies=protected_with_company)` — 회사 판정 `common_util/common_util_auth.py:173-203` 은 project_id 만 봄 → D 프로젝트도 통과
- storage 단계 폴더 허용 목록 `config/config_system.py:205-215` · `common_util/common_util_storage.py:12-22` (345-A 와 겹침)
### 2. 지도 · 좌표
- 카카오맵은 B08 거리 이정표에만 있음.
- SDK 적재 `loadKakaoMaps(projectId)` `B08_Quantity/B08_Quantity_UI_Milestone_KakaoMap.ts:61-92` · 키 = `GET /api/projects/{id}/quantity/milestone/map-key` `B08_Quantity/B08_Quantity_Router_Milestone.py:684-687`(환경변수 이름 `KAKAO_JS_KEY` · storage 안 읽음)
- 고르는 지도 `editMap(projectId, {onMove, onClick, center, hint})` `KakaoMap.ts:112-120` → `set(pins, lines)` `:105-110` · 표지 `MapPin{key,name,lon,lat,movable,fixed}` `:95-103` · 끌기 `draggable` + `dragend → onMove(key, lon, lat)` `:173-178` · 지도 누름 `onClick(lon, lat)`
- 묶임: B08 `request` 를 `B08_Quantity_UI_Hydro` 에서 import `KakaoMap.ts:14` · CSS 이름 `b08-milestone__map` `:121`
- 다른 지도: B04/B05 평면 = 자체 Canvas2D + VWorld 위성 PNG 한 장(`GET /{pid}/vworld-map` `B04_PreProcess/B04_PreProcess_Router_GIS.py:66`) · 그리기 부품 `B04_PreProcess/B04_PreProcess_UI_MapRender.ts`(`metricToScreen` `:343` · `computeRouteView` `:193` · `drawPreparedLayer` `:555`). `maplibre-gl` 은 설치만 되고 안 씀(`package.json:24`).
- 좌표 입력칸(경위도 · TM X/Y)은 어디에도 없음 → [새로].
- 좌표 변환:
- 파이썬 공용 `common_util/common_util_crs.py` 는 좌표계 고르기만 함 — `resolve_project_crs(project_root, …)` `:231-262`(사다리 끝 폴백 `EPSG:5186`) · `find_project_prj` `:130-168`(자리 `B03_FileInput/input/prj/`). **점 변환 공용 함수 없음** — 쓰는 곳마다 `pyproj.Transformer` 를 새로 만듦(예 `B08_Quantity_Router_Milestone.py:218-229` `_lonlat` · `B04_PreProcess/B04_PreProcess_Engine_Extent.py:32` `_to_target_crs`).
- TS 는 proj4 없음 — 지도 메타 상자 사이 직선 비례(`lonLatToScreen` `B04_PreProcess_UI_MapRender.ts:326`)뿐이라 좌표 입력 정밀 변환에는 못 씀.
### 3. 수치지형도 받기 · DEM
- API: VWorld. 1:5,000 도엽(SHP v2.0 zip)은 VWorld 내부 지도 서비스(검색 `getDisitalMapList.do` · 내려받기 `digitalDownload.do`, 로그인 세션 필요) `B04_PreProcess/B04_PreProcess_Engine_SheetStore.py:6-13,72-143`. 환경변수 이름 `VWORLD_LOGIN_ID` · `VWORLD_LOGIN_PW` · `VWORLD_SESSION_COOKIE` `config/config_system.py:144-147`.
- 참고(보안): 위성 · WFS 용 VWorld 키는 환경변수가 아니라 소스에 박혀 있음 `B04_PreProcess/B04_PreProcess_Engine_VWorld.py:22-29` · `B04_PreProcess/B04_PreProcess_Engine_GisVector.py:17-22` (값은 적지 않음).
- 받는 단위: **도엽 번호**. 기준 좌표마다 그 도엽 + 주변 8매 `neighbors_for_points(points_latlon)` `B04_PreProcess/B04_PreProcess_Engine_MapSheet.py:109-123` (기준만 `sheets_for_points` `:93`). 1:5,000 도엽 한 장 ≈ 2.8 km × 2.3 km.
- B 의 흐름 `download_geodata(project_root, processed_dir, bounds, prj_dir, rebuild, …)` `B04_PreProcess/B04_PreProcess_Engine.py:397-554`:
- 기준 좌표 = B03 노선 CSV 의 시점 · 종점 두 개 `B04_PreProcess_Engine_Extent.py:177-206` (CSV 자리 고정 `:17`)
- `ensure_sheets(store, sheet_nos)` `SheetStore.py:185` → **`prune_sheets(store, keep)`** `SheetStore.py:233` 가 목록 밖 zip 을 지움 `Engine.py:527` → `parse_and_merge_sheets(store, sheets, processed_dir)` `SheetParser.py:69` (열쇠 = 도엽 목록 `Engine.py:530-550`)
- 저장 자리: `<root>/B04_PreProcess/processed/map_sheets/{번호}.zip` + `map_sheets_index.json` · `도엽_{등고선,하천중심선,표고점,…}.geojson`(EPSG:4326) `SheetParser.py:27-36`
- DEM: `build_sheet_surface_model(project_root, processed_dir, models_dir, route_xy, crs, methods)` `B04_PreProcess/B04_PreProcess_Engine_SheetSurface.py:476-` — 노선 정점 상자 + 300 m(`SHEET_SURFACE_MARGIN_M` `config/config_system_terrain.py:139`)를 1 m 격자로 등고선 굽기 → 보간(자동은 laplace `config_system_terrain.py:157`). 산출 `models/dtm_sheet_{방식}.npz` · `_preview.glb` · `_smooth.npz` · `.key.json`(열쇠에 노선 해시 `:436`). 격자 칸 수 상한 없음.
- 업로드 없이 도는가: B 의 「LAS 없는 길」 `run_sheet_surface_analysis` `SheetSurface.py:585-660` 은 **B03 노선 파일을 꼭 요구**함(`load_design_route` 실패 시 ValueError `:612-614`). 그러나 그 안에서 부르는 `neighbors_for_points` · `ensure_sheets` · `parse_and_merge_sheets` · `build_sheet_surface_model` 은 모두 경로 · 배열 인자뿐 → D 가 지점 좌표로 직접 부르면 업로드 없이 돎.
- 위성 배경 `download_vworld_satellite_map(prj_path, bounds, output_dir, …)` `B04_PreProcess_Engine_VWorld.py:72-` 는 **.prj 파일**을 요구함 → D 작업 좌표계 .prj 한 장을 써 두면 [그대로].
- B05 가 읽는 것: `models/dtm_{filter}[_smooth].npz` → 2 m 비용면 캐시 `<root>/B05_Profile/route/cost_surface_*.npz` `B05_Profile/B05_Profile_Engine_Solver.py:42-44,214-257` · 계류 `processed/도엽_하천중심선.geojson` `B05_Profile/B05_Profile_Engine_RouteInitial.py:160`.
- 영역 늘려 받기: B 에는 기능 없음(재실행 = 시점 · 종점 두 점 기준으로 다시 고르고 나머지는 지움). 그러나 `ensure_sheets` 는 이미 있는 zip 을 건너뜀 `SheetStore.py:185-201` → **합집합 목록으로 부르고 prune 을 안 부르면** 늘려 받기가 됨. 병합 · DEM 은 열쇠가 바뀌면 다시 셈.
- 빈틈 둘(D 에서 새로 막을 것):
- 지점이 서로 3 km 넘게 떨어지면 두 3×3 묶음 사이 도엽이 빔 → 지점 사이 직선을 1 km 간격으로 표본해 기준 좌표에 넣음 [새로 · 몇 줄]
- 다년 노선 전체 상자 한 벌이면 1 m 격자가 수천만 칸이 되고, 비용면은 2 m 에서 400만 칸 넘으면 오류 `B05_Profile_Engine_Solver.py:188-193`(`ROUTE_MAX_COST_CELLS` `config/config_system_design.py:33`) → DEM 은 연도 구간별
### 4. B05 노선 추천 엔진
- 진입: `POST /api/projects/{id}/route/initial` → `compute_initial` `B05_Profile/B05_Profile_Router_RouteInitial.py:33-47` · 진행률 `:364-366` · 미리 계산 `schedule_precompute` `:264-380`(B03 체인 끝에서 부름). 화면 요청은 저장본만 읽고 없으면 409 `:138-174`.
- 엔진 본체(파이썬 · 동기 · `asyncio.to_thread` `:180-184`): `generate_initial_route(expected, terrain, streams, *, mode, weights, max_grade, min_radius_m, stream_offset_m, grade_smooth_m, target_grade, design_speed, pipes, with_profile, standard)` `B05_Profile/B05_Profile_Engine_RouteInitial.py:289-305`.
- `Terrain(x, y, z, valid, signature)` `B05_Profile/B05_Profile_Engine_RouteInitial_Search.py:63-72`
- 시점 · 종점 = `expected[0]` · `expected[-1]` 를 **옮기지 않음** `_Search.py:300,385-390`. 가운데 점은 탐색 복도 · 「예상노선 가까이」 비용만 바꿈(강제 통과 아님).
- 탐색 복도 = 예상선에서 ±100 m 상수 `_Search.py:31,125` · 탐색 칸 4 m `:32`
- 지형 · 계류 로더 `load_terrain_and_streams(project_root, selection)` `B05_Profile_Engine_RouteInitial.py:134-191` — models 자리 `project_root/B04_PreProcess/models` 고정 `:159`, 비용면 캐시 자리 `project_root/B05_Profile/route` 고정 `Solver.py:44,219`
- 기준값: 종단 상한 = `legal_grade_limit_pct(grade_class, terrain_type, paved, design_speed_kph)` `B05_Profile/B05_Profile_Engine_Grade.py:124` · R = `legal_plan_radius_min_m` 등 `B05_Profile/B05_Profile_Router_Replan.py:131-160`. 입력값(임도 종류 · 설계속도 · 지형)은 `projects.road_type` + workflow stage 2 에서 읽음 `Router_Replan.py:163-195`.
- 갈래 다섯: `follow · gradeline · earthwork · gentle · weighted` `B05_Profile/B05_Profile_UI_RouteEdit_Recommend.ts:83` · `B05_Profile_Engine_RouteInitial_Store.py:58`. follow = 예상선에 곡선만 맞춤(탐색 없음) `Engine_RouteInitial.py:355-360` → 두 점만 있는 D 에서는 직선이 나와 뜻 없음. 나머지는 후보 묶음 `build_pool` `B05_Profile_Engine_RouteInitial_Pool.py:249-279` 에서 고름.
- 출력: `planned [[x,y]]` · `nodes{x,y,inner_angle_deg,radius_m,tangent_m,violations}` · `curves` · `metrics`(종단 켜면 profile) `Engine_RouteInitial.py:483-522`. 저장본 = `<root>/B05_Profile/route_recommend/<지문>.json`(입력 지문 + 엔진 소스 해시) `_Store.py:44-120`. 엔진 자체는 DB · 파일을 안 씀.
- [적용] = `POST /route/replan as_initial` → 계획 노선 · 종단 · 횡단 · B06 까지 저장 체인 `Router_Replan.py:452-601` — **D 는 안 씀**.
- 순수성 증거: 지킴 시험이 가짜 `Terrain` 으로 엔진을 바로 부름 `resources/tester/test_route_initial.py:58-75`.
- D 가 끊을 의존(전부 라우터 · 로더 쪽): project_id → storage 경로(DB) · 예상선 CSV · `road_type`/stage 2 기준값 · 지형 선택(DB) · 표준 횡단(DB, None 이면 설정 기본값) · `project_pipes` · `initial_profile_of`(B DB 표) — D 라우터는 엔진만 부르고 이것들을 안 부름.
- 숨은 상태: 메모리 캐시 `_POOLS` · `_TERRAINS` 각 4칸 `Engine_RouteInitial.py:127-131` → 연도 구간이 다섯 넘으면 캐시가 돌기만 함(맞음 문제는 없음).
- 여러 연도 잇기:
- **구간마다 따로**(권함): `[P(i-1), P(i)]` 로 한 번씩 → 시점 · 종점이 그대로라 경계가 정확히 맞물림 · 연도별 갈래를 따로 고를 수 있음
- 한 번에(`[P0, P1, …, Pn]`): P1 통과 보장 없음 + 상자가 커져 비용면 한도에 걸림 → 안 씀
- 강제 경유가 꼭 필요하면 옛 자동설계 `solve_optimal_route` 가 BP→CP→EP 구간 탐색을 함 `B05_Profile_Engine_Solver.py:284-330` — 사용자 원문은 「노선 추천 로직」이라 대안으로만 둠
- 시간: 첫 계산 수십 초(화면 안내 `B05_Profile_UI_RouteEdit_Recommend.ts:529`) · 저장본 0.2 s 꼴 · 브라우저 대기 5 분 `B05_Profile_Api_RouteInitial.ts:15`. 한 구간 × 갈래 넷이면 연도 다섯 = 수 분 → 뒤에서 돌리고 진행률을 보여야 함.
### 5. 측점 · 횡단
- 측점(TS · 순수): `buildStations(line, curves, pipes, structures, options)` `B05_Profile/logic/B05_Profile_Sections_Stations.ts:290` (간격 기본 20 m `:39` · `types` 필수 `:227` → `[]`). 부품 `stationsAlong` · `stationFrameAt` `B05_Profile/logic/B05_Profile_UI_RouteEdit_Frame.ts:98,61`. 이름 `stationLabel` `common_util/common_util_station.ts:11` · 열쇠 `common_util_station_key.ts:32` ↔ `.py:30`.
- 측점 · 지반(파이썬 짝 · 순수): `generate_sections(polyline, sampler, options, …)` `B05_Profile/B05_Profile_Engine_Sections_Core.py:422` (±20 m · 0.5 m 표본 `:479-494`) · 표고 `build_surface_sampler(models_dir, …)` `common_util/common_util_surface_sampler.py:212` (models_dir 인자 → D 자리 그대로).
- 지반선 횡단(TS · 순수): `sectionsGround(line, stationsM, grid, opts)` `B05_Profile/logic/B05_Profile_Sections_Ground.ts:145` · 격자 `parseDtmGrid` · `heightAt` `common_util/common_util_surface_sampler.ts:29,65` · 격자 받기 `GET /{pid}/surface/models/{mid}/grid` `B05_Profile/B05_Profile_Router_Terrain.py:228` (DB 모델 행으로 찾음 → D 모델 행이면 그대로).
- 평면 측점 표기 · 스냅:
- 눈금 · 이름(겹침 피함) `drawStationTicks(ctx, points, opts)` `B04_PreProcess/B04_PreProcess_UI_MapOverlays.ts:230` — B04 지도 · B05 편집 · 배수 지도가 이미 같이 씀
- 스냅 `stationAtScreen` · `pickAtScreen` · `routePointAtScreen` `B05_Profile/B05_Profile_UI_RouteEdit_Input.ts:329,365,290` — import 는 손가락 설정 · MapRender 뿐 `:16-21` → [그대로] import 가능
- 측점 법선 `drawStationNormal` `B05_Profile/B05_Profile_UI_RouteEdit_Hover.ts:22`(B05 장면 타입을 받음)
- 측점 누름 → 횡단은 B05 편집기 안 묶음(`RouteEdit_Pointer.ts:147-171,295-299` → `RouteEdit_Cross.ts:370` → B 파이프라인 · `selectDesign`) → D 는 이 연결을 안 쓰고 위 부품으로 직접 이음
- 횡단 그림:
- 가벼운 SVG `buildCrossSvg(preview, w, h)` `B05_Profile/B05_Profile_UI_RouteEdit_Cross_Draw.ts:100` — 입력 `CrossPreviewResponse{samples, design|null}` `B05_Profile/B05_Profile_Api_Replan.ts:214-235`. `design=null` 이면 지반선만 그림. 다만 `calcChecked`(B 계산 자리 검사) `:24,119` 와 「기본 계획 횡단」 범례가 늘 붙음 → **지반만 모드 [인자]**
- B06 카드 `createCrossSectionCard` `B06_Section/B06_Section_UI_Cross_View.ts:141` 는 설계 없이도 그려지나 모듈 40여 개 · 페이지 상태를 끌고 옴 → 안 씀
- 계산 자리(5장): 측점 · 지반 횡단은 이미 ① 파이썬 · TS 짝(`generate_sections` ↔ `buildStations`+`sectionsGround`) → D 화면은 TS 로 즉시, 내보낼 측점 좌표표는 서버 파이썬으로.
### 6. 3D 보기
- `createRouteViewer()` `B05_Profile/B05_Profile_UI_Viewer.ts:101` — `loadSurface(projectId, modelId, method, smooth, interval, bounds)` `:62` 가 `GET /surface/models/{id}/preview`(glb) `B04_PreProcess/B04_PreProcess_Router_Status.py:153` 를 받음(DB `model_file_path` 로 찾음 `:164-188`).
- 노선 = `renderRoute(polyline)`(지형에 2 m 마다 붙임) `B05_Profile/B05_Profile_UI_Markers.ts:251` · 측점 막대 `renderStationLines(stations, halfWidth)` `B05_Profile_UI_Viewer.ts:405`.
- 구조물 끄기: 구조물은 코리도 묶음 안에만 있음 `B05_Profile/B05_Profile_UI_Viewer_Corridor.ts:95-101` → **`setCorridor` 를 안 부르면 구조물 · 노견 · 절성토면 없이 원지형 + 중심선**. 서버 Node 묶음(코리도 미리 짓기 `B05_Profile/B05_Profile_Corridor_Prebuild.py:47`)도 안 씀.
- 큰 모달로 띄우는 본보기 `A00_Common/design/design_view_profile_3d_modal.ts`(숨긴 자리 → `openModal({wide})`).
- 뷰어 자체는 세션 · 저장소 묶임 없음(구조물 고르기만 `design_selection.isNear` import `B05_Profile_UI_Viewer_Structure_Pick.ts:14` · 안 쓰면 잠잠함).
### 7. 공용으로 빼야 할 것(최소)
| 무엇 | 지금 자리 | 할 일 | 까닭 |
| --- | --- | --- | --- |
| 아이콘 · [<][>] · 도움말 | `ui_template_workflow_layout.ts:63,211` · `ui_template_help.ts:27-38` · `common_util_help_router.py:17` | [인자] `icons?` · D 경로 한 줄 | B 7단계 고정 |
| 지형 로더 models 자리 | `B05_Profile_Engine_RouteInitial.py:159` | [인자] `models_dir=None` | 연도별 DEM |
| 비용면 캐시 자리 | `B05_Profile_Engine_Solver.py:219` | [인자] `cache_dir=None` | 연도별 캐시가 서로 덮지 않게 |
| 탐색 복도 반폭 | `_Search.py:31` 상수 100 m | [인자](기본 100 그대로) — 정할 거리 8 | 두 점 직선 복도 |
| 횡단 SVG | `B05_Profile_UI_RouteEdit_Cross_Draw.ts:24,119,187-192` | [인자] 지반만 모드(범례 · `calcChecked` 건너뜀) | B 계산 검사 · 설계 범례 |
| 카카오 지도 | `B08_Quantity_UI_Milestone_KakaoMap.ts` + 키 길 `B08_Quantity_Router_Milestone.py:684` | [이동] `ui_template/` + 키 길 공용 — 정할 거리 9 | B08 Hydro 묶음 · 키 길 이름 |
- 나머지는 **빼지 않고 그대로 import**: `generate_initial_route` · `Terrain` · `stream_lines` · `legal_grade_limit_pct` · `legal_plan_radius_min_m` · `neighbors_for_points` · `ensure_sheets` · `parse_and_merge_sheets` · `build_sheet_surface_model` · `download_vworld_satellite_map` · `build_surface_sampler` · `generate_sections` · `buildStations` · `sectionsGround` · `parseDtmGrid` · `drawStationTicks` · `stationAtScreen` · MapRender 부품 · `createRouteViewer` · `createWorkflowLayout` · `createWorkflowPanelHandle` · `createSidePanels` · `editMap`.
## ③ D 페이지 구성안
전제: D 프로젝트는 `projects` 표 한 줄(종류 칸 · 345-A) · storage = `storage/{회사}/{사용자}/{project_id}/` · 지형은 그 안 `B04_PreProcess/` 배치 그대로(정할 거리 2) · D 자체 정본은 `D0x_*/` 폴더.
| 페이지 | 화면 | 그대로 부르는 B 코드 | [새로] (B 에 없음) |
| --- | --- | --- | --- |
| D01 등록 | 345-A 몫 | B02 이름 조합기 등 | 345-A 참고 |
| D02 기준 지정 | 메인 = 카카오맵(연도 표지 끌기 · 지도 누름으로 놓기 · 연도 구간 선) · 좌 = 연도 표(연도 · 시점 · 종점 · 좌표 입력칸) · [>] = 저장 → 수치지형도 받기 시작 | 틀 `createWorkflowLayout` · `editMap`/`MapPin`(끌기 · 선) · `createSidePanels` | 연도 표 · 좌표 입력칸 · 「직전 종점 = 다음 시점」 잇기 규칙 · 점 저장 API · 점 변환 함수 |
| D03 지형 · 분석 | 메인 = 수치지형도 평면(위성 + 도엽 등고선 + 지점 + 노선) · 지점 끌기 · 받은 범위 밖이면 더 받기 · [분석] → 연도 구간마다 추천 노선(갈래 넷 중 고름) · 측점 표기 · 스냅 · 하 패널 = 측점 누르면 지반선 횡단 · [3D] 모달 | 지형: `neighbors_for_points` · `ensure_sheets` · `parse_and_merge_sheets` · `build_sheet_surface_model` · `download_vworld_satellite_map` · GIS/지형 API(vworld-map · geojson · preview · grid · contour)<br>평면: MapRender 부품 · `drawStationTicks` · `stationAtScreen` · `createRecommendMap` 본보기<br>추천: `generate_initial_route` · `stream_lines` · 법정 기준 함수<br>측점 · 횡단: `buildStations` · `sectionsGround` · `parseDtmGrid` · `buildCrossSvg`(지반만)<br>3D: `createRouteViewer` · `loadSurface` · `renderRoute` · `renderStationLines` · 3D 모달 본보기 | 지형 받기 묶음 서비스(합집합 · prune 안 함 · 지점 사이 메우기 · 연도별 DEM · 모델 행) · 분석 API(구간 반복 · 잇기 · 누가거리 · 진행률) · 평면 캔버스 조립 파일 · 수치지형도 위 지점 끌기 겹 |
| D04 확정 · 업체 · 내보내기 | 345-C 몫 | — | 345-C 참고 |
서버 쪽(D 라우터 한 벌 · 얇게):
- `PUT /api/projects/{id}/plan/points` — 연도 지점 정본 저장(경위도 + 서버가 셈한 TM). [그대로] 회사 판정 · `atomic_write_json`.
- `POST …/plan/terrain` (뒤에서 · 진행률) — 모든 지점 + 구간 표본 → `neighbors_for_points` → `ensure_sheets`(prune 없음) → `parse_and_merge_sheets` → 위성 지도(합집합 범위 · 덮으면 건너뜀 `map_meta_covers` `Extent.py:157`) → 연도마다 `build_sheet_surface_model(root, processed, models_<연도>, [시점, 종점], crs, ['laplace'])` → `surface_models` 행.
- `POST …/plan/analyze` (뒤에서 · 진행률) — 연도마다 `load_terrain_and_streams(…, models_dir=연도)` → 갈래 넷 `generate_initial_route([P(i-1), P(i)], …, with_profile=False)` → 저장본(입력 지문 열쇠 = 5장 「파생 저장본」) → 화면이 연도별 갈래 고름 → [저장] 때 고른 노선을 이어 작업본으로.
- 계산 자리(5장): 추천 = ③ 서버 단독(B 와 같음) · 측점 · 지반 횡단 = ① 짝 이미 있음(화면 TS 즉시 · 내보내기 서버 파이썬).
## ④ 정할 거리
1. **D02 · D03 나눔** — ㉮ 두 페이지(카카오 → 수치지형도 · 분석) ㉯ 한 페이지 두 보기(B05 · B06 처럼). → 권함 ㉮ (원문 「다음 페이지로 넘어가면 받아 보여줌」 · 받기 시점이 페이지 경계로 또렷함).
2. **지형 storage 자리** — ㉮ D 루트 안 `B04_PreProcess/` 배치 그대로 ㉯ `D0x_Terrain/` 새 이름. → 권함 ㉮ (B04 GIS 길이 `B04_PreProcess/…` 를 여섯 줄에 박아 둠 `B04_PreProcess_Router_GIS.py:43,76,122,211,320,353` + `B05_Profile_Engine_Solver.py:42` · ㉮ 면 고칠 곳 0 · 지형을 낳는 코드 주인도 B04).
3. **DEM 단위** — ㉮ 프로젝트 한 벌(전체 상자) ㉯ 연도 구간별. → 권함 ㉯ (전체 상자는 긴 노선에서 1 m 격자 메모리 · 2 m 비용면 400만 칸 한도에 걸림 · 추천도 구간별이라 짝이 맞음). 도엽 zip · 병합 등고선은 프로젝트 한 벌.
4. **작업 좌표계 · 변환 자리** — 좌표계 ㉮ 5186 고정 ㉯ 경도로 5185/5186/5187 자동 · 변환 ㉠ 서버 pyproj(표지 끌기는 경위도 그대로 · 입력칸은 확정 때 한 번) ㉡ TS 변환기(proj4 새 의존 또는 짝 코드). → 권함 ㉯ + ㉠ (B03 으로 넘길 노선 파일에 .prj 동봉 · 끌기 중 왕복 없음).
5. **수치지형도 위 지점 끌기** — ㉮ 카카오에서만 끌고 수치지형도는 보기만 ㉯ 수치지형도에서도 끌기. → 권함 ㉯ (원문 「평면도(카카오맵, 수치지형도…)에서 드래그」) · B05 노드 끌기는 편집기 통째(B 묶임)라 MapRender 위에 끌기 겹을 [새로] 작게.
6. **갈래** — ㉮ follow 빼고 넷 ㉯ 영선(gradeline) 하나. → 권함 ㉮ (follow 는 두 점 직선이 나옴 · 연도마다 고르게 함).
7. **추천 기준값(종단 상한 · R)** — ㉮ D 에 임도 종류 · 설계속도 · 지형 칸을 두고 B 법정 함수로 냄 ㉯ 고정값. → 권함 ㉮ (값은 지식DB · 사용자 확정 · 임의 확정 금지).
8. **탐색 복도 폭** — ㉮ 지금 ±100 m 그대로 ㉯ 인자로 열고 D 가 넓힘. → 권함 ㉯ (두 점 직선 복도라 급경사 지그재그를 못 찾을 수 있음 · B 기본값은 그대로).
9. **카카오 지도 자리** — ㉮ B08 파일을 그대로 import ㉯ `ui_template/` 로 옮기고 키 길 공용. → 권함 ㉯ (B08 Hydro 를 끌고 옴 · 키 길이 `quantity/milestone` 이름).
10. **연도 경계 곡선** — ㉮ 경계점에서 꺾인 채 둠(경계점 = 측점) ㉯ 이은 뒤 곡선을 다시 맞춤(경계점이 길에서 벗어남). → 권함 ㉮ (연도 끝점이 다음 해 시점이라 길 위에 있어야 함 · 누가거리는 등록 「노선 시작 누가거리」부터 이어 셈).
11. **계류 이격** — ㉮ 도엽 하천중심선으로 반영 ㉯ 빈 목록. → 권함 ㉮ (같은 도엽에서 오고 B 와 같은 규칙).
## ⑤ 계획 걸음 후보
1. 틀 아이콘 인자 · D 경로 — `ui_template_workflow_layout.ts:63,211` · `ui_template_help.ts:27-38` · `common_util_help_router.py:17` · `ui_template_native_menu.ts:11` · `ui_template_loupe.ts:37` — ORCA 로 D02 의 단계 막대 · [<][>] · [?] 확인 + B05 화면 그대로인지.
2. D 페이지 길 둘 — `D02_*/draft/D02_*_Route.ts` · `D03_*/draft/D03_*_Route.ts` + D 단계 목록(345-A 단계 시드와 묶음) — ORCA 로 주소 열림 · 단계 이동.
3. 카카오 지도 공용 이전 — `B08_Quantity_UI_Milestone_KakaoMap.ts` → `ui_template/` · 키 길 공용 라우터 — B08 이정표 시험 + ORCA B08 지도 그대로.
4. 점 변환 · 좌표계 고르기 — `common_util/common_util_crs.py` 에 경위도↔TM 함수 + 경도로 EPSG 고르기 — 새 지킴 시험(알려진 점 왕복 1 mm 안).
5. 지점 정본 API · 잇기 규칙 — D 라우터(`D02_*_Router.py`) `points.json` — 시험: 직전 종점 = 다음 시점 강제 · 빈 연도 거절.
6. D02 화면 — 연도 표 · 좌표 입력칸 · `editMap` 표지 끌기 · 구간 선 — ORCA: 끌기 → 표 좌표 바뀜 · 입력 → 표지 옮김 · [저장] 뒤 정본 수치.
7. 지형 받기 서비스 — D 서비스가 `neighbors_for_points` · `ensure_sheets`(prune 없음) · `parse_and_merge_sheets` · 위성 지도 · 지점 사이 1 km 표본 — 시험(내려받기는 가짜): 지점 추가 때 옛 zip 유지 · 새 도엽만 받음 · 3 km 떨어진 두 점 사이 도엽 빠짐 없음.
8. 연도별 DEM · 모델 행 — `build_sheet_surface_model(…, models_<연도>, [시점, 종점], …)` + `surface_models` 행 — 시험: 구간 DEM 생김 · 열쇠 같으면 다시 안 셈 · `/surface/models/{mid}/grid` 가 D 모델을 돌려줌.
9. 지형 로더 · 비용면 캐시 · 복도 인자 — `B05_Profile_Engine_RouteInitial.py:134` `models_dir` · `B05_Profile_Engine_Solver.py:214` `cache_dir` · `_Search.py:31` 복도 — `resources/tester/test_route_initial.py` + B05 추천 시험 그대로 통과(B 결과 불변).
10. D 분석 API — 연도 구간 반복 · 갈래 넷 · 지문 저장 · 진행률 · 잇기 — 시험(가짜 지형 두 구간): 경계점 좌표 일치 · 누가거리 이어짐 · 같은 입력 재요청은 저장본.
11. D03 평면 캔버스 — MapRender 부품 + `drawStationTicks` + `stationAtScreen` + 지점 끌기 겹 + 받은 범위 밖 알림 → 더 받기 — ORCA: 측점 이름 · 스냅 · 끌기 뒤 범위 밖이면 도엽 늘어남(파일 수).
12. 지반선 횡단 — `buildCrossSvg` 지반만 모드 + `buildStations` · `sectionsGround` · `parseDtmGrid` — B05 횡단 미리보기 시험 그대로 + ORCA: 측점 누름 → SVG 지반선 실좌표가 격자 표고와 맞음.
13. 3D 모달 — `createRouteViewer` · `loadSurface` · `renderRoute` · `renderStationLines` (코리도 안 부름) — ORCA: 지형 + 중심선만 · 구조물 없음 · 측점 막대.
@@ -0,0 +1,104 @@
# 345-C 예정노선 내보내기 양식 분석
## ① 결론
1. 용화 폴더의 「노선·좌표」 자료는 `예정노선/대상지_일월.용화.2.2` shapefile 한 벌(.shp·.shx·.dbf·.prj·.cpg)뿐임 — 발주처가 준 실물 예정노선 양식이며 나머지(.las·.tif·.tfw·.prj)는 지형 측량 자료임.
2. 양식 = 2D 폴리라인 1레코드 · UTM-K(EPSG 5179, ESRI WKT) · cp949(.cpg `949`) · 속성 2칸(`대상지` 문자20 · `길이` 숫자11.3 km) · 정점 121개(간격 5.9~26.8 m, 평균 17.8 m) — 측점·IP/BC/EC·표고 없음.
3. B03 은 이 shapefile 한 벌을 그대로 읽음(검증_랩탑메인이 바로 이 파일로 설계 완료) — 한 프로젝트에 노선 파일 정확히 1개 · 파트가 여럿이면 가장 긴 것만 씀 · 화면은 .csv 를 받지 않음.
4. 그래서 D 내보내기 = **연도마다 shapefile 한 벌**(용화와 같은 양식 + 연도·누가거리 속성 추가) + 발주처 보관용 전체 한 벌 · 업체에는 그 업체가 지정된 연도 묶음만 보냄.
5. 선례 있음 — 2024년 간선임도가 공구별 shp 1·2·3 + 전체노선 shp 를 따로 두었고 앞 공구 종점 = 다음 공구 시점(연장 합 3,526.8 m = 전체 3,526.9 m) · D 의 「직전연도 종점 = 다음년도 시점」과 같은 꼴임.
## ② 용화 폴더 파일 표
`resources/knowledge/original/실무문서/2026년 임도 용화/`
| 파일 | 형식 | 노선/좌표 관련 내용 |
| --- | --- | --- |
| `예정노선/대상지_일월.용화.2.2.shp` | ESRI Shapefile · PolyLine(3) · 1레코드 · 2,092 B | 2D 선 1개 · 정점 121 · 연장 2,135.9 m · 시점 (1142250.8, 1869463.2) · 종점 (1143484.5, 1869508.3) · Z 없음 |
| `예정노선/대상지_일월.용화.2.2.dbf` | dBASE · 130 B | `대상지` C(20) = `일월.용화.2.2` · `길이` N(11,3) = `2.200`(km · 0.1 km 반올림 · 실연장 2.136 km) |
| `예정노선/대상지_일월.용화.2.2.prj` | ESRI WKT | `PCS_ITRF2000_UTM_K` = UTM-K(EPSG 5179) · 중앙자오선 127.5 · FE 1,000,000 · FN 2,000,000 · 축척 0.9996 |
| `예정노선/대상지_일월.용화.2.2.cpg` | 텍스트 | `949`(cp949) |
| `예정노선/대상지_일월.용화.2.2.shx` | 색인 · 108 B | 레코드 색인만 |
| `용화.las` | LAS · 1.67 GB | 지형 점군(노선 아님) |
| `용화.prj` | OGC WKT | EPSG 5176(Korean 1985 / Modified East Belt) — 지형 좌표계 = 프로젝트 좌표계 |
| `용화.tfw` · `용화.tif` | 월드파일 · GeoTIFF 48 MB | 0.2 m 격자 · 원점 (208288.8, 368092.3) — 지형 영상 |
- 파일명 꼴 = `대상지_<면>.<리>.<연장km>` · 속성 `대상지` 도 같은 값.
- 측점 간격 · IP · BC · EC 칸 없음 — 손으로 그린 계획선(꺾은선)임. IP·곡선은 B03 뒤 자동 체인이 만듦.
다른 실무 폴더(가볍게):
| 폴더 | 노선 파일 | 성격 |
| --- | --- | --- |
| 2024년 간선임도 1·2·3공구 · 공통 | `shp/<n>공구/<n>_dxf_Polyline.shp` · `전체노선/all_dxf_Polyline.shp` | 설계 결과 중심선(DXF→SHP) · .prj 없음 · 속성은 DXF 잔재(Layer=`측점` 등) · 공구별 + 전체 한 벌 · 시종점 이어짐 |
| 25년 산불진화임도(울진소광) | `05-SHP/…중심선(EPSG5176).shp` · `…용지폭(EPSG5176).shp` | 설계 결과 중심선 600 m + 용지폭 폴리곤 · EPSG 5176 · cp949 |
| 01~05 산불(오솔길) | `.pln` · `.PIN` · `.crv` · `EARTH.DAT` · 토량 `.csv` | 설계 프로그램 내부 파일(측점·지반고·곡선표) · 좌표 노선 아님 |
- 발주처 「예정노선」 양식은 용화 하나뿐 · 다른 폴더는 설계 결과물이라 공통 양식 아님. 공통점은 「shapefile 2D 폴리라인 1레코드」뿐.
## ③ B03 입력 형식(근거 파일:줄)
받는 파일:
- 화면 노선 칸 = `.shp` + 형제 `.shx`·`.dbf`·`.cpg`·`.prj`(카드 5장) · `.csv` 는 화면에서 안 받음 — `B03_FileInput/B03_FileInput_UI_Support.ts:12`, `:64-101`(`.csv` 제외 `:69-71`).
- shapefile 필수 = `.shp`·`.shx`·`.dbf`·노선 `.prj` · `.cpg` 는 없으면 cp949 — `B03_FileInput/B03_FileInput_UI_Support.ts:18`, `B03_FileInput/B03_FileInput_Router_Helpers.py:107-110`, `:145-156`, `config/config_system.py:91-92`.
- 노선 파일은 정확히 1개 — `B03_FileInput/B03_FileInput_Router.py:182-190`.
- 노선 `.prj` 는 `.shp` 와 basename 이 같아야 노선 좌표계로 갈림(다르면 지형 PRJ 로 앉음) — `B03_FileInput/B03_FileInput_Engine.py:56-59`, `B03_FileInput/B03_FileInput_Router_Helpers.py:126-142`.
- 허용 확장자 — `config/config_system.py:77-89`.
파서:
- shapefile 직접 판독(GDAL 안 씀) · 폴리라인(3·13·23)만 · Z 없으면 0 — `B03_FileInput/B03_FileInput_Engine_Shapefile.py:23`, `:124-174`.
- 인코딩 = `.cpg`(숫자면 `cp<숫자>`) · 없으면 cp949 — `B03_FileInput/B03_FileInput_Engine_Shapefile.py:42-70`.
- 좌표계 = `.prj` 원문 WKT 를 그대로 변환 입력으로 씀(EPSG 라벨 불필요) — `B03_FileInput/B03_FileInput_Engine_Shapefile.py:73-80`.
- 노선 이름 = 속성 `대상지`→`노선명`→`route_name`→`NAME` 차례 · 없으면 파일명 — `B03_FileInput/B03_FileInput_Engine_Shapefile.py:208-213`. 속성은 첫 레코드만 읽음 — `:177-205`.
- 파트가 여럿이면 **가장 긴 것만** 노선으로 씀 — `common_util/common_util_route_geometry.py:135`, `:153`.
- 노선 파일 고르기 = 입력 폴더에서 `.shp` 우선 · 여럿이면 최신 — `common_util/common_util_route_geometry.py:200-214`.
- 서버 CSV 경로(화면 미노출) = utf-8-sig · 필수 칸 `route_name, sequence(1부터 연속), x, y, z, crs_epsg` · 노선 1개 — `B03_FileInput/B03_FileInput_Engine_Analyze.py:395`, `:418-480`.
저장:
- `storage/<…>/<프로젝트ID>/B03_FileInput/input/shp/<원래 이름>.{shp,shx,dbf,cpg,prj}` — 원래 파일명 그대로 · 노선 세트는 한 폴더 — `B03_FileInput/B03_FileInput_Engine.py:18-19`, `:43-66`.
- DB `input_files`(file_type · original_filename · raw_file_path=`B03_FileInput/input/...` · crs_epsg · metadata) — `B03_FileInput/B03_FileInput_Repository.py:30-57` · 노선 PRJ 는 경로 `/input/shp/` 로 `route_prj` 판정 — `:64-110`.
- 뒤 단계: 노선을 지형 PRJ 좌표계로 변환 → 사용 범위(`route_start_m`·`route_end_m`) 자르기 → 서피스 트림 — `common_util/common_util_route_geometry.py:323-339` · 범위 읽기 `B03_FileInput/B03_FileInput_Service_Chain.py:213-225` · 등록 칸 `B02_ProjRegister/B02_ProjRegister_Schema.py:20-21`.
- 예상노선 정본 `B05_Profile/route/expected_route.csv`(`sequence,x,y`, 프로젝트 좌표계) — `common_util/common_util_route_geometry.py:217-236`.
실물 예(검증_랩탑메인 `storage/1/3/dad81824-…/`, 읽기만):
- `B03_FileInput/input/shp/대상지_일월.용화.2.2.{shp,shx,dbf,prj,cpg}` · `input/las/용화.las` · `input/prj/용화.prj` · `input/tfw/용화.tfw` · `input/tif/용화.tif` · `metadata.json`.
- 파생: `B05_Profile/route/expected_route.csv`(332점 · EPSG 5176 좌표) · `planned_route_initial_nodes.csv`(IP) · `planned_route_initial_curves.json`(apex=IP · start=BC · end=EC · radius_m) · `route_main.geojson`(XYZ).
- 즉 용화 예정노선 shp 는 UTM-K 그대로 올라가 지형 좌표계(5176)로 변환돼 설계까지 감 — 양식 호환 실증됨.
주의:
- B03 은 노선 말고 지형(LAS + 지형 PRJ + TFW)도 필수 · 아니면 「LAS 없이 설계」 — `B03_FileInput/B03_FileInput_Router_Helpers.py:145-156`. D 내보내기만으로는 B03 이 다 차지 않음(노선 칸만 참).
- 노선 누가거리는 언제나 그 파일의 시점 0 부터 셈 — `common_util/common_util_route_geometry.py:158-165`. 시점 측점 이어 받기(예: 2차년도 No.40 부터) 기능 없음.
## ④ 내보내기 묶음 제안
연도(구간)마다 한 묶음 · 업체에는 지정된 연도 묶음만 · 발주처 [내보내기]는 전 연도 + 전체.
| 파일 | 형식 | 칸 · 내용 | 근거(용화) | B03 그대로 읽음 |
| --- | --- | --- | --- | --- |
| `대상지_<지역>.<연장km>_<연도>.shp` | Shapefile PolyLine · 2D · 1레코드 | 그해 시점→종점 중심선 꺾은선(추천 노선 정점 · 곡선은 잘게 펴서) | `대상지_일월.용화.2.2.shp` | 예 |
| 같은 이름 `.shx` | 색인 | — | 같음 | 예(필수) |
| 같은 이름 `.dbf` | dBASE · cp949 | `대상지` C(20) · `길이` N(11,3) km — 용화 두 칸 그대로 + 덧칸 `연도` N(4) · `시점누가` N(11,2) m · `종점누가` N(11,2) m (칸 이름 10바이트 = 한글 5자 이내) | `.dbf` 두 칸 | 예(덧칸은 무시되고 보관만) |
| 같은 이름 `.prj` | ESRI WKT | UTM-K(EPSG 5179) — 용화 `.prj` 원문 그대로 | `.prj` | 예(필수 · basename 같아야 함) |
| 같은 이름 `.cpg` | 텍스트 | `949` | `.cpg` | 예 |
| `대상지_<지역>.<연장km>_전체.*` (발주처용) | 위와 같음 | 전 연도 이은 한 선 · `연도` 칸 비움 | 2024 간선임도 `전체노선/all` | 예(한 업체가 전 구간을 맡을 때) |
| `좌표표_<프로젝트명>.xlsx` (선택) | xlsx 한 시트 | 연도 · 시점 X/Y · 종점 X/Y · 위경도 · 시점누가 · 종점누가 · 연장 m | 용화엔 없음(사람용) | 아니오(B03 입력 아님) |
- 묶는 방법: 업체별 zip `<프로젝트명>_예정노선_<연도>.zip` — shp 한 벌이 수 KB 라 메일 첨부로 충분.
- 연도 나누기: 연도마다 파일(한 파일 여러 레코드 · 한 파일 여러 시트 아님). 까닭 — B03 은 노선 파일 1개 · 가장 긴 파트만 · 첫 레코드 속성만 읽으므로 여러 레코드 한 파일은 그대로 못 씀.
- 프로그램 안 연결: 위 연도 shp 한 벌을 연결된 임도 프로젝트 `B03_FileInput/input/shp/` 에 원래 이름으로 복사 + `input_files` 행 5개(shp·shx·dbf·cpg·prj) + `metadata.json` 갱신(`analyze_input_metadata` 재사용) → 파일로 올린 것과 같은 길을 탐. 지형 칸은 업체 몫.
- 쓰기 도구: 코드에 shapefile 쓰개 없음 · 설치된 geopandas `to_file(driver="ESRI Shapefile", encoding="cp949")` 로 충분(.prj 는 용화 원문으로 덮어쓰면 양식 일치) — 새 의존성 불필요.
## ⑤ 정할 거리
1. 연도 나누기 — 연도마다 shp 한 벌 / 전체 한 벌 + 연도별 누가거리(B02 사용 범위로 자름) / 한 파일 여러 레코드 → **연도마다 한 벌(+발주처용 전체)** 권함 · 둘째는 다른 연도 노선이 다른 업체에 새고, 셋째는 B03 이 못 읽음.
2. 좌표계 — UTM-K 5179(용화 실물) / GRS80 중부원점 5186 / 프로젝트 지형 좌표계 → **5179** 권함 · B03 은 무엇이든 변환하므로 실물 양식을 따름.
3. 좌표표 xlsx 포함 — 넣음 / 뺌 → **넣음(선택 파일)** 권함 · 요구의 「좌표정보」를 사람이 읽는 표로 · B03 입력은 아님.
4. 선 모양 — 추천 노선 정점 그대로(곡선 펴서 조밀) / IP 꺾은선만 → **정점 그대로** 권함 · 용화도 조밀 꺾은선이고 IP·곡선은 B03 뒤 체인이 다시 만듦.
5. dbf 덧칸 — 용화 두 칸만 / `연도`·`시점누가`·`종점누가` 추가 → **추가** 권함 · B03 은 무시하므로 해 없음, 연도 확인에 씀.
6. 다음 연도 측점 이어 받기 — 각 연도 0 부터 / 전체 누가거리 이어서 → **0 부터**(지금 B03 그대로) 권함 · 이어 받기는 B03 에 시점 측점 칸이 새로 필요해 별건.
7. 파일명 — `대상지_<지역>.<연장km>_<연도>` / 프로젝트명 기반 → **대상지_ 꼴** 권함 · 용화 실물 꼴 · B03 이름 칸 `대상지` 와 맞음.
@@ -0,0 +1,217 @@
# 요구 345 E 안정성평가 — 방법 제안 (분석)
> 원문: `docs/raw/요구_1025/사용자요구_1025.md` L89~96 · 조사 대상 = 사전조사 초안 `resources/knowledge/original/안정성평가/` 5건 · `예정노선/` 3건 · 지식DB 원문 · B06 코드 · 검증 프로젝트 `검증_랩탑메인`(dad81824…) storage(읽기만)
> 값은 모두 **후보** — 확정은 사용자.
---
## ① 결론 · 권하는 갈래
1. **2D 먼저** — 측점별 횡단(B06 이 이미 가진 단면)에 **2D 한계평형해석(LEM, Bishop 간편법 기본 + Janbu 보정 보조)** 을 돌려 측점마다 건기·우기 안전율과 판정(O.K/N.G)을 냄. 국내 기준(KDS 11 70 05)이 토사 비탈면 = LEM 기본으로 정하고 납품 보고서도 단면 단위임.
2. **B06 데이터만으로 기하는 다 나옴** — 지반선 · 설계선 · 절성토 경사 · 소단 · 토사/암 경계 · 벽. 빠진 것은 **지반 강도정수(c·φ·γ) · 지하수 · 암반 절리 방향** — 앞의 둘은 기준 규칙 + 문헌 후보값으로 채우고(사용자 확정), 절리는 현장 조사 입력이라 2차로 미룸.
3. 단계 = **1차 토사·성토 2D LEM + 보고서 → 2차 암반 평사투영·블록 · 광역 무한사면 지도 · 보강 · 옹벽 → 3차 엄밀해 · 확률 · 선택 구간 3D LEM**. 3D 유한요소(FEM)는 입력·라이센스·비용 모두 맞지 않아 보류.
4. 계산 자리 = **서버 파이썬 단독(③)** — E 는 복사본이라 화면에서 기하를 안 만짐 · 값만 바꾸고 [해석] → 서버 계산 → 파생 저장본. 파이썬·TS 짝 불필요.
5. 라이브러리는 **자체 NumPy+Shapely 구현** — MIT·BSD 패키지는 대조·참고만, GPL·AGPL·비상업 조건 코드는 가져오지 않음. 「3D」 요구는 1~2차에서 **2D 결과를 복사된 3D 노선 위에 색칠**하는 보기로 먼저 채움.
---
## ② B06 데이터 현황 (E 가 복사해 쓸 것)
### 2-1. 측점별 횡단 — 있는 것
| 항목 | 있음 | 자리 · 근거 |
|---|---|---|
| 지반선 | 측점마다 ±20 m · 0.5 m 간격 81점(offset · x · y · z) | storage `B06_Section/cross_sections/cross_NNNNNm.json` `samples` · 반폭·간격 = `longitudinal_sections.data.options`(cross_half_width_m 20 · cross_sample_interval_m 0.5) |
| 측점 좌표·방향 | 중심 x·y·z · 방위각 · 좌측 단위벡터 · 오르막 쪽 | 같은 파일 `center_*` · `azimuth_deg` · `frame.left_xy` · `uphill_side` |
| 설계선 | 폴리라인(검증 프로젝트 86점) · 노면 끝 · 차도 끝 · 계획고 | DB `cross_sections.data.design.design_line` · `road_edges` — 엔진 결과 `B06_Section/B06_Section_Engine_Design.py:435-561` |
| 단면 유형 | 좌절 · 우절 · 양절 · 양성 | `design.section_mode` (`Engine_Design.py:426-433`) |
| 절토 경사 | 토사 1:1.0 · 암 1:0.4 기본 · 측점별 사용자 값 · 2단 경사(암/토사) | `config/config_system_design.py:277-311` · `design.cut_slope_ratio` · `soil_cut_slope_ratio` · `two_stage_slope` · 측점 값 `B06_Section_Schema.py:195` |
| 성토 경사 | 1:1.2 | `config_system_design.py:285` · `design.fill_slope_ratio` |
| 소단 | 폭 · 간격 · 안쪽 기울기 · 깊이(절토 계단 · 성토 한 단) | `design.berm` (`Engine_Design.py:537-549`) · 기본값 `common_util/common_util_cross_berm.py:1-30` · 구간 원천 = `B05_Profile/route/structures.json` 의 `berm` |
| 지반 유형 | 측점마다 토사 / 리핑암 / 발파암 **세 라벨**(기하 프리셋은 토사·암 둘) | `design.ground_type` · `config_system_design.py:342-346` |
| 토사/암 경계 | **암 측점만** · 지반선을 평행으로 내린 선 한 줄(기본 −0.5 m · 0.1 m 단위 조절) | `design.rock_boundary_offset_m` · `config_system_design.py:313` · 면적 가름 `Engine_Design.py:363-377` |
| 절토 토사/암 면적 | 측점별 ㎡ | `design.cut_soil_area_m2` · `cut_rock_area_m2` |
| 벽(사면 안정 C군) | 옹벽 · 찰쌓기 · 메쌓기 · 흙막이 · 큰돌쌓기 — 구간 · 높이 · 형태가 횡단에 얹힘 | `B05_Profile/route/structures.json`(`B05_Profile_Structures_Repository.py:1,23-24`) · 종류 `resources/master_template/구조물정의.json`(retaining_wall · masonry_wet/dry · soil_guard · boulder_masonry) · 얹기 `B06_Section/B06_Section_Engine_Structures_Wall.py:1-20` |
| 사면 미폐합 경고 | 사면이 ±20 m 안에서 지반과 안 만난 측점 | `design.slope_unclosed` (`Engine_Design.py:356-361`) |
### 2-2. 면 · 격자 — 있는 것
| 항목 | 자리 · 크기(검증 프로젝트 실측) |
|---|---|
| DTM 1 m 격자(x · y · z · valid_mask) | `B04_PreProcess/models/dtm_*_smooth.npz` 1.4~5.9 MB · `models/manifest.json`(grid_resolution_meters 1.0) |
| 3D 노선면(설계면 리본) | `B05_Profile/corridor/corridor_NNNN.json`(ribbons · outline · caps · structures) 14 MB |
| 흐름방향 · 유역 | `B04_PreProcess/drainage/02_flow_direction.npz` · `04_detailed_basins.geojson` (폴더 81 MB) |
| 노선 · 종단 | `B05_Profile/route/` 1.5 MB · `B06_Section/longitudinal/longitudinal.json` |
### 2-3. 없는 것 · 한계
| 항목 | 상태 · 근거 |
|---|---|
| 연암·경암 위치 | 프로젝트 전체 **비율 하나**(기본 연암 90 : 경암 10)뿐 · 측점별 암질 없음 — `common_util/common_util_project_settings.py:60-62,270-288,369-373` · 「암질을 횡단도에서 안 고르기로 사용자 확정」 `Engine_Design.py:516-518` |
| 지층 두께(지질) | 암 경계는 **물량 가름용** 평행선(기본 0.5 m) — 지반조사 결과 아님 · 토사 측점은 경계 자체 없음 |
| 지반 강도정수 c · φ · γ | 없음 |
| 지하수위 | 없음 |
| 절리(불연속면) 방향 · 강도 | 없음 — 현장 조사(주향/경사) 입력 필요 |
| 연약지반 표시 | 없음 — 코드 검색 「안정해석·연약지반」 0건(B0* · common_util) · 지식DB 의 경고 플래그(`technical_info/01_임도/03_계산정보/구조물_안정계산.md:29`)는 아직 미구현 |
| 횡단 폭 | ±20 m — 사면이 높으면 원호가 단면 밖으로 나갈 수 있음 → E 생성 때 복사한 DTM 에서 넓혀 다시 뜸(기존 `B06_Section_Engine_SampleExtend.py` · `common_util_surface_sampler`) |
| 프로젝트 그룹 칸 | `projects` 표에 그룹(B/C/D/E) · 원본 프로젝트 칸 없음 — `B02_ProjRegister/B02_ProjRegister_Repository.py:82` (D 계획과 공통으로 추가) |
### 2-4. 검증 프로젝트 실측(초기값 스냅샷 `initial_snapshot/db.json` — 읽기만)
- 측점 57개 · 연장 1,080 m · **전 측점 리핑암 · 우절 · 암 경계 −0.5 m**(자동설계 기본값 그대로).
- 절토 사면 높이 최대 6.25 m(STA 0+740) · 성토 면적 최대 56.0 ㎡(STA 0+280) — 별표2 「15 m」 트리거에는 안 걸리나 **급경사 위 성토**가 큼(임도 피해 6유형 중 「성토사면 붕괴」 — `original/임도기술교본/14. 임도의 유지관리/3. 임도의 보수.md:17`).
- storage 전체 3.0 GB 중 LAS 1.6 GB · 전처리 점군 1.1 GB — **E 에 필요한 것만 뜨면 약 20 MB(광역 포함 시 약 100 MB)**.
- 복사 틀 재사용 — 초기값 스냅샷이 이미 「정본 파일 트리 + DB 행 → db.json」을 함(`common_util/common_util_initial_snapshot.py:39-54`).
---
## ③ 방법 비교
| # | 방법 | 차원·대상 | B06 로 되는 입력 | 더 받을 입력 | 출력 | 오픈소스 · 라이센스 | 자체 구현 | 단계 |
|---|---|---|---|---|---|---|---|---|
| 1 | 2D LEM Fellenius | 측점 횡단 · 원호 | 기하 전부 | c·φ·γ · 수위 규칙 | Fs | 자체 | 하 | 1차(비교·초기값) |
| 2 | **2D LEM Bishop 간편법** | 측점 횡단 · 원호 · 토사·성토·풍화암 | 기하 전부 | 〃 | 측점별 최소 Fs · 임계 원호 · 등안전율 · 절편표 | `pyslope` MIT(수평 지층만 → 참고만) · `pyCSS`(라이센스 미확인) | 하(300~500줄) | **1차 기본** |
| 3 | 2D LEM Janbu 보정 | 비원호 · 토사가 암 경계 따라 미끄럼 | 기하 + 암 경계 | 〃 | Fs · 비원호 활동면 | `pyBIMstab` BSD-2(비원호 탐색 참고) | 중 | 1차 보조 |
| 4 | 2D LEM Spencer · M-P · GLE | 엄밀해 | 〃 | 〃 | Fs(힘·모멘트 동시) | `xslope` Apache-2.0(PyPI 표기 · 대조용) | 중 | 3차 |
| 5 | 무한사면(격자) | 노선 주변 자연사면 표층 | DTM 경사 | 토심 z · 포화비 m · c·φ·γ · 뿌리 점착 c_r | 격자 Fs 지도 | `Landlab` MIT(참고) · 자체 NumPy | 하 | 2차 |
| 6 | SINMAP · SHALSTAB류 | 〃 + 집수면적 | DTM · 흐름방향 | + 투수량계수/강우 비(T/R) | 안정지수(SI) 등급도 | WhiteboxTools MIT(집수면적) · 원 SINMAP 코드는 안 가져오고 식만 구현 | 하~중 | 2차(D 예정노선과 엔진 공유) |
| 7 | 평사투영 Markland | 암반 절취면 | 사면 경사방향(방위각·절토 쪽) · 사면 경사(절토 경사비) | **절리 방향·경사 · φj(현장 조사)** | 평면·쐐기·전도 가능성 · 스테레오넷 | `mplstereonet` MIT(투영식 참고) | 하~중 | 2차 |
| 8 | Hoek-Bray 평면 · 쐐기 | 위험 판정된 암괴 | 사면 높이 | + cj · 인장균열 · 수압 | 블록 Fs | 자체 | 하(평면) · 중(쐐기) | 2차 |
| 9 | 옹벽 외적 안정 | C군 벽 | 벽 높이 · 형태 | 배면토 강도 · 기초 지지력 | 활동 · 전도 · 지지력 Fs | 자체 | 하~중 | 2차 |
| 10 | 보강 재해석 | N.G 측점 | 단면 | 네일·록볼트·앵커 제원 | 보강 후 Fs | 자체(LEM 에 T 항) | 하 | 2차 |
| 11 | 3D LEM(기둥법 · Scoops3D) | 선택 구간 3D | DTM · 설계면 | **3D 지층면 없음**(암 경계는 측점별 오프셋뿐) | 3D Fs · 붕괴 체적 | Scoops3D = USGS 공공 저작물(실행 파일 연계 · 소스 패키지 표기 재확인) | 상 | 3차 |
| 12 | 확률 해석(몬테카를로) | LEM 위 | — | 물성 표준편차 | 파괴확률 Pf | 자체 | 하 | 3차 |
| 13 | Newmark 변위 | 지진 시 미달 측점 | — | 설계 지반운동 | 변위(허용 = 사면고 1%) | 자체 | 중 | 3차(지진 켤 때) |
| 14 | 2D FEM 강도감소법 | 단면 응력·변형 | 기하 | 탄성계수 · 포아송비 + 메쉬 | 소성역 · Fs | scikit-fem BSD-3(확인 필요) · **메셔 Gmsh GPL · TetGen AGPL · Triangle 비상업 — 주의** | 상 | 보류 |
| 15 | 3D FEM · 강우침투(TRIGRS · SEEP) | 3D · 시간 | — | 투수계수 · 함수특성곡선 · 강우 · 3D 지층 | 시간별 Fs | TRIGRS USGS · 상용 GeoStudio | 최상 | 보류 |
---
## ④ 단계별 제안
### 1차 — 토사·성토 2D LEM + 보고서 (MVP)
- **방법**: 측점마다 절토 쪽 · 성토 쪽을 따로 해석. Bishop 간편법(원호) 기본 · Fellenius 비교 · Janbu 보정(암 경계 따라 비원호). 탐색 = Entry & Exit 자동(사면 상단~하단) + Grid & Radius(등안전율 그림용). 조건 = 건기 · 우기(+ 지진 선택).
- **모델 만들기(자동)**: 복사본에서 측점별 2D 지층 폴리곤 — ① 지반선(DTM 에서 넓혀 다시 뜬 것) ② 설계선(절토 · 소단 · 측구 포함) ③ 암 경계(암 측점: 지반선 − |offset| · E 에서 구간별 덮어쓰기) ④ 성토체(설계선이 지반 위인 부분 = 성토층) ⑤ 벽(C군 — 활동면이 벽을 못 지나게 · 고강도 영역).
- **입력**: B06 복사본 + 지반물성치 후보(⑤) + 지하수 규칙(건기 u=0 · 우기 토사·풍화암 지표 포화 또는 r_u · KDS 11 70 05 표 4.3-3 · KDS 44 30 00 L366) + 상재하중(노면) + 기준안전율.
- **출력**: 측점별 최소 Fs(건기·우기) · 판정 O.K/N.G · 임계 원호 그림 · 등안전율 · 절편표 · 평면·종단에 위험 구간 색띠 · 「비탈면 안정해석 보고서」 6·7장 분량(대표 단면 = 쌓기 10 m 이상 · 15 m 트리거 · 최소 Fs 하위 N개).
- **화면(폴더 후보 · 이름은 사용자 확정)**:
- `E01_StabRegister` — 생성: 임도설계 프로젝트 고르기(B06 확정본만 목록) · 생성 시점 동결 복사.
- `E02_StabGround` — 지반 조건: 물성치 표(라벨별 프리셋 · 구간별 덮어쓰기) · 층 두께 · 지하수 규칙 · 지진 켬/끔·k_h · 상재하중 · 기준안전율.
- `E03_StabSection` — 측점 해석: 좌 측점 목록(Fs 색) · 가운데 횡단 + 임계 원호 + 등안전율 · 우 결과·절편표 · 위 평면 위험 띠 · 3D 보기(복사된 노선면에 측점 Fs 색칠 — 표시용).
- `E06_StabReport` — 보고서 출력(형식은 정할 거리).
- **계산 자리**: ③ 서버 단독. 조작은 캐시(sessionStorage)에 쌓고 [해석]·[저장] 때 서버 계산 · 결과 = `_derived/` 파생 저장본(입력 지문이 다를 때만 다시 셈 · CLAUDE.md 5장). 전 측점 1회 = 57측점 × 2쪽 × 2~3조건 — NumPy 벡터화로 수십 초 추정(측정 전 · 진행 표시).
- **라이브러리**: NumPy + Shapely(설치됨 · 절편 교차) + SciPy(설치됨). 외부 LEM 패키지 의존 없음.
- **시험**: 공개 기준 문제(ACADS 사면안정 시험문제 등) · 손계산 대조 ±3 % · 사용자가 가진 SoilWorks/Slide2 결과가 있으면 같은 단면 대조 · 모델 폴리곤 면적 = B06 절성토 면적 대조.
### 2차 — 암반 · 광역 · 보강
- **암반**(`E04_StabRock`): 절리군 입력표(구간별 경사방향/경사 · φj · cj) → Markland 판정(평면 · 쐐기 · 전도) → 위험 모드만 Hoek-Bray 평면·쐐기 Fs. 사면 방향은 측점 `frame.left_xy` + 절토 쪽으로 자동 · 사면 경사 = 절토 경사비. 출력 = 스테레오넷(서버가 투영 좌표까지 내려 줌) · 측점별 모드·Fs. 근거 = KDS 11 70 05 L196 · L276 · KDS 44 30 00 L332(리핑암 이상 평사투영).
- **광역**(`E05_StabArea`): 노선 띠(예 좌우 100 m) DTM 격자에 무한사면 + SINMAP 포화비 → 상부 자연사면 표층붕괴 위험 지도. **D 예정노선과 같은 엔진**(한 벌).
- **보강·옹벽**: N.G 측점에 경사 완화 · 소단 · 네일/앵커 가정 → 보강 후 Fs(E 안 가정 검토만 · 임도설계로 안 돌려 씀) · C군 벽 활동·전도·지지력.
- 계산 자리 · 라이브러리 = 1차와 같음(서버 · 자체).
### 3차 — 정밀 · 3D
- Spencer · Morgenstern-Price(엄밀해) · 확률 해석(Pf) · 지진 미달 시 Newmark 변위.
- 선택 구간 3D LEM — Scoops3D(공공 저작물 · Windows 실행 파일 있음)를 바깥 프로그램으로 부르는 시험 먼저, 맞으면 자체 기둥법. 전제 = 3D 지층면 입력(시추·물리탐사 자료).
- FEM(2D·3D)은 메쉬 도구 라이센스(GPL·AGPL·비상업)와 입력(변형 계수)이 없어 **보류** — 필요 시 상용 SW 내보내기(DXF 단면)로 갈음.
---
## ⑤ 기본값 후보 (전부 사용자 확정 대상)
### 5-1. 기준안전율
| 조건 | 깎기 | 쌓기(일반) | 쌓기(연약지반) | 근거 |
|---|---|---|---|---|
| 건기 | 1.5 | 1.5 | 1.3 | KDS 11 70 05 표 4.3-3 · 4.3-1 · 4.3-2 (md L245-252 · L218-231) |
| 우기 | 1.2(지하수위 결정 · 암 ½H) / 1.3(강우침투 해석) | 1.3 | 1.2 | 같은 표 |
| 지진 | 1.1 | 1.1 | 1.1 | 같은 표 · KDS 11 90 00 표 4.2-1 (md L100-106) |
| 단기(시공 중) | 1.1 | 1.1 | 1.1 | 같은 표 |
- 1차 우기 깎기 후보 = **1.2**(지하수위 규칙 방식이라).
- 옹벽(2차) = 활동 1.5/1.2 · 전도 2.0/1.5 · 지지력 3.0/2.0 · 전체 1.2~1.5/1.1 — `technical_info/01_임도/03_계산정보/구조물_안정계산.md:33-38`(KDS 11 80 05).
### 5-2. 지반물성치 (B06 라벨 → 지층)
| B06 라벨 · 자리 | 지층 | γt (kN/m³) | γsat | c (kPa) | φ (°) |
|---|---|---|---|---|---|
| 토사 측점 전체 · 암 측점의 경계 위 | 풍화토 | 18.0 | 19.0 | 15 | 30 |
| 리핑암 측점 경계 아래 | 풍화암 | 20.0 | 21.0 | 30~40 | 33 |
| 발파암 측점 경계 아래 | 연암 | 24.0 | 24.5 | 150 | 35 |
| (경암 — 위치 정보 없음 · 블록 자중용) | 경암 | 26.0 | 26.0 | 300 | 40 |
| 성토체 | 성토층 | 18.0 | 19.0 | 10~15 | 25~28 |
| (선택) 표층 | 붕적토 | 17.5 | 18.5 | 5 | 27 |
| 절리면(2차) | — | — | — | cj 10~20 | φj 30~33 |
- 출처 = 사전조사 초안 `original/안정성평가/04_…md:14-22`. **원문 미수록** — 초안이 든 「KDS 11 70 05 · 도로설계요령」 중 KDS 원문에는 물성치 표가 없음(검색 0건) · 도로설계요령은 지식DB 에 없음 → 원문 수집 또는 사용자 확정 필요.
- KDS 11 70 05 1.7.2(md L80-86) = 물성치는 조사·시험·경험식·역해석으로 정함 · 여러 값이면 「평균 − 표준편차」 → 보고서에 「문헌 추정치 · 현장 시험 없음」을 밝혀 적는 칸 필요.
### 5-3. 그 밖
| 항목 | 후보 | 근거 |
|---|---|---|
| 지하수 — 건기 | 수위 없음(u=0) | KDS 11 70 05 표 4.3-3 |
| 지하수 — 우기 토사·풍화암 | 지표면 일치(완전 포화) · 대안 r_u | KDS 44 30 00 md L366 · KDS 11 70 05 표 4.3-3 |
| 지하수 — 우기 암반 | 사면 높이 ½ 심도 | KDS 11 70 05 표 4.3-3 |
| 지진 검토 | **기본 끔** · 켜면 k_h 입력 | KDS 11 90 00 1.8.1 ②(md L58-62) — 영향 범위에 주구조물 없으면 비적용 · 임도는 발주자 협의 |
| k_h | 지반가속도 A 의 비율로 사용자 입력 | 지진구역계수 0.22g(Ⅰ) · 0.14g(Ⅱ)는 **건축 기준 2400년 재현주기 값**(KDS 41 10 15 md L1601-1605) · 비탈면 II등급 = 500년(KDS 11 90 00 md L68-70) · 위험도계수 표(KDS 17 10 00)는 지식DB 미수록 → 수집 필요 |
| 노면 상재하중 | 10 kPa | 옹벽 배면 상재하중 10 kN/㎡ 준용(`구조물_안정계산.md:40`) · 임도 차량하중 고유 근거 없음 |
| 층 두께 | B06 암 경계(−0.5 m) 그대로 초기값 · 구간별 덮어쓰기 | `config_system_design.py:313` (물량용 값임에 주의) |
| 해석 대상 표시 | 별표2 15 m · 쌓기 10 m · 리핑암 이상 암반 | 별표2 md L253 · KDS 11 70 05 md L205-213 · KDS 44 30 00 md L332 |
---
## ⑥ 정할 거리 (갈래 · 권하는 쪽)
1. **2D 먼저 vs 3D 먼저** — 권함: 2D 먼저(기준 · 데이터 · 보고서 형식 · 대조 가능성 모두 2D · 2D 가 보통 보수적).
2. **1차 범위: 토사·성토 LEM 만 vs 암반 포함** — 권함: LEM 만(암반은 절리 현장 입력 필요 → 2차).
3. **기본 메소드** — 권함: Bishop 간편법 기본 · Janbu 보정 보조 · Fellenius 비교(엄밀해는 3차).
4. **해석 측점: 전 측점 자동 vs 트리거 구간만** — 권함: 전 측점 자동 · 보고서 대표 단면 = 트리거 + 최소 Fs 하위.
5. **지반물성치 기본값(⑤ 5-2 각 칸)** — 권함: 표의 후보값 · 사용자 칸별 확정 · 원문 수집 병행.
6. **층 구조: B06 암 경계 그대로 vs E 에서 구간별 층 두께 입력** — 권함: B06 값 초기값 + E 에서 구간별 덮어쓰기.
7. **지하수: 기준 규칙 자동 vs 사용자 수위선** — 권함: 규칙 자동 + r_u 선택.
8. **지진 검토: 기본 끔 vs 켬** — 권함: 끔(켜면 k_h 사용자 입력).
9. **기준안전율(⑤ 5-1)** — 권함: KDS 표 그대로 · 우기 깎기 1.2.
10. **노면 상재하중** — 권함: 10 kPa(근거 약함 · 확정 필요).
11. **횡단 폭: ±20 m 그대로 vs 생성 때 DTM 에서 넓혀 다시 뜸** — 권함: 다시 뜸(예 ±40 m 또는 사면고 3배).
12. **계산 자리** — 권함: 서버 단독(③) · 짝 없음.
13. **복사 범위: 필요한 것만(약 20 MB) vs 폴더 통째(3 GB)** — 권함: 필요한 것만(DB 행 + B06 · B05 route · structures · 쓰인 DTM 하나 · corridor · 광역 때 drainage).
14. **보강·경사 완화 검토: E 안 가정만 vs 임도설계로 되돌림** — 권함: E 안 가정만(「업데이트 없음」 원칙과 맞음) · 2차.
15. **오픈소스: 코드 가져오기 vs 자체 구현** — 권함: 자체 구현 · MIT/BSD 는 대조용 · GPL/AGPL/비상업 금지.
16. **지식DB 기존 확정 「프로그램은 안정계산 안 함」**(`구조물_안정계산.md:29`) — 권함: E 별도 유료 모듈은 예외로 하고 지식DB 구현 메모 갱신(설계 모듈은 경고만 유지).
17. **보고서 형식(PDF · DOCX · HWPX)** — 권함: 사용자 결정(발주처 제출 관행 기준).
18. **페이지 폴더 이름(E01~E06)** — 권함: ④ 후보 이름 · 사용자 확정.
---
## ⑦ 계획 걸음 후보
1차
1. 공통(D 계획과 함께): `projects` 그룹 칸(B/C/D/E) · 원본 프로젝트 칸 · [+] 새 프로젝트 네 갈래 화면.
2. E 생성 API: 원본 B06 확정 확인 → 동결 복사(DB 행 → `db.json` · 필요한 파일) → E storage 레이아웃. 시험: 복사본만으로 측점 57개 · 설계선 재현 · 원본 바꿔도 E 불변.
3. 횡단 모델 빌더: 복사본 → 측점별 2D 지층 폴리곤(지반선 다시 뜸 · 설계선 · 암 경계 · 성토체 · 벽). 시험: 폴리곤 닫힘 · 절성토 면적 = B06 값.
4. LEM 솔버: Fellenius · Bishop · Janbu 보정 · Entry&Exit · Grid&Radius · 수압 규칙 · k_h · 상재하중. 시험: 기준 문제 · 손계산 ±3 %.
5. `E02_StabGround` 지반 조건 화면 · 저장(캐시 → [저장]) · 기본값 = 사용자 확정표.
6. `E03_StabSection` 측점 해석 화면 · 파생 저장본(입력 지문) · 평면 위험 띠 · 3D 노선 색칠.
7. `E06_StabReport` 보고서 1차(표 · 단면 그림 · 판정 요약).
2차
8. `E04_StabRock` 절리 입력 · Markland · Hoek-Bray 평면·쐐기 · 스테레오넷.
9. `E05_StabArea` 광역 무한사면 · SINMAP 지도(D 와 엔진 공유).
10. 보강 재해석 · C군 벽 외적 안정.
3차
11. Spencer · M-P · 확률 해석 · Newmark.
12. 선택 구간 3D LEM(Scoops3D 연계 시험 → 자체 기둥법 여부 판단).
---
## 참고 출처(웹 · 라이센스 확인)
- xslope — Apache-2.0 표기: https://pypi.org/project/xslope/
- pySlope — MIT(SafetyCLI 표기) · 수평 지층만: https://pyslope.readthedocs.io · https://data.safetycli.com/packages/pypi/pyslope
- pyBIMstab — BSD-2-Clause: https://github.com/eamontoyaa/pyBIMstab
- pyCSS — 라이센스 표기 못 찾음: https://pypi.org/project/pycss-lem
- Scoops3D — USGS 공공 저작물: https://www.usgs.gov/media/files/scoops3d-fortran-source-code-updated-v1302-may-23-2025
@@ -0,0 +1,151 @@
# 요구서 345 — 신규 프로젝트 그룹 D 예정노선 · E 안정성평가
원문 = `사용자요구_1025.md` 요구 345 · 346 · 근거 분석 = `_분석_345-A_등록권한공유.md` · `_분석_345-B_틀노선추천.md` · `_분석_345-C_내보내기양식.md` · `_분석_345-D_안정성평가제안.md` · 계획 = `PLAN.md` 528~532.
## 1. 범위
| 그룹 | 폴더 | 이번 범위 |
| --- | --- | --- |
| B 임도설계 | `B0x_*` (지금) | 종류 칸 · [+] 카드 · 예정노선 가져오기만 더함 |
| C 사방설계 | `C0x_*` | 카드 자리만(「준비 중」) |
| D 예정노선 | `D0x_*` | 전부 |
| E 안정성평가 | `E0x_*` | 1차(2D 해석 · 보고서) · 2·3차는 뒤 |
- 원칙 = B 그룹 로직 재활용(요구 346) — 새로 만드는 것은 B 에 없는 것만 · 로직 주인은 B 에 두고 D · E 가 가져다 씀.
## 2. 공통
### 2-1. 프로젝트 생성
- 대시보드 [+] → 고르기 모달 · 카드 넷(그림 + 제목) = 예정노선 · 임도설계 · 사방설계 · 안정성평가.
- 산림청이 아니면 예정노선 카드 흐림(누르면 까닭 안내) · 사방설계 = 「준비 중」.
- 카드별 등록 화면 — 임도설계 = B02 그대로 · 예정노선 = D01 · 안정성평가 = E01.
- 대시보드 프로젝트 표에 「종류」 열 · 행 누르면 종류별 첫 화면.
### 2-2. 역할 · 권한
- 산림청 = 시스템관리자 또는 메일 `*.go.kr` 사용자(이름은 「산림청」 · 요구 346) · 예정노선 생성 · 고침은 산림청만.
- 산림청 기관도 회사로 등록(사업자번호 칸에 기관 고유번호) — 지금 회사 · 권한 구조 그대로 씀.
- 예정노선을 지정받은 아이슬로 등록 회사의 구성원 = 그 예정노선 **보기만** — 판정은 공용 접근 판정 한 곳(「공유 회사는 GET 만」).
- 지정받은 회사는 대시보드 「받은 예정노선」 구역에서 봄(연도 · 노선 · 연결 상태 · 업데이트 있음 배지).
### 2-3. 연결 · 복사 원칙
| 연결 | 시점 | 원본이 바뀌면 |
| --- | --- | --- |
| D 예정노선 → B 임도설계 | 업체가 연결할 때 그 연도 노선을 복사 | 「업데이트 있음」 알림 · 반영은 사용자 판단 |
| B 임도설계 → E 안정성평가 | E 생성 때 필요한 자료만 복사(별도 storage) | 업데이트 기능 없음 · 원하면 새 E 프로젝트 |
- 바뀜 판정 = 내용 지문 비교(같은 값으로 되돌리면 알림 꺼짐).
## 3. D 예정노선
- 쓰는 사람 = 산림청(발주처) · 다년 노선을 연도 단위로 세우고 이어 감 · 업체는 연도마다 여럿 · 다를 수 있음.
- 페이지 = `D01_PlanRegister`(등록) → `D02_PlanBase`(1단계 기준 지정) → `D03_PlanAnalysis`(2단계 분석) → `D04_PlanConfirm`(확정 · 업체 · 내보내기) · 화면 틀 = B05~B09 틀 그대로(메인 · 좌우상하 패널 · 패널 안 페이지 이동 단추).
### 3-1. 등록 (D01)
| 칸 | 값 |
| --- | --- |
| 사업 연도 | 범위(시작 · 끝) |
| 사업 지역 | 수기 |
| 종류 | 「노선 계획」 하나 |
| 프로젝트명 | 수기 또는 자동(B02 이름 조합기 재활용) |
| 노선 시작 누가거리 | 첫 연도 시점의 측점 값 · 이후 연도는 이어 셈 |
| 노선 종료 누가거리 | 계획 목표 · 분석 뒤 실제 누가와 다르면 차이 표시 |
| 도면 관련 칸 | 없음 |
### 3-2. 1단계 기준 지정 (D02)
- 메인 = 카카오맵 · 좌 = 연도 표(연도 · 시점 · 종점 · 좌표 입력칸).
- 지점 지정 = 지도에서 끌기 · 누르기 또는 좌표 입력(다른 프로그램 결과).
- 직전 연도 종점 = 다음 연도 시점(서버가 저장할 때 맞춤 · 빈 연도 거절).
- [>] = 지점 저장 → 그 지점 기준으로 수치지형도를 외부 API 로 받아 영구저장 시작.
### 3-3. 2단계 분석 (D03)
- 메인 = 수치지형도 평면(위성 + 등고선 + 지점 + 노선) · 여기서도 지점 끌기 · 받은 범위 밖으로 가면 그 영역 더 받음(옛 도엽 유지).
- [분석] = 연도 구간마다 B05 노선 추천 엔진(코드 한 벌 · B05 에 둠)으로 지점을 잇는 노선 · 갈래 넷 중 연도마다 고름.
- 보임 = 노선 중심선 · 평면 측점 스냅 · 표기 · 측점 누르면 지반선 횡단 · 3D(지형 + 중심선 · 구조물 없음).
- 안 보임 = 노견 · 절성토선 · 종단도 · 배수유역 · 구조물.
- 분석 조건 칸 = 임도 종류 · 설계속도(추천의 종단 상한 · 최소 R 을 B 법정 함수로 냄 · 기본값은 사용자 확정).
### 3-4. 확정 · 업체 · 내보내기 (D04)
- 연도마다 업체 여럿 지정 — 아이슬로 등록 회사 고르기 또는 업체명 + 메일 수기.
- [확정] = 지정 업체에 메일(그 업체 연도 묶음 zip 첨부) + 등록 회사는 「받은 예정노선」에 뜸.
- 내보내기 양식 = `실무문서/2026년 임도 용화/예정노선/대상지_일월.용화.2.2` 와 같은 꼴:
| 파일 | 내용 |
| --- | --- |
| `대상지_<지역>.<연장km>_<연도>.shp/.shx/.dbf/.prj/.cpg` | 그해 시점→종점 중심선 한 선 · UTM-K(EPSG 5179) · cp949 · 칸 `대상지` · `길이`(km) + 덧칸 `연도` · `시점누가` · `종점누가` |
| `대상지_<지역>.<연장km>_전체.*` | 전 연도 이은 한 선(발주처 보관용) |
| `좌표표_<프로젝트명>.xlsx` (선택) | 연도별 시점 · 종점 좌표 · 위경도 · 누가 · 연장(사람용) |
### 3-5. 업체 쪽 받기 · 임도 연결
- 받은 예정노선에서 [새 임도 프로젝트로] 또는 [기존 프로젝트에 연결].
- 연결 = 그 연도 shp 한 벌을 임도 프로젝트 B03 입력에 넣음(파일로 올린 것과 같은 길 · 옛 결과 지우기 확인 거침) · 지형 자료는 업체가 올림.
- B03 노선 칸 옆 [예정노선에서 가져오기] — 파일 대신 지정받은 연도 노선을 고름.
- 연도 측점은 0 부터(이어 받기는 B03 새 기능이 필요해 뒤로).
## 4. E 안정성평가
- 대상 = B06(횡단 설계)까지 끝난 같은 회사 임도 프로젝트.
- 페이지 = `E01_StabRegister`(생성) → `E02_StabGround`(지반 조건) → `E03_StabSection`(측점 해석) → `E04_StabReport`(보고서) · 2차 `E05_StabRock`(암반) · `E06_StabArea`(광역).
### 4-1. 생성 · 복사 (E01)
- 임도 프로젝트 고르기(B06 완료만 목록) → 생성 시점 동결 복사 → 별도 storage.
- 복사 범위 = 해석에 쓰는 것만(DB 행 · B06 횡단 · B05 노선 · 구조물 · 쓰인 지형 하나 등 약 20 MB) · 원본 점군(약 1.6 GB) · B07~B09 는 안 가져옴.
### 4-2. 방법 (브레인 제안)
| 단계 | 방법 | 입력 | 출력 |
| --- | --- | --- | --- |
| 1차 | 측점별 횡단 2D 한계평형해석 — Bishop 간편법 기본 · Janbu 보정(암 경계 따라) · Fellenius 비교 · 절토 · 성토 쪽 따로 · 건기 · 우기(지진 선택) | B06 복사본(지반선 · 설계선 · 경사 · 소단 · 토사/암 경계 · 벽) + 지반물성치 + 지하수 규칙 + 노면 하중 + 기준안전율 | 측점별 최소 안전율 · 판정 · 임계 원호 그림 · 위험 구간 색띠 · 보고서 |
| 2차 | 암반 평사투영(평면 · 쐐기 · 전도) · 노선 주변 광역 무한사면 위험 지도 · 보강 가정 재해석 · 벽 외적 안정 | 절리 방향(현장 조사) · 지형 격자 | 측점별 파괴 모드 · 위험 지도 |
| 3차 | 엄밀해(Spencer 등) · 확률 해석 · 고른 구간만 3D 해석 | 3D 지층(시추 등) | 정밀 안전율 |
- 2D 먼저 까닭 — 국내 기준(KDS 11 70 05)이 흙 비탈면 = 2D 한계평형 기본 · 납품 보고서가 단면 단위 · B06 단면이 이미 있음 · 3D 는 필요한 입력(3D 지층)이 없고 쓸 만한 해석 도구가 상용 판매에 막히는 라이센스.
- 「3D」 = 1·2차에서 2D 결과를 3D 노선 위에 색으로 칠해 보여 줌.
- 계산 = 서버 파이썬 단독(화면은 값만 바꿈 · [해석] → 서버) · 결과 = 파생 저장본(입력 지문이 다를 때만 다시 셈) · 코드는 직접 짬(MIT · BSD 오픈소스는 결과 대조만 · GPL · AGPL · 비상업 금지).
### 4-3. 1차 화면
- E02 = 지반물성치 표(지층별 프리셋 · 구간별 덮어쓰기) · 층 두께(B06 암 경계 초기값) · 지하수 규칙 · 지진 켬/끔 · 노면 하중 · 기준안전율.
- E03 = 좌 측점 목록(안전율 색) · 가운데 횡단 + 임계 원호 · 우 결과 · 절편표 · 위 평면 위험 띠 · 3D 색칠 보기.
- E04 = 보고서(표 · 대표 단면 그림 · 판정 요약 · 「문헌 추정치 · 현장 시험 없음」 표기).
## 5. 데이터 · 계산 자리
- DB(추가만) — `projects` 에 종류 · 사업연도 끝 · 원본 프로젝트 · 복사 시각 · 복사 지문 · 새 표 = 예정노선 연도 구간 · 연도별 지정 업체(등록 회사 또는 수기 이름 · 메일 · 연결한 임도 프로젝트).
- storage — D · E 프로젝트도 `storage/{회사}/{사용자}/{project_id}/` · D 지형은 그 안 `B04_PreProcess/` 배치 그대로(지형 코드 주인 = B04 · 고칠 곳 0) · D 정본은 `D0x_*/` · E 복사본 · 결과는 `E0x_*/`.
- 계산 자리(CLAUDE.md 5장) — D 노선 추천 = ③ 서버 단독(B 와 같음) · D 측점 · 지반 횡단 = ① 짝 이미 있음 · E 해석 = ③ 서버 단독.
## 6. 정함(브레인 · 사용자가 바꿀 수 있음)
- 산림청 판정 = `*.go.kr` 전부(지자체 · 다른 부처 포함) · 산림조합처럼 go.kr 아닌 발주처가 생기면 계정 깃발을 덧붙임.
- 지정 회사의 보기 범위 = 그 회사 구성원 전부.
- 완료 메일 = 파일 첨부(수기 업체도 로그인 없이 받음).
- D 좌표계 = 작업은 경도로 5185/5186/5187 자동 · 변환은 서버 · 내보내기는 5179(용화 양식).
- D DEM = 연도 구간별(긴 노선 메모리 · 비용면 한도) · 도엽 · 위성은 프로젝트 한 벌.
- D 추천 갈래 = 넷(follow 뺌) 연도마다 고름 · 연도 경계는 꺾인 채(경계점 = 측점) · 계류 이격은 도엽 하천선으로 반영 · 탐색 복도 폭은 D 만 넓힘(B 기본 그대로 · 폭은 실측으로).
- 카카오 지도 부품 = B08 에서 공용(`ui_template/`)으로 옮김.
- 페이지 폴더 이름 = 3장 · 4장 이름.
- E = 2D 먼저 · 1차 토사 · 성토만(암반은 절리 입력이 필요해 2차) · 전 측점 자동 · 지하수 규칙 자동 · 지진 기본 끔 · 보강 검토는 E 안 가정만(2차).
## 7. 사용자 확정 필요
1. E 방향 — 2D 먼저(위 제안)로 갈지.
2. E 지반물성치 기본값 — 후보 = 풍화토 γ 18 · c 15 · φ 30 / 풍화암 γ 20 · c 30~40 · φ 33 / 연암 γ 24 · c 150 · φ 35 / 성토 γ 18 · c 10~15 · φ 25~28(kN/m³ · kPa · °) · **원문 근거가 지식DB 에 없음**(사전조사 초안에만) — 원문 수집 또는 직접 정함.
3. E 기준안전율 — 후보 = KDS 11 70 05 표 그대로(건기 1.5 · 우기 깎기 1.2 · 쌓기 1.3 · 지진 1.1).
4. E 노면 하중 — 후보 10 kPa(옹벽 상재하중 준용 · 임도 고유 근거 없음).
5. E 보고서 형식 — PDF · DOCX · HWPX 중.
6. 지식DB 옛 결정 「프로그램은 안정계산 안 함」 — E 유료 모듈은 예외로 둘지.
7. D 분석 조건 기본값 — 임도 종류 · 설계속도.
## 8. 범위 밖 · 나중
- C 사방설계 그룹 · E 2·3차 · D 연도 측점 이어 받기(B03 시점 측점 칸) · 앱 안 알림함.
- D 예정노선 재해안전성 평가(사전조사 `original/예정노선/`) — 요구가 오면 E 광역 엔진과 한 벌로.