fix(472 덧 관 지움 ↶): 서버 상세 읽기 관 세트 = 지금 노선에 얹은 관 자리 — 측점 계획 · 관 지점 GET · 화면과 한 벌

- 관 지점 정본 지문이 지금 노선과 어긋난 저장분(검증_sub4 · 파일 394 · 좌표 351) — 측점 계획(_load_pipe_points) · GET 은 351 에 얹고 서버 상세 읽기(attach_saved_shapes)만 파일 누가거리로 찾아 351 관 세트 빠짐 → 새로고침 = 관 세트 없음 · 관 지움 ↶ = 화면이 다시 얹어 관 세트 있음(누가토량 갈림)
- saved_pipes(노선 경로) — 상세 GET · 재생성 응답 · 설계 미리보기가 노선 경로를 넘김 · 노선 못 읽으면 저장분 그대로
- 시험 test_472_d_pipe_route_attach(옛 코드 실패) · golden 헬퍼도 같은 읽기

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-19 11:22:37 +09:00
co-authored by Claude Opus 5.5
parent 0e77191421
commit 789bd9ce09
5 changed files with 126 additions and 9 deletions
+12 -4
View File
@@ -232,7 +232,9 @@ async def get_sections(project_id: UUID, route_id: int) -> SectionSummaryRespons
)
def _read_section_detail(project_root: Path, longitudinal_file_path: str) -> dict:
def _read_section_detail(
project_root: Path, longitudinal_file_path: str, route_data_path: str | None = None
) -> dict:
"""검증된 프로젝트 루트 안의 종단 및 횡단 JSON을 읽는다."""
root = project_root.resolve()
longitudinal_path = (root / longitudinal_file_path).resolve()
@@ -258,7 +260,7 @@ def _read_section_detail(project_root: Path, longitudinal_file_path: str) -> dic
):
raise ValueError("종횡단 상세 파일 형식이 올바르지 않습니다.")
# 측점 그림 자료(관 세트 · 벽 · 포장 · 맹암거 · 빈칸 경고) = 형상 얹기 한 벌(323-4 · 화면 짝 attachShapes)
attach_saved_shapes(root, cross_sections)
attach_saved_shapes(root, cross_sections, route_data_path)
relabel_pipe_stations(root, cross_sections) # 저장으로 종류만 바꾼 관 — 카드 제목(54-4)
return {"longitudinal": longitudinal, "cross_sections": cross_sections}
@@ -314,10 +316,11 @@ async def get_section_detail(
try:
# 서로 기다릴 이유가 없는 읽기 셋 — 원격 DB 라 순차로 내면 왕복이 그대로 더해진다
# (질의 하나 약 12ms, 2026-09-06 실측). 같이 보내 가장 느린 하나의 시간만 쓴다.
longitudinal, stored_path, designs = await asyncio.gather(
longitudinal, stored_path, designs, source = await asyncio.gather(
run_with_connection(get_longitudinal_section, project_id, route_id),
run_with_connection(get_project_storage_relative_path, project_id),
run_with_connection(get_cross_section_designs, route_id),
run_with_connection(get_route_generation_source, project_id, route_id),
)
if not longitudinal:
return JSONResponse(
@@ -329,6 +332,9 @@ async def get_section_detail(
_read_section_detail,
project_root,
str(longitudinal["longitudinal_file_path"]),
(source or {}).get(
"route_data_path"
), # 관 = 이 노선에 얹은 것(측점 계획 · 화면과 같음)
)
# DB에만 있는 잠정 설계 지정을 chainage 근사로 각 횡단에 얹어 화면 복원을 돕는다.
for record in designs:
@@ -461,7 +467,7 @@ async def regenerate_route_sections(
raise
result = sections["result"]
# 재생성 응답도 상세 조회와 같은 형상 얹기 한 벌(323-4) — 화면이 어긋나지 않게.
attach_saved_shapes(project_root, result["cross_sections"])
attach_saved_shapes(project_root, result["cross_sections"], source["route_data_path"])
return SectionDetailResponse(
longitudinal=result["longitudinal"], cross_sections=result["cross_sections"]
)
@@ -517,12 +523,14 @@ async def preview_cross_designs(
)
stored_path = await get_project_storage_relative_path(connection, project_id)
designs = await get_cross_section_designs(connection, route_id)
source = await get_route_generation_source(connection, project_id, route_id)
designs = _with_design_choices(designs, request.design_choices)
project_root = Path(resolve_stored_project_path(stored_path))
detail = await asyncio.to_thread(
_read_section_detail,
project_root,
str(longitudinal_row["longitudinal_file_path"]),
(source or {}).get("route_data_path"),
)
def rebuild() -> None: