Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_5

This commit is contained in:
2026-10-13 18:38:16 +09:00
2 changed files with 73 additions and 0 deletions
@@ -234,3 +234,4 @@
203. (원문 · 10-13) 7. b09 페이지의 탭의 상세페이지에서 안내문구 영역이 있음. 영역을 텍스트 3줄정도만 보이게 하고 이후는 스크롤로 처리, 테이블을 더 넓게 사용하도록 조절, 이때 제일 하단행 고정기능이나 행이 적을 경우 합계행이 끌려올라가야하니 조심. 이때 안내문구 영역도 끌려올라가야함. 안내문구 영역은 2줄로 바꿀수도 있으니 참고하여 코드 반영
204. (원문 · 10-13) 8. B09의 좌측페널 데이터 점검 및 공기 옵션 컨티이너의 기본값은 접힘상태. 9. B07 좌측패널의 평면도, 종단도, 횡단도는 접힘상태가 기본값이며 B07 초기 접근시 보여주는 페이지는 표지로 변경 10. B06 좌측 패널의 횡단보기 설정 기본값 접힘. 11. B05 좌측 패널의 컨테이너 이름을 계획노선 컨테이너의 기본값은 접힘상태로 변경 12. exp_sub1_device 브랜치 삭제
205. (원문 · 10-13) 다음은 B05와 B06의 좌측 공용 패널의 내용 중 하단의 구조물 리스트에서 구조물을 하나씩 삭제하면서 리프레시 해봤는데 하나만 남을때까지는 문제없어 보이는데 마지막을 구조물을 삭제한 직후 구조물 리스트가 초기화 되고 리프레시 하면 마지막 하나가 남아있는 상황이야. 확인해줘. 뭔가 저장에 대한 제어가 문제가 있는것같아. 주고 자동생성된 횡단배수 구조물로 봐서는 배수유역에 대한 자동계산이나 영구저장소 문제로 판단됨.
206. (원문 · 10-13) 1. 조사하는 동안 구조물리스트 제일 하단에 구조물 전체삭제 버튼을 넣어줘. 하나도 없으면 당연히 숨김처리되어야함. 2. 직전 깃 요청이 깃 싱크였어. 전역 깃 싱크였어?
@@ -0,0 +1,72 @@
# 312 분석 — B05 · B06 좌측 구조물 목록: 마지막 하나 지움이 새로고침 뒤 되살아남
sub5 · 조사만 · 코드 고치지 않음 · 2026-10-13
## 한 줄 결론
관(자동 생성 횡단배수 = `pipe_points.json`) 목록에서 **「빈 목록」이 세 군데에서 「값 없음」으로 읽힘** — 화면 초안 읽기 · 서버 계산 · 서버 저장. 그래서 마지막 관을 지우면 화면은 자동 배치로 다시 차고(「초기화」), 새로고침 · [저장] 뒤에는 저장돼 있던 마지막 하나가 되살아남. 손으로 놓은 구조물(`structures.json`)은 빈 목록을 바르게 다룸 — 흠 없음.
## 재현
방법 — 검증_sub5(`bec7fe41-…`) storage **사본**(임시 폴더) + DB 읽기 전용 세션으로 서버 API 를 화면 차례대로 부름(기존 `test_b05_b06_save_roundtrip.py` 와 같은 틀). 화면(ORCA)은 띄우지 않음 — 화면 쪽은 코드 길을 따라 확인.
시작 상태 — 저장된 관 11개(전부 자동 배치 `spacing`·`stream`) · 구조물 0개.
| 단계 | 화면에서 하는 일 | 서버 요청 | 결과 |
|---|---|---|---|
| P1 | 하나씩 지우고 [저장] → 2개 | PUT pipe-points [2개] | 저장 2 · 파일 2 ✔ |
| P2 | 하나 더 지우고 [저장] → 1개 | PUT [1개] | 저장 1 · 파일 1 ✔ |
| P3 | **마지막 하나 지움** | POST detail-basins `[]` (화면 다시 나눔) | **응답 관 11개 = 자동 배치** → 목록 「초기화」 |
| P4 | 새로고침([저장] 안 함) | 초안 `[]` 를 「없음」으로 봄 → GET pipe-points | **1개(85.05) 되살아남** |
| P5 | [저장] | PUT `[]` | **저장 1 · 파일 1 그대로** (빈 목록 안 써짐) |
| P6 | (파일이 `points: []` 라면) | GET | **자동 배치 11개 · saved=false** |
| S1~S3 | 손으로 놓은 구조물 1개 → 지우고 [저장] → 새로고침 | PUT structures `[]` → GET | 0개 ✔ (정상) |
화면 길별 결과(코드 추적):
| 화면 | [저장] 안 함 · 새로고침 | [저장] 함 |
|---|---|---|
| B05 (배수유역도 · 좌측 목록) | 지운 직후 자동 11개로 참(P3) · 새로고침 → 저장분 1개(P4) | 관 초안 `[]` PUT → 서버가 저장분 1개 유지(P5) · 이어서 `side.savePipes()` 가 **화면 목록(자동 11개)을 PUT** → 자동 11개가 정본에 저장됨 |
| B06 (구조물 목록) | B06 목록은 `??` 라 빈 목록 유지 · 그러나 초안 쓰기 뒤 `side.reload()` → 배수유역도가 저장분 1개를 다시 읽어 B05 쪽 목록 · 종단 알약에 1개 | 관 초안 `[]` PUT → 1개 유지 · `side.savePipes()` 가 배수유역도 목록(1개) PUT → 1개 되살아남 |
## 원인 — 「빈 목록 = 없음」 자리
1. **화면 초안 읽기** — `B05_Profile/B05_Profile_UI_Drainage_Panel.ts:424` `return pending?.length ? computeDetailBasins(...) : fetchDetailPipePoints(...)` — 초안 `[]` 를 「초안 없음」으로 보고 저장분을 읽음. 같은 초안을 B06 은 `readPendingPipes(projectId) ?? 저장분`(`B06_Section_UI_Page_Structures_Panel.ts:388`)으로 읽어 두 보기가 갈림.
2. **서버 관 목록 고르기** — `B04_PreProcess/B04_PreProcess_Router_Basins.py:373` `points = requested or stored or None` — 요청 `[]` 는 저장분으로, 저장분 `[]` 는 `None`(자동 배치)으로 넘어감. PUT 도 이 줄을 거쳐 **빈 목록이 절대 저장되지 않음**(P5).
3. **서버 계산** — 같은 파일 `:70` `chainages = [...] if points else None` · `common_util/common_util_drainage_detail.py:189` `if confirmed_chainages:` — 빈 확정 목록을 「기본 관 + 간격 보충(자동 배치)」으로 바꿈(P3 · P6). 사용자가 말한 「배수유역 자동 계산이 다시 돎」이 이 자리.
4. 덤 — `A00_Common/design/design_save.ts` 의 관 차례는 초안 내보내기 뒤 `side.savePipes()`(`design_shared.ts:301`)로 **배수유역도 화면 목록을 한 번 더 PUT** — 1~3 때문에 화면 목록이 자동 11개 · 저장분 1개로 바뀐 뒤라 그 값이 정본이 됨.
정상인 자리(빈 목록을 바르게 다룸): 세션 캐시 `readState`(`[]` 그대로) · `flushPendingPipes`(`if (!pending)` — `[]` 도 보냄) · 구조물 PUT · GET(`structures.json` `[]` 저장 · 읽기) · B05 계획선 · 횡단 측점의 관 읽기(`B05_Profile_Engine_Sections.py:175` — `[]` 그대로). `initial_snapshot` · [초기화](DELETE pipe-points)는 이 흐름과 무관.
곁 흠(같은 꼴 · 표시만) — `B06_Section/B06_Section_Section_Store.ts:81` `if (!drafts || !drafts.length)` — 구조물 초안 `[]` 를 「초안 없음」으로 봐 저장 전 횡단도에 저장분 벽(C군)이 남음. [저장] 뒤에는 정본이 `[]` 라 풀림.
## 고칠 자리 제안 (한 벌 · ③ 서버 단독 + 화면 한 줄)
뜻 정함 — **`None`(파일 없음 · 노선 바뀜 · 요청에 칸 없음) = 자동 배치 · `[]` = 사용자가 다 지움(관 0개)**. 자동 배치로 되돌리기는 [초기화](DELETE)만.
1. 서버 `B04_PreProcess_Router_Basins.py` `_resolve` — 요청 본문에 `points` 칸이 있으면(빈 목록 포함) 그 값 · 없으면 `None`. `points = requested if requested is not None else stored`. 응답 `saved` 판정(`bool(stored) and not requested`)도 `is None` 으로.
2. 서버 같은 파일 `_build:70 · :74` — `if points is not None` 로.
3. 서버 `common_util_drainage_detail.py:189` `build_detail` — `if confirmed_chainages is not None:` (빈 목록이면 관 0 · 유역 0 — 아래 `if not pipes: return detail` 가 이미 받음).
4. 화면 `B05_Profile_UI_Drainage_Panel.ts:424` — `pending !== null` 로(B06 `??` 와 같은 규칙).
5. (선택) 곁 흠 `B06_Section_Section_Store.ts:81` — 「`[]` 도 초안 없음」 주석(2026-09-09)이 막던 결함(저장분 벽을 통째로 지움)을 다시 보고 `drafts === null` 로 바꿀지 판단 필요 — 그 결함의 까닭이 「빈 초안」이 아니라 다른 곳이었는지 먼저 확인.
짝 파일 — 없음(관 목록 고르기는 서버 단독 · 화면은 한 줄). `load_pipe_points` 는 이미 `[]` 와 `None` 을 가름 — 고칠 것 없음.
영향:
- B04 배수유역 편집(`B04_PreProcess_UI_Basins.ts:334` 다시 나눔 · `:479` 저장)도 관을 다 지우면 이제 0개로 남음(지금은 자동 배치로 다시 참) — 같은 뜻으로 맞춰짐.
- 관 0개 정본 → B05 계획선 정착 · 구조물 측점 · B06 암거 횡단 · B08 수량에서 관이 빠짐 — 사용자가 다 지운 뜻 그대로.
- 문서 줄 고침 — `computeDetailBasins` 머리 주석(`B04_PreProcess_Api_Fetch.ts:586~588`) · `post_detail_basins` 독스트링 「points 를 비우면 자동 배치」.
시험 거리(`resources/tester/test_312_empty_pipes.py` 가칭 · 위 재현과 같은 사본 틀):
- PUT `[]` → 응답 0 · 파일 `points: []` · GET 0 · `saved=true`.
- POST detail-basins `[]` → 관 0 · 유역 0.
- 파일 없음 → GET 자동 배치(지금대로) · DELETE 뒤 자동 배치(지금대로).
- 노선 지문 바뀌고 좌표 없는 저장분 → 자동 배치(지금대로 · `None` 길).
- 화면 소스 — `loadSaved` 가 `pending !== null` 로 고르는지(기존 `test_298_add_reanalyze.py` 문자열 시험 그대로 통과).
## 되돌림 확인
- 실제 프로젝트 파일 손 안 댐 — 재현은 임시 사본에서 · 끝나고 사본 지움.
- `pipe_points.json` sha1 `503f60d6…` · `structures.json` sha1 `a12ee824…` — 재현 앞뒤 같음.
- DB — 읽기 전용 세션(`tx_read_only=1`) · 하류 무효화 함수는 가짜로 갈음 · 쓰기 없음.
- 화면 탭 · 서버 재시작 없음 · git 작업 트리 깨끗(커밋 없음).