diff --git a/A00_Common/design/design_pipeline_cross.ts b/A00_Common/design/design_pipeline_cross.ts
index c3d92c4fc..0cd2ea14b 100644
--- a/A00_Common/design/design_pipeline_cross.ts
+++ b/A00_Common/design/design_pipeline_cross.ts
@@ -14,7 +14,7 @@
import type { CrossSection, SectionDetailResponse } from "../../B06_Section/B06_Section_Api_Fetch";
import { effectiveStandardCross } from "../../B06_Section/B06_Section_UI_Standard_Panel";
import type { CrossInput, SectionSpecs } from "../../B05_Profile/logic/B05_Profile_Pipeline_Detail";
-import type { PipelineStation } from "./design_pipeline_types";
+import type { PipelineStation } from "./logic/design_pipeline_types";
export interface PipelineCrossSource {
input: CrossInput;
diff --git a/A00_Common/design/design_pipeline_page.ts b/A00_Common/design/design_pipeline_page.ts
index fd941dd97..46aebc78f 100644
--- a/A00_Common/design/design_pipeline_page.ts
+++ b/A00_Common/design/design_pipeline_page.ts
@@ -19,26 +19,26 @@
* [저장](sub5)이 서버 정본 — 노선을 먼저 보내고 `pendingAlignment(DRAFT_ROUTE_ID)` 를 새 노선에 보냄.
* ========================================================================== */
-import { createDesignPipeline, publishToStore, type DesignPipeline } from "./design_pipeline";
+import { createDesignPipeline, publishToStore, type DesignPipeline } from "./logic/design_pipeline";
import { pipelineCrossSource, type PipelineCrossSource } from "./design_pipeline_cross";
-import { createStationsStage } from "./design_pipeline_stations";
+import { createStationsStage } from "./logic/design_pipeline_stations";
import type {
PipelineInputs,
PipelineStation,
RouteDraft,
StageFn,
Vertex,
-} from "./design_pipeline_types";
+} from "./logic/design_pipeline_types";
import { useDesignStore } from "./design_store";
import { fetchDetailPipePoints } from "../../B04_PreProcess/B04_PreProcess_Api_Fetch";
import type { SectionDetailResponse } from "../../B06_Section/B06_Section_Api_Fetch";
-import { createCrossStage } from "../../B06_Section/B06_Section_Cross_Stage";
+import { createCrossStage } from "../../B06_Section/logic/B06_Section_Cross_Stage";
import {
emptyEdits,
type AlignmentBase,
type AlignmentEdits,
type ProfileAlignment,
-} from "../../B05_Profile/B05_Profile_UI_Profile_Alignment";
+} from "../../B05_Profile/logic/B05_Profile_UI_Profile_Alignment";
import {
markAlignmentSaved,
readAlignmentDraft,
diff --git a/A00_Common/design/design_profile.ts b/A00_Common/design/design_profile.ts
index ecf90d80b..05787a867 100644
--- a/A00_Common/design/design_profile.ts
+++ b/A00_Common/design/design_profile.ts
@@ -23,7 +23,7 @@ import {
hasLegacyAlignment,
readAlignment,
toDesignProfile,
-} from "../../B05_Profile/B05_Profile_UI_Profile_Data";
+} from "../../B05_Profile/logic/B05_Profile_UI_Profile_Data";
import { createProgressCircle } from "@ui/ui_template_progress";
import { showToast } from "@ui/ui_template_elements";
import { saveProfileAlignment } from "../../B05_Profile/B05_Profile_Api_Fetch";
@@ -39,12 +39,12 @@ import type {
AlignmentBase,
AlignmentEdits,
ProfileAlignment,
-} from "../../B05_Profile/B05_Profile_UI_Profile_Alignment";
+} from "../../B05_Profile/logic/B05_Profile_UI_Profile_Alignment";
import {
buildAlignment,
emptyEdits,
toAlignmentBase,
-} from "../../B05_Profile/B05_Profile_UI_Profile_Alignment";
+} from "../../B05_Profile/logic/B05_Profile_UI_Profile_Alignment";
import { createProfileEditStore } from "../../B05_Profile/B05_Profile_UI_Profile_Edit";
import {
structureGroupMenuItems,
@@ -69,7 +69,7 @@ import {
createElevationHold,
createProfileDrag,
} from "../../B05_Profile/B05_Profile_UI_Profile_Drag";
-import { planCurveWarning, sampleAt } from "../../B05_Profile/B05_Profile_UI_Profile_Guard";
+import { planCurveWarning, sampleAt } from "../../B05_Profile/logic/B05_Profile_UI_Profile_Guard";
import { listedBase } from "./design_profile_base";
import * as pagePipeline from "./design_pipeline_page";
import type { RouteProfilePanelCallbacks } from "../../B05_Profile/B05_Profile_UI_Profile_Panel_Types";
diff --git a/A00_Common/design/design_profile_base.ts b/A00_Common/design/design_profile_base.ts
index b706bfe86..423667a34 100644
--- a/A00_Common/design/design_profile_base.ts
+++ b/A00_Common/design/design_profile_base.ts
@@ -5,7 +5,7 @@
* ========================================================================== */
import type { SectionDetailResponse } from "../../B06_Section/B06_Section_Api_Fetch";
-import type { AlignmentBase } from "../../B05_Profile/B05_Profile_UI_Profile_Alignment";
+import type { AlignmentBase } from "../../B05_Profile/logic/B05_Profile_UI_Profile_Alignment";
import type { IrregularStation } from "../../B05_Profile/B05_Profile_UI_IrregularStations";
import {
irregularGraphStations,
diff --git a/A00_Common/design/design_profile_free_view.ts b/A00_Common/design/design_profile_free_view.ts
index 9584478f9..48584c4ee 100644
--- a/A00_Common/design/design_profile_free_view.ts
+++ b/A00_Common/design/design_profile_free_view.ts
@@ -17,7 +17,7 @@ import {
parseWindowTransform,
type ChartWindow,
type FreeDraw,
-} from "./design_profile_free";
+} from "./logic/design_profile_free";
const SVG_NS = "http://www.w3.org/2000/svg";
diff --git a/A00_Common/design/design_store.ts b/A00_Common/design/design_store.ts
index 3b0720983..9f5199e22 100644
--- a/A00_Common/design/design_store.ts
+++ b/A00_Common/design/design_store.ts
@@ -24,10 +24,10 @@ import type { StateName } from "../b_page_state";
import { CURRENT_PROJECT_ID_KEY } from "../../config/config_frontend";
import type { StructureInstance } from "../../B05_Profile/B05_Profile_Api_Structures";
import type { DetailPipeInput } from "../../B04_PreProcess/B04_PreProcess_Api_Fetch";
-import type { AlignmentEdits } from "../../B05_Profile/B05_Profile_UI_Profile_Alignment";
+import type { AlignmentEdits } from "../../B05_Profile/logic/B05_Profile_UI_Profile_Alignment";
import type { SectionDetailResponse } from "../../B06_Section/B06_Section_Api_Fetch";
-import type { ProfileAlignment } from "../../B05_Profile/B05_Profile_UI_Profile_Alignment";
-import type { PipelineStation, PlanFootprint, RouteDraft } from "./design_pipeline_types";
+import type { ProfileAlignment } from "../../B05_Profile/logic/B05_Profile_UI_Profile_Alignment";
+import type { PipelineStation, PlanFootprint, RouteDraft } from "./logic/design_pipeline_types";
/** 한 페이지의 두 보기(계획서 24-1). */
export type DesignView = "profile" | "cross";
diff --git a/A00_Common/design/design_structure_ford_calc.ts b/A00_Common/design/design_structure_ford_calc.ts
index 0cfa6c52d..afe825847 100644
--- a/A00_Common/design/design_structure_ford_calc.ts
+++ b/A00_Common/design/design_structure_ford_calc.ts
@@ -17,7 +17,7 @@
import { fordSection } from "../../B05_Profile/B05_Profile_UI_Drainage_Facility_Fields";
import type { SpecForm } from "./design_structure_form";
-import type { SpecContainer, SpecItem } from "./design_structure_spec";
+import type { SpecContainer, SpecItem } from "./logic/design_structure_spec";
/** 월류 폭(m) → 필요 월류 높이(m) · 0.01 m 올림. 유량 · 폭이 없으면 null. */
export function fordHeightM(designFlowM3s: number | null, widthM: number): number | null {
diff --git a/A00_Common/design/design_structure_form.ts b/A00_Common/design/design_structure_form.ts
index 20014b367..1448cc72e 100644
--- a/A00_Common/design/design_structure_form.ts
+++ b/A00_Common/design/design_structure_form.ts
@@ -32,7 +32,7 @@ import {
type SpecState,
type SplitRole,
type StructureSpec,
-} from "./design_structure_spec";
+} from "./logic/design_structure_spec";
import {
group,
grid,
diff --git a/A00_Common/design/design_structure_pipe_calc.ts b/A00_Common/design/design_structure_pipe_calc.ts
index 3f8223d5c..ee2e6a242 100644
--- a/A00_Common/design/design_structure_pipe_calc.ts
+++ b/A00_Common/design/design_structure_pipe_calc.ts
@@ -11,8 +11,8 @@
import type { CrossSection } from "../../B06_Section/B06_Section_Api_Fetch";
import { computeStoredLayouts } from "../../B06_Section/B06_Section_Structure_Layouts";
-export { DEFAULT_BASIN_SHAPE } from "../../B06_Section/B06_Section_UI_Cross_Culvert_Basin";
-export { pipeLengthText } from "../../B06_Section/B06_Section_UI_Cross_Culvert_Const"; // 「8 m (7.6)」(225-1)
+export { DEFAULT_BASIN_SHAPE } from "../../B06_Section/logic/B06_Section_UI_Cross_Culvert_Basin";
+export { pipeLengthText } from "../../B06_Section/logic/B06_Section_UI_Cross_Culvert_Const"; // 「8 m (7.6)」(225-1)
import { PIPE_MATCH_M } from "./design_selection";
/** 횡단 측점 목록을 대는 곳 — 횡단 보기가 자료를 받으면 걸어 둠(종단만 연 동안은 없음). */
diff --git a/A00_Common/design/design_view_cross.ts b/A00_Common/design/design_view_cross.ts
index 1abcf1a1b..85da53112 100644
--- a/A00_Common/design/design_view_cross.ts
+++ b/A00_Common/design/design_view_cross.ts
@@ -43,7 +43,10 @@ import { savingDesign } from "./design_save";
import { applyStructurePick } from "../../B06_Section/B06_Section_UI_Page_Structure_Pick";
import { bindCrossPick } from "../../B06_Section/B06_Section_UI_Page_Pick_Sync";
import { createSectionView } from "../../B06_Section/B06_Section_UI_Section_View";
-import { revetFormOf, revetWallSpec } from "../../B06_Section/B06_Section_UI_Cross_Culvert_Const";
+import {
+ revetFormOf,
+ revetWallSpec,
+} from "../../B06_Section/logic/B06_Section_UI_Cross_Culvert_Const";
import {
applyPipeOptionsToCache,
type PipeOptionsContext,
diff --git a/A00_Common/design/design_pipeline.ts b/A00_Common/design/logic/design_pipeline.ts
similarity index 99%
rename from A00_Common/design/design_pipeline.ts
rename to A00_Common/design/logic/design_pipeline.ts
index 7b2f1728a..df3f19950 100644
--- a/A00_Common/design/design_pipeline.ts
+++ b/A00_Common/design/logic/design_pipeline.ts
@@ -1,5 +1,5 @@
/* =============================================================================
- * A00_Common/design/design_pipeline.ts
+ * A00_Common/design/logic/design_pipeline.ts
* 실시간 계산 묶음 하나(PLAN 344-4) — 조작마다 차례 번호(generation) +1 · 단계 사이마다 번호
* 확인 · 옛 번호 결과 버림 · 뒤 단계 요청은 AbortController 로 끊음. 계약(키 모양 · 단계 · deps)
* = `design_pipeline_types.ts` 머리 주석.
@@ -13,7 +13,7 @@
* 화면 · fetch · 세션은 단계 함수(주입) 몫 — 이 파일은 차례 · 버림 · 범위 · 기록만.
* ========================================================================== */
-import type { DesignStore } from "./design_store";
+import type { DesignStore } from "../design_store";
import type {
ChangeRange,
ChangeSource,
diff --git a/A00_Common/design/design_pipeline_stations.ts b/A00_Common/design/logic/design_pipeline_stations.ts
similarity index 91%
rename from A00_Common/design/design_pipeline_stations.ts
rename to A00_Common/design/logic/design_pipeline_stations.ts
index 851cd4d63..9dc61c492 100644
--- a/A00_Common/design/design_pipeline_stations.ts
+++ b/A00_Common/design/logic/design_pipeline_stations.ts
@@ -1,5 +1,5 @@
/* =============================================================================
- * A00_Common/design/design_pipeline_stations.ts
+ * A00_Common/design/logic/design_pipeline_stations.ts
* 계산 묶음 stations 단계(PLAN 346-1) — 측점 계산은 `B05_Profile/logic/B05_Profile_Sections_Stations.ts`
* (서버 `generate_sections` 짝) · 여기는 단계 꼴 · 범위 밖 앞 값 재사용만.
* ========================================================================== */
@@ -8,12 +8,12 @@ import {
buildStations,
REUSE_MARGIN_M,
type StationsOptions,
-} from "../../B05_Profile/logic/B05_Profile_Sections_Stations";
+} from "../../../B05_Profile/logic/B05_Profile_Sections_Stations";
import type {
PlanPipe,
PlanStructure,
PlanType,
-} from "../../common_util/common_util_structure_station";
+} from "../../../common_util/common_util_structure_station";
import type { PipelineStation, StageContext, StageFn } from "./design_pipeline_types";
/** 범위 밖 측점은 앞 값(같은 열쇠 · 같은 자리)을 그대로 — 뒤 단계가 같은 객체로 「안 바뀜」을 앎. */
diff --git a/A00_Common/design/design_pipeline_types.ts b/A00_Common/design/logic/design_pipeline_types.ts
similarity index 99%
rename from A00_Common/design/design_pipeline_types.ts
rename to A00_Common/design/logic/design_pipeline_types.ts
index 74e08a4dd..d8fd3122c 100644
--- a/A00_Common/design/design_pipeline_types.ts
+++ b/A00_Common/design/logic/design_pipeline_types.ts
@@ -1,5 +1,5 @@
/* =============================================================================
- * A00_Common/design/design_pipeline_types.ts
+ * A00_Common/design/logic/design_pipeline_types.ts
* 실시간 계산 묶음 **계약**(PLAN 344-4) — 키별 모양 · 단계 입력 · 출력. 다른 창(sub1 · sub2 ·
* sub3 · sub6 · sub8)은 이 모양대로 단계 함수를 만들어 `createDesignPipeline({ stages })` 에 넣음.
* 계산 묶음 본체 = `design_pipeline.ts`.
@@ -53,7 +53,7 @@ import type {
AlignmentBase,
AlignmentEdits,
ProfileAlignment,
-} from "../../B05_Profile/B05_Profile_UI_Profile_Alignment";
+} from "../../../B05_Profile/logic/B05_Profile_UI_Profile_Alignment";
/** 평면 좌표(m) — 도면 좌표계 x · y. */
export type Vertex = [number, number];
diff --git a/A00_Common/design/design_profile_free.ts b/A00_Common/design/logic/design_profile_free.ts
similarity index 98%
rename from A00_Common/design/design_profile_free.ts
rename to A00_Common/design/logic/design_profile_free.ts
index 9a35981fb..4bb03c965 100644
--- a/A00_Common/design/design_profile_free.ts
+++ b/A00_Common/design/logic/design_profile_free.ts
@@ -1,5 +1,5 @@
/* =============================================================================
- * A00_Common/design/design_profile_free.ts
+ * A00_Common/design/logic/design_profile_free.ts
* 종단 [자유지정] 계산 — 범위 · 클릭 점 · 측점선 붙음 · 높이 변환 · 기울기 판정 · 적용(215-1).
*
* 흐름: 세로 측점선 둘로 범위를 고름 → 시작(또는 끝) 세로선 근처 클릭 = 그 측점 계획고에 이은
@@ -17,16 +17,16 @@ import type {
AlignmentBase,
AlignmentEdits,
ProfileAlignment,
-} from "../../B05_Profile/B05_Profile_UI_Profile_Alignment";
+} from "../../../B05_Profile/logic/B05_Profile_UI_Profile_Alignment";
import {
buildAlignment,
chainageKey,
controlElevationAt,
-} from "../../B05_Profile/B05_Profile_UI_Profile_Alignment";
+} from "../../../B05_Profile/logic/B05_Profile_UI_Profile_Alignment";
import {
baseElevationAt,
defaultCurveLength,
-} from "../../B05_Profile/B05_Profile_UI_Profile_Straighten";
+} from "../../../B05_Profile/logic/B05_Profile_UI_Profile_Straighten";
/** 두 chainage 를 같은 측점으로 볼 허용 오차(m). */
const SAME_M = 1e-6;
diff --git a/A00_Common/design/design_structure_box.ts b/A00_Common/design/logic/design_structure_box.ts
similarity index 100%
rename from A00_Common/design/design_structure_box.ts
rename to A00_Common/design/logic/design_structure_box.ts
diff --git a/A00_Common/design/design_structure_ford.ts b/A00_Common/design/logic/design_structure_ford.ts
similarity index 100%
rename from A00_Common/design/design_structure_ford.ts
rename to A00_Common/design/logic/design_structure_ford.ts
diff --git a/A00_Common/design/design_structure_ford_pavement.ts b/A00_Common/design/logic/design_structure_ford_pavement.ts
similarity index 100%
rename from A00_Common/design/design_structure_ford_pavement.ts
rename to A00_Common/design/logic/design_structure_ford_pavement.ts
diff --git a/A00_Common/design/design_structure_guard.ts b/A00_Common/design/logic/design_structure_guard.ts
similarity index 100%
rename from A00_Common/design/design_structure_guard.ts
rename to A00_Common/design/logic/design_structure_guard.ts
diff --git a/A00_Common/design/design_structure_pipe.ts b/A00_Common/design/logic/design_structure_pipe.ts
similarity index 98%
rename from A00_Common/design/design_structure_pipe.ts
rename to A00_Common/design/logic/design_structure_pipe.ts
index 9f1371201..128cf4e88 100644
--- a/A00_Common/design/design_structure_pipe.ts
+++ b/A00_Common/design/logic/design_structure_pipe.ts
@@ -18,7 +18,7 @@ import { BOX_SPEC } from "./design_structure_box";
import { FORD_SPEC } from "./design_structure_ford";
import { FORD_PAVEMENT_SPEC } from "./design_structure_ford_pavement";
import { ETC_SPEC, PAVEMENT_SPEC } from "./design_structure_road";
-import { baseType } from "../../common_util/common_util_structure_catalog";
+import { baseType } from "../../../common_util/common_util_structure_catalog";
const SOIL = "기슭막이"; // 저장 값(옛 키 그대로) — 화면 이름은 흙막이
const BASIN = "집수정";
diff --git a/A00_Common/design/design_structure_road.ts b/A00_Common/design/logic/design_structure_road.ts
similarity index 100%
rename from A00_Common/design/design_structure_road.ts
rename to A00_Common/design/logic/design_structure_road.ts
diff --git a/A00_Common/design/design_structure_slope_tier.ts b/A00_Common/design/logic/design_structure_slope_tier.ts
similarity index 100%
rename from A00_Common/design/design_structure_slope_tier.ts
rename to A00_Common/design/logic/design_structure_slope_tier.ts
diff --git a/A00_Common/design/design_structure_spec.ts b/A00_Common/design/logic/design_structure_spec.ts
similarity index 100%
rename from A00_Common/design/design_structure_spec.ts
rename to A00_Common/design/logic/design_structure_spec.ts
diff --git a/A00_Common/design/design_structure_widening.ts b/A00_Common/design/logic/design_structure_widening.ts
similarity index 100%
rename from A00_Common/design/design_structure_widening.ts
rename to A00_Common/design/logic/design_structure_widening.ts
diff --git a/B04_PreProcess/B04_PreProcess_UI_Basins.ts b/B04_PreProcess/B04_PreProcess_UI_Basins.ts
index 39b93d257..408614e69 100644
--- a/B04_PreProcess/B04_PreProcess_UI_Basins.ts
+++ b/B04_PreProcess/B04_PreProcess_UI_Basins.ts
@@ -39,7 +39,7 @@ import {
pointAtChainage,
resampleRoute,
type RoutePoint,
-} from "./B04_PreProcess_UI_RouteSamples";
+} from "./logic/B04_PreProcess_UI_RouteSamples";
import { PIPE_MATCH_M } from "../A00_Common/design/design_selection";
function L(key: keyof typeof ui_locales): string {
diff --git a/B04_PreProcess/B04_PreProcess_UI_FlowRamp.ts b/B04_PreProcess/B04_PreProcess_UI_FlowRamp.ts
index fb64a8e9a..aa777a11e 100644
--- a/B04_PreProcess/B04_PreProcess_UI_FlowRamp.ts
+++ b/B04_PreProcess/B04_PreProcess_UI_FlowRamp.ts
@@ -11,7 +11,7 @@
import "@ui/ui_template_flow_legend.css";
import { currentLanguageIndex, ui_locales } from "@ui/ui_template_locale";
import { themeColor } from "@ui/ui_template_palette";
-import type { RoutePoint } from "./B04_PreProcess_UI_RouteSamples";
+import type { RoutePoint } from "./logic/B04_PreProcess_UI_RouteSamples";
/** 강도 색띠 — 파랑(적음) → 빨강(많음). 정의처는 `ui_template_theme.css`. */
const RAMP_TOKENS: ReadonlyArray<[name: string, fallback: string]> = [
diff --git a/B04_PreProcess/B04_PreProcess_UI_FlowStrength.ts b/B04_PreProcess/B04_PreProcess_UI_FlowStrength.ts
index 80499ab85..a6c6ea3bf 100644
--- a/B04_PreProcess/B04_PreProcess_UI_FlowStrength.ts
+++ b/B04_PreProcess/B04_PreProcess_UI_FlowStrength.ts
@@ -27,7 +27,11 @@ import {
normalizeStrength,
rampColor,
} from "./B04_PreProcess_UI_FlowRamp";
-import { pointAtChainage, resampleRoute, type RoutePoint } from "./B04_PreProcess_UI_RouteSamples";
+import {
+ pointAtChainage,
+ resampleRoute,
+ type RoutePoint,
+} from "./logic/B04_PreProcess_UI_RouteSamples";
function L(key: keyof typeof ui_locales): string {
return ui_locales[key][currentLanguageIndex];
diff --git a/B04_PreProcess/B04_PreProcess_UI_MapViewer.ts b/B04_PreProcess/B04_PreProcess_UI_MapViewer.ts
index edb6cbf2a..cf4ec2f40 100644
--- a/B04_PreProcess/B04_PreProcess_UI_MapViewer.ts
+++ b/B04_PreProcess/B04_PreProcess_UI_MapViewer.ts
@@ -41,7 +41,7 @@ import {
type PreparedLayer,
type ViewState,
} from "./B04_PreProcess_UI_MapRender";
-import { prepareLayer, prepareMetricPolyline } from "./B04_PreProcess_UI_MapRender_Prepare";
+import { prepareLayer, prepareMetricPolyline } from "./logic/B04_PreProcess_UI_MapRender_Prepare";
import { drawStationTicks } from "./B04_PreProcess_UI_MapOverlays";
import type { WatershedAnalysis } from "./B04_PreProcess_Api_Fetch";
diff --git a/B04_PreProcess/B04_PreProcess_UI_MapRender_Prepare.ts b/B04_PreProcess/logic/B04_PreProcess_UI_MapRender_Prepare.ts
similarity index 99%
rename from B04_PreProcess/B04_PreProcess_UI_MapRender_Prepare.ts
rename to B04_PreProcess/logic/B04_PreProcess_UI_MapRender_Prepare.ts
index 149cfeea0..5eca0fcaa 100644
--- a/B04_PreProcess/B04_PreProcess_UI_MapRender_Prepare.ts
+++ b/B04_PreProcess/logic/B04_PreProcess_UI_MapRender_Prepare.ts
@@ -8,7 +8,7 @@
* 순환 참조가 생기지 않는다.
* ========================================================================== */
-import type { VWorldMeta } from "./B04_PreProcess_Api_Fetch";
+import type { VWorldMeta } from "../B04_PreProcess_Api_Fetch";
import type {
GeoJsonCollection,
GeoJsonGeometry,
@@ -16,7 +16,7 @@ import type {
PreparedFeature,
PreparedLayer,
PreparedPart,
-} from "./B04_PreProcess_UI_MapRender";
+} from "../B04_PreProcess_UI_MapRender";
function isPoint(value: unknown): value is [number, number] {
return Array.isArray(value) && typeof value[0] === "number" && typeof value[1] === "number";
diff --git a/B04_PreProcess/B04_PreProcess_UI_RouteSamples.ts b/B04_PreProcess/logic/B04_PreProcess_UI_RouteSamples.ts
similarity index 100%
rename from B04_PreProcess/B04_PreProcess_UI_RouteSamples.ts
rename to B04_PreProcess/logic/B04_PreProcess_UI_RouteSamples.ts
diff --git a/B05_Profile/B05_Profile_Api_HaulPlan.ts b/B05_Profile/B05_Profile_Api_HaulPlan.ts
index b4813838a..acfa2e943 100644
--- a/B05_Profile/B05_Profile_Api_HaulPlan.ts
+++ b/B05_Profile/B05_Profile_Api_HaulPlan.ts
@@ -12,7 +12,7 @@
import { API_BASE_URL } from "@config/config_frontend";
import type { HaulPlan } from "@util/common_util_mass_haul_balance";
-import type { StageContext } from "../A00_Common/design/design_pipeline_types";
+import type { StageContext } from "../A00_Common/design/logic/design_pipeline_types";
import type { MassHaulStageOutput } from "./logic/B05_Profile_MassHaul_Stage";
/** 서버가 돌려주는 배분 한 벌 — **화면이 쓰는 꼴 그대로**라 그리기 코드가 손대지 않는다.
diff --git a/B05_Profile/B05_Profile_Api_Replan.ts b/B05_Profile/B05_Profile_Api_Replan.ts
index 40ac0fbba..d6626e02e 100644
--- a/B05_Profile/B05_Profile_Api_Replan.ts
+++ b/B05_Profile/B05_Profile_Api_Replan.ts
@@ -18,7 +18,7 @@ import { API_BASE_URL } from "@config/config_frontend";
import { readState, writeState } from "../A00_Common/b_page_state";
import { heightAt } from "../common_util/common_util_surface_sampler";
import { loadDesignTerrainGrid } from "./B05_Profile_Api_TerrainGrid";
-import type { RouteDraft } from "../A00_Common/design/design_pipeline_types";
+import type { RouteDraft } from "../A00_Common/design/logic/design_pipeline_types";
/** 편집 창 분석 지형 — las = 확정 지표면(라이다) · sheet = 수치지형도 서피스. */
export type AnalysisTerrain = "las" | "sheet";
diff --git a/B05_Profile/B05_Profile_Api_Structures.ts b/B05_Profile/B05_Profile_Api_Structures.ts
index 0a89149af..005ac7089 100644
--- a/B05_Profile/B05_Profile_Api_Structures.ts
+++ b/B05_Profile/B05_Profile_Api_Structures.ts
@@ -23,7 +23,7 @@ import {
type DefinedSpot,
type StructureDefinition,
withDefinition,
-} from "./B05_Profile_UI_Structures_Define";
+} from "./logic/B05_Profile_UI_Structures_Define";
/** 배치형태 — 점형(측점 1개) / 구간형(시~종점) / 부지형(위치+면적). */
export type StructurePlacement = "point" | "interval" | "site";
diff --git a/B05_Profile/B05_Profile_Route_Save.py b/B05_Profile/B05_Profile_Route_Save.py
index 9354d5d44..8207b29ca 100644
--- a/B05_Profile/B05_Profile_Route_Save.py
+++ b/B05_Profile/B05_Profile_Route_Save.py
@@ -4,7 +4,7 @@
API — `POST /api/projects/{id}/route/replan`(`B05_Profile_Router_Replan.replan_route`):
요청 `RouteSaveRequest` = 옛 칸(`vertices` · `initial` · `balanced_profile` · `terrain` ·
`station_snap`) +
- `draft` — 계약 `RouteDraft`(`A00_Common/design/design_pipeline_types.ts`) 그대로
+ `draft` — 계약 `RouteDraft`(`A00_Common/design/logic/design_pipeline_types.ts`) 그대로
`{rev, nodes: [[x, y]…], curveOn: [bool…], curveRadius: [m | null…], curveLock, curveArc,
stationSnap, terrain}` · 오면 `vertices` · `station_snap` · `terrain` 대신 이것.
`as_initial` — 추천 노선 [적용](초기값 다시 뜸) · 손으로 고친 노선 저장은 false(초기값 그대로).
diff --git a/B05_Profile/B05_Profile_UI_Corridor_Build.ts b/B05_Profile/B05_Profile_UI_Corridor_Build.ts
index 518edba60..610c8a0e9 100644
--- a/B05_Profile/B05_Profile_UI_Corridor_Build.ts
+++ b/B05_Profile/B05_Profile_UI_Corridor_Build.ts
@@ -38,20 +38,20 @@ import {
lerpPoints,
slerpLeft,
type PieceControl,
-} from "./B05_Profile_UI_Corridor_Frames";
+} from "./logic/B05_Profile_UI_Corridor_Frames";
import { buildCorridorStructures, type RouteFrame } from "./B05_Profile_UI_Corridor_Structures";
export type { CorridorStructure, StructureFrame } from "./B05_Profile_UI_Corridor_Structures";
import type {
CorridorBuildResult,
CorridorCap,
CorridorRibbon,
-} from "./B05_Profile_UI_Corridor_Build_Types";
+} from "./logic/B05_Profile_UI_Corridor_Build_Types";
// 결과 자료형은 `_Build_Types` 에 있다(2026-09-02 분리) — 호출부 경로 유지를 위해 재수출.
export type {
CorridorBuildResult,
CorridorCap,
CorridorRibbon,
-} from "./B05_Profile_UI_Corridor_Build_Types";
+} from "./logic/B05_Profile_UI_Corridor_Build_Types";
import { structureSilhouettes } from "./B05_Profile_UI_Corridor_Station_Structure";
/** 종방향 세분 간격(m) — 곡선 각짐 방지(2026-08-23 사용자: 노선 폴리라인 따라 세분).
diff --git a/B05_Profile/B05_Profile_UI_Corridor_Deform_Structure.ts b/B05_Profile/B05_Profile_UI_Corridor_Deform_Structure.ts
index 605a28595..a4f5dfa6b 100644
--- a/B05_Profile/B05_Profile_UI_Corridor_Deform_Structure.ts
+++ b/B05_Profile/B05_Profile_UI_Corridor_Deform_Structure.ts
@@ -10,7 +10,7 @@
import type { CrossSection } from "../B06_Section/B06_Section_Api_Fetch";
import type { CorridorStructure } from "./B05_Profile_UI_Corridor_Structures";
import { structureSilhouettes } from "./B05_Profile_UI_Corridor_Station_Structure";
-import type { DeformLimit, DeformSide } from "./B05_Profile_UI_Corridor_Deform";
+import type { DeformLimit, DeformSide } from "./logic/B05_Profile_UI_Corridor_Deform";
/** 측점 프레임 축(모델 좌표) — 중심 · 좌향 단위 벡터. */
interface StationAxis {
diff --git a/B05_Profile/B05_Profile_UI_Corridor_Envelope.ts b/B05_Profile/B05_Profile_UI_Corridor_Envelope.ts
index 3530d33cc..ab489928a 100644
--- a/B05_Profile/B05_Profile_UI_Corridor_Envelope.ts
+++ b/B05_Profile/B05_Profile_UI_Corridor_Envelope.ts
@@ -12,7 +12,10 @@
import type { SectionDetailResponse } from "../B06_Section/B06_Section_Api_Fetch";
import type { RoutePoint } from "./B05_Profile_Api_Fetch";
-import type { CorridorBuildResult, CorridorRibbon } from "./B05_Profile_UI_Corridor_Build_Types";
+import type {
+ CorridorBuildResult,
+ CorridorRibbon,
+} from "./logic/B05_Profile_UI_Corridor_Build_Types";
import { structureHashParts } from "./B05_Profile_UI_Corridor_Structures";
/**
diff --git a/B05_Profile/B05_Profile_UI_Corridor_Loft.ts b/B05_Profile/B05_Profile_UI_Corridor_Loft.ts
index 6830e7acd..cb6a38fc1 100644
--- a/B05_Profile/B05_Profile_UI_Corridor_Loft.ts
+++ b/B05_Profile/B05_Profile_UI_Corridor_Loft.ts
@@ -16,10 +16,10 @@
import type * as THREE from "three";
import type { ModelBounds } from "./B05_Profile_UI_Markers";
-import type { CorridorBuildResult } from "./B05_Profile_UI_Corridor_Build_Types";
+import type { CorridorBuildResult } from "./logic/B05_Profile_UI_Corridor_Build_Types";
import type { TerrainBandSplit } from "./B05_Profile_UI_Corridor_Split";
import type { TerrainHeightIndex } from "./B05_Profile_UI_Corridor_Terrain";
-import { roadRows } from "./B05_Profile_UI_Corridor_Deform";
+import { roadRows } from "./logic/B05_Profile_UI_Corridor_Deform";
import { noFillLimits } from "./B05_Profile_UI_Corridor_Deform_Structure";
import { tinTerrain, type TinDesigner, type TinStats } from "./B05_Profile_UI_Corridor_Tin";
import {
@@ -27,7 +27,7 @@ import {
SECTION_STEP_M,
structureTopLoops,
type TinDesign,
-} from "./B05_Profile_UI_Corridor_Tin_Design";
+} from "./logic/B05_Profile_UI_Corridor_Tin_Design";
import {
EDGE_ANCHOR,
EDGE_DESIGN,
@@ -39,7 +39,7 @@ import {
TAG_CUT,
TAG_FILL,
TAG_HOLE,
-} from "./B05_Profile_UI_Corridor_Tin_Pslg";
+} from "./logic/B05_Profile_UI_Corridor_Tin_Pslg";
import {
arcFractions,
atFraction,
@@ -50,8 +50,8 @@ import {
stationLofts,
} from "./B05_Profile_UI_Corridor_Loft_Profile";
import { smoothSlopeNormals } from "./B05_Profile_UI_Corridor_Loft_Shade";
-import { gauss, pinBack, smoothToe } from "./B05_Profile_UI_Corridor_Loft_Toe";
-import { taubin, type GridRow } from "./B05_Profile_UI_Corridor_Loft_Grid";
+import { gauss, pinBack, smoothToe } from "./logic/B05_Profile_UI_Corridor_Loft_Toe";
+import { taubin, type GridRow } from "./logic/B05_Profile_UI_Corridor_Loft_Grid";
// ponytail: 이보다 짧은 비탈은 없는 것으로(10 cm) — 부채꼴 끝 0.2 m 행 사이 실오라기 삼각형을 막음.
const MIN_SLOPE_M = 0.1;
diff --git a/B05_Profile/B05_Profile_UI_Corridor_Station_Structure.ts b/B05_Profile/B05_Profile_UI_Corridor_Station_Structure.ts
index 13b7a6c7e..8a22ff43b 100644
--- a/B05_Profile/B05_Profile_UI_Corridor_Station_Structure.ts
+++ b/B05_Profile/B05_Profile_UI_Corridor_Station_Structure.ts
@@ -21,7 +21,7 @@ import {
fordLayoutOf,
wallSpanOf,
} from "./B05_Profile_UI_Corridor_Structures";
-import { groundInterpolator } from "../B06_Section/B06_Section_UI_Cross_Culvert_Solve";
+import { groundInterpolator } from "../B06_Section/logic/B06_Section_UI_Cross_Culvert_Solve";
/** 한 측의 구조물 실루엣 — 비탈 조각을 이걸로 갈아 끼운다. */
export interface StructureSilhouette {
diff --git a/B05_Profile/B05_Profile_UI_Corridor_Structures.ts b/B05_Profile/B05_Profile_UI_Corridor_Structures.ts
index 9365f237b..fbdeb6050 100644
--- a/B05_Profile/B05_Profile_UI_Corridor_Structures.ts
+++ b/B05_Profile/B05_Profile_UI_Corridor_Structures.ts
@@ -20,7 +20,7 @@
* 폴리곤을 갈아 끼워(`polygons`) 측점 사이를 Catmull-Rom으로 잇는다. 벽은 여전히 하나다.
* ========================================================================== */
-import { structureHashParts, wallSweepAt } from "./B05_Profile_UI_Corridor_Structures_Hash";
+import { structureHashParts, wallSweepAt } from "./logic/B05_Profile_UI_Corridor_Structures_Hash";
import type { CrossSection, CulvertSideSpec } from "../B06_Section/B06_Section_Api_Fetch";
import { computeCulvertLayout } from "../B06_Section/B06_Section_UI_Cross_Culvert";
import {
@@ -29,7 +29,7 @@ import {
restrictToSide,
tierSpanOf,
} from "../B06_Section/B06_Section_UI_Cross_Culvert_Wire";
-import { pipeWallThicknessM } from "../B06_Section/B06_Section_UI_Cross_Culvert_Const";
+import { pipeWallThicknessM } from "../B06_Section/logic/B06_Section_UI_Cross_Culvert_Const";
import type { CulvertLayout } from "../B06_Section/B06_Section_UI_Cross_Culvert";
import { computeFordLayout, fordAdjustOf } from "../B06_Section/B06_Section_UI_Cross_Ford";
import type { FordLayout } from "../B06_Section/B06_Section_UI_Cross_Ford";
@@ -42,7 +42,7 @@ import {
import type { SectionPolygon } from "./B05_Profile_UI_Corridor_Structures_Box";
import { computeBoxLayout, DEFAULT_BOX_SIDE_ADJUST } from "../B06_Section/B06_Section_UI_Cross_Box";
import type { BoxAdjust, BoxLayout } from "../B06_Section/B06_Section_UI_Cross_Box";
-import { buildWingSolids } from "./B05_Profile_UI_Corridor_Structures_Wing";
+import { buildWingSolids } from "./logic/B05_Profile_UI_Corridor_Structures_Wing";
import {
buildWallPath,
detachedControlsOf,
@@ -54,7 +54,7 @@ import { computeRevetmentLayout } from "../B06_Section/B06_Section_UI_Cross_Reve
import { withoutGuardedFill } from "../B06_Section/B06_Section_UI_Cross_Body_Guard";
import { chuteBands, fordPavementChute } from "./B05_Profile_UI_Corridor_Structures_Chute";
import { isChuteSegment } from "../B06_Section/B06_Section_UI_Cross_Wall_Hatch";
-import { builds, culvertBody, ownsBody } from "./B05_Profile_UI_Corridor_Structures_Pick";
+import { builds, culvertBody, ownsBody } from "./logic/B05_Profile_UI_Corridor_Structures_Pick";
/** 스윕 프레임 하나 — 노선 위 한 지점의 중심 XY·좌향 단위벡터와 종단 표고 오프셋. */
export interface StructureFrame {
@@ -695,4 +695,4 @@ export function buildCorridorStructures(
}
// 해시 요약은 `_Structures_Hash.ts` 에 있다(2026-09-02 분리) — 호출부 경로 유지를 위해 재수출.
-export { structureHashParts } from "./B05_Profile_UI_Corridor_Structures_Hash";
+export { structureHashParts } from "./logic/B05_Profile_UI_Corridor_Structures_Hash";
diff --git a/B05_Profile/B05_Profile_UI_Corridor_Structures_Box.ts b/B05_Profile/B05_Profile_UI_Corridor_Structures_Box.ts
index 01a49e1aa..347f64537 100644
--- a/B05_Profile/B05_Profile_UI_Corridor_Structures_Box.ts
+++ b/B05_Profile/B05_Profile_UI_Corridor_Structures_Box.ts
@@ -15,7 +15,7 @@ import type { CrossSection } from "../B06_Section/B06_Section_Api_Fetch";
import { computeBoxLayout } from "../B06_Section/B06_Section_UI_Cross_Box";
import type { BoxAdjust } from "../B06_Section/B06_Section_UI_Cross_Box";
import type { CorridorStructure, StructureFrame } from "./B05_Profile_UI_Corridor_Structures";
-import { buildWingSolids } from "./B05_Profile_UI_Corridor_Structures_Wing";
+import { buildWingSolids } from "./logic/B05_Profile_UI_Corridor_Structures_Wing";
import { chuteBands } from "./B05_Profile_UI_Corridor_Structures_Chute";
/** 단면 폴리곤 한 장 — [offset, elevation] 목록. */
diff --git a/B05_Profile/B05_Profile_UI_Corridor_Tin.ts b/B05_Profile/B05_Profile_UI_Corridor_Tin.ts
index 8baab4e3e..865a4ffcf 100644
--- a/B05_Profile/B05_Profile_UI_Corridor_Tin.ts
+++ b/B05_Profile/B05_Profile_UI_Corridor_Tin.ts
@@ -14,11 +14,11 @@
import * as THREE from "three";
import type { ModelBounds } from "./B05_Profile_UI_Markers";
-import type { CorridorBuildResult } from "./B05_Profile_UI_Corridor_Build_Types";
+import type { CorridorBuildResult } from "./logic/B05_Profile_UI_Corridor_Build_Types";
import type { TerrainBandSplit } from "./B05_Profile_UI_Corridor_Split";
import type { TerrainHeightIndex } from "./B05_Profile_UI_Corridor_Terrain";
-import { CellRegion } from "./B05_Profile_UI_Corridor_Region";
-import type { TinDesign } from "./B05_Profile_UI_Corridor_Tin_Design";
+import { CellRegion } from "./logic/B05_Profile_UI_Corridor_Region";
+import type { TinDesign } from "./logic/B05_Profile_UI_Corridor_Tin_Design";
import {
EDGE_TERRAIN,
LoopIndex,
@@ -28,7 +28,7 @@ import {
TAG_FILL,
TAG_TERRAIN,
TriGrid,
-} from "./B05_Profile_UI_Corridor_Tin_Pslg";
+} from "./logic/B05_Profile_UI_Corridor_Tin_Pslg";
/** 절토 · 성토 색 — 리본 색과 같은 값. */
const CUT_COLOR = new THREE.Color(0xb5179e);
diff --git a/B05_Profile/B05_Profile_UI_Drainage_Facility.ts b/B05_Profile/B05_Profile_UI_Drainage_Facility.ts
index 253be24d5..f2cf3a0dc 100644
--- a/B05_Profile/B05_Profile_UI_Drainage_Facility.ts
+++ b/B05_Profile/B05_Profile_UI_Drainage_Facility.ts
@@ -7,7 +7,7 @@
* 시설 종류는 구조물 배치의 "종류" 드롭다운이, 위치(시작·기준·종료 측점)는 위치
* 칸이 담당하므로 여기에는 부속 옵션 필드만 있다.
*
- * 배관 부속(PLAN 52-1): 사용자 구조물 표 01 명세 폼(`A00_Common/design/design_structure_pipe`)
+ * 배관 부속(PLAN 52-1): 사용자 구조물 표 01 명세 폼(`A00_Common/design/logic/design_structure_pipe`)
* — 관 · 관 보호공(유입 · 유출) · 흙막이 추가 · 도수로/돌붙임 컨테이너. 저장 키는 옛 키 그대로 ·
* 옛 관종 · 날개벽 · 집수정 형식 칸은 화면에서 빠지고 값은 남음(지난 정의 값).
*
@@ -56,15 +56,15 @@ import {
type SpecForm,
type SpecLinks,
} from "../A00_Common/design/design_structure_form";
-import { PIPE_SPEC } from "../A00_Common/design/design_structure_pipe";
+import { PIPE_SPEC } from "../A00_Common/design/logic/design_structure_pipe";
import { catalogRow } from "../common_util/common_util_structure_catalog";
import {
BOX_SPEC,
bodyOf,
bodyOptions,
boxOptionsIn,
-} from "../A00_Common/design/design_structure_box";
-import { FORD_SPEC, withLegacyGuards } from "../A00_Common/design/design_structure_ford";
+} from "../A00_Common/design/logic/design_structure_box";
+import { FORD_SPEC, withLegacyGuards } from "../A00_Common/design/logic/design_structure_ford";
import { overflowSync } from "../A00_Common/design/design_structure_ford_calc";
import {
pipeDrawn,
@@ -78,7 +78,7 @@ import {
type GroupItems,
type SummaryItem,
} from "../common_util/common_util_summary_item";
-import { FORD_PAVEMENT_SPEC } from "../A00_Common/design/design_structure_ford_pavement";
+import { FORD_PAVEMENT_SPEC } from "../A00_Common/design/logic/design_structure_ford_pavement";
import { createHiddenOptions } from "./B05_Profile_UI_Drainage_Facility_Hidden";
export type { InletStructureKind }; // 목록은 700줄 한계로 `_Fields` 로 옮김 — 부르던 곳은 그대로
diff --git a/B05_Profile/B05_Profile_UI_Drainage_Facility_Hidden.ts b/B05_Profile/B05_Profile_UI_Drainage_Facility_Hidden.ts
index 5567822b7..0d97bf32d 100644
--- a/B05_Profile/B05_Profile_UI_Drainage_Facility_Hidden.ts
+++ b/B05_Profile/B05_Profile_UI_Drainage_Facility_Hidden.ts
@@ -11,7 +11,7 @@
* · 필수 검사는 이 폼에 없다(레지스트리 옵션 칸은 `renderOptionFields` 가 숨긴 칸을 뺌).
* ========================================================================== */
-import { hiddenFormKeys } from "./B05_Profile_UI_Drainage_Facility_Merge";
+import { hiddenFormKeys } from "./logic/B05_Profile_UI_Drainage_Facility_Merge";
export interface HiddenOptions {
/** 폼이 받은 옵션 — 숨긴 칸의 옛 값 보존용. `setFacility` 가 부른다. */
diff --git a/B05_Profile/B05_Profile_UI_Drainage_Live.ts b/B05_Profile/B05_Profile_UI_Drainage_Live.ts
index 06cf8df7e..0714734cb 100644
--- a/B05_Profile/B05_Profile_UI_Drainage_Live.ts
+++ b/B05_Profile/B05_Profile_UI_Drainage_Live.ts
@@ -15,7 +15,7 @@ import { API_BASE_URL } from "@config/config_frontend";
import { createProgressCircle } from "@ui/ui_template_progress";
import { openModal } from "@ui/ui_template_modal";
import { readStateRaw, writeStateRaw } from "../A00_Common/b_page_state";
-import type { StageFn } from "../A00_Common/design/design_pipeline_types";
+import type { StageFn } from "../A00_Common/design/logic/design_pipeline_types";
import {
computeDetailBasins,
type DetailBasinResponse,
diff --git a/B05_Profile/B05_Profile_UI_Drainage_Panel.ts b/B05_Profile/B05_Profile_UI_Drainage_Panel.ts
index 8ce773bbb..ec29e8a39 100644
--- a/B05_Profile/B05_Profile_UI_Drainage_Panel.ts
+++ b/B05_Profile/B05_Profile_UI_Drainage_Panel.ts
@@ -24,16 +24,16 @@ import {
import {
prepareLayer,
prepareMetricPolyline,
-} from "../B04_PreProcess/B04_PreProcess_UI_MapRender_Prepare";
+} from "../B04_PreProcess/logic/B04_PreProcess_UI_MapRender_Prepare";
import { type RoutePoint } from "./B05_Profile_Api_Fetch";
import type { FlowArrow } from "../B04_PreProcess/B04_PreProcess_UI_FlowArrows";
import { buildStrengthArray } from "../B04_PreProcess/B04_PreProcess_UI_FlowRamp";
-import { resampleRoute } from "../B04_PreProcess/B04_PreProcess_UI_RouteSamples";
+import { resampleRoute } from "../B04_PreProcess/logic/B04_PreProcess_UI_RouteSamples";
import { batched, createPipeEditor } from "./B05_Profile_UI_Drainage_Pipes";
import { followMovedPipe, PIPE_MATCH_M } from "../A00_Common/design/design_pipe_ids";
import { snapStructureStation } from "../common_util/common_util_structure_station";
import { createFacilityStore } from "./B05_Profile_UI_Drainage_Facility";
-import { mergeFacilityOptions } from "./B05_Profile_UI_Drainage_Facility_Merge";
+import { mergeFacilityOptions } from "./logic/B05_Profile_UI_Drainage_Facility_Merge";
import { readPendingPipes, writePendingPipes } from "./B05_Profile_Api_Pipes_Draft";
import { buildPipeReports } from "./B05_Profile_UI_Drainage_Report";
import { fillFordHeights, fordWaitsOf, waitsFordHeight } from "./B05_Profile_UI_Drainage_Ford_Fill";
diff --git a/B05_Profile/B05_Profile_UI_Drainage_Panel_Types.ts b/B05_Profile/B05_Profile_UI_Drainage_Panel_Types.ts
index cf31e5cb2..442b186c4 100644
--- a/B05_Profile/B05_Profile_UI_Drainage_Panel_Types.ts
+++ b/B05_Profile/B05_Profile_UI_Drainage_Panel_Types.ts
@@ -13,7 +13,7 @@ import type { FacilityAttributes } from "./B05_Profile_UI_Drainage_Facility";
import type { PipeFacility, PipeSource } from "../B04_PreProcess/B04_PreProcess_Api_Fetch";
import type { MapContextMenuItem } from "@ui/ui_template_context_menu";
import type { RouteSpanBand } from "./B05_Profile_UI_Drainage_Spans";
-import type { StageFn } from "../A00_Common/design/design_pipeline_types";
+import type { StageFn } from "../A00_Common/design/logic/design_pipeline_types";
export interface DrainagePanel {
root: HTMLElement;
diff --git a/B05_Profile/B05_Profile_UI_Drainage_Render.ts b/B05_Profile/B05_Profile_UI_Drainage_Render.ts
index c50ea8138..706b7af6e 100644
--- a/B05_Profile/B05_Profile_UI_Drainage_Render.ts
+++ b/B05_Profile/B05_Profile_UI_Drainage_Render.ts
@@ -29,7 +29,7 @@ import {
import type { DetailBasin, VWorldMeta } from "../B04_PreProcess/B04_PreProcess_Api_Fetch";
import { drawFlowArrows, type FlowArrow } from "../B04_PreProcess/B04_PreProcess_UI_FlowArrows";
import { drawStrengthLine } from "../B04_PreProcess/B04_PreProcess_UI_FlowRamp";
-import type { RoutePoint } from "../B04_PreProcess/B04_PreProcess_UI_RouteSamples";
+import type { RoutePoint } from "../B04_PreProcess/logic/B04_PreProcess_UI_RouteSamples";
import {
basinColor,
createMetricProjector,
diff --git a/B05_Profile/B05_Profile_UI_Drainage_Spans.ts b/B05_Profile/B05_Profile_UI_Drainage_Spans.ts
index 3b86acf97..e3de5596a 100644
--- a/B05_Profile/B05_Profile_UI_Drainage_Spans.ts
+++ b/B05_Profile/B05_Profile_UI_Drainage_Spans.ts
@@ -11,7 +11,7 @@
* 않는다. 이름은 안 적는다(종단에 이미 있고, 지도에 글자를 얹으면 눈금·유역 번호와 겹친다).
* ========================================================================== */
-import type { RoutePoint } from "../B04_PreProcess/B04_PreProcess_UI_RouteSamples";
+import type { RoutePoint } from "../B04_PreProcess/logic/B04_PreProcess_UI_RouteSamples";
import type { StructureInstance, StructureType } from "./B05_Profile_Api_Structures";
/** 계획선 위에 얹을 구간 하나 — 누가거리 두 값과 색. */
diff --git a/B05_Profile/B05_Profile_UI_Page_Structures.ts b/B05_Profile/B05_Profile_UI_Page_Structures.ts
index 0009778ff..39e67f418 100644
--- a/B05_Profile/B05_Profile_UI_Page_Structures.ts
+++ b/B05_Profile/B05_Profile_UI_Page_Structures.ts
@@ -30,7 +30,7 @@ import {
import type { IrregularStation } from "./B05_Profile_UI_IrregularStations";
import type { createRoutePanel } from "./B05_Profile_UI_Panel";
import type { createRouteProfilePanel } from "./B05_Profile_UI_Profile_Panel";
-import { followedStation } from "./B05_Profile_UI_Profile_Alignment";
+import { followedStation } from "./logic/B05_Profile_UI_Profile_Alignment";
import { followSnapped } from "./B05_Profile_UI_Structures_Snap";
import { plantsStation } from "./B05_Profile_UI_Profile_Structures";
import { listPick } from "../common_util/common_util_structure_catalog";
diff --git a/B05_Profile/B05_Profile_UI_Profile_Balance.ts b/B05_Profile/B05_Profile_UI_Profile_Balance.ts
index 16dbea888..03013d8e5 100644
--- a/B05_Profile/B05_Profile_UI_Profile_Balance.ts
+++ b/B05_Profile/B05_Profile_UI_Profile_Balance.ts
@@ -14,7 +14,7 @@
* 표시줄은 상태를 갖지 않는다 — 그릴 때마다 현재 선형·편집 상태를 인자로 받는다.
* ========================================================================== */
-import type { ProfileAlignment } from "./B05_Profile_UI_Profile_Alignment";
+import type { ProfileAlignment } from "./logic/B05_Profile_UI_Profile_Alignment";
import type { MinCoverViolation } from "./B05_Profile_UI_Profile_MinCover";
export interface BalanceBarParams {
diff --git a/B05_Profile/B05_Profile_UI_Profile_Edit.ts b/B05_Profile/B05_Profile_UI_Profile_Edit.ts
index 2c653d574..108c60135 100644
--- a/B05_Profile/B05_Profile_UI_Profile_Edit.ts
+++ b/B05_Profile/B05_Profile_UI_Profile_Edit.ts
@@ -15,8 +15,8 @@
* 라벨에 가려 보이지 않기 때문이다.
* ========================================================================== */
-import type { AlignmentEdits, ProfileAlignment } from "./B05_Profile_UI_Profile_Alignment";
-import { chainageKey, emptyEdits, hasEdits } from "./B05_Profile_UI_Profile_Alignment";
+import type { AlignmentEdits, ProfileAlignment } from "./logic/B05_Profile_UI_Profile_Alignment";
+import { chainageKey, emptyEdits, hasEdits } from "./logic/B05_Profile_UI_Profile_Alignment";
import {
ALIGNMENT_DRAFT_KEY_PREFIX,
draftProjectId,
diff --git a/B05_Profile/B05_Profile_UI_Profile_Layout.ts b/B05_Profile/B05_Profile_UI_Profile_Layout.ts
index cbf42e8ab..859c49c75 100644
--- a/B05_Profile/B05_Profile_UI_Profile_Layout.ts
+++ b/B05_Profile/B05_Profile_UI_Profile_Layout.ts
@@ -8,7 +8,7 @@
* ========================================================================== */
import { LONG_PAD } from "../B06_Section/B06_Section_UI_Section_Common";
-import { normalizedLongitudinal } from "./B05_Profile_UI_Profile_Data";
+import { normalizedLongitudinal } from "./logic/B05_Profile_UI_Profile_Data";
import { TABLE_TARGET_FONT_PX, tableCellWidthFor } from "./B05_Profile_UI_Profile_Table";
import type { LongitudinalSection, SectionStation } from "../B06_Section/B06_Section_Api_Fetch";
import {
diff --git a/B05_Profile/B05_Profile_UI_Profile_MinCover.ts b/B05_Profile/B05_Profile_UI_Profile_MinCover.ts
index e52f83b3c..f69067f2b 100644
--- a/B05_Profile/B05_Profile_UI_Profile_MinCover.ts
+++ b/B05_Profile/B05_Profile_UI_Profile_MinCover.ts
@@ -20,8 +20,8 @@
* ========================================================================== */
import { showToast } from "@ui/ui_template_elements";
-import { controlElevationAt } from "./B05_Profile_UI_Profile_Alignment";
-import type { AlignmentBase, ProfileAlignment } from "./B05_Profile_UI_Profile_Alignment";
+import { controlElevationAt } from "./logic/B05_Profile_UI_Profile_Alignment";
+import type { AlignmentBase, ProfileAlignment } from "./logic/B05_Profile_UI_Profile_Alignment";
import type { PipeFacility } from "../B04_PreProcess/B04_PreProcess_Api_Fetch";
diff --git a/B05_Profile/B05_Profile_UI_Profile_Panel_Tools.ts b/B05_Profile/B05_Profile_UI_Profile_Panel_Tools.ts
index 46f861f58..8d173cd0f 100644
--- a/B05_Profile/B05_Profile_UI_Profile_Panel_Tools.ts
+++ b/B05_Profile/B05_Profile_UI_Profile_Panel_Tools.ts
@@ -15,8 +15,8 @@ import type {
AlignmentBase,
AlignmentEdits,
ProfileAlignment,
-} from "./B05_Profile_UI_Profile_Alignment";
-import { adjustStation } from "./B05_Profile_UI_Profile_Alignment";
+} from "./logic/B05_Profile_UI_Profile_Alignment";
+import { adjustStation } from "./logic/B05_Profile_UI_Profile_Alignment";
import { HOLD_DELAY_MS, HOLD_INTERVAL_MS } from "./B05_Profile_UI_Profile_Edit";
import {
createProfileHistory,
@@ -30,9 +30,9 @@ import {
shiftStraightRuns,
straightenBetween,
tiltStraightRun,
-} from "./B05_Profile_UI_Profile_Straighten";
+} from "./logic/B05_Profile_UI_Profile_Straighten";
import type { IrregularStation } from "./B05_Profile_UI_IrregularStations";
-import { createFreeDraw } from "../A00_Common/design/design_profile_free";
+import { createFreeDraw } from "../A00_Common/design/logic/design_profile_free";
import { createFreeView, type FreeChartGeom } from "../A00_Common/design/design_profile_free_view";
import { arrowsBelongToProfile } from "../B06_Section/B06_Section_UI_Cross_Panel_Base";
import { stepStructureStation } from "../common_util/common_util_structure_station";
diff --git a/B05_Profile/B05_Profile_UI_Profile_Preview.ts b/B05_Profile/B05_Profile_UI_Profile_Preview.ts
index 4ed712a3b..5457feaf6 100644
--- a/B05_Profile/B05_Profile_UI_Profile_Preview.ts
+++ b/B05_Profile/B05_Profile_UI_Profile_Preview.ts
@@ -9,7 +9,7 @@
* 끌기 중에는 계속 호출되므로 디바운스하고, 늦게 온 응답은 seq 비교로 버린다.
* ========================================================================== */
-import type { AlignmentEdits, ProfileAlignment } from "./B05_Profile_UI_Profile_Alignment";
+import type { AlignmentEdits, ProfileAlignment } from "./logic/B05_Profile_UI_Profile_Alignment";
import { holdScreenAlignment, refreshCrossDesigns } from "../B06_Section/B06_Section_Cross_Refresh";
import { staleChainages } from "../B06_Section/B06_Section_UI_Section_Common";
import type { SectionDetailResponse } from "../B06_Section/B06_Section_Api_Fetch";
diff --git a/B05_Profile/B05_Profile_UI_Profile_Render.ts b/B05_Profile/B05_Profile_UI_Profile_Render.ts
index 60bca4a84..dc5f5ba8b 100644
--- a/B05_Profile/B05_Profile_UI_Profile_Render.ts
+++ b/B05_Profile/B05_Profile_UI_Profile_Render.ts
@@ -20,14 +20,14 @@ import {
windowElevationRange,
} from "../B06_Section/B06_Section_UI_Section_Common";
import type { SectionDetailResponse } from "../B06_Section/B06_Section_Api_Fetch";
-import { normalizedLongitudinal, toDesignProfile } from "./B05_Profile_UI_Profile_Data";
+import { normalizedLongitudinal, toDesignProfile } from "./logic/B05_Profile_UI_Profile_Data";
import {
adjustStation,
setCurveRadius,
type AlignmentBase,
type AlignmentEdits,
type ProfileAlignment,
-} from "./B05_Profile_UI_Profile_Alignment";
+} from "./logic/B05_Profile_UI_Profile_Alignment";
import { createEditOverlay } from "./B05_Profile_UI_Profile_Edit";
import { createRunHighlight } from "./B05_Profile_UI_Profile_RunHighlight";
import {
diff --git a/B05_Profile/B05_Profile_UI_Profile_RunHighlight.ts b/B05_Profile/B05_Profile_UI_Profile_RunHighlight.ts
index c8db8b66a..65e544fc8 100644
--- a/B05_Profile/B05_Profile_UI_Profile_RunHighlight.ts
+++ b/B05_Profile/B05_Profile_UI_Profile_RunHighlight.ts
@@ -12,8 +12,8 @@
* (`onYAxis`)에서 되짚는다 — 두 눈금의 (표고, y) 두 쌍이면 1차식이 정해진다.
* ========================================================================== */
-import type { ProfileAlignment } from "./B05_Profile_UI_Profile_Alignment";
-import type { StraightRun } from "./B05_Profile_UI_Profile_Straighten";
+import type { ProfileAlignment } from "./logic/B05_Profile_UI_Profile_Alignment";
+import type { StraightRun } from "./logic/B05_Profile_UI_Profile_Straighten";
const SVG_NS = "http://www.w3.org/2000/svg";
/** 두 chainage를 같은 변화점으로 볼 허용 오차(m). */
diff --git a/B05_Profile/B05_Profile_UI_Profile_Table.ts b/B05_Profile/B05_Profile_UI_Profile_Table.ts
index e1cb163fb..b48c66550 100644
--- a/B05_Profile/B05_Profile_UI_Profile_Table.ts
+++ b/B05_Profile/B05_Profile_UI_Profile_Table.ts
@@ -17,7 +17,7 @@ import type {
AlignmentCurve,
AlignmentSegment,
ProfileAlignment,
-} from "./B05_Profile_UI_Profile_Alignment";
+} from "./logic/B05_Profile_UI_Profile_Alignment";
import { stationLabel } from "../B06_Section/B06_Section_UI_Section_Common";
import {
irregularStationId,
diff --git a/B05_Profile/B05_Profile_UI_Profile_Tools.ts b/B05_Profile/B05_Profile_UI_Profile_Tools.ts
index 35182c856..f14a0b087 100644
--- a/B05_Profile/B05_Profile_UI_Profile_Tools.ts
+++ b/B05_Profile/B05_Profile_UI_Profile_Tools.ts
@@ -14,8 +14,8 @@
* [자유지정] → 범위를 고르고 클릭으로 계획선을 잇는다(`design_profile_free` 몫 · 215-1).
* ========================================================================== */
-import type { StraightRun } from "./B05_Profile_UI_Profile_Straighten";
-import { sameRun } from "./B05_Profile_UI_Profile_Straighten";
+import type { StraightRun } from "./logic/B05_Profile_UI_Profile_Straighten";
+import { sameRun } from "./logic/B05_Profile_UI_Profile_Straighten";
import type { FreeChartGeom } from "../A00_Common/design/design_profile_free_view";
export type ProfileToolMode = "none" | "straighten" | "shift" | "free";
diff --git a/B05_Profile/B05_Profile_UI_RouteEdit.ts b/B05_Profile/B05_Profile_UI_RouteEdit.ts
index 186c5eff1..e13a17937 100644
--- a/B05_Profile/B05_Profile_UI_RouteEdit.ts
+++ b/B05_Profile/B05_Profile_UI_RouteEdit.ts
@@ -41,7 +41,7 @@ import {
buildEditedPolyline,
type EditedCurve,
type EditedNode,
-} from "./B05_Profile_UI_RouteEdit_Curve";
+} from "./logic/B05_Profile_UI_RouteEdit_Curve";
import { drawRouteEditScene, polylineLengthM } from "./B05_Profile_UI_RouteEdit_Render";
import { bindNodeSplice, bindRouteEditNavigation } from "./B05_Profile_UI_RouteEdit_Input";
import { bindRouteEditPointer } from "./B05_Profile_UI_RouteEdit_Pointer";
@@ -61,7 +61,11 @@ import {
viewPxPerMeter,
} from "./B05_Profile_UI_RouteEdit_View";
import { createCurveBar } from "./B05_Profile_UI_RouteEdit_CurveBar";
-import { curveSpans, snapCurveStations, stationsAlong } from "./B05_Profile_UI_RouteEdit_Frame";
+import {
+ curveSpans,
+ snapCurveStations,
+ stationsAlong,
+} from "./logic/B05_Profile_UI_RouteEdit_Frame";
import {
lockColumn,
readRouteLocks,
@@ -76,7 +80,7 @@ import {
flattenServerPlan,
spliceNode,
type CurveLock,
-} from "./B05_Profile_UI_RouteEdit_Edits";
+} from "./logic/B05_Profile_UI_RouteEdit_Edits";
import {
bindHistoryControls,
createRouteEditHistory,
diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Apply.ts b/B05_Profile/B05_Profile_UI_RouteEdit_Apply.ts
index bd43901b7..01405b58d 100644
--- a/B05_Profile/B05_Profile_UI_RouteEdit_Apply.ts
+++ b/B05_Profile/B05_Profile_UI_RouteEdit_Apply.ts
@@ -12,7 +12,7 @@
* ========================================================================== */
import { clearDrafts, clearResults } from "../A00_Common/b_page_state";
-import type { RouteDraft } from "../A00_Common/design/design_pipeline_types";
+import type { RouteDraft } from "../A00_Common/design/logic/design_pipeline_types";
import { useDesignStore } from "../A00_Common/design/design_store";
import { currentRoute, remountRoute } from "../A00_Common/router";
import { hideLoadingOverlay, showLoadingOverlay, showToast } from "@ui/ui_template_elements";
diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Contour.ts b/B05_Profile/B05_Profile_UI_RouteEdit_Contour.ts
index 709e616e8..41ad14506 100644
--- a/B05_Profile/B05_Profile_UI_RouteEdit_Contour.ts
+++ b/B05_Profile/B05_Profile_UI_RouteEdit_Contour.ts
@@ -21,7 +21,7 @@ import {
import {
prepareLayer,
prepareMetricPolylines,
-} from "../B04_PreProcess/B04_PreProcess_UI_MapRender_Prepare";
+} from "../B04_PreProcess/logic/B04_PreProcess_UI_MapRender_Prepare";
import type { VWorldMeta } from "../B04_PreProcess/B04_PreProcess_Api_Fetch";
/** 도엽 등고선의 표고 속성 이름 — B04 지도가 쓰는 것과 같은 키. */
diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Cross_Draw.ts b/B05_Profile/B05_Profile_UI_RouteEdit_Cross_Draw.ts
index 5d06c97c7..37c0a30e2 100644
--- a/B05_Profile/B05_Profile_UI_RouteEdit_Cross_Draw.ts
+++ b/B05_Profile/B05_Profile_UI_RouteEdit_Cross_Draw.ts
@@ -19,7 +19,7 @@
import { svgElement, svgText } from "@util/common_util_svg";
import type { ContentBounds } from "../A00_Common/b_svg_zoom_pan";
import type { CrossSection } from "./../B06_Section/B06_Section_Api_Fetch";
-import { fillSlopeLengths, toeOffsets } from "./../B06_Section/B06_Section_UI_Cross_Fit";
+import { fillSlopeLengths, toeOffsets } from "../B06_Section/logic/B06_Section_UI_Cross_Fit";
import type { CrossPreviewResponse } from "./B05_Profile_Api_Replan";
/** 그림 가장자리 여백(px) — 위는 범례 한 줄, 아래는 눈금 안내 한 줄 몫이다. */
diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_CurveBar.ts b/B05_Profile/B05_Profile_UI_RouteEdit_CurveBar.ts
index 06483dc4b..b15278aa0 100644
--- a/B05_Profile/B05_Profile_UI_RouteEdit_CurveBar.ts
+++ b/B05_Profile/B05_Profile_UI_RouteEdit_CurveBar.ts
@@ -10,13 +10,13 @@
* 들고 간다. 두 벌로 두면 교각이 바뀔 때 서로 어긋난다(`_Edits.ts` 설명 참고).
* ========================================================================== */
-import type { EditedCurve, EditedNode, Vertex } from "./B05_Profile_UI_RouteEdit_Curve";
+import type { EditedCurve, EditedNode, Vertex } from "./logic/B05_Profile_UI_RouteEdit_Curve";
import {
curveOptionalAt,
deflectionRad,
radiusFloorM,
type CurveLock,
-} from "./B05_Profile_UI_RouteEdit_Edits";
+} from "./logic/B05_Profile_UI_RouteEdit_Edits";
import {
centerDirectionOf,
createCurveLabel,
diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Draft.ts b/B05_Profile/B05_Profile_UI_RouteEdit_Draft.ts
index 8775940d4..a9fdd9ebe 100644
--- a/B05_Profile/B05_Profile_UI_RouteEdit_Draft.ts
+++ b/B05_Profile/B05_Profile_UI_RouteEdit_Draft.ts
@@ -13,7 +13,7 @@
* 초안은 `fromPage` 로 편집기 새 걸음이 됨. 사진첩이 없으면 편집기 사진 그대로.
* ========================================================================== */
-import type { RouteDraft } from "../A00_Common/design/design_pipeline_types";
+import type { RouteDraft } from "../A00_Common/design/logic/design_pipeline_types";
import { pageHistory } from "./B05_Profile_UI_Profile_History";
import {
sameLine,
diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Footprint.ts b/B05_Profile/B05_Profile_UI_RouteEdit_Footprint.ts
index de4b89298..82faeb7d3 100644
--- a/B05_Profile/B05_Profile_UI_RouteEdit_Footprint.ts
+++ b/B05_Profile/B05_Profile_UI_RouteEdit_Footprint.ts
@@ -9,7 +9,7 @@
* ========================================================================== */
import { draftProjectId, useDesignStore } from "../A00_Common/design/design_store";
-import type { Vertex } from "./B05_Profile_UI_RouteEdit_Curve";
+import type { Vertex } from "./logic/B05_Profile_UI_RouteEdit_Curve";
import {
type FootprintStrokeKind,
type FootprintValue,
diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Initial_Model.ts b/B05_Profile/B05_Profile_UI_RouteEdit_Initial_Model.ts
index 7199fa9b8..38346cfce 100644
--- a/B05_Profile/B05_Profile_UI_RouteEdit_Initial_Model.ts
+++ b/B05_Profile/B05_Profile_UI_RouteEdit_Initial_Model.ts
@@ -10,7 +10,7 @@ import type {
RouteInitialLogic,
RouteInitialWeights,
} from "./B05_Profile_Api_RouteInitial";
-import { flattenServerPlan } from "./B05_Profile_UI_RouteEdit_Edits";
+import { flattenServerPlan } from "./logic/B05_Profile_UI_RouteEdit_Edits";
import type { RouteEditSnapshot } from "./B05_Profile_UI_RouteEdit_History";
import { parseBalance, type BalanceProfile } from "./B05_Profile_UI_RouteEdit_Recommend_Profile";
diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Input.ts b/B05_Profile/B05_Profile_UI_RouteEdit_Input.ts
index 4eef74ec3..910775aef 100644
--- a/B05_Profile/B05_Profile_UI_RouteEdit_Input.ts
+++ b/B05_Profile/B05_Profile_UI_RouteEdit_Input.ts
@@ -17,7 +17,7 @@ import { pickPx, wheelZoomsIn } from "../A00_Common/touch_bridge";
import { computeMaxScale, type ViewState } from "../B04_PreProcess/B04_PreProcess_UI_MapRender";
import type { VWorldMeta } from "../B04_PreProcess/B04_PreProcess_Api_Fetch";
import type { StationLabelBox } from "../B04_PreProcess/B04_PreProcess_UI_MapOverlays";
-import { curveArcVertices, type EditedCurve } from "./B05_Profile_UI_RouteEdit_Curve";
+import { curveArcVertices, type EditedCurve } from "./logic/B05_Profile_UI_RouteEdit_Curve";
/** 배수유역도와 같은 값 — 한 번에 얼마나 확대·축소할지. */
const ZOOM_IN_FACTOR = 1.15;
diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Label.ts b/B05_Profile/B05_Profile_UI_RouteEdit_Label.ts
index 6a139feb2..b4bfdb3ca 100644
--- a/B05_Profile/B05_Profile_UI_RouteEdit_Label.ts
+++ b/B05_Profile/B05_Profile_UI_RouteEdit_Label.ts
@@ -22,11 +22,14 @@
import { createButton } from "@ui/ui_template_elements";
import { numberField, toggleButton } from "./B05_Profile_UI_Panel_Fields";
-import { CURVE_OPTIONAL_INNER_ANGLE_DEG, type CurveLock } from "./B05_Profile_UI_RouteEdit_Edits";
+import {
+ CURVE_OPTIONAL_INNER_ANGLE_DEG,
+ type CurveLock,
+} from "./logic/B05_Profile_UI_RouteEdit_Edits";
// `deflectionRad` 는 화면을 안 만지는 셈이라 `_Edits.ts` 로 옮겼다(2026-09-12) — 순수
// 함수가 DOM 파일에 얹혀 있으면 시험이 화면째 들여와야 한다. 재수출로 부르던 자리를 지킨다.
-export { deflectionRad } from "./B05_Profile_UI_RouteEdit_Edits";
+export { deflectionRad } from "./logic/B05_Profile_UI_RouteEdit_Edits";
/** 곡선 중심이 있는 **화면 방향**(단위벡터) — 패널을 그 반대쪽에 붙이는 데 쓴다.
*
diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Pointer.ts b/B05_Profile/B05_Profile_UI_RouteEdit_Pointer.ts
index 2da4c4f10..1f9dc33de 100644
--- a/B05_Profile/B05_Profile_UI_RouteEdit_Pointer.ts
+++ b/B05_Profile/B05_Profile_UI_RouteEdit_Pointer.ts
@@ -16,7 +16,7 @@ import {
type EditedCurve,
type EditedNode,
type Vertex,
-} from "./B05_Profile_UI_RouteEdit_Curve";
+} from "./logic/B05_Profile_UI_RouteEdit_Curve";
import {
arcAtScreen,
handleAtScreen,
@@ -30,7 +30,7 @@ import {
radiusFloorM,
shortfallCrossed,
type CurveLock,
-} from "./B05_Profile_UI_RouteEdit_Edits";
+} from "./logic/B05_Profile_UI_RouteEdit_Edits";
/** 노드를 잡았다고 볼 거리(px). 손가락·마우스 모두 무리 없는 크기. */
const NODE_HIT_PX = 9;
diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Render.ts b/B05_Profile/B05_Profile_UI_RouteEdit_Render.ts
index e3c70d476..11d93c8b1 100644
--- a/B05_Profile/B05_Profile_UI_RouteEdit_Render.ts
+++ b/B05_Profile/B05_Profile_UI_RouteEdit_Render.ts
@@ -24,10 +24,10 @@ import {
drawStationTicks,
type StationLabelBox,
} from "../B04_PreProcess/B04_PreProcess_UI_MapOverlays";
-import type { EditedCurve, EditedNode, Vertex } from "./B05_Profile_UI_RouteEdit_Curve";
+import type { EditedCurve, EditedNode, Vertex } from "./logic/B05_Profile_UI_RouteEdit_Curve";
import { contourBandRect, setStationLabelBoxes } from "./B05_Profile_UI_RouteEdit_Input";
import type { CrossWatch } from "./B05_Profile_UI_RouteEdit_Cross";
-import { stationFrameAt } from "./B05_Profile_UI_RouteEdit_Frame";
+import { stationFrameAt } from "./logic/B05_Profile_UI_RouteEdit_Frame";
import type { MeasureMark } from "./B05_Profile_UI_RouteEdit_Measure";
import { stationLabel as formatStation } from "../common_util/common_util_station";
import { arcLocked, straightLocked } from "./B05_Profile_UI_RouteEdit_Lock";
diff --git a/B05_Profile/B05_Profile_UI_Structures_Define_Form.ts b/B05_Profile/B05_Profile_UI_Structures_Define_Form.ts
index bce554803..13958c0b8 100644
--- a/B05_Profile/B05_Profile_UI_Structures_Define_Form.ts
+++ b/B05_Profile/B05_Profile_UI_Structures_Define_Form.ts
@@ -11,8 +11,8 @@
* ========================================================================== */
import type { StructureType } from "./B05_Profile_Api_Structures";
-import { ruleDefaults, ruleStates } from "./B05_Profile_UI_Structures_Define";
-import { isOptionVisible } from "./B05_Profile_UI_Structures_Summary";
+import { ruleDefaults, ruleStates } from "./logic/B05_Profile_UI_Structures_Define";
+import { isOptionVisible } from "./logic/B05_Profile_UI_Structures_Summary";
/** 시설 폼이 가릴 옵션 키 — 「구조물 옵션 보이기」에서 끈 것 + 정의 「안 씀」. */
export function hiddenOptionKeys(type: StructureType | null): string[] {
diff --git a/B05_Profile/B05_Profile_UI_Structures_Fields.ts b/B05_Profile/B05_Profile_UI_Structures_Fields.ts
index 82e43d2d8..4879405f3 100644
--- a/B05_Profile/B05_Profile_UI_Structures_Fields.ts
+++ b/B05_Profile/B05_Profile_UI_Structures_Fields.ts
@@ -7,8 +7,8 @@
* 저장은 누가거리(m), 화면 입출력만 측점번호+잔여거리.
* ========================================================================== */
-import { chainageToStation, stationToChainage } from "./B05_Profile_Util_Station";
-import { DEFAULT_BASIN_SHAPE } from "../B06_Section/B06_Section_UI_Cross_Culvert_Basin";
+import { chainageToStation, stationToChainage } from "./logic/B05_Profile_Util_Station";
+import { DEFAULT_BASIN_SHAPE } from "../B06_Section/logic/B06_Section_UI_Cross_Culvert_Basin";
import { fillPipeHeights } from "../common_util/common_util_culvert_sets";
import { snapStructureStation } from "../common_util/common_util_structure_station";
diff --git a/B05_Profile/B05_Profile_UI_Structures_Groups.ts b/B05_Profile/B05_Profile_UI_Structures_Groups.ts
index aac595a29..7c9c262e2 100644
--- a/B05_Profile/B05_Profile_UI_Structures_Groups.ts
+++ b/B05_Profile/B05_Profile_UI_Structures_Groups.ts
@@ -17,13 +17,13 @@
import { openItemPicker } from "@ui/ui_template_item_picker";
import { pipeStructureId } from "@ui/ui_template_item_picker_project";
import type { StructureType } from "./B05_Profile_Api_Structures";
-import { hiddenFormKeys } from "./B05_Profile_UI_Drainage_Facility_Merge";
+import { hiddenFormKeys } from "./logic/B05_Profile_UI_Drainage_Facility_Merge";
import { buildSummaryRow, type SummaryRow } from "./B05_Profile_UI_Structures_Summary_Row";
-import { isOptionVisible } from "./B05_Profile_UI_Structures_Summary";
-import { SHAPE_FIELDS, shapeFields, shapeKey } from "./B05_Profile_UI_Structures_Define";
+import { isOptionVisible } from "./logic/B05_Profile_UI_Structures_Summary";
+import { SHAPE_FIELDS, shapeFields, shapeKey } from "./logic/B05_Profile_UI_Structures_Define";
import { numberInput } from "./B05_Profile_UI_Structures_Fields";
import { grid, group as boxOf, labeled, stepper } from "./B05_Profile_UI_Drainage_Facility_Fields";
-import { specFor } from "../A00_Common/design/design_structure_pipe";
+import { specFor } from "../A00_Common/design/logic/design_structure_pipe";
import {
GROUP_JOIN,
type GroupItems,
diff --git a/B05_Profile/B05_Profile_UI_Structures_List.ts b/B05_Profile/B05_Profile_UI_Structures_List.ts
index 424ab6a62..9d30940a8 100644
--- a/B05_Profile/B05_Profile_UI_Structures_List.ts
+++ b/B05_Profile/B05_Profile_UI_Structures_List.ts
@@ -22,7 +22,7 @@ import {
summaryTooltip,
type SummaryItem,
} from "../common_util/common_util_summary_item";
-import { specFor } from "../A00_Common/design/design_structure_pipe";
+import { specFor } from "../A00_Common/design/logic/design_structure_pipe";
import { PIPE_MATCH_M } from "../A00_Common/design/design_selection";
import { pipeExtraCount } from "../A00_Common/design/design_structure_pipe_calc";
import {
@@ -30,9 +30,9 @@ import {
isNone,
linkOf,
readState,
-} from "../A00_Common/design/design_structure_spec";
-import { withLegacyGuards } from "../A00_Common/design/design_structure_ford";
-import { asRoad } from "./B05_Profile_UI_Structures_Define";
+} from "../A00_Common/design/logic/design_structure_spec";
+import { withLegacyGuards } from "../A00_Common/design/logic/design_structure_ford";
+import { asRoad } from "./logic/B05_Profile_UI_Structures_Define";
export interface StructureListParams {
/** 목록을 담을
. 그릴 때마다 통째로 갈아 끼운다. */
diff --git a/B05_Profile/B05_Profile_UI_Structures_Marks.ts b/B05_Profile/B05_Profile_UI_Structures_Marks.ts
index 8056f5040..6e831fe3d 100644
--- a/B05_Profile/B05_Profile_UI_Structures_Marks.ts
+++ b/B05_Profile/B05_Profile_UI_Structures_Marks.ts
@@ -22,7 +22,7 @@ import {
type StructureType,
} from "./B05_Profile_Api_Structures";
import { etcName, numberDuplicateNames } from "./B05_Profile_UI_Structures_List";
-import { balloonLines, type ContainerCount } from "./B05_Profile_UI_Structures_Balloon";
+import { balloonLines, type ContainerCount } from "./logic/B05_Profile_UI_Structures_Balloon";
import { stationLabel as formatStation } from "../common_util/common_util_station";
import { frameOf } from "../common_util/common_util_view_window";
import { catalogRow } from "../common_util/common_util_structure_catalog";
diff --git a/B05_Profile/B05_Profile_UI_Structures_Panel.ts b/B05_Profile/B05_Profile_UI_Structures_Panel.ts
index 05e25caf4..8b6328978 100644
--- a/B05_Profile/B05_Profile_UI_Structures_Panel.ts
+++ b/B05_Profile/B05_Profile_UI_Structures_Panel.ts
@@ -43,7 +43,7 @@ import {
} from "./B05_Profile_UI_Structures_Panel_Commit";
import { renderStructureList } from "./B05_Profile_UI_Structures_List";
import { addsAtOnce, finishAdd } from "./B05_Profile_UI_Structures_Panel_AddAt";
-import { showsAnchor } from "./B05_Profile_UI_Structures_Define";
+import { showsAnchor } from "./logic/B05_Profile_UI_Structures_Define";
import { hiddenOptionKeys } from "./B05_Profile_UI_Structures_Define_Form";
import { stationLabel as formatStation } from "../common_util/common_util_station";
import { PIPE_MATCH_M, resolveSelection } from "../A00_Common/design/design_selection";
diff --git a/B05_Profile/B05_Profile_UI_Structures_Panel_Commit.ts b/B05_Profile/B05_Profile_UI_Structures_Panel_Commit.ts
index aabcc1501..a5d8d2110 100644
--- a/B05_Profile/B05_Profile_UI_Structures_Panel_Commit.ts
+++ b/B05_Profile/B05_Profile_UI_Structures_Panel_Commit.ts
@@ -18,11 +18,11 @@ import type { PipeFacility } from "../B04_PreProcess/B04_PreProcess_Api_Fetch";
import type { FacilityAttributes, FacilityOptionsForm } from "./B05_Profile_UI_Drainage_Facility";
import type { StationFields } from "./B05_Profile_UI_Structures_Fields";
import { splitPavementRange } from "./B05_Profile_UI_Structures_Pavement";
-import { mergeStructureOptions } from "./B05_Profile_UI_Structures_Summary";
+import { mergeStructureOptions } from "./logic/B05_Profile_UI_Structures_Summary";
import { readStructureSpec, specRenderedKeys } from "./B05_Profile_UI_Structures_Spec";
-import { asRoad } from "./B05_Profile_UI_Structures_Define";
+import { asRoad } from "./logic/B05_Profile_UI_Structures_Define";
import type { GroupBoxes } from "./B05_Profile_UI_Structures_Groups";
-import { specFor } from "../A00_Common/design/design_structure_pipe";
+import { specFor } from "../A00_Common/design/logic/design_structure_pipe";
import { snapStructureStation } from "../common_util/common_util_structure_station";
import {
readGroupItems,
diff --git a/B05_Profile/B05_Profile_UI_Structures_Panel_Events.ts b/B05_Profile/B05_Profile_UI_Structures_Panel_Events.ts
index a9e3ebaad..f37532549 100644
--- a/B05_Profile/B05_Profile_UI_Structures_Panel_Events.ts
+++ b/B05_Profile/B05_Profile_UI_Structures_Panel_Events.ts
@@ -14,7 +14,7 @@ import {
type StructureType,
} from "./B05_Profile_Api_Structures";
import type { StructuresCommitContext } from "./B05_Profile_UI_Structures_Panel_Commit";
-import { asRoad } from "./B05_Profile_UI_Structures_Define";
+import { asRoad } from "./logic/B05_Profile_UI_Structures_Define";
import { readState, writeState } from "../A00_Common/b_page_state";
import { NO_SELECTION, PIPE_MATCH_M, selectDesign } from "../A00_Common/design/design_selection";
import { readGroupItems, readSummaryItem } from "../common_util/common_util_summary_item";
diff --git a/B05_Profile/B05_Profile_UI_Structures_Panel_Options.ts b/B05_Profile/B05_Profile_UI_Structures_Panel_Options.ts
index 6c3227f2a..aaa4756b0 100644
--- a/B05_Profile/B05_Profile_UI_Structures_Panel_Options.ts
+++ b/B05_Profile/B05_Profile_UI_Structures_Panel_Options.ts
@@ -18,13 +18,17 @@ import {
ruleDefaults,
ruleStates,
staleValues,
-} from "./B05_Profile_UI_Structures_Define";
-import { FORM_OPTION_KEYS } from "./B05_Profile_UI_Drainage_Facility_Merge";
+} from "./logic/B05_Profile_UI_Structures_Define";
+import { FORM_OPTION_KEYS } from "./logic/B05_Profile_UI_Drainage_Facility_Merge";
import { stepper } from "./B05_Profile_UI_Drainage_Facility_Fields";
-import { specFor } from "../A00_Common/design/design_structure_pipe";
+import { specFor } from "../A00_Common/design/logic/design_structure_pipe";
import { baseType } from "../common_util/common_util_structure_catalog";
import { paintStructureSpec, specOwnedKeys } from "./B05_Profile_UI_Structures_Spec";
-import { solveSplit, specKeys, type SplitRole } from "../A00_Common/design/design_structure_spec";
+import {
+ solveSplit,
+ specKeys,
+ type SplitRole,
+} from "../A00_Common/design/logic/design_structure_spec";
/** 종류 단위 「구조물 조합」 줄을 가릴 종류인지 — 구조물 명세 컨테이너 · 정의 그룹 상자(그룹마다 잇기 줄)로
* 그리는 종류(PLAN 52-1 · 52-6b · 52-7) · 종단배수(B군 · 조합 잇기 없음 · 표 07). */
diff --git a/B05_Profile/B05_Profile_UI_Structures_Panel_Types.ts b/B05_Profile/B05_Profile_UI_Structures_Panel_Types.ts
index f47e9df0a..36db77ddf 100644
--- a/B05_Profile/B05_Profile_UI_Structures_Panel_Types.ts
+++ b/B05_Profile/B05_Profile_UI_Structures_Panel_Types.ts
@@ -20,7 +20,7 @@ import {
} from "./B05_Profile_Api_Structures";
import type { DesignSelection, ResolvedSelection } from "../A00_Common/design/design_selection";
import type { GroupItems, SummaryItem } from "../common_util/common_util_summary_item";
-import { specFor } from "../A00_Common/design/design_structure_pipe";
+import { specFor } from "../A00_Common/design/logic/design_structure_pipe";
import { catalogRow } from "../common_util/common_util_structure_catalog";
/** 구조물군 표시 이름. 리스트 기호(A~G)만으로는 무엇인지 알기 어렵다.
diff --git a/B05_Profile/B05_Profile_UI_Structures_Spec.ts b/B05_Profile/B05_Profile_UI_Structures_Spec.ts
index 56a1661f3..98209cfbe 100644
--- a/B05_Profile/B05_Profile_UI_Structures_Spec.ts
+++ b/B05_Profile/B05_Profile_UI_Structures_Spec.ts
@@ -15,10 +15,10 @@ import {
type SpecFormHooks,
type SpecLinks,
} from "../A00_Common/design/design_structure_form";
-import { specFor } from "../A00_Common/design/design_structure_pipe";
-import { ADDON_SPECS } from "../A00_Common/design/design_structure_slope_tier";
+import { specFor } from "../A00_Common/design/logic/design_structure_pipe";
+import { ADDON_SPECS } from "../A00_Common/design/logic/design_structure_slope_tier";
import { baseType } from "../common_util/common_util_structure_catalog";
-import { specKeys, type StructureSpec } from "../A00_Common/design/design_structure_spec";
+import { specKeys, type StructureSpec } from "../A00_Common/design/logic/design_structure_spec";
import { hiddenOptionKeys, optionDefaults } from "./B05_Profile_UI_Structures_Fields";
import type { WideningBox } from "./B05_Profile_UI_Structures_Widening";
diff --git a/B05_Profile/B05_Profile_UI_Structures_Widening.ts b/B05_Profile/B05_Profile_UI_Structures_Widening.ts
index 3ef019b40..ee2c7cf48 100644
--- a/B05_Profile/B05_Profile_UI_Structures_Widening.ts
+++ b/B05_Profile/B05_Profile_UI_Structures_Widening.ts
@@ -13,7 +13,7 @@ import {
wideningArea,
wideningRuns,
type WideningRun,
-} from "../A00_Common/design/design_structure_widening";
+} from "../A00_Common/design/logic/design_structure_widening";
import { stationLabel } from "../common_util/common_util_station";
import { group } from "./B05_Profile_UI_Drainage_Facility_Fields";
diff --git a/B05_Profile/CLAUDE.md b/B05_Profile/CLAUDE.md
index 99b95a30f..5d32937d4 100644
--- a/B05_Profile/CLAUDE.md
+++ b/B05_Profile/CLAUDE.md
@@ -11,8 +11,8 @@
① 짝(ts ↔ py · 거울 시험):
-- `UI_RouteEdit_Curve.ts` ↔ `common_util_route_polyline.py` · `test_route_polyline_browser_mirror.py`
-- `UI_RouteEdit_Frame.ts` ↔ `Engine_Sections_Core.py`(측점 틀 · 스냅) · `test_b05_routeedit_frame_mirror.py` · `test_224_2_station_snap.py`
+- `logic/UI_RouteEdit_Curve.ts` ↔ `common_util_route_polyline.py` · `test_route_polyline_browser_mirror.py`
+- `logic/UI_RouteEdit_Frame.ts` ↔ `Engine_Sections_Core.py`(측점 틀 · 스냅) · `test_b05_routeedit_frame_mirror.py` · `test_224_2_station_snap.py`
- `UI_Drainage_Facility.ts` carryIndices ↔ `common_util_drainage_pipes.py` · `test_b05_facility_carry.py`
- `logic/B05_Profile_PlanFootprint.ts` ↔ `B07_DesignDetail_Engine_Cad_PlanSlope.py` · `test_346_2_plan_footprint_mirror.py`
- 지형 표본 = `common_util_surface_sampler.build_surface_sampler` 하나 · 2 m 비용면은 노선 추천 점수만
diff --git a/B05_Profile/logic/B05_Profile_Footprint_Stage.ts b/B05_Profile/logic/B05_Profile_Footprint_Stage.ts
index ede536f16..3f3d816e6 100644
--- a/B05_Profile/logic/B05_Profile_Footprint_Stage.ts
+++ b/B05_Profile/logic/B05_Profile_Footprint_Stage.ts
@@ -15,7 +15,7 @@ import type {
CrossStationResult,
PipelineStation,
StageContext,
-} from "../../A00_Common/design/design_pipeline_types";
+} from "../../A00_Common/design/logic/design_pipeline_types";
import {
footprintLines,
footprintRecord,
diff --git a/B05_Profile/logic/B05_Profile_Footprint_Strokes.ts b/B05_Profile/logic/B05_Profile_Footprint_Strokes.ts
index da638f3c9..73311f99d 100644
--- a/B05_Profile/logic/B05_Profile_Footprint_Strokes.ts
+++ b/B05_Profile/logic/B05_Profile_Footprint_Strokes.ts
@@ -7,7 +7,7 @@
* 조각이 바뀌는 점은 앞뒤 조각이 함께 가짐(선이 끊겨 보이지 않게 · `splitRuns` 와 같은 규칙).
* ========================================================================== */
-import type { PlanFootprint, Vertex } from "../../A00_Common/design/design_pipeline_types";
+import type { PlanFootprint, Vertex } from "../../A00_Common/design/logic/design_pipeline_types";
export type FootprintStrokeKind = "road" | "cut" | "fill" | "slope";
diff --git a/B05_Profile/logic/B05_Profile_Grade_Carry.ts b/B05_Profile/logic/B05_Profile_Grade_Carry.ts
index fa82bd8a7..f464f47fc 100644
--- a/B05_Profile/logic/B05_Profile_Grade_Carry.ts
+++ b/B05_Profile/logic/B05_Profile_Grade_Carry.ts
@@ -14,7 +14,7 @@ import {
chainageKey,
type AlignmentEdits,
type AlignmentNode,
-} from "../B05_Profile_UI_Profile_Alignment";
+} from "./B05_Profile_UI_Profile_Alignment";
/** 같은 정점으로 볼 거리(m) — 파이썬 `SAME_VERTEX_M` 짝. */
export const SAME_VERTEX_M = 1e-3;
diff --git a/B05_Profile/logic/B05_Profile_Grade_Ground.ts b/B05_Profile/logic/B05_Profile_Grade_Ground.ts
index dfdebf236..374af92ae 100644
--- a/B05_Profile/logic/B05_Profile_Grade_Ground.ts
+++ b/B05_Profile/logic/B05_Profile_Grade_Ground.ts
@@ -13,7 +13,7 @@ import {
evaluateAt,
type AlignmentNode,
type AlignmentPolicy,
-} from "../B05_Profile_UI_Profile_Alignment";
+} from "./B05_Profile_UI_Profile_Alignment";
/** 종단 지반 표본 한 점 — 저장 종단 `samples[]` 꼴. */
export interface GroundSample {
diff --git a/B05_Profile/logic/B05_Profile_MassHaul_Stage.ts b/B05_Profile/logic/B05_Profile_MassHaul_Stage.ts
index 883b083f0..68f01ce28 100644
--- a/B05_Profile/logic/B05_Profile_MassHaul_Stage.ts
+++ b/B05_Profile/logic/B05_Profile_MassHaul_Stage.ts
@@ -9,7 +9,7 @@
import { computeMassHaulSeries, type MassHaulSeries } from "@util/common_util_mass_haul";
import type { EarthworkConversion, MassHaulSection } from "@util/common_util_mass_haul_types";
-import type { StageContext } from "../../A00_Common/design/design_pipeline_types";
+import type { StageContext } from "../../A00_Common/design/logic/design_pipeline_types";
export interface MassHaulStageContext {
conversion: EarthworkConversion;
diff --git a/B05_Profile/logic/B05_Profile_Pipeline_Detail.ts b/B05_Profile/logic/B05_Profile_Pipeline_Detail.ts
index e47e9ce49..1576a6a01 100644
--- a/B05_Profile/logic/B05_Profile_Pipeline_Detail.ts
+++ b/B05_Profile/logic/B05_Profile_Pipeline_Detail.ts
@@ -22,8 +22,8 @@ import type {
CrossOutput,
GroundOutput,
PipelineStation,
-} from "../../A00_Common/design/design_pipeline_types";
-import type { ProfileAlignment } from "../B05_Profile_UI_Profile_Alignment";
+} from "../../A00_Common/design/logic/design_pipeline_types";
+import type { ProfileAlignment } from "./B05_Profile_UI_Profile_Alignment";
import { stationLabel } from "../../common_util/common_util_station";
import { stationIdOf } from "./B05_Profile_Pipeline_Grade";
diff --git a/B05_Profile/logic/B05_Profile_Pipeline_Grade.ts b/B05_Profile/logic/B05_Profile_Pipeline_Grade.ts
index 20afd7852..cbefd29f0 100644
--- a/B05_Profile/logic/B05_Profile_Pipeline_Grade.ts
+++ b/B05_Profile/logic/B05_Profile_Pipeline_Grade.ts
@@ -1,7 +1,7 @@
/* =============================================================================
* B05_Profile_Pipeline_Grade.ts
* 계산 묶음(PLAN 346-1) **follow · planline · profile 단계** + 바뀐 범위 — 계약 =
- * `A00_Common/design/design_pipeline_types.ts`. 셈은 이미 있는 짝을 부르기만(어댑터):
+ * `A00_Common/design/logic/design_pipeline_types.ts`. 셈은 이미 있는 짝을 부르기만(어댑터):
*
* follow — 관 · 구조물 좌표 따라감(`common_util_route_follow`) · 계획고 편집 옮김(`Grade_Carry`
* `carryProfileEdits` 의 edits 몫 · 옛 노선 `before.route` 가 있을 때만).
@@ -17,7 +17,7 @@ import type {
RangePart,
StageFn,
Vertex,
-} from "../../A00_Common/design/design_pipeline_types";
+} from "../../A00_Common/design/logic/design_pipeline_types";
import {
followStructures,
projectPipePoints,
@@ -29,7 +29,7 @@ import {
emptyEdits,
type AlignmentBase,
type AlignmentEdits,
-} from "../B05_Profile_UI_Profile_Alignment";
+} from "./B05_Profile_UI_Profile_Alignment";
import { carryProfileEdits, changedSpan } from "./B05_Profile_Grade_Carry";
import { groundFollowingBasePvi, groundProfile } from "./B05_Profile_Grade_Ground";
diff --git a/B05_Profile/logic/B05_Profile_Pipeline_RouteGround.ts b/B05_Profile/logic/B05_Profile_Pipeline_RouteGround.ts
index b9e3d0d88..de95e6c63 100644
--- a/B05_Profile/logic/B05_Profile_Pipeline_RouteGround.ts
+++ b/B05_Profile/logic/B05_Profile_Pipeline_RouteGround.ts
@@ -22,10 +22,10 @@ import type {
StageFn,
StationGround,
Vertex,
-} from "../../A00_Common/design/design_pipeline_types";
+} from "../../A00_Common/design/logic/design_pipeline_types";
import { type DtmGrid, heightAt } from "../../common_util/common_util_surface_sampler";
-import { buildEditedPolyline } from "../B05_Profile_UI_RouteEdit_Curve";
-import { applyArcLocks } from "../B05_Profile_UI_RouteEdit_Edits";
+import { buildEditedPolyline } from "./B05_Profile_UI_RouteEdit_Curve";
+import { applyArcLocks } from "./B05_Profile_UI_RouteEdit_Edits";
import {
crossOffsets,
longitudinalPoints,
diff --git a/B05_Profile/logic/B05_Profile_PlanFootprint.ts b/B05_Profile/logic/B05_Profile_PlanFootprint.ts
index b3ea9acfc..62ca60b39 100644
--- a/B05_Profile/logic/B05_Profile_PlanFootprint.ts
+++ b/B05_Profile/logic/B05_Profile_PlanFootprint.ts
@@ -11,7 +11,7 @@
* 순수 계산 — 화면 · three · fetch · sessionStorage 없음 · 좌표 = 사업지 m · 오프셋 좌(+) · 우(-).
* ========================================================================== */
-import type { PlanFootprint, Vertex } from "../../A00_Common/design/design_pipeline_types";
+import type { PlanFootprint, Vertex } from "../../A00_Common/design/logic/design_pipeline_types";
/** 횡단 설계선 · 지반 표본 한 점(`CrossDesignEdge` · `CrossGroundSample` 꼴). */
export interface FootprintPoint {
diff --git a/B05_Profile/logic/B05_Profile_Sections_Ground.ts b/B05_Profile/logic/B05_Profile_Sections_Ground.ts
index 64c6f3dc7..b0b81e635 100644
--- a/B05_Profile/logic/B05_Profile_Sections_Ground.ts
+++ b/B05_Profile/logic/B05_Profile_Sections_Ground.ts
@@ -16,7 +16,7 @@
import { type DtmGrid, heightAt } from "../../common_util/common_util_surface_sampler";
import type { CrossDesignEdge } from "../../common_util/common_util_cross_design";
-import { stationFrameAt, stationsAlong } from "../B05_Profile_UI_RouteEdit_Frame";
+import { stationFrameAt, stationsAlong } from "./B05_Profile_UI_RouteEdit_Frame";
type Vertex = [number, number];
diff --git a/B05_Profile/logic/B05_Profile_Sections_Stations.ts b/B05_Profile/logic/B05_Profile_Sections_Stations.ts
index c184d750c..7782a524b 100644
--- a/B05_Profile/logic/B05_Profile_Sections_Stations.ts
+++ b/B05_Profile/logic/B05_Profile_Sections_Stations.ts
@@ -1,8 +1,8 @@
/* =============================================================================
* B05_Profile/logic/B05_Profile_Sections_Stations.ts
* 측점 한 벌(PLAN 344-3 뼈대 · 346-1) — 그린 노선 + 관 · 구조물 → 측점(지반 null). 계산 묶음 stations
- * 단계(`A00_Common/design/design_pipeline_stations.ts`)가 부름. 측점 열쇠 규칙 한 곳(`stationKey` ·
- * 계약 = `A00_Common/design/design_pipeline_types.ts` 머리).
+ * 단계(`A00_Common/design/logic/design_pipeline_stations.ts`)가 부름. 측점 열쇠 규칙 한 곳(`stationKey` ·
+ * 계약 = `A00_Common/design/logic/design_pipeline_types.ts` 머리).
*
* ⚠ 파이썬·TS 짝 — `B05_Profile_Engine_Sections_Core.py` `generate_sections` 의 측점 부분
* (격자 · 스냅 · 구조물 측점 병합 · 종류 · 틀 · 방위각) ↔ `buildStations` ·
@@ -20,7 +20,7 @@ import {
snapCurveStations,
stationFrameAt,
stationsAlong,
-} from "../B05_Profile_UI_RouteEdit_Frame";
+} from "./B05_Profile_UI_RouteEdit_Frame";
import {
planStations,
type PlanPipe,
@@ -33,7 +33,7 @@ import type {
PipelineStation,
StationKind,
Vertex,
-} from "../../A00_Common/design/design_pipeline_types";
+} from "../../A00_Common/design/logic/design_pipeline_types";
/** 짝: `config_system_design.py` 같은 이름. */
export const SECTION_STATION_INTERVAL_M = 20.0;
diff --git a/B05_Profile/B05_Profile_UI_Corridor_Build_Types.ts b/B05_Profile/logic/B05_Profile_UI_Corridor_Build_Types.ts
similarity index 89%
rename from B05_Profile/B05_Profile_UI_Corridor_Build_Types.ts
rename to B05_Profile/logic/B05_Profile_UI_Corridor_Build_Types.ts
index d984d4c9d..e6cdec212 100644
--- a/B05_Profile/B05_Profile_UI_Corridor_Build_Types.ts
+++ b/B05_Profile/logic/B05_Profile_UI_Corridor_Build_Types.ts
@@ -7,9 +7,9 @@
* (`... from "./B05_Profile_UI_Corridor_Build"`)는 전부 유효하다.
* ========================================================================== */
-import type { CrossSection } from "../B06_Section/B06_Section_Api_Fetch";
-import type { CorridorKind, CorridorSide } from "./B05_Profile_UI_Corridor_Station";
-import type { CorridorStructure } from "./B05_Profile_UI_Corridor_Structures";
+import type { CrossSection } from "../../B06_Section/B06_Section_Api_Fetch";
+import type { CorridorKind, CorridorSide } from "../B05_Profile_UI_Corridor_Station";
+import type { CorridorStructure } from "../B05_Profile_UI_Corridor_Structures";
export interface CorridorRibbon {
kind: CorridorKind;
diff --git a/B05_Profile/B05_Profile_UI_Corridor_Deform.ts b/B05_Profile/logic/B05_Profile_UI_Corridor_Deform.ts
similarity index 100%
rename from B05_Profile/B05_Profile_UI_Corridor_Deform.ts
rename to B05_Profile/logic/B05_Profile_UI_Corridor_Deform.ts
diff --git a/B05_Profile/B05_Profile_UI_Corridor_Frames.ts b/B05_Profile/logic/B05_Profile_UI_Corridor_Frames.ts
similarity index 98%
rename from B05_Profile/B05_Profile_UI_Corridor_Frames.ts
rename to B05_Profile/logic/B05_Profile_UI_Corridor_Frames.ts
index 35a6ab924..6a7af5459 100644
--- a/B05_Profile/B05_Profile_UI_Corridor_Frames.ts
+++ b/B05_Profile/logic/B05_Profile_UI_Corridor_Frames.ts
@@ -10,8 +10,8 @@
* 테이퍼가 생긴다. 접속 길이 기준 = **인접 측점까지**(2026-08-24 사용자 확정).
* ========================================================================== */
-import type { OffsetPoint, StationPieces, XY } from "./B05_Profile_UI_Corridor_Station";
-import type { RoutePoint } from "./B05_Profile_Api_Fetch";
+import type { OffsetPoint, StationPieces, XY } from "../B05_Profile_UI_Corridor_Station";
+import type { RoutePoint } from "../B05_Profile_Api_Fetch";
/** 제어점 하나 — 그 누가거리에서 쓸 단면과 출처. */
export interface PieceControl {
diff --git a/B05_Profile/B05_Profile_UI_Corridor_Loft_Grid.ts b/B05_Profile/logic/B05_Profile_UI_Corridor_Loft_Grid.ts
similarity index 100%
rename from B05_Profile/B05_Profile_UI_Corridor_Loft_Grid.ts
rename to B05_Profile/logic/B05_Profile_UI_Corridor_Loft_Grid.ts
diff --git a/B05_Profile/B05_Profile_UI_Corridor_Loft_Toe.ts b/B05_Profile/logic/B05_Profile_UI_Corridor_Loft_Toe.ts
similarity index 100%
rename from B05_Profile/B05_Profile_UI_Corridor_Loft_Toe.ts
rename to B05_Profile/logic/B05_Profile_UI_Corridor_Loft_Toe.ts
diff --git a/B05_Profile/B05_Profile_UI_Corridor_Region.ts b/B05_Profile/logic/B05_Profile_UI_Corridor_Region.ts
similarity index 100%
rename from B05_Profile/B05_Profile_UI_Corridor_Region.ts
rename to B05_Profile/logic/B05_Profile_UI_Corridor_Region.ts
diff --git a/B05_Profile/B05_Profile_UI_Corridor_Structures_Hash.ts b/B05_Profile/logic/B05_Profile_UI_Corridor_Structures_Hash.ts
similarity index 95%
rename from B05_Profile/B05_Profile_UI_Corridor_Structures_Hash.ts
rename to B05_Profile/logic/B05_Profile_UI_Corridor_Structures_Hash.ts
index 464815174..d2618748d 100644
--- a/B05_Profile/B05_Profile_UI_Corridor_Structures_Hash.ts
+++ b/B05_Profile/logic/B05_Profile_UI_Corridor_Structures_Hash.ts
@@ -7,8 +7,8 @@
* 원래 파일(`B05_Profile_UI_Corridor_Structures`)이 그대로 다시 내보내므로 기존 import 경로는 유효하다.
* ========================================================================== */
-import type { CrossSection } from "../B06_Section/B06_Section_Api_Fetch";
-import { SHAPE_KEYS } from "../common_util/common_util_structure_shape_keys";
+import type { CrossSection } from "../../B06_Section/B06_Section_Api_Fetch";
+import { SHAPE_KEYS } from "../../common_util/common_util_structure_shape_keys";
/** 형상을 바꾸는 조작값(정본 `design` 칸) — 조정창 · 다단 · 연동 · 유입 구조. */
const ADJUST_KEYS = [
diff --git a/B05_Profile/B05_Profile_UI_Corridor_Structures_Pick.ts b/B05_Profile/logic/B05_Profile_UI_Corridor_Structures_Pick.ts
similarity index 92%
rename from B05_Profile/B05_Profile_UI_Corridor_Structures_Pick.ts
rename to B05_Profile/logic/B05_Profile_UI_Corridor_Structures_Pick.ts
index 52b6b96cd..7d03eb79c 100644
--- a/B05_Profile/B05_Profile_UI_Corridor_Structures_Pick.ts
+++ b/B05_Profile/logic/B05_Profile_UI_Corridor_Structures_Pick.ts
@@ -5,8 +5,8 @@
* 쓰는 곳 = `B05_Profile_UI_Corridor_Structures.buildCorridorStructures`.
* ========================================================================== */
-import type { CrossSection } from "../B06_Section/B06_Section_Api_Fetch";
-import { catalogRow } from "../common_util/common_util_structure_catalog";
+import type { CrossSection } from "../../B06_Section/B06_Section_Api_Fetch";
+import { catalogRow } from "../../common_util/common_util_structure_catalog";
/** 그림 자료의 주인 종류가 이 3D 몸체를 세우는가 — 표에 없는 종류면 세움. */
export const builds = (typeId: string | null | undefined, body: string): boolean =>
diff --git a/B05_Profile/B05_Profile_UI_Corridor_Structures_Wing.ts b/B05_Profile/logic/B05_Profile_UI_Corridor_Structures_Wing.ts
similarity index 98%
rename from B05_Profile/B05_Profile_UI_Corridor_Structures_Wing.ts
rename to B05_Profile/logic/B05_Profile_UI_Corridor_Structures_Wing.ts
index 399ea3f62..c0d3685f3 100644
--- a/B05_Profile/B05_Profile_UI_Corridor_Structures_Wing.ts
+++ b/B05_Profile/logic/B05_Profile_UI_Corridor_Structures_Wing.ts
@@ -12,13 +12,13 @@
* 곡선 구간에서 구체 끝과 어긋나고 옆 측점에 물려 잘린다(2026-08-25 사용자).
* ========================================================================== */
-import type { FordWingSpec } from "../B06_Section/B06_Section_Api_Fetch";
+import type { FordWingSpec } from "../../B06_Section/B06_Section_Api_Fetch";
import type {
CorridorStructure,
RouteFrame,
StructureFrame,
-} from "./B05_Profile_UI_Corridor_Structures";
-import type { SectionPolygon } from "./B05_Profile_UI_Corridor_Structures_Box";
+} from "../B05_Profile_UI_Corridor_Structures";
+import type { SectionPolygon } from "../B05_Profile_UI_Corridor_Structures_Box";
/** 날개벽이 붙는 구조물 한쪽 끝 — 좌·우 각각 하나. */
export interface WingAnchor {
diff --git a/B05_Profile/B05_Profile_UI_Corridor_Tin_Design.ts b/B05_Profile/logic/B05_Profile_UI_Corridor_Tin_Design.ts
similarity index 97%
rename from B05_Profile/B05_Profile_UI_Corridor_Tin_Design.ts
rename to B05_Profile/logic/B05_Profile_UI_Corridor_Tin_Design.ts
index bf7a36f9c..934b72266 100644
--- a/B05_Profile/B05_Profile_UI_Corridor_Tin_Design.ts
+++ b/B05_Profile/logic/B05_Profile_UI_Corridor_Tin_Design.ts
@@ -7,7 +7,7 @@
* 옛 제안 ② 설계(변형 장에서 · buildTinDesign)는 `Old/` 에.
* ========================================================================== */
-import type { CorridorStructure } from "./B05_Profile_UI_Corridor_Structures";
+import type { CorridorStructure } from "../B05_Profile_UI_Corridor_Structures";
import type { Pslg } from "./B05_Profile_UI_Corridor_Tin_Pslg";
/** 단면 행 걸음(m) — 측점 사이 보간 단면. */
diff --git a/B05_Profile/B05_Profile_UI_Corridor_Tin_Pslg.ts b/B05_Profile/logic/B05_Profile_UI_Corridor_Tin_Pslg.ts
similarity index 100%
rename from B05_Profile/B05_Profile_UI_Corridor_Tin_Pslg.ts
rename to B05_Profile/logic/B05_Profile_UI_Corridor_Tin_Pslg.ts
diff --git a/B05_Profile/B05_Profile_UI_Drainage_Facility_Merge.ts b/B05_Profile/logic/B05_Profile_UI_Drainage_Facility_Merge.ts
similarity index 100%
rename from B05_Profile/B05_Profile_UI_Drainage_Facility_Merge.ts
rename to B05_Profile/logic/B05_Profile_UI_Drainage_Facility_Merge.ts
diff --git a/B05_Profile/B05_Profile_UI_Profile_Alignment.ts b/B05_Profile/logic/B05_Profile_UI_Profile_Alignment.ts
similarity index 100%
rename from B05_Profile/B05_Profile_UI_Profile_Alignment.ts
rename to B05_Profile/logic/B05_Profile_UI_Profile_Alignment.ts
diff --git a/B05_Profile/B05_Profile_UI_Profile_Data.ts b/B05_Profile/logic/B05_Profile_UI_Profile_Data.ts
similarity index 96%
rename from B05_Profile/B05_Profile_UI_Profile_Data.ts
rename to B05_Profile/logic/B05_Profile_UI_Profile_Data.ts
index b0be06167..2968725fe 100644
--- a/B05_Profile/B05_Profile_UI_Profile_Data.ts
+++ b/B05_Profile/logic/B05_Profile_UI_Profile_Data.ts
@@ -5,7 +5,7 @@
* 상태를 갖지 않으며 DOM도 만들지 않는다 — 패널 본체가 700줄 한계에 닿아 분리했다.
* ========================================================================== */
-import type { DesignProfile, LongitudinalSection } from "../B06_Section/B06_Section_Api_Fetch";
+import type { DesignProfile, LongitudinalSection } from "../../B06_Section/B06_Section_Api_Fetch";
import type { ProfileAlignment } from "./B05_Profile_UI_Profile_Alignment";
export function readAlignment(data: LongitudinalSection): ProfileAlignment | null {
diff --git a/B05_Profile/B05_Profile_UI_Profile_Guard.ts b/B05_Profile/logic/B05_Profile_UI_Profile_Guard.ts
similarity index 96%
rename from B05_Profile/B05_Profile_UI_Profile_Guard.ts
rename to B05_Profile/logic/B05_Profile_UI_Profile_Guard.ts
index d909d0821..e49081199 100644
--- a/B05_Profile/B05_Profile_UI_Profile_Guard.ts
+++ b/B05_Profile/logic/B05_Profile_UI_Profile_Guard.ts
@@ -7,7 +7,7 @@
* (계획서 24-2c). 본문 로직과 수치는 그대로이고 화면 상태를 인자로 받는다.
* ========================================================================== */
-import type { SectionDetailResponse } from "../B06_Section/B06_Section_Api_Fetch";
+import type { SectionDetailResponse } from "../../B06_Section/B06_Section_Api_Fetch";
import type { ProfileAlignment } from "./B05_Profile_UI_Profile_Alignment";
/** 계획선 샘플에서 chainage로 계획고·지반고를 되짚는 보간기(최소고 판정 입력). */
diff --git a/B05_Profile/B05_Profile_UI_Profile_Straighten.ts b/B05_Profile/logic/B05_Profile_UI_Profile_Straighten.ts
similarity index 100%
rename from B05_Profile/B05_Profile_UI_Profile_Straighten.ts
rename to B05_Profile/logic/B05_Profile_UI_Profile_Straighten.ts
diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Curve.ts b/B05_Profile/logic/B05_Profile_UI_RouteEdit_Curve.ts
similarity index 100%
rename from B05_Profile/B05_Profile_UI_RouteEdit_Curve.ts
rename to B05_Profile/logic/B05_Profile_UI_RouteEdit_Curve.ts
diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Edits.ts b/B05_Profile/logic/B05_Profile_UI_RouteEdit_Edits.ts
similarity index 100%
rename from B05_Profile/B05_Profile_UI_RouteEdit_Edits.ts
rename to B05_Profile/logic/B05_Profile_UI_RouteEdit_Edits.ts
diff --git a/B05_Profile/B05_Profile_UI_RouteEdit_Frame.ts b/B05_Profile/logic/B05_Profile_UI_RouteEdit_Frame.ts
similarity index 100%
rename from B05_Profile/B05_Profile_UI_RouteEdit_Frame.ts
rename to B05_Profile/logic/B05_Profile_UI_RouteEdit_Frame.ts
diff --git a/B05_Profile/B05_Profile_UI_Structures_Balloon.ts b/B05_Profile/logic/B05_Profile_UI_Structures_Balloon.ts
similarity index 95%
rename from B05_Profile/B05_Profile_UI_Structures_Balloon.ts
rename to B05_Profile/logic/B05_Profile_UI_Structures_Balloon.ts
index 1c30e739c..725d4c2d6 100644
--- a/B05_Profile/B05_Profile_UI_Structures_Balloon.ts
+++ b/B05_Profile/logic/B05_Profile_UI_Structures_Balloon.ts
@@ -12,11 +12,11 @@
* 미리 넣음 · B07 짝(서버 Node `B07_DesignDetail_Note_Options_Node`)이 같이 씀
* ========================================================================== */
-import type { StructureInstance, StructureType } from "./B05_Profile_Api_Structures";
+import type { StructureInstance, StructureType } from "../B05_Profile_Api_Structures";
import { shapeFields, shapeKey } from "./B05_Profile_UI_Structures_Define";
-import { specFor } from "../A00_Common/design/design_structure_pipe";
-import { bodyOf, boxOptionsIn } from "../A00_Common/design/design_structure_box";
-import { withLegacyGuards } from "../A00_Common/design/design_structure_ford";
+import { specFor } from "../../A00_Common/design/logic/design_structure_pipe";
+import { bodyOf, boxOptionsIn } from "../../A00_Common/design/logic/design_structure_box";
+import { withLegacyGuards } from "../../A00_Common/design/logic/design_structure_ford";
import {
branchOf,
choiceLabel,
@@ -28,7 +28,7 @@ import {
type SpecContainer,
type SpecItem,
type StructureSpec,
-} from "../A00_Common/design/design_structure_spec";
+} from "../../A00_Common/design/logic/design_structure_spec";
const AUTO_MARK = "(자동)";
const SEP = " · ";
diff --git a/B05_Profile/B05_Profile_UI_Structures_Define.ts b/B05_Profile/logic/B05_Profile_UI_Structures_Define.ts
similarity index 100%
rename from B05_Profile/B05_Profile_UI_Structures_Define.ts
rename to B05_Profile/logic/B05_Profile_UI_Structures_Define.ts
diff --git a/B05_Profile/B05_Profile_UI_Structures_Summary.ts b/B05_Profile/logic/B05_Profile_UI_Structures_Summary.ts
similarity index 100%
rename from B05_Profile/B05_Profile_UI_Structures_Summary.ts
rename to B05_Profile/logic/B05_Profile_UI_Structures_Summary.ts
diff --git a/B05_Profile/B05_Profile_Util_Station.ts b/B05_Profile/logic/B05_Profile_Util_Station.ts
similarity index 100%
rename from B05_Profile/B05_Profile_Util_Station.ts
rename to B05_Profile/logic/B05_Profile_Util_Station.ts
diff --git a/B06_Section/B06_Section_Cross_Refresh.ts b/B06_Section/B06_Section_Cross_Refresh.ts
index 07233dac9..f1496380d 100644
--- a/B06_Section/B06_Section_Cross_Refresh.ts
+++ b/B06_Section/B06_Section_Cross_Refresh.ts
@@ -50,9 +50,9 @@ import {
buildAlignment,
planElevationAt,
toAlignmentBase,
-} from "../B05_Profile/B05_Profile_UI_Profile_Alignment";
-import type { ProfileAlignment } from "../B05_Profile/B05_Profile_UI_Profile_Alignment";
-import { readAlignment, toDesignProfile } from "../B05_Profile/B05_Profile_UI_Profile_Data";
+} from "../B05_Profile/logic/B05_Profile_UI_Profile_Alignment";
+import type { ProfileAlignment } from "../B05_Profile/logic/B05_Profile_UI_Profile_Alignment";
+import { readAlignment, toDesignProfile } from "../B05_Profile/logic/B05_Profile_UI_Profile_Data";
import { useStationKeys } from "./B06_Section_Station_Keys";
import { readAlignmentDraft } from "../B05_Profile/B05_Profile_UI_Profile_Edit";
import { hasStaleDesigns } from "./B06_Section_UI_Section_Common";
diff --git a/B06_Section/B06_Section_Section_Store.ts b/B06_Section/B06_Section_Section_Store.ts
index 9df278c0e..036b73f39 100644
--- a/B06_Section/B06_Section_Section_Store.ts
+++ b/B06_Section/B06_Section_Section_Store.ts
@@ -30,7 +30,7 @@ import type { CrossSectionPatch, SectionDetailResponse } from "./B06_Section_Api
import { fetchSectionDetail, saveSections } from "./B06_Section_Api_Fetch";
import { USER_TOUCHED_KEYS } from "./B06_Section_Cross_Refresh";
import { kindChangedChainages, STRUCTURE_ADJUST_KEYS } from "./B06_Section_Api_Culvert_Options";
-import type { PipelineStation } from "../A00_Common/design/design_pipeline_types";
+import type { PipelineStation } from "../A00_Common/design/logic/design_pipeline_types";
import {
carryStationKeys,
registeredKeys,
diff --git a/B06_Section/B06_Section_Structure_Layouts.ts b/B06_Section/B06_Section_Structure_Layouts.ts
index 9c4aeaff3..0f0f47ef2 100644
--- a/B06_Section/B06_Section_Structure_Layouts.ts
+++ b/B06_Section/B06_Section_Structure_Layouts.ts
@@ -15,8 +15,8 @@ import type { CrossSection } from "./B06_Section_Api_Fetch";
import { withoutGuardedFill } from "./B06_Section_UI_Cross_Body_Guard";
import { computeBoxLayout, DEFAULT_BOX_SIDE_ADJUST } from "./B06_Section_UI_Cross_Box_Geom";
import type { BoxLayout } from "./B06_Section_UI_Cross_Box_Geom";
-import { REVET_EMBED_DEPTH_M } from "./B06_Section_UI_Cross_Culvert_Const";
-import { groundInterpolator } from "./B06_Section_UI_Cross_Culvert_Solve";
+import { REVET_EMBED_DEPTH_M } from "./logic/B06_Section_UI_Cross_Culvert_Const";
+import { groundInterpolator } from "./logic/B06_Section_UI_Cross_Culvert_Solve";
import { DEFAULT_BASIN_ADJUST, ZERO_ADJUST } from "./B06_Section_UI_Cross_Culvert_Types";
import type { BasinShape, WallAdjust, WallLayout } from "./B06_Section_UI_Cross_Culvert_Types";
import {
diff --git a/B06_Section/B06_Section_UI_Cross_Body_Guard.ts b/B06_Section/B06_Section_UI_Cross_Body_Guard.ts
index d9e5c8461..83e6b671b 100644
--- a/B06_Section/B06_Section_UI_Cross_Body_Guard.ts
+++ b/B06_Section/B06_Section_UI_Cross_Body_Guard.ts
@@ -13,7 +13,7 @@
import type { CrossSection, SectionSample } from "./B06_Section_Api_Fetch";
import { computeBoxLayout, DEFAULT_BOX_SIDE_ADJUST } from "./B06_Section_UI_Cross_Box_Geom";
import type { BoxLayout } from "./B06_Section_UI_Cross_Box_Geom";
-import { FILL_SLOPE_RATIO_MIN } from "./B06_Section_UI_Cross_Culvert_Const";
+import { FILL_SLOPE_RATIO_MIN } from "./logic/B06_Section_UI_Cross_Culvert_Const";
import type {
CulvertDesignTrim,
CulvertLayout,
diff --git a/B06_Section/B06_Section_UI_Cross_Box_Geom.ts b/B06_Section/B06_Section_UI_Cross_Box_Geom.ts
index c7014e1b5..ff0268907 100644
--- a/B06_Section/B06_Section_UI_Cross_Box_Geom.ts
+++ b/B06_Section/B06_Section_UI_Cross_Box_Geom.ts
@@ -25,9 +25,9 @@ import type {
OutletFillSegment,
} from "./B06_Section_UI_Cross_Culvert_Types";
import { buildExtrasAt } from "./B06_Section_UI_Cross_Culvert_Extra";
-import { FILL_SLOPE_RATIO_MIN } from "./B06_Section_UI_Cross_Culvert_Const";
-import { designInterpolator, groundInterpolator } from "./B06_Section_UI_Cross_Culvert_Solve";
-import { structureCutPoints, structureCutSpec } from "./B06_Section_UI_Cross_Structure_Cut";
+import { FILL_SLOPE_RATIO_MIN } from "./logic/B06_Section_UI_Cross_Culvert_Const";
+import { designInterpolator, groundInterpolator } from "./logic/B06_Section_UI_Cross_Culvert_Solve";
+import { structureCutPoints, structureCutSpec } from "./logic/B06_Section_UI_Cross_Structure_Cut";
/** 구체 한쪽 끝의 조작값 — 좌·우를 따로 잡는다(2026-08-25 사용자). */
export interface BoxSideAdjust {
diff --git a/B06_Section/B06_Section_UI_Cross_Card_Chrome.ts b/B06_Section/B06_Section_UI_Cross_Card_Chrome.ts
index 0fdf3e559..4cdc67dd1 100644
--- a/B06_Section/B06_Section_UI_Cross_Card_Chrome.ts
+++ b/B06_Section/B06_Section_UI_Cross_Card_Chrome.ts
@@ -14,7 +14,7 @@ import {
buildRockBoundaryControl,
sectionModeLabel,
} from "./B06_Section_UI_Cross_Design";
-import { type FillSlopeLength, fillSlopeLengths } from "./B06_Section_UI_Cross_Fit";
+import { type FillSlopeLength, fillSlopeLengths } from "./logic/B06_Section_UI_Cross_Fit";
import {
type DesignChangeHandler,
L,
diff --git a/B06_Section/B06_Section_UI_Cross_Culvert.ts b/B06_Section/B06_Section_UI_Cross_Culvert.ts
index 325e00c3b..9d53cf141 100644
--- a/B06_Section/B06_Section_UI_Cross_Culvert.ts
+++ b/B06_Section/B06_Section_UI_Cross_Culvert.ts
@@ -24,7 +24,7 @@ import type {
WallLayout,
} from "./B06_Section_UI_Cross_Culvert_Geom";
import { appendPipeInfoText, outlineBox } from "./B06_Section_UI_Cross_Culvert_Types";
-import { pipeLengthText } from "./B06_Section_UI_Cross_Culvert_Const";
+import { pipeLengthText } from "./logic/B06_Section_UI_Cross_Culvert_Const";
import { appendWallTrench, foundationChoice } from "./B06_Section_UI_Cross_Excavation";
import {
appendChuteBand,
diff --git a/B06_Section/B06_Section_UI_Cross_Culvert_Extra.ts b/B06_Section/B06_Section_UI_Cross_Culvert_Extra.ts
index 234aa2bb1..406e38e33 100644
--- a/B06_Section/B06_Section_UI_Cross_Culvert_Extra.ts
+++ b/B06_Section/B06_Section_UI_Cross_Culvert_Extra.ts
@@ -22,15 +22,15 @@ import {
REVET_LEAN_RATIO,
REVET_THICKNESS_M,
WALL_MIN_PURE_HEIGHT_M,
-} from "./B06_Section_UI_Cross_Culvert_Const";
+} from "./logic/B06_Section_UI_Cross_Culvert_Const";
import type {
OffsetPoint,
OutletFillSegment,
WallAdjust,
WallLayout,
} from "./B06_Section_UI_Cross_Culvert_Types";
-import { structureCutPoints } from "./B06_Section_UI_Cross_Structure_Cut";
-import type { StructureCutSpec } from "./B06_Section_UI_Cross_Structure_Cut";
+import { structureCutPoints } from "./logic/B06_Section_UI_Cross_Structure_Cut";
+import type { StructureCutSpec } from "./logic/B06_Section_UI_Cross_Structure_Cut";
import { buildRevetWallGeometry } from "./B06_Section_UI_Cross_Wall";
export interface OutletExtrasInput {
diff --git a/B06_Section/B06_Section_UI_Cross_Culvert_Geom.ts b/B06_Section/B06_Section_UI_Cross_Culvert_Geom.ts
index 0b66c0e2e..dee524084 100644
--- a/B06_Section/B06_Section_UI_Cross_Culvert_Geom.ts
+++ b/B06_Section/B06_Section_UI_Cross_Culvert_Geom.ts
@@ -19,9 +19,9 @@ import {
REVET_LEAN_RATIO,
REVET_THICKNESS_M,
revetTargetHeight,
-} from "./B06_Section_UI_Cross_Culvert_Const";
-import type { RevetMaterial } from "./B06_Section_UI_Cross_Culvert_Const";
-import { outlineLeanOf } from "./B06_Section_UI_Cross_Lean";
+} from "./logic/B06_Section_UI_Cross_Culvert_Const";
+import type { RevetMaterial } from "./logic/B06_Section_UI_Cross_Culvert_Const";
+import { outlineLeanOf } from "./logic/B06_Section_UI_Cross_Lean";
import { buildRevetWallGeometry } from "./B06_Section_UI_Cross_Wall";
import {
bodyGuardAxes,
@@ -46,7 +46,7 @@ import type {
import { DEFAULT_BASIN_ADJUST } from "./B06_Section_UI_Cross_Culvert_Types";
// 상수·자료형은 분리 파일에 있고, 기존 import 경로를 유지하기 위해 그대로 다시 내보낸다.
-export * from "./B06_Section_UI_Cross_Culvert_Const";
+export * from "./logic/B06_Section_UI_Cross_Culvert_Const";
export * from "./B06_Section_UI_Cross_Culvert_Types";
import {
@@ -56,16 +56,16 @@ import {
decideInletBasin,
BASIN_INNER_WIDTH_M,
inletChoiceAvailability,
-} from "./B06_Section_UI_Cross_Culvert_Basin";
+} from "./logic/B06_Section_UI_Cross_Culvert_Basin";
import { inletGroundConnector } from "./B06_Section_UI_Cross_Culvert_Extra";
-import { withBackCut } from "./B06_Section_UI_Cross_Structure_Cut";
+import { withBackCut } from "./logic/B06_Section_UI_Cross_Structure_Cut";
import {
buildCulvertTiers,
drawnFillPoints,
outletPipeEnd,
slopeZeroAnchor,
} from "./B06_Section_UI_Cross_Culvert_Tiers";
-import type { FillSlopeSegment, WallVertical } from "./B06_Section_UI_Cross_Culvert_Solve";
+import type { FillSlopeSegment, WallVertical } from "./logic/B06_Section_UI_Cross_Culvert_Solve";
import {
cutLength,
fillSlopeOf,
@@ -75,7 +75,7 @@ import {
pipeAxisSolver,
placePipeWall,
slopeLengthAlong,
-} from "./B06_Section_UI_Cross_Culvert_Solve";
+} from "./logic/B06_Section_UI_Cross_Culvert_Solve";
/** 배수관 세트 기하 계산. 부족한 입력이면 null — 그리기와 분리(설계선 트림이 먼저 쓴다). */
export function computeCulvertLayout(
diff --git a/B06_Section/B06_Section_UI_Cross_Culvert_Tiers.ts b/B06_Section/B06_Section_UI_Cross_Culvert_Tiers.ts
index c97709e44..06c103e63 100644
--- a/B06_Section/B06_Section_UI_Cross_Culvert_Tiers.ts
+++ b/B06_Section/B06_Section_UI_Cross_Culvert_Tiers.ts
@@ -10,13 +10,13 @@ import {
GUARD_CUT_BERM_M,
REVET_EMBED_DEPTH_M,
REVET_TRAP_TOP_M,
-} from "./B06_Section_UI_Cross_Culvert_Const";
+} from "./logic/B06_Section_UI_Cross_Culvert_Const";
import type { OutletExtrasResult } from "./B06_Section_UI_Cross_Culvert_Extra";
import { buildExtrasAt } from "./B06_Section_UI_Cross_Culvert_Extra";
-import { fillWallBaseWidth } from "./B06_Section_UI_Cross_Culvert_Solve";
+import { fillWallBaseWidth } from "./logic/B06_Section_UI_Cross_Culvert_Solve";
import type { OffsetPoint, WallAdjust, WallLayout } from "./B06_Section_UI_Cross_Culvert_Types";
-import { outlineLeanOf } from "./B06_Section_UI_Cross_Lean";
-import { structureCutSpec } from "./B06_Section_UI_Cross_Structure_Cut";
+import { outlineLeanOf } from "./logic/B06_Section_UI_Cross_Lean";
+import { structureCutSpec } from "./logic/B06_Section_UI_Cross_Structure_Cut";
// d의 0점 = **성토선 길이 0 지점**(벽 상단 = 노견 — 2026-08-23 사용자 확정).
// 그 자리(하단선 중점)는 이음선 상단점이 노견 끝에 오는 offset이고, 기본 자리는
diff --git a/B06_Section/B06_Section_UI_Cross_Culvert_Types.ts b/B06_Section/B06_Section_UI_Cross_Culvert_Types.ts
index 1b21ed7cc..65c5dae08 100644
--- a/B06_Section/B06_Section_UI_Cross_Culvert_Types.ts
+++ b/B06_Section/B06_Section_UI_Cross_Culvert_Types.ts
@@ -5,7 +5,7 @@
* ========================================================================== */
import type { CulvertSet } from "./B06_Section_Api_Fetch";
-import type { RevetMaterial } from "./B06_Section_UI_Cross_Culvert_Const";
+import type { RevetMaterial } from "./logic/B06_Section_UI_Cross_Culvert_Const";
/**
* 기슭막이 1매의 사용자 조작값(2026-08-22 확정 4축):
diff --git a/B06_Section/B06_Section_UI_Cross_Culvert_Wire.ts b/B06_Section/B06_Section_UI_Cross_Culvert_Wire.ts
index 44b82ef41..c00cf4b20 100644
--- a/B06_Section/B06_Section_UI_Cross_Culvert_Wire.ts
+++ b/B06_Section/B06_Section_UI_Cross_Culvert_Wire.ts
@@ -18,15 +18,15 @@ import {
basinSpanOfSpec,
FILL_SLOPE_RATIO_MIN,
revetSpanOfSpec,
-} from "./B06_Section_UI_Cross_Culvert_Const";
-import { EXTRA_SPAN_DEFAULT } from "./B06_Section_UI_Cross_Culvert_Const";
-import type { StructureSpan } from "./B06_Section_UI_Cross_Culvert_Const";
+} from "./logic/B06_Section_UI_Cross_Culvert_Const";
+import { EXTRA_SPAN_DEFAULT } from "./logic/B06_Section_UI_Cross_Culvert_Const";
+import type { StructureSpan } from "./logic/B06_Section_UI_Cross_Culvert_Const";
import type { WallAdjust } from "./B06_Section_UI_Cross_Culvert_Types";
import {
designInterpolator,
groundInterpolator,
slopeToeOffset,
-} from "./B06_Section_UI_Cross_Culvert_Solve";
+} from "./logic/B06_Section_UI_Cross_Culvert_Solve";
/**
* 기슭막이 4축 조작 제어(2026-08-22 확정) — 벽을 눌러 고르고 조정창에서
* 좌우(x)·상하(d, 성토선 대각)·높이(h)·재질(m)을 만진다. 고른 벽은 여기 담아 두어
diff --git a/B06_Section/B06_Section_UI_Cross_Detail_Cad.ts b/B06_Section/B06_Section_UI_Cross_Detail_Cad.ts
index f2c9fd852..a61eb785d 100644
--- a/B06_Section/B06_Section_UI_Cross_Detail_Cad.ts
+++ b/B06_Section/B06_Section_UI_Cross_Detail_Cad.ts
@@ -24,7 +24,7 @@ import {
fetchStructureTypes,
readPendingStructures,
} from "../B05_Profile/B05_Profile_Api_Structures";
-import { structureOptionLines } from "../B05_Profile/B05_Profile_UI_Structures_Balloon";
+import { structureOptionLines } from "../B05_Profile/logic/B05_Profile_UI_Structures_Balloon";
import {
readGroupItems,
readSummaryItem,
@@ -32,7 +32,7 @@ import {
type SummaryItem,
} from "../common_util/common_util_summary_item";
import type { CrossNoteCad, CrossSection } from "./B06_Section_Api_Fetch";
-import { pipeLengthWhole } from "./B06_Section_UI_Cross_Culvert_Const";
+import { pipeLengthWhole } from "./logic/B06_Section_UI_Cross_Culvert_Const";
const noteKey = (chainageM: number): string => chainageM.toFixed(2);
diff --git a/B06_Section/B06_Section_UI_Cross_Detail_Select.ts b/B06_Section/B06_Section_UI_Cross_Detail_Select.ts
index 648171d0d..ac3b77f36 100644
--- a/B06_Section/B06_Section_UI_Cross_Detail_Select.ts
+++ b/B06_Section/B06_Section_UI_Cross_Detail_Select.ts
@@ -33,7 +33,7 @@ import {
type Face,
type Pt,
type SplitPiece,
-} from "./B06_Section_UI_Cross_Detail_Geom";
+} from "./logic/B06_Section_UI_Cross_Detail_Geom";
const SVG_NS = "http://www.w3.org/2000/svg";
export const PIECE_HIT_CLASS = "b06-detail__piece";
diff --git a/B06_Section/B06_Section_UI_Cross_Detail_Table.ts b/B06_Section/B06_Section_UI_Cross_Detail_Table.ts
index 690908d7c..3ae185d90 100644
--- a/B06_Section/B06_Section_UI_Cross_Detail_Table.ts
+++ b/B06_Section/B06_Section_UI_Cross_Detail_Table.ts
@@ -23,7 +23,7 @@ import type {
} from "./B06_Section_Api_Fetch";
import type { CrossPickPiece, SectionSample } from "./B06_Section_Api_Types";
import type { CrossAxesOptions } from "./B06_Section_UI_Cross_Axes";
-import { pickLines, piecesValue } from "./B06_Section_UI_Cross_Detail_Geom";
+import { pickLines, piecesValue } from "./logic/B06_Section_UI_Cross_Detail_Geom";
import { attachDetailSelect } from "./B06_Section_UI_Cross_Detail_Select";
import { pointsArea } from "./B06_Section_UI_Cross_Pick_Order";
diff --git a/B06_Section/B06_Section_UI_Cross_FillSlope_Notice.ts b/B06_Section/B06_Section_UI_Cross_FillSlope_Notice.ts
index 0ab8bcb08..e9e4961f2 100644
--- a/B06_Section/B06_Section_UI_Cross_FillSlope_Notice.ts
+++ b/B06_Section/B06_Section_UI_Cross_FillSlope_Notice.ts
@@ -10,13 +10,13 @@
* ========================================================================== */
import type { CrossSection } from "./B06_Section_Api_Fetch";
-import { BERM_INFO_TEXT, bermReviewStations } from "./B06_Section_UI_Cross_Berm_Info";
-import { fillSlopeLengths, slopeRunLengths } from "./B06_Section_UI_Cross_Fit";
+import { BERM_INFO_TEXT, bermReviewStations } from "./logic/B06_Section_UI_Cross_Berm_Info";
+import { fillSlopeLengths, slopeRunLengths } from "./logic/B06_Section_UI_Cross_Fit";
import {
FILL_SLOPE_WARN_TEXT,
fillSlopeWarnings,
type FillSlopeWarning,
-} from "./B06_Section_UI_Cross_FillSlope_Warn";
+} from "./logic/B06_Section_UI_Cross_FillSlope_Warn";
import { L, stationLabel } from "./B06_Section_UI_Section_Common";
import { pavedBySpecs } from "./B06_Section_Cross_Refresh";
import { createNoticeChips, type NoticeChipRow } from "./B06_Section_UI_Cross_Notice_Chips";
diff --git a/B06_Section/B06_Section_UI_Cross_Ford_Geom.ts b/B06_Section/B06_Section_UI_Cross_Ford_Geom.ts
index b3ba4642f..dd456b134 100644
--- a/B06_Section/B06_Section_UI_Cross_Ford_Geom.ts
+++ b/B06_Section/B06_Section_UI_Cross_Ford_Geom.ts
@@ -21,17 +21,17 @@
import { groundLine } from "./B06_Section_UI_Cross_Wall_Hatch";
import type { CrossSection, FordSet, SectionSample } from "./B06_Section_Api_Fetch";
-import { GUARD_CUT_BERM_M, pipeWallThicknessM } from "./B06_Section_UI_Cross_Culvert_Const";
+import { GUARD_CUT_BERM_M, pipeWallThicknessM } from "./logic/B06_Section_UI_Cross_Culvert_Const";
import type {
BasinLayout,
CulvertDesignTrim,
OffsetPoint,
OutletFillSegment,
} from "./B06_Section_UI_Cross_Culvert_Types";
-import { basinApproachPoints, buildBasin } from "./B06_Section_UI_Cross_Culvert_Basin";
+import { basinApproachPoints, buildBasin } from "./logic/B06_Section_UI_Cross_Culvert_Basin";
import { bermCut, buildExtrasAt } from "./B06_Section_UI_Cross_Culvert_Extra";
-import { designInterpolator, groundInterpolator } from "./B06_Section_UI_Cross_Culvert_Solve";
-import { structureCutSpec } from "./B06_Section_UI_Cross_Structure_Cut";
+import { designInterpolator, groundInterpolator } from "./logic/B06_Section_UI_Cross_Culvert_Solve";
+import { structureCutSpec } from "./logic/B06_Section_UI_Cross_Structure_Cut";
/** 측벽 한 매의 조작값 — 좌우만(139-3). `heightM` · `slopeM` 은 옛 저장(측벽마다 높이 · 1:1.2
* 대각) 읽기 전용 — `dropM` 이 없을 때 바닥판 표고로 옮김(`fordDropOf`). */
diff --git a/B06_Section/B06_Section_UI_Cross_Panel_Base.ts b/B06_Section/B06_Section_UI_Cross_Panel_Base.ts
index 53ff81b73..adf92bce3 100644
--- a/B06_Section/B06_Section_UI_Cross_Panel_Base.ts
+++ b/B06_Section/B06_Section_UI_Cross_Panel_Base.ts
@@ -10,7 +10,7 @@
* · 키보드 방향키 = 십자 버튼(2026-08-23) — 셀렉트·입력 포커스 중엔 양보.
* ========================================================================== */
-import { FILL_SLOPE_RATIO_MIN } from "./B06_Section_UI_Cross_Culvert_Const";
+import { FILL_SLOPE_RATIO_MIN } from "./logic/B06_Section_UI_Cross_Culvert_Const";
/** 조작 버튼 하나 — 클릭이 카드 선택·팬으로 번지지 않게 막는다. */
export function makeButton(label: string, title: string, onClick: () => void): HTMLButtonElement {
diff --git a/B06_Section/B06_Section_UI_Cross_Revetment.ts b/B06_Section/B06_Section_UI_Cross_Revetment.ts
index 6c36b1dfe..d664d6bdd 100644
--- a/B06_Section/B06_Section_UI_Cross_Revetment.ts
+++ b/B06_Section/B06_Section_UI_Cross_Revetment.ts
@@ -24,11 +24,11 @@ import {
REVET_EMBED_DEPTH_M,
REVET_THICKNESS_M,
WALL_MIN_PURE_HEIGHT_M,
-} from "./B06_Section_UI_Cross_Culvert_Const";
-import { outlineLeanOf } from "./B06_Section_UI_Cross_Lean";
+} from "./logic/B06_Section_UI_Cross_Culvert_Const";
+import { outlineLeanOf } from "./logic/B06_Section_UI_Cross_Lean";
import { catalogRow } from "../common_util/common_util_structure_catalog";
-import type { RevetMaterial } from "./B06_Section_UI_Cross_Culvert_Const";
-import { fillWallBaseWidth, groundInterpolator } from "./B06_Section_UI_Cross_Culvert_Solve";
+import type { RevetMaterial } from "./logic/B06_Section_UI_Cross_Culvert_Const";
+import { fillWallBaseWidth, groundInterpolator } from "./logic/B06_Section_UI_Cross_Culvert_Solve";
import { buildExtrasAt } from "./B06_Section_UI_Cross_Culvert_Extra";
import {
ZERO_ADJUST,
diff --git a/B06_Section/B06_Section_UI_Cross_Structure_Panel.ts b/B06_Section/B06_Section_UI_Cross_Structure_Panel.ts
index 57a37320c..318a9b786 100644
--- a/B06_Section/B06_Section_UI_Cross_Structure_Panel.ts
+++ b/B06_Section/B06_Section_UI_Cross_Structure_Panel.ts
@@ -15,7 +15,7 @@
* ========================================================================== */
import type { InletStructureChoice, RevetKey, RevetPick } from "./B06_Section_UI_Cross_Culvert";
-import { REVET_FORMS } from "./B06_Section_UI_Cross_Culvert_Const";
+import { REVET_FORMS } from "./logic/B06_Section_UI_Cross_Culvert_Const";
import type { BasinAdjust, WallAdjust } from "./B06_Section_UI_Cross_Culvert_Types";
import type { SpanValues } from "./B06_Section_UI_Cross_Culvert_Wire";
import { L } from "./B06_Section_UI_Section_Common";
diff --git a/B06_Section/B06_Section_UI_Cross_View.ts b/B06_Section/B06_Section_UI_Cross_View.ts
index b78abd6d5..cda48dec7 100644
--- a/B06_Section/B06_Section_UI_Cross_View.ts
+++ b/B06_Section/B06_Section_UI_Cross_View.ts
@@ -72,7 +72,7 @@ import type { CrossWidthActions } from "./B06_Section_UI_Cross_View_Zoom";
import type { CutSlopeControl } from "./B06_Section_UI_Cross_CutSlope";
import { createCrossAxes, IDENTITY_VIEW } from "./B06_Section_UI_Cross_Axes";
import type { RevetHighlightSetter, RevetPick } from "./B06_Section_UI_Cross_Culvert";
-import { REVET_FORM_DEFAULT } from "./B06_Section_UI_Cross_Culvert_Const";
+import { REVET_FORM_DEFAULT } from "./logic/B06_Section_UI_Cross_Culvert_Const";
import {
CROSS_PAD,
CROSS_WIDTH,
diff --git a/B06_Section/B06_Section_UI_Cross_View_Panels.ts b/B06_Section/B06_Section_UI_Cross_View_Panels.ts
index 7face8a37..7f53c1105 100644
--- a/B06_Section/B06_Section_UI_Cross_View_Panels.ts
+++ b/B06_Section/B06_Section_UI_Cross_View_Panels.ts
@@ -6,7 +6,7 @@
import type { CrossSection } from "./B06_Section_Api_Fetch";
import type { RevetKey, RevetPick } from "./B06_Section_UI_Cross_Culvert";
-import { REVET_FORM_DEFAULT } from "./B06_Section_UI_Cross_Culvert_Const";
+import { REVET_FORM_DEFAULT } from "./logic/B06_Section_UI_Cross_Culvert_Const";
import type { WallAdjust } from "./B06_Section_UI_Cross_Culvert_Types";
import type {
CulvertLink,
diff --git a/B06_Section/B06_Section_UI_Cross_View_Structure.ts b/B06_Section/B06_Section_UI_Cross_View_Structure.ts
index 15cb2226a..ff68ab31c 100644
--- a/B06_Section/B06_Section_UI_Cross_View_Structure.ts
+++ b/B06_Section/B06_Section_UI_Cross_View_Structure.ts
@@ -13,7 +13,7 @@ import {
REVET_EMBED_DEPTH_M,
REVET_FORM_DEFAULT,
WALL_MIN_PURE_HEIGHT_M,
-} from "./B06_Section_UI_Cross_Culvert_Const";
+} from "./logic/B06_Section_UI_Cross_Culvert_Const";
import { clampAxis, type AxisDragSpec } from "./B06_Section_UI_Cross_Panel_Base";
import type { CulvertLayout } from "./B06_Section_UI_Cross_Culvert_Types";
import type { WallAdjust } from "./B06_Section_UI_Cross_Culvert_Types";
diff --git a/B06_Section/B06_Section_UI_Cross_Wall.ts b/B06_Section/B06_Section_UI_Cross_Wall.ts
index 4702ee779..2acbf3b55 100644
--- a/B06_Section/B06_Section_UI_Cross_Wall.ts
+++ b/B06_Section/B06_Section_UI_Cross_Wall.ts
@@ -15,8 +15,8 @@ import {
REVET_LEAN_RATIO,
REVET_THICKNESS_M,
WALL_MIN_PURE_HEIGHT_M,
-} from "./B06_Section_UI_Cross_Culvert_Const";
-import type { RevetMaterial } from "./B06_Section_UI_Cross_Culvert_Const";
+} from "./logic/B06_Section_UI_Cross_Culvert_Const";
+import type { RevetMaterial } from "./logic/B06_Section_UI_Cross_Culvert_Const";
import type { OffsetPoint, WallLayout } from "./B06_Section_UI_Cross_Culvert_Types";
import { appendWallHatch } from "./B06_Section_UI_Cross_Wall_Hatch";
diff --git a/B06_Section/B06_Section_UI_Cross_Wall_Hatch.ts b/B06_Section/B06_Section_UI_Cross_Wall_Hatch.ts
index 2b402938b..38ac262c8 100644
--- a/B06_Section/B06_Section_UI_Cross_Wall_Hatch.ts
+++ b/B06_Section/B06_Section_UI_Cross_Wall_Hatch.ts
@@ -16,7 +16,7 @@
* · 바자 : 세로 말뚝 3줄 + 가로 엮음 눈금.
* ========================================================================== */
-import { REVET_THICKNESS_M } from "./B06_Section_UI_Cross_Culvert_Const";
+import { REVET_THICKNESS_M } from "./logic/B06_Section_UI_Cross_Culvert_Const";
import type { OffsetPoint, WallLayout } from "./B06_Section_UI_Cross_Culvert_Types";
const SVG_NS = "http://www.w3.org/2000/svg";
diff --git a/B06_Section/B06_Section_UI_Page_Persist.ts b/B06_Section/B06_Section_UI_Page_Persist.ts
index 398fe1520..4dfbd6730 100644
--- a/B06_Section/B06_Section_UI_Page_Persist.ts
+++ b/B06_Section/B06_Section_UI_Page_Persist.ts
@@ -17,7 +17,7 @@ import {
import { invalidateSectionDetail } from "./B06_Section_Section_Store";
import { onAnySwap } from "./B06_Section_Swap_Bus";
import type { DesignViewSave } from "../A00_Common/design/design_shared";
-import { buildCrossPatches, type CrossPatchSources } from "./B06_Section_UI_Page_Patches";
+import { buildCrossPatches, type CrossPatchSources } from "./logic/B06_Section_UI_Page_Patches";
import {
clearState,
readByKey,
diff --git a/B06_Section/B06_Section_UI_Page_Pipe_Options.ts b/B06_Section/B06_Section_UI_Page_Pipe_Options.ts
index c39fc5dbc..722041cf7 100644
--- a/B06_Section/B06_Section_UI_Page_Pipe_Options.ts
+++ b/B06_Section/B06_Section_UI_Page_Pipe_Options.ts
@@ -15,7 +15,7 @@ import {
applySpanPatch,
revetWallSpec,
WALL_MIN_PURE_HEIGHT_M,
-} from "./B06_Section_UI_Cross_Culvert_Const";
+} from "./logic/B06_Section_UI_Cross_Culvert_Const";
import type { CrossSection, CulvertSet } from "./B06_Section_Api_Fetch";
import type { createStationControls } from "./B06_Section_UI_Page_Station_Controls";
diff --git a/B06_Section/B06_Section_UI_Page_Span_Control.ts b/B06_Section/B06_Section_UI_Page_Span_Control.ts
index 2a9ffb30b..83f35a97c 100644
--- a/B06_Section/B06_Section_UI_Page_Span_Control.ts
+++ b/B06_Section/B06_Section_UI_Page_Span_Control.ts
@@ -13,7 +13,7 @@ import {
type SpanValues,
type StructureSpanControl,
} from "./B06_Section_UI_Cross_Culvert_Wire";
-import * as CulvertConst from "./B06_Section_UI_Cross_Culvert_Const";
+import * as CulvertConst from "./logic/B06_Section_UI_Cross_Culvert_Const";
/** 구간값 제어가 페이지·상위 제어기에서 받아 쓰는 창구. */
export interface SpanControlDeps {
diff --git a/B06_Section/B06_Section_UI_Page_Station_Swap.ts b/B06_Section/B06_Section_UI_Page_Station_Swap.ts
index 5e8d19612..b1fc9b5ef 100644
--- a/B06_Section/B06_Section_UI_Page_Station_Swap.ts
+++ b/B06_Section/B06_Section_UI_Page_Station_Swap.ts
@@ -9,7 +9,7 @@
* ========================================================================== */
import { useDesignStore } from "../A00_Common/design/design_store";
-import type { DesignPipeline } from "../A00_Common/design/design_pipeline";
+import type { DesignPipeline } from "../A00_Common/design/logic/design_pipeline";
import { pagePipeline, pipelineDetail } from "../A00_Common/design/design_pipeline_page";
import type { SectionDetailResponse } from "./B06_Section_Api_Types";
import { onAnySwap, swapSectionStations } from "./B06_Section_Section_Store";
diff --git a/B06_Section/B06_Section_UI_Page_Structures_Panel.ts b/B06_Section/B06_Section_UI_Page_Structures_Panel.ts
index 435cc2c02..cfd085df3 100644
--- a/B06_Section/B06_Section_UI_Page_Structures_Panel.ts
+++ b/B06_Section/B06_Section_UI_Page_Structures_Panel.ts
@@ -31,7 +31,7 @@ import {
type StructureType,
} from "../B05_Profile/B05_Profile_Api_Structures";
import { readPendingPipes, writePendingPipes } from "../B05_Profile/B05_Profile_Api_Pipes_Draft";
-import { mergeFacilityOptions } from "../B05_Profile/B05_Profile_UI_Drainage_Facility_Merge";
+import { mergeFacilityOptions } from "../B05_Profile/logic/B05_Profile_UI_Drainage_Facility_Merge";
import { fordWaitsOf, waitsFordHeight } from "../B05_Profile/B05_Profile_UI_Drainage_Ford_Fill";
import { fetchDetailPipePoints } from "../B04_PreProcess/B04_PreProcess_Api_Fetch";
import {
diff --git a/B06_Section/CLAUDE.md b/B06_Section/CLAUDE.md
index 62b92b79a..195c2679c 100644
--- a/B06_Section/CLAUDE.md
+++ b/B06_Section/CLAUDE.md
@@ -12,7 +12,7 @@
① 짝(ts ↔ py · 거울 시험):
- `Engine_Design.py` ↔ `common_util_cross_design.ts` · `Engine_Areas.py` ↔ `common_util_cross_design_areas.ts` · `test_b06_cross_design_mirror.py`
-- `Engine_Culvert.py` ↔ `common_util_culvert_sets.ts` · `UI_Cross_Culvert_Const.ts` · `test_b06_culvert_sets_mirror.py` · `test_b06_pipe_wall_height_mirror.py`
+- `Engine_Culvert.py` ↔ `common_util_culvert_sets.ts` · `logic/UI_Cross_Culvert_Const.ts` · `test_b06_culvert_sets_mirror.py` · `test_b06_pipe_wall_height_mirror.py`
- `Engine_Structures_Wall.py` ↔ `common_util_structure_walls.ts` · `test_b06_structure_walls_mirror.py`
- 지형 표본 = `common_util_surface_sampler` 하나(`Engine_SampleExtend` 도)
diff --git a/B06_Section/B06_Section_Cross_Stage.ts b/B06_Section/logic/B06_Section_Cross_Stage.ts
similarity index 95%
rename from B06_Section/B06_Section_Cross_Stage.ts
rename to B06_Section/logic/B06_Section_Cross_Stage.ts
index bd5247b7f..e350e2d47 100644
--- a/B06_Section/B06_Section_Cross_Stage.ts
+++ b/B06_Section/logic/B06_Section_Cross_Stage.ts
@@ -17,9 +17,9 @@ import type {
CrossStationResult,
PipelineStation,
StageContext,
-} from "../A00_Common/design/design_pipeline_types";
-import { planElevationAt } from "../B05_Profile/B05_Profile_UI_Profile_Alignment";
-import { groundSamples } from "./logic/B06_Section_Station_Swap";
+} from "../../A00_Common/design/logic/design_pipeline_types";
+import { planElevationAt } from "../../B05_Profile/logic/B05_Profile_UI_Profile_Alignment";
+import { groundSamples } from "./B06_Section_Station_Swap";
export { groundSamples };
diff --git a/B06_Section/logic/B06_Section_Station_Swap.ts b/B06_Section/logic/B06_Section_Station_Swap.ts
index 99b79d875..f32c8be10 100644
--- a/B06_Section/logic/B06_Section_Station_Swap.ts
+++ b/B06_Section/logic/B06_Section_Station_Swap.ts
@@ -13,7 +13,7 @@
* 순수 계산(DOM · fetch · 세션 없음).
* ========================================================================== */
-import type { PipelineStation } from "../../A00_Common/design/design_pipeline_types";
+import type { PipelineStation } from "../../A00_Common/design/logic/design_pipeline_types";
import type { CrossSection, SectionDetailResponse, SectionStation } from "../B06_Section_Api_Fetch";
interface Sample {
diff --git a/B06_Section/B06_Section_UI_Cross_Berm_Info.ts b/B06_Section/logic/B06_Section_UI_Cross_Berm_Info.ts
similarity index 97%
rename from B06_Section/B06_Section_UI_Cross_Berm_Info.ts
rename to B06_Section/logic/B06_Section_UI_Cross_Berm_Info.ts
index b7fad0edf..8ceddb65f 100644
--- a/B06_Section/B06_Section_UI_Cross_Berm_Info.ts
+++ b/B06_Section/logic/B06_Section_UI_Cross_Berm_Info.ts
@@ -9,7 +9,7 @@
* 벽이 선 쪽은 뺀다 — 성토사면 경고와 같은 규칙(`wallSides`).
* ========================================================================== */
-import type { CrossSection } from "./B06_Section_Api_Fetch";
+import type { CrossSection } from "../B06_Section_Api_Fetch";
import {
wallSides,
type FillSlopeSideLength,
diff --git a/B06_Section/B06_Section_UI_Cross_Culvert_Basin.ts b/B06_Section/logic/B06_Section_UI_Cross_Culvert_Basin.ts
similarity index 99%
rename from B06_Section/B06_Section_UI_Cross_Culvert_Basin.ts
rename to B06_Section/logic/B06_Section_UI_Cross_Culvert_Basin.ts
index 3d362750a..0bf390a13 100644
--- a/B06_Section/B06_Section_UI_Cross_Culvert_Basin.ts
+++ b/B06_Section/logic/B06_Section_UI_Cross_Culvert_Basin.ts
@@ -20,7 +20,7 @@ import {
REVET_FREEBOARD_M,
REVET_LEAN_RATIO,
} from "./B06_Section_UI_Cross_Culvert_Const";
-import type { CrossDesign, CulvertSideSpec } from "./B06_Section_Api_Fetch";
+import type { CrossDesign, CulvertSideSpec } from "../B06_Section_Api_Fetch";
import {
minShoulderWallOffset,
slopeLengthAlong,
@@ -33,7 +33,7 @@ import type {
EndFace,
OffsetPoint,
InletStructureChoice,
-} from "./B06_Section_UI_Cross_Culvert_Types";
+} from "../B06_Section_UI_Cross_Culvert_Types";
import { structureCutPoints, structureCutSpec } from "./B06_Section_UI_Cross_Structure_Cut";
/** 자동(기본) 집수정 모양(54-36) — 좌측 폼 「(기본)」 표시도 이 값. */
diff --git a/B06_Section/B06_Section_UI_Cross_Culvert_Const.ts b/B06_Section/logic/B06_Section_UI_Cross_Culvert_Const.ts
similarity index 99%
rename from B06_Section/B06_Section_UI_Cross_Culvert_Const.ts
rename to B06_Section/logic/B06_Section_UI_Cross_Culvert_Const.ts
index 73a94ed11..12191aff8 100644
--- a/B06_Section/B06_Section_UI_Cross_Culvert_Const.ts
+++ b/B06_Section/logic/B06_Section_UI_Cross_Culvert_Const.ts
@@ -4,8 +4,8 @@
* 분리했다(700줄 제한). 값의 근거는 각 상수 주석에 지식DB 출처로 남긴다.
* ========================================================================== */
-import type { CrossSection, CulvertSideSpec } from "./B06_Section_Api_Fetch";
-import type { SpanRole, SpanValues } from "./B06_Section_UI_Cross_Culvert_Wire";
+import type { CrossSection, CulvertSideSpec } from "../B06_Section_Api_Fetch";
+import type { SpanRole, SpanValues } from "../B06_Section_UI_Cross_Culvert_Wire";
/** 관 위 최소 토피(m) — 프론트 정의처(백엔드는 `B06_Section_Engine_Culvert.MIN_PIPE_COVER_M`).
* ⚠ 임도 배수관 토피 규정이 지식DB에 없어 별표2 교량·암거 "복토 50㎝ 이상"을 교차
diff --git a/B06_Section/B06_Section_UI_Cross_Culvert_Solve.ts b/B06_Section/logic/B06_Section_UI_Cross_Culvert_Solve.ts
similarity index 99%
rename from B06_Section/B06_Section_UI_Cross_Culvert_Solve.ts
rename to B06_Section/logic/B06_Section_UI_Cross_Culvert_Solve.ts
index 9888d2c48..db9a03ed9 100644
--- a/B06_Section/B06_Section_UI_Cross_Culvert_Solve.ts
+++ b/B06_Section/logic/B06_Section_UI_Cross_Culvert_Solve.ts
@@ -4,7 +4,7 @@
* 자리 풀이. 본체(`_Cross_Culvert_Geom.ts`)에서 분리했다(700줄 제한).
* ========================================================================== */
-import type { SectionSample } from "./B06_Section_Api_Fetch";
+import type { SectionSample } from "../B06_Section_Api_Fetch";
import {
FILL_MIN_RISE_M,
FILL_SLOPE_MAX_LENGTH_M,
@@ -18,7 +18,7 @@ import type {
OffsetPoint,
PipeEnd,
WallAdjust,
-} from "./B06_Section_UI_Cross_Culvert_Types";
+} from "../B06_Section_UI_Cross_Culvert_Types";
/** 기슭막이 하단선 폭(m) — 사다리꼴 밑변. 자리 기준(하단선 중점) 환산에 쓴다.
* `lean` = 그 벽의 전면 기울기(표준경사 · `revetWallSpec().lean`). */
diff --git a/B06_Section/B06_Section_UI_Cross_Detail_Geom.ts b/B06_Section/logic/B06_Section_UI_Cross_Detail_Geom.ts
similarity index 99%
rename from B06_Section/B06_Section_UI_Cross_Detail_Geom.ts
rename to B06_Section/logic/B06_Section_UI_Cross_Detail_Geom.ts
index aef35f7bd..be1571f2a 100644
--- a/B06_Section/B06_Section_UI_Cross_Detail_Geom.ts
+++ b/B06_Section/logic/B06_Section_UI_Cross_Detail_Geom.ts
@@ -8,7 +8,7 @@
* 나눔(`splitAtCrossings`) · 닫힌 영역(`findFaces` · 259-2)은 화면 몫 — 서버는 저장된 조각 두 끝만 검산.
* ========================================================================== */
-import type { CrossDesign, CrossPickPiece, SectionSample } from "./B06_Section_Api_Types";
+import type { CrossDesign, CrossPickPiece, SectionSample } from "../B06_Section_Api_Types";
export type Pt = [number, number];
export type LineKind = CrossPickPiece["line"];
diff --git a/B06_Section/B06_Section_UI_Cross_FillSlope_Warn.ts b/B06_Section/logic/B06_Section_UI_Cross_FillSlope_Warn.ts
similarity index 98%
rename from B06_Section/B06_Section_UI_Cross_FillSlope_Warn.ts
rename to B06_Section/logic/B06_Section_UI_Cross_FillSlope_Warn.ts
index 30ba1c773..30a5ba4c2 100644
--- a/B06_Section/B06_Section_UI_Cross_FillSlope_Warn.ts
+++ b/B06_Section/logic/B06_Section_UI_Cross_FillSlope_Warn.ts
@@ -11,7 +11,7 @@
* 길이는 `fillSlopeLengths`(카드 머리 「성토사면」 칸과 같은 값)를 받아 쓴다 — 여기서 다시 재지 않는다.
* ========================================================================== */
-import type { CrossSection } from "./B06_Section_Api_Fetch";
+import type { CrossSection } from "../B06_Section_Api_Fetch";
import { FILL_SLOPE_MAX_LENGTH_M } from "./B06_Section_UI_Cross_Culvert_Const";
/** 브레인 승인 문구 그대로(2026-09-14) — 고치면 승인을 다시 받을 것. */
diff --git a/B06_Section/B06_Section_UI_Cross_Fit.ts b/B06_Section/logic/B06_Section_UI_Cross_Fit.ts
similarity index 99%
rename from B06_Section/B06_Section_UI_Cross_Fit.ts
rename to B06_Section/logic/B06_Section_UI_Cross_Fit.ts
index 4e9005562..305ab66ec 100644
--- a/B06_Section/B06_Section_UI_Cross_Fit.ts
+++ b/B06_Section/logic/B06_Section_UI_Cross_Fit.ts
@@ -12,7 +12,7 @@
* 기울기와 지반 기울기 차이로 만나는 자리를 추정한다.
* ========================================================================== */
-import type { CrossDesign, CrossSection } from "./B06_Section_Api_Fetch";
+import type { CrossDesign, CrossSection } from "../B06_Section_Api_Fetch";
import { designInterpolator, groundInterpolator } from "./B06_Section_UI_Cross_Culvert_Solve";
/** 설계선과 지반선이 만났다고 보는 표고 차(m). */
diff --git a/B06_Section/B06_Section_UI_Cross_Lean.ts b/B06_Section/logic/B06_Section_UI_Cross_Lean.ts
similarity index 88%
rename from B06_Section/B06_Section_UI_Cross_Lean.ts
rename to B06_Section/logic/B06_Section_UI_Cross_Lean.ts
index 5607cab81..931eeca7d 100644
--- a/B06_Section/B06_Section_UI_Cross_Lean.ts
+++ b/B06_Section/logic/B06_Section_UI_Cross_Lean.ts
@@ -9,8 +9,8 @@
* ⚠ 파일 판이 바뀌면 이 import 도 옮길 것 — 시험 `test_b06_wall_lean_table` 이 최신 판을 대조.
* ========================================================================== */
-import { type WallLeanInput, wallLeanRatio } from "../common_util/common_util_masonry_slope";
-import masonrySlope from "../resources/data_masonry/masonry_slope_2026-01-01.json";
+import { type WallLeanInput, wallLeanRatio } from "../../common_util/common_util_masonry_slope";
+import masonrySlope from "../../resources/data_masonry/masonry_slope_2026-01-01.json";
import { REVET_FORM_DEFAULT } from "./B06_Section_UI_Cross_Culvert_Const";
/** 벽 전면 기울기 n — 표를 못 고르면 종전 0.3. */
diff --git a/B06_Section/B06_Section_UI_Cross_Structure_Cut.ts b/B06_Section/logic/B06_Section_UI_Cross_Structure_Cut.ts
similarity index 94%
rename from B06_Section/B06_Section_UI_Cross_Structure_Cut.ts
rename to B06_Section/logic/B06_Section_UI_Cross_Structure_Cut.ts
index 9fdf7053e..e23394541 100644
--- a/B06_Section/B06_Section_UI_Cross_Structure_Cut.ts
+++ b/B06_Section/logic/B06_Section_UI_Cross_Structure_Cut.ts
@@ -8,10 +8,10 @@
* 쓰는 곳 = 흙막이 수평공간 뒤 · 박스 끝 · 세월교 측벽 끝 · ㄴ·ㄷ 집수정 끝 · 절토 쪽 배관 유출 벽 뒤.
* ========================================================================== */
-import { cutProfilePoints } from "../common_util/common_util_cross_berm";
-import type { BermSpec } from "../common_util/common_util_cross_berm";
-import type { CrossDesign } from "./B06_Section_Api_Fetch";
-import type { OffsetPoint } from "./B06_Section_UI_Cross_Culvert_Types";
+import { cutProfilePoints } from "../../common_util/common_util_cross_berm";
+import type { BermSpec } from "../../common_util/common_util_cross_berm";
+import type { CrossDesign } from "../B06_Section_Api_Fetch";
+import type { OffsetPoint } from "../B06_Section_UI_Cross_Culvert_Types";
/** 절토 제원 — 암(또는 단일) 경사 · 토사 경사 · 암 경계 오프셋(없으면 경사 하나) · 소단. */
export interface StructureCutSpec {
diff --git a/B06_Section/B06_Section_UI_Page_Patches.ts b/B06_Section/logic/B06_Section_UI_Page_Patches.ts
similarity index 92%
rename from B06_Section/B06_Section_UI_Page_Patches.ts
rename to B06_Section/logic/B06_Section_UI_Page_Patches.ts
index 4853d8959..bd11427e9 100644
--- a/B06_Section/B06_Section_UI_Page_Patches.ts
+++ b/B06_Section/logic/B06_Section_UI_Page_Patches.ts
@@ -7,11 +7,11 @@
* 모으기만 한다 — 판정·한계는 각 제어기가 이미 끝냈다.
* ========================================================================== */
-import type { CrossSectionPatch, StoredWallAdjust, StoredWallSpan } from "./B06_Section_Api_Fetch";
-import type { BasinAdjust } from "./B06_Section_UI_Cross_Culvert_Types";
-import type { FordAdjust } from "./B06_Section_UI_Cross_Ford";
-import type { BoxAdjust } from "./B06_Section_UI_Cross_Box";
-import type { InletStructureChoice } from "./B06_Section_UI_Cross_Culvert";
+import type { CrossSectionPatch, StoredWallAdjust, StoredWallSpan } from "../B06_Section_Api_Fetch";
+import type { BasinAdjust } from "../B06_Section_UI_Cross_Culvert_Types";
+import type { FordAdjust } from "../B06_Section_UI_Cross_Ford";
+import type { BoxAdjust } from "../B06_Section_UI_Cross_Box";
+import type { InletStructureChoice } from "../B06_Section_UI_Cross_Culvert";
export interface CrossPatchSources {
/** 암 경계선 오프셋(누가거리 문자열 키). */
diff --git a/B07_DesignDetail/B07_DesignDetail_Engine_Cross_Table_Edit.py b/B07_DesignDetail/B07_DesignDetail_Engine_Cross_Table_Edit.py
index 3cc85c50f..ea2fa7091 100644
--- a/B07_DesignDetail/B07_DesignDetail_Engine_Cross_Table_Edit.py
+++ b/B07_DesignDetail/B07_DesignDetail_Engine_Cross_Table_Edit.py
@@ -15,7 +15,7 @@
열(`columns`) = 오른쪽 끝 · 모든 행(비고 등).
짝(① 파이썬 · TS) = `B06_Section/B06_Section_UI_Cross_Detail_Table.ts` `localCellValue`
-(조작 중 즉시 표시) · 조각 길 · 넓이 = `B06_Section/B06_Section_UI_Cross_Detail_Geom.ts` ·
+(조작 중 즉시 표시) · 조각 길 · 넓이 = `B06_Section/logic/B06_Section_UI_Cross_Detail_Geom.ts` ·
거울 시험 `resources/tester/test_179_4_detail_table.py` · `test_209_1_detail_select.py`.
"""
diff --git a/B07_DesignDetail/B07_DesignDetail_Note_Options_Node.ts b/B07_DesignDetail/B07_DesignDetail_Note_Options_Node.ts
index edce66077..0c157193a 100644
--- a/B07_DesignDetail/B07_DesignDetail_Note_Options_Node.ts
+++ b/B07_DesignDetail/B07_DesignDetail_Note_Options_Node.ts
@@ -15,11 +15,11 @@
import { readFileSync, writeFileSync } from "node:fs";
import type { StructureType } from "../B05_Profile/B05_Profile_Api_Structures";
-import { structureOptionLines } from "../B05_Profile/B05_Profile_UI_Structures_Balloon";
+import { structureOptionLines } from "../B05_Profile/logic/B05_Profile_UI_Structures_Balloon";
import {
withDefinition,
type StructureDefinition,
-} from "../B05_Profile/B05_Profile_UI_Structures_Define";
+} from "../B05_Profile/logic/B05_Profile_UI_Structures_Define";
interface Input {
things?: Array<{ type_id: string; options?: Record }>;
diff --git a/M02_MasterTemplete/M02_Table_Fill_Spec.py b/M02_MasterTemplete/M02_Table_Fill_Spec.py
index 6e077e1d5..7fd8320c2 100644
--- a/M02_MasterTemplete/M02_Table_Fill_Spec.py
+++ b/M02_MasterTemplete/M02_Table_Fill_Spec.py
@@ -4,7 +4,7 @@
집계 항목 = 잇기 `group_items[{잇기}{n}]` · 복사본 `{구조물 id}__{잇기}{n}` · 옵션 = 그 컨테이너 값.
열 바인딩이 읽는 칸이 갈래마다 달라(독립 기슭막이 `form` · `length_m` … · 관 `{유입|유출}_revet_*`)
컨테이너 값을 그 칸들에 함께 얹음 — 어느 출처로 읽어도 그 컨테이너 값.
-짝: `A00_Common/design/design_structure_guard.ts` · `_road.ts` 선택 컨테이너(머리 · 잇기 · 제목) —
+짝: `A00_Common/design/logic/design_structure_guard.ts` · `_road.ts` 선택 컨테이너(머리 · 잇기 · 제목) —
시험이 대조.
기타(52-14) = 사용자가 적은 상세 종류 이름이 집계 건 이름(`그룹`) · 비면 「기타」.
배관 · 세월교 · 박스 흙막이 = 지형이 세운 유출 다단 수(`흙막이단`)까지만 — 넘친 컨테이너 값은
diff --git a/M02_MasterTemplete/StructOptions/M02_SO_Def.ts b/M02_MasterTemplete/StructOptions/M02_SO_Def.ts
index 3d6479ad2..204da47bf 100644
--- a/M02_MasterTemplete/StructOptions/M02_SO_Def.ts
+++ b/M02_MasterTemplete/StructOptions/M02_SO_Def.ts
@@ -29,7 +29,7 @@ import {
import { buildOptionsBlock } from "./M02_SO_Def_Options";
import { buildRulesBlock } from "./M02_SO_Def_Rules";
import { buildSpecBlock } from "./M02_SO_Def_Spec";
-import { specFor } from "../../A00_Common/design/design_structure_pipe";
+import { specFor } from "../../A00_Common/design/logic/design_structure_pipe";
import { catalogProblems, type CheckDef } from "./M02_SO_Def_Check";
import { buildParts } from "./M02_SO_Def_Parts";
import { differs, setReflect, tidy } from "./M02_SO_Def_Reflect";
diff --git a/M02_MasterTemplete/StructOptions/M02_SO_Def_Spec.ts b/M02_MasterTemplete/StructOptions/M02_SO_Def_Spec.ts
index 425295186..d74155e09 100644
--- a/M02_MasterTemplete/StructOptions/M02_SO_Def_Spec.ts
+++ b/M02_MasterTemplete/StructOptions/M02_SO_Def_Spec.ts
@@ -12,7 +12,10 @@
import { createTag, el } from "@ui/ui_template_elements";
import { createSpecForm } from "../../A00_Common/design/design_structure_form";
-import { specItemKeys, type StructureSpec } from "../../A00_Common/design/design_structure_spec";
+import {
+ specItemKeys,
+ type StructureSpec,
+} from "../../A00_Common/design/logic/design_structure_spec";
import { group } from "../../B05_Profile/B05_Profile_UI_Drainage_Facility_Fields";
import { field, optionControl } from "../../B05_Profile/B05_Profile_UI_Structures_Fields";
import type { StructDef, TypeDef } from "./M02_SO_Def_Model";
diff --git a/M02_MasterTemplete/StructOptions/M02_SO_Def_Spec_Model.ts b/M02_MasterTemplete/StructOptions/M02_SO_Def_Spec_Model.ts
index 52634ecbc..3178030f3 100644
--- a/M02_MasterTemplete/StructOptions/M02_SO_Def_Spec_Model.ts
+++ b/M02_MasterTemplete/StructOptions/M02_SO_Def_Spec_Model.ts
@@ -11,7 +11,7 @@
* import 는 꼴만 — 시험이 이 파일만 옮겨 돌림.
* ========================================================================== */
-import type { StructureSpec } from "../../A00_Common/design/design_structure_spec";
+import type { StructureSpec } from "../../A00_Common/design/logic/design_structure_spec";
import type { StructDef, TypeDef } from "./M02_SO_Def_Model";
export interface SpecNameRow {
diff --git a/M02_MasterTemplete/StructOptions/M02_SO_Def_Table.ts b/M02_MasterTemplete/StructOptions/M02_SO_Def_Table.ts
index c5cd176b7..8e3efb5ec 100644
--- a/M02_MasterTemplete/StructOptions/M02_SO_Def_Table.ts
+++ b/M02_MasterTemplete/StructOptions/M02_SO_Def_Table.ts
@@ -9,7 +9,7 @@
import { createButton, createTag, el } from "@ui/ui_template_elements";
import type { CatalogRow } from "../../common_util/common_util_structure_catalog";
import { stepFamily, stepType, type StructDef, type TypeDef } from "./M02_SO_Def_Model";
-import { REVET_FORMS } from "../../B06_Section/B06_Section_UI_Cross_Culvert_Const";
+import { REVET_FORMS } from "../../B06_Section/logic/B06_Section_UI_Cross_Culvert_Const";
import {
isSet,
OWNER_KO,
diff --git a/resources/master_data/ref/_걷을_옛코드.md b/resources/master_data/ref/_걷을_옛코드.md
index 5095131fa..740fbc127 100644
--- a/resources/master_data/ref/_걷을_옛코드.md
+++ b/resources/master_data/ref/_걷을_옛코드.md
@@ -65,7 +65,7 @@
| common_util/common_util_work_item_key.py | old/ 열쇠대장 | B08 Handoff · B09 BillOfQuantities_Input · 시험 2 | 없음 — 필요: 공종별 고유키 체계 새 마스터(열쇠대장 대응) |
| common_util/common_util_work_item_link.py | old/ 연결 | B09 BillOfQuantities · _Input · test_work_item_link_choice | 없음 — 필요: 공종 마스터·연결표 새 마스터 |
| B05_Profile/B05_Profile_UI_Drainage_Facility_Fields.ts | ref/수량_사방기슭막이치수 (import) | B05 화면 | B08 Engine_Pipe.py 와 같음 — 필요: 사방기술교본 치수표 새 마스터 |
-| B06_Section/B06_Section_UI_Cross_Lean.ts | old/3_품셈_산림_돌쌓기경사 (import) | B06 화면 | 계수_산림품셈_13장_구조물.json(StoneSpec.py 와 같음) |
+| B06_Section/logic/B06_Section_UI_Cross_Lean.ts | old/3_품셈_산림_돌쌓기경사 (import) | B06 화면 | 계수_산림품셈_13장_구조물.json(StoneSpec.py 와 같음) |
## 바꿈 — 시험
diff --git a/resources/tester/helper_108_drag_box_hit.cjs b/resources/tester/helper_108_drag_box_hit.cjs
index 1ab75d93f..f513ccd12 100644
--- a/resources/tester/helper_108_drag_box_hit.cjs
+++ b/resources/tester/helper_108_drag_box_hit.cjs
@@ -111,7 +111,7 @@ const { buildStructurePanel } = loadTs(B06("B06_Section_UI_Cross_Structure_Panel
const { buildBoxPanel } = loadTs(B06("B06_Section_UI_Cross_Box_Panel"));
const { buildFordPanel } = loadTs(B06("B06_Section_UI_Cross_Ford_Panel"));
const { structurePanelDeps } = loadTs(B06("B06_Section_UI_Cross_View_Structure"));
-const { placePipeWall } = loadTs(B06("B06_Section_UI_Cross_Culvert_Solve"));
+const { placePipeWall } = loadTs(B06("logic/B06_Section_UI_Cross_Culvert_Solve"));
const { boxHitBands } = loadTs(B06("B06_Section_UI_Cross_Box"));
const r3 = (v) => Math.round(v * 1000) / 1000;
diff --git a/resources/tester/helper_115_8_corridor_loft.cjs b/resources/tester/helper_115_8_corridor_loft.cjs
index c122162db..4d89e3ba9 100644
--- a/resources/tester/helper_115_8_corridor_loft.cjs
+++ b/resources/tester/helper_115_8_corridor_loft.cjs
@@ -52,11 +52,11 @@ const B05 = (name) => path.join(ROOT, "B05_Profile", `${name}.ts`);
const { buildCorridor } = loadTs(B05("B05_Profile_UI_Corridor_Build"));
const { loftTerrain } = loadTs(B05("B05_Profile_UI_Corridor_Loft"));
const { pairProfiles } = loadTs(B05("B05_Profile_UI_Corridor_Loft_Profile"));
-const { selfCrossings } = loadTs(B05("B05_Profile_UI_Corridor_Loft_Toe"));
-const { taubin } = loadTs(B05("B05_Profile_UI_Corridor_Loft_Grid"));
+const { selfCrossings } = loadTs(B05("logic/B05_Profile_UI_Corridor_Loft_Toe"));
+const { taubin } = loadTs(B05("logic/B05_Profile_UI_Corridor_Loft_Grid"));
const { TerrainBandSplit } = loadTs(B05("B05_Profile_UI_Corridor_Split"));
const { TerrainHeightIndex } = loadTs(B05("B05_Profile_UI_Corridor_Terrain"));
-const PSLG = loadTs(B05("B05_Profile_UI_Corridor_Tin_Pslg"));
+const PSLG = loadTs(B05("logic/B05_Profile_UI_Corridor_Tin_Pslg"));
const { SEAM_M } = loadTs(B05("B05_Profile_UI_Corridor_Tin"));
const HALF = 3;
diff --git a/resources/tester/helper_129_menu_equals_panel.cjs b/resources/tester/helper_129_menu_equals_panel.cjs
index aa75ceee4..98fd5df57 100644
--- a/resources/tester/helper_129_menu_equals_panel.cjs
+++ b/resources/tester/helper_129_menu_equals_panel.cjs
@@ -46,7 +46,7 @@ function loadTs(file) {
const B05 = path.join(ROOT, "B05_Profile");
const T = loadTs(path.join(B05, "B05_Profile_UI_Structures_Panel_Types.ts"));
const M = loadTs(path.join(B05, "B05_Profile_UI_Profile_Structures.ts"));
-const D = loadTs(path.join(B05, "B05_Profile_UI_Structures_Define.ts"));
+const D = loadTs(path.join(B05, "logic/B05_Profile_UI_Structures_Define.ts"));
const C = loadTs(path.join(ROOT, "common_util", "common_util_structure_catalog.ts"));
const read = (file) => JSON.parse(fs.readFileSync(file, "utf8"));
diff --git a/resources/tester/helper_135_3_chute_solid.cjs b/resources/tester/helper_135_3_chute_solid.cjs
index befdea96a..9eb750323 100644
--- a/resources/tester/helper_135_3_chute_solid.cjs
+++ b/resources/tester/helper_135_3_chute_solid.cjs
@@ -47,8 +47,8 @@ function loadTs(file) {
const B05 = (f) => path.join(ROOT, "B05_Profile", `${f}.ts`);
const B06 = (f) => path.join(ROOT, "B06_Section", `${f}.ts`);
const { buildCorridorStructures } = loadTs(B05("B05_Profile_UI_Corridor_Structures"));
-const { structureHashParts } = loadTs(B05("B05_Profile_UI_Corridor_Structures_Hash"));
-const { structureTopLoops } = loadTs(B05("B05_Profile_UI_Corridor_Tin_Design"));
+const { structureHashParts } = loadTs(B05("logic/B05_Profile_UI_Corridor_Structures_Hash"));
+const { structureTopLoops } = loadTs(B05("logic/B05_Profile_UI_Corridor_Tin_Design"));
const { chuteBandOutline, isChuteSegment } = loadTs(B06("B06_Section_UI_Cross_Wall_Hatch"));
const { computeBoxLayout } = loadTs(B06("B06_Section_UI_Cross_Box_Geom"));
const { computeFordLayout } = loadTs(B06("B06_Section_UI_Cross_Ford"));
diff --git a/resources/tester/helper_139_4_buried_outlet.cjs b/resources/tester/helper_139_4_buried_outlet.cjs
index 34a26c770..9cc617d61 100644
--- a/resources/tester/helper_139_4_buried_outlet.cjs
+++ b/resources/tester/helper_139_4_buried_outlet.cjs
@@ -46,7 +46,7 @@ const { computeStoredLayouts } = loadTs(B06("B06_Section_Structure_Layouts"));
const { computeStructureAreas } = loadTs(
path.join(ROOT, "common_util", "common_util_cross_structure_areas.ts"),
);
-const { PIPE_CONNECT_GRADE } = loadTs(B06("B06_Section_UI_Cross_Culvert_Const"));
+const { PIPE_CONNECT_GRADE } = loadTs(B06("logic/B06_Section_UI_Cross_Culvert_Const"));
const fixture = (name) =>
JSON.parse(fs.readFileSync(path.join(__dirname, "fixtures", name), "utf8")).cross_sections;
const clone = (v) => JSON.parse(JSON.stringify(v));
diff --git a/resources/tester/helper_139_6_pipe_fit.cjs b/resources/tester/helper_139_6_pipe_fit.cjs
index 9a908b470..0258b405d 100644
--- a/resources/tester/helper_139_6_pipe_fit.cjs
+++ b/resources/tester/helper_139_6_pipe_fit.cjs
@@ -40,7 +40,7 @@ const { computeCulvertLayout, REVET_EMBED_DEPTH_M } = loadTs(
path.join(ROOT, "B06_Section", "B06_Section_UI_Cross_Culvert_Geom.ts"),
);
const { cutLength } = loadTs(
- path.join(ROOT, "B06_Section", "B06_Section_UI_Cross_Culvert_Solve.ts"),
+ path.join(ROOT, "B06_Section", "logic", "B06_Section_UI_Cross_Culvert_Solve.ts"),
);
const sections = JSON.parse(
diff --git a/resources/tester/helper_165_pavement_flow.cjs b/resources/tester/helper_165_pavement_flow.cjs
index 3a82fb648..c9beb6b73 100644
--- a/resources/tester/helper_165_pavement_flow.cjs
+++ b/resources/tester/helper_165_pavement_flow.cjs
@@ -140,7 +140,9 @@ const panelModule = loadTs(
readPendingPipes: () => null,
writePendingPipes() {},
},
- "../B05_Profile/B05_Profile_UI_Drainage_Facility_Merge": { mergeFacilityOptions: (x) => x },
+ "../B05_Profile/logic/B05_Profile_UI_Drainage_Facility_Merge": {
+ mergeFacilityOptions: (x) => x,
+ },
"../B05_Profile/B05_Profile_UI_Drainage_Ford_Fill": {
fordWaitsOf: () => new Set(),
waitsFordHeight: () => false,
diff --git a/resources/tester/helper_166_1_note_options.cjs b/resources/tester/helper_166_1_note_options.cjs
index 2ac2f22df..6f2912ab2 100644
--- a/resources/tester/helper_166_1_note_options.cjs
+++ b/resources/tester/helper_166_1_note_options.cjs
@@ -29,10 +29,10 @@ function loadTs(file) {
}
const { structureOptionLines } = loadTs(
- path.join(ROOT, "B05_Profile", "B05_Profile_UI_Structures_Balloon.ts"),
+ path.join(ROOT, "B05_Profile", "logic", "B05_Profile_UI_Structures_Balloon.ts"),
);
const { withDefinition } = loadTs(
- path.join(ROOT, "B05_Profile", "B05_Profile_UI_Structures_Define.ts"),
+ path.join(ROOT, "B05_Profile", "logic", "B05_Profile_UI_Structures_Define.ts"),
);
const input = JSON.parse(fs.readFileSync(0, "utf8"));
const types = new Map(
diff --git a/resources/tester/helper_172_1_loft_wrinkle.cjs b/resources/tester/helper_172_1_loft_wrinkle.cjs
index 3f7c44d7b..236f43ef6 100644
--- a/resources/tester/helper_172_1_loft_wrinkle.cjs
+++ b/resources/tester/helper_172_1_loft_wrinkle.cjs
@@ -48,7 +48,7 @@ const { buildCorridor } = loadTs(B05("B05_Profile_UI_Corridor_Build"));
const { loftTerrain } = loadTs(B05("B05_Profile_UI_Corridor_Loft"));
const { TerrainBandSplit } = loadTs(B05("B05_Profile_UI_Corridor_Split"));
const { TerrainHeightIndex } = loadTs(B05("B05_Profile_UI_Corridor_Terrain"));
-const PSLG = loadTs(B05("B05_Profile_UI_Corridor_Tin_Pslg"));
+const PSLG = loadTs(B05("logic/B05_Profile_UI_Corridor_Tin_Pslg"));
const HALF = 3;
const ROAD_Z = 100;
diff --git a/resources/tester/helper_173_7_inlet_animal.cjs b/resources/tester/helper_173_7_inlet_animal.cjs
index f6e63557d..863ba5493 100644
--- a/resources/tester/helper_173_7_inlet_animal.cjs
+++ b/resources/tester/helper_173_7_inlet_animal.cjs
@@ -120,7 +120,9 @@ function loadTs(file) {
const { createSpecForm } = loadTs(
path.join(ROOT, "A00_Common", "design", "design_structure_form.ts"),
);
-const { PIPE_SPEC } = loadTs(path.join(ROOT, "A00_Common", "design", "design_structure_pipe.ts"));
+const { PIPE_SPEC } = loadTs(
+ path.join(ROOT, "A00_Common", "design", "logic", "design_structure_pipe.ts"),
+);
const form = createSpecForm(null, {});
// 177-2 — 체크박스 → 고르기(유 / 무) · 저장 글 "true" / "false" 그대로
diff --git a/resources/tester/helper_176_1_seam.cjs b/resources/tester/helper_176_1_seam.cjs
index 31138097d..9f364de98 100644
--- a/resources/tester/helper_176_1_seam.cjs
+++ b/resources/tester/helper_176_1_seam.cjs
@@ -48,7 +48,7 @@ const { buildCorridor } = loadTs(B05("B05_Profile_UI_Corridor_Build"));
const { loftTerrain } = loadTs(B05("B05_Profile_UI_Corridor_Loft"));
const { TerrainBandSplit } = loadTs(B05("B05_Profile_UI_Corridor_Split"));
const { TerrainHeightIndex } = loadTs(B05("B05_Profile_UI_Corridor_Terrain"));
-const PSLG = loadTs(B05("B05_Profile_UI_Corridor_Tin_Pslg"));
+const PSLG = loadTs(B05("logic/B05_Profile_UI_Corridor_Tin_Pslg"));
const { SEAM_M } = loadTs(B05("B05_Profile_UI_Corridor_Tin"));
diff --git a/resources/tester/helper_178_3_slope_tiers.cjs b/resources/tester/helper_178_3_slope_tiers.cjs
index 290e69156..869a134f0 100644
--- a/resources/tester/helper_178_3_slope_tiers.cjs
+++ b/resources/tester/helper_178_3_slope_tiers.cjs
@@ -48,9 +48,9 @@ const resolve = (base) =>
) ?? `${base}.ts`;
const design = (f) => path.join(ROOT, "A00_Common", "design", f);
-const spec = loadTs(design("design_structure_spec.ts"));
-const { ADDON_SPECS } = loadTs(design("design_structure_slope_tier.ts"));
-const { STRUCTURE_SPECS } = loadTs(design("design_structure_pipe.ts"));
+const spec = loadTs(design("logic/design_structure_spec.ts"));
+const { ADDON_SPECS } = loadTs(design("logic/design_structure_slope_tier.ts"));
+const { STRUCTURE_SPECS } = loadTs(design("logic/design_structure_pipe.ts"));
const { wallSpecsFrom } = loadTs(path.join(ROOT, "common_util", "common_util_structure_walls.ts"));
const { computeRevetmentLayout } = loadTs(
path.join(ROOT, "B06_Section", "B06_Section_UI_Cross_Revetment.ts"),
diff --git a/resources/tester/helper_209_1_detail_select.cjs b/resources/tester/helper_209_1_detail_select.cjs
index 81862f3cd..9390a94c6 100644
--- a/resources/tester/helper_209_1_detail_select.cjs
+++ b/resources/tester/helper_209_1_detail_select.cjs
@@ -33,7 +33,7 @@ function loadTs(full) {
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
return box.exports;
}
-const G = loadTs(path.join(B06, "B06_Section_UI_Cross_Detail_Geom.ts"));
+const G = loadTs(path.join(B06, "logic/B06_Section_UI_Cross_Detail_Geom.ts"));
const S = loadTs(path.join(B06, "B06_Section_UI_Cross_Detail_Select.ts"));
const T = loadTs(path.join(B06, "B06_Section_UI_Cross_Detail_Table.ts"));
diff --git a/resources/tester/helper_215_1_free_profile.cjs b/resources/tester/helper_215_1_free_profile.cjs
index 7944663cf..3c27f333b 100644
--- a/resources/tester/helper_215_1_free_profile.cjs
+++ b/resources/tester/helper_215_1_free_profile.cjs
@@ -25,8 +25,8 @@ function loadTs(file) {
return box.exports;
}
-const free = loadTs(path.join(ROOT, "A00_Common", "design", "design_profile_free.ts"));
-const align = loadTs(path.join(ROOT, "B05_Profile", "B05_Profile_UI_Profile_Alignment.ts"));
+const free = loadTs(path.join(ROOT, "A00_Common", "design", "logic", "design_profile_free.ts"));
+const align = loadTs(path.join(ROOT, "B05_Profile", "logic", "B05_Profile_UI_Profile_Alignment.ts"));
// 전체 측점 폴리라인(20m 간격 · 0~200m) — 계획고 = 지반고, 마디마다 기울기가 다르다.
const stations = Array.from({ length: 11 }, (_, i) => i * 20);
diff --git a/resources/tester/helper_219_1_arrow_owner.cjs b/resources/tester/helper_219_1_arrow_owner.cjs
index 110850bb8..a4a3c0054 100644
--- a/resources/tester/helper_219_1_arrow_owner.cjs
+++ b/resources/tester/helper_219_1_arrow_owner.cjs
@@ -33,7 +33,7 @@ globalThis.document = { addEventListener: on("document"), removeEventListener: o
// 화면 계산 · 이력 · 도구줄은 이 흠과 무관 — 쓰는 꼴만 흉내
const calls = { move: [], edits: 0 };
const STUBS = {
- "./B05_Profile_UI_Profile_Alignment": { adjustStation: () => (calls.edits++, {}) },
+ "./logic/B05_Profile_UI_Profile_Alignment": { adjustStation: () => (calls.edits++, {}) },
"./B05_Profile_UI_Profile_Edit": { HOLD_DELAY_MS: 500, HOLD_INTERVAL_MS: 100 },
"./B05_Profile_UI_Profile_History": {
createProfileHistory: () => ({
@@ -50,9 +50,9 @@ const STUBS = {
"./B05_Profile_UI_Profile_Tools": {
createProfileTools: () => ({ mode: () => "none", clear: () => undefined }),
},
- "./B05_Profile_UI_Profile_Straighten": {},
+ "./logic/B05_Profile_UI_Profile_Straighten": {},
// [자유지정](215-1) — 화면 설정(@config) 줄기를 끌고 옴 · 이 흠과 무관
- "../A00_Common/design/design_profile_free": {
+ "../A00_Common/design/logic/design_profile_free": {
createFreeDraw: () => ({ key: () => false, hint: () => "" }),
},
"../A00_Common/design/design_profile_free_view": {
diff --git a/resources/tester/helper_225_1_pipe_round.cjs b/resources/tester/helper_225_1_pipe_round.cjs
index a56c21a89..64919dca3 100644
--- a/resources/tester/helper_225_1_pipe_round.cjs
+++ b/resources/tester/helper_225_1_pipe_round.cjs
@@ -70,8 +70,8 @@ function loadTs(file) {
const B06 = (name) => loadTs(path.join(ROOT, "B06_Section", `${name}.ts`));
const { computeCulvertLayout } = B06("B06_Section_UI_Cross_Culvert_Geom");
-const { cutLength } = B06("B06_Section_UI_Cross_Culvert_Solve");
-const { pipeLengthText, pipeLengthWhole } = B06("B06_Section_UI_Cross_Culvert_Const");
+const { cutLength } = B06("logic/B06_Section_UI_Cross_Culvert_Solve");
+const { pipeLengthText, pipeLengthWhole } = B06("logic/B06_Section_UI_Cross_Culvert_Const");
const { appendPipeInfoText } = B06("B06_Section_UI_Cross_Culvert_Types");
const { structurePanelDeps } = B06("B06_Section_UI_Cross_View_Structure");
diff --git a/resources/tester/helper_231_1_pave_reload.cjs b/resources/tester/helper_231_1_pave_reload.cjs
index 836b3c577..474994deb 100644
--- a/resources/tester/helper_231_1_pave_reload.cjs
+++ b/resources/tester/helper_231_1_pave_reload.cjs
@@ -159,7 +159,9 @@ const panelModule = loadTs(
readPendingPipes: () => null,
writePendingPipes() {},
},
- "../B05_Profile/B05_Profile_UI_Drainage_Facility_Merge": { mergeFacilityOptions: (x) => x },
+ "../B05_Profile/logic/B05_Profile_UI_Drainage_Facility_Merge": {
+ mergeFacilityOptions: (x) => x,
+ },
"../B05_Profile/B05_Profile_UI_Drainage_Ford_Fill": {
fordWaitsOf: () => new Set(),
waitsFordHeight: () => false,
diff --git a/resources/tester/helper_234_1_structure_station.cjs b/resources/tester/helper_234_1_structure_station.cjs
index 74e6c98f2..f7ba635ec 100644
--- a/resources/tester/helper_234_1_structure_station.cjs
+++ b/resources/tester/helper_234_1_structure_station.cjs
@@ -80,8 +80,8 @@ out.defaultSnap = station.snapStructureStation(80.4);
// ② 좌측 폼 칸 — 친 값 80.17 → 80 · 안 고친 옛 값은 그대로
const fields = loadTs("B05_Profile/B05_Profile_UI_Structures_Fields.ts", {
- "./B05_Profile_Util_Station": loadTs("B05_Profile/B05_Profile_Util_Station.ts"),
- "../B06_Section/B06_Section_UI_Cross_Culvert_Basin": { DEFAULT_BASIN_SHAPE: {} },
+ "./logic/B05_Profile_Util_Station": loadTs("B05_Profile/logic/B05_Profile_Util_Station.ts"),
+ "../B06_Section/logic/B06_Section_UI_Cross_Culvert_Basin": { DEFAULT_BASIN_SHAPE: {} },
"../common_util/common_util_culvert_sets": { fillPipeHeights: () => {} },
"../common_util/common_util_structure_station": station,
});
@@ -159,7 +159,7 @@ Promise.resolve(
out.second = { count: snap.snapOldStations(again), toasts: [...toasts] };
// ④ 계획고 편집 따라감 — 한꺼번에 여럿 옮김(사라진 둘 · 새 둘)
- const alignment = loadTs("B05_Profile/B05_Profile_UI_Profile_Alignment.ts");
+ const alignment = loadTs("B05_Profile/logic/B05_Profile_UI_Profile_Alignment.ts");
const gone = [
{ id: "pipe-80.17", chainage_m: 80.17 },
{ id: "pipe-263.31", chainage_m: 263.31 },
diff --git a/resources/tester/helper_259_detail_region.cjs b/resources/tester/helper_259_detail_region.cjs
index a17c883c6..1ce888c3e 100644
--- a/resources/tester/helper_259_detail_region.cjs
+++ b/resources/tester/helper_259_detail_region.cjs
@@ -34,7 +34,7 @@ function loadTs(full) {
return box.exports;
}
const Z = loadTs(path.join(ROOT, "A00_Common", "b_svg_zoom_pan.ts"));
-const G = loadTs(path.join(B06, "B06_Section_UI_Cross_Detail_Geom.ts"));
+const G = loadTs(path.join(B06, "logic/B06_Section_UI_Cross_Detail_Geom.ts"));
const S = loadTs(path.join(B06, "B06_Section_UI_Cross_Detail_Select.ts"));
const T = loadTs(path.join(B06, "B06_Section_UI_Cross_Detail_Table.ts"));
diff --git a/resources/tester/helper_260_note_cad.cjs b/resources/tester/helper_260_note_cad.cjs
index 9f6f8727b..c6589721c 100644
--- a/resources/tester/helper_260_note_cad.cjs
+++ b/resources/tester/helper_260_note_cad.cjs
@@ -23,7 +23,7 @@ const STUBS = {
readPendingStructures: () => null,
},
// 좌측 패널 옵션 줄(166-1)은 test_166_1 이 진짜 명세로 봄 — 여기는 조합 줄 · 마크만
- "../B05_Profile/B05_Profile_UI_Structures_Balloon": { structureOptionLines: () => [] },
+ "../B05_Profile/logic/B05_Profile_UI_Structures_Balloon": { structureOptionLines: () => [] },
};
function loadTs(file) {
@@ -40,8 +40,8 @@ function loadTs(file) {
}
// 관 길이 정수(265-3) = 실제 `pipeLengthWhole` · 조합 참조 읽기(265-2) = 실제(둘 다 import 없음)
-STUBS["./B06_Section_UI_Cross_Culvert_Const"] = loadTs(
- path.join(ROOT, "B06_Section", "B06_Section_UI_Cross_Culvert_Const.ts"),
+STUBS["./logic/B06_Section_UI_Cross_Culvert_Const"] = loadTs(
+ path.join(ROOT, "B06_Section", "logic", "B06_Section_UI_Cross_Culvert_Const.ts"),
);
STUBS["../common_util/common_util_summary_item"] = loadTs(
path.join(ROOT, "common_util", "common_util_summary_item.ts"),
diff --git a/resources/tester/helper_261_3_detail_pick.cjs b/resources/tester/helper_261_3_detail_pick.cjs
index 5e913780e..8ef57da1e 100644
--- a/resources/tester/helper_261_3_detail_pick.cjs
+++ b/resources/tester/helper_261_3_detail_pick.cjs
@@ -34,7 +34,7 @@ function loadTs(full) {
new Function("exports", "module", "require", js)(box.exports, box, localRequire);
return box.exports;
}
-const G = loadTs(path.join(B06, "B06_Section_UI_Cross_Detail_Geom.ts"));
+const G = loadTs(path.join(B06, "logic/B06_Section_UI_Cross_Detail_Geom.ts"));
const S = loadTs(path.join(B06, "B06_Section_UI_Cross_Detail_Select.ts"));
const element = (e) => ({
diff --git a/resources/tester/helper_286_1_ford_pavement.cjs b/resources/tester/helper_286_1_ford_pavement.cjs
index 2c1e1c3be..11a4dd122 100644
--- a/resources/tester/helper_286_1_ford_pavement.cjs
+++ b/resources/tester/helper_286_1_ford_pavement.cjs
@@ -28,7 +28,7 @@ const station = loadTs(path.join(ROOT, "common_util", "common_util_structure_sta
const ford = loadTs(path.join(ROOT, "B06_Section", "B06_Section_UI_Cross_Ford_Pavement.ts"), {
"./B06_Section_UI_Cross_Wall_Hatch": loadTs(
path.join(ROOT, "B06_Section", "B06_Section_UI_Cross_Wall_Hatch.ts"),
- { "./B06_Section_UI_Cross_Culvert_Const": {} },
+ { "./logic/B06_Section_UI_Cross_Culvert_Const": {} },
),
"./B06_Section_UI_Cross_Design_Surface": { appendPavementOverlay() {} },
// 관 세션 id · 신원표(323-5) — 프로젝트 없음 = 옛 자리 이름
diff --git a/resources/tester/helper_287_ford_pavement.cjs b/resources/tester/helper_287_ford_pavement.cjs
index be81c96c4..e0c0faf0b 100644
--- a/resources/tester/helper_287_ford_pavement.cjs
+++ b/resources/tester/helper_287_ford_pavement.cjs
@@ -248,7 +248,7 @@ const out = {
// 287-3 월류 폭 → 높이 = 세월교와 같은 풀이(유량 1.2 ㎥/s · 폭 10 m) · 유량 없으면 null(손 입력)
heightByWidth: calc.fordHeightM(1.2, 10),
heightNoFlow: calc.fordHeightM(null, 10),
- paveSlopeItems: load(D("design_structure_ford_pavement.ts"))
+ paveSlopeItems: load(D("logic/design_structure_ford_pavement.ts"))
.FORD_PAVEMENT_SPEC.containers.find((c) => c.id === "slope")
.items.map((i) => i.id),
// 301-1 면적 = 늘 손 입력 — 길이 · 월류 폭을 바꾸거나 길이를 비워도 면적 그대로(물넘이 · 세월교 폼 훅)
diff --git a/resources/tester/helper_294_3_ford_extend_chute.cjs b/resources/tester/helper_294_3_ford_extend_chute.cjs
index c7ea1bf0b..d4a04dc54 100644
--- a/resources/tester/helper_294_3_ford_extend_chute.cjs
+++ b/resources/tester/helper_294_3_ford_extend_chute.cjs
@@ -64,8 +64,10 @@ const pts = (lines) =>
lines.map((l) => l.points.map((p) => [+p.offset.toFixed(4), +p.elevation.toFixed(4)]));
const dipGround = hatch.groundLine(input.dipSamples);
const fillGround = hatch.groundLine(input.fillSamples);
-const guard = load(path.join(ROOT, "A00_Common", "design", "design_structure_guard.ts"));
-const fordPave = load(path.join(ROOT, "A00_Common", "design", "design_structure_ford_pavement.ts"));
+const guard = load(path.join(ROOT, "A00_Common", "design", "logic", "design_structure_guard.ts"));
+const fordPave = load(
+ path.join(ROOT, "A00_Common", "design", "logic", "design_structure_ford_pavement.ts"),
+);
const out = {
edges: pave.fordEdges(design),
diff --git a/resources/tester/helper_295_pick_order_detail.cjs b/resources/tester/helper_295_pick_order_detail.cjs
index f380f8e9f..64f1f61f6 100644
--- a/resources/tester/helper_295_pick_order_detail.cjs
+++ b/resources/tester/helper_295_pick_order_detail.cjs
@@ -34,7 +34,7 @@ function loadTs(full) {
return box.exports;
}
const P = loadTs(path.join(B06, "B06_Section_UI_Cross_Pick_Order.ts"));
-const G = loadTs(path.join(B06, "B06_Section_UI_Cross_Detail_Geom.ts"));
+const G = loadTs(path.join(B06, "logic/B06_Section_UI_Cross_Detail_Geom.ts"));
const S = loadTs(path.join(B06, "B06_Section_UI_Cross_Detail_Select.ts"));
const H = loadTs(path.join(B06, "B06_Section_UI_Cross_Detail_Home.ts"));
const out = {};
diff --git a/resources/tester/helper_319_kind_swap.cjs b/resources/tester/helper_319_kind_swap.cjs
index 6eb4ee982..9ccbf496e 100644
--- a/resources/tester/helper_319_kind_swap.cjs
+++ b/resources/tester/helper_319_kind_swap.cjs
@@ -94,7 +94,7 @@ const part1 = (async () => {
path.join(ROOT, "common_util", "common_util_summary_item.ts"),
],
{
- "./B05_Profile_UI_Structures_Define": { asRoad: (record) => record },
+ "./logic/B05_Profile_UI_Structures_Define": { asRoad: (record) => record },
"@ui/ui_template_elements": {
showConfirmDialog: async () => true,
showToast: (text, kind) => toasts.push([text, kind ?? null]),
diff --git a/resources/tester/helper_322_2_check.cjs b/resources/tester/helper_322_2_check.cjs
index faf8f8b8a..5d2b7c70f 100644
--- a/resources/tester/helper_322_2_check.cjs
+++ b/resources/tester/helper_322_2_check.cjs
@@ -36,9 +36,9 @@ function load(file) {
const SO = (name) => path.join(ROOT, "M02_MasterTemplete", "StructOptions", `${name}.ts`);
const check = load(SO("M02_SO_Def_Check"));
const reflect = load(SO("M02_SO_Def_Reflect"));
-const spec = load(path.join(ROOT, "A00_Common", "design", "design_structure_spec.ts"));
+const spec = load(path.join(ROOT, "A00_Common", "design", "logic", "design_structure_spec.ts"));
const { STRUCTURE_SPECS } = load(
- path.join(ROOT, "A00_Common", "design", "design_structure_pipe.ts"),
+ path.join(ROOT, "A00_Common", "design", "logic", "design_structure_pipe.ts"),
);
const input = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
const clone = (v) => JSON.parse(JSON.stringify(v));
diff --git a/resources/tester/helper_323_4_attach.cjs b/resources/tester/helper_323_4_attach.cjs
index c476f931d..26de1bdb1 100644
--- a/resources/tester/helper_323_4_attach.cjs
+++ b/resources/tester/helper_323_4_attach.cjs
@@ -36,7 +36,9 @@ function load(file) {
const input = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
const catalog = load(path.join(ROOT, "common_util", "common_util_structure_catalog.ts"));
const attach = load(path.join(ROOT, "common_util", "common_util_structure_attach.ts"));
-const hash = load(path.join(ROOT, "B05_Profile", "B05_Profile_UI_Corridor_Structures_Hash.ts"));
+const hash = load(
+ path.join(ROOT, "B05_Profile", "logic", "B05_Profile_UI_Corridor_Structures_Hash.ts"),
+);
catalog.useCatalogDefinition({ types: input.types, ...input.definition });
const out = { cases: {} };
diff --git a/resources/tester/helper_323_7_new_type.cjs b/resources/tester/helper_323_7_new_type.cjs
index 6ad52de98..9395dceff 100644
--- a/resources/tester/helper_323_7_new_type.cjs
+++ b/resources/tester/helper_323_7_new_type.cjs
@@ -45,7 +45,9 @@ const catalog = load(C("common_util_structure_catalog"));
const station = load(C("common_util_structure_station"));
const attach = load(C("common_util_structure_attach"));
const walls = load(C("common_util_structure_walls"));
-const pipeSpecs = load(path.join(ROOT, "A00_Common", "design", "design_structure_pipe.ts"));
+const pipeSpecs = load(
+ path.join(ROOT, "A00_Common", "design", "logic", "design_structure_pipe.ts"),
+);
const check = load(M("M02_SO_Def_Check"));
const out = {};
diff --git a/resources/tester/helper_323_9_twin_cards_3d.cjs b/resources/tester/helper_323_9_twin_cards_3d.cjs
index 437064ae8..472538640 100644
--- a/resources/tester/helper_323_9_twin_cards_3d.cjs
+++ b/resources/tester/helper_323_9_twin_cards_3d.cjs
@@ -73,7 +73,9 @@ const kinds = (sections) =>
buildCorridorStructures(sections, frameAtOf(sections))
.map((s) => `${s.kind}:${s.key ?? ""}:${s.chainage_m.toFixed(2)}`)
.sort();
-const pick = loadTs(path.join(ROOT, "B05_Profile", "B05_Profile_UI_Corridor_Structures_Pick.ts"));
+const pick = loadTs(
+ path.join(ROOT, "B05_Profile", "logic", "B05_Profile_UI_Corridor_Structures_Pick.ts"),
+);
const own = pick.ownsBody;
/** 노선 끝 꼴 — 같은 시설을 그리는 카드가 소수 차(EP 1078 · 1078.010813)로 하나 더. */
const ep = (one) => Object.assign(clone(one), { chainage_m: one.chainage_m + 0.010813 });
diff --git a/resources/tester/helper_342_1_entry.ts b/resources/tester/helper_342_1_entry.ts
index c1a660fff..8a0cdb813 100644
--- a/resources/tester/helper_342_1_entry.ts
+++ b/resources/tester/helper_342_1_entry.ts
@@ -15,8 +15,8 @@ export {
buildAlignment,
emptyEdits,
toAlignmentBase,
-} from "../../B05_Profile/B05_Profile_UI_Profile_Alignment";
-export { toDesignProfile } from "../../B05_Profile/B05_Profile_UI_Profile_Data";
+} from "../../B05_Profile/logic/B05_Profile_UI_Profile_Alignment";
+export { toDesignProfile } from "../../B05_Profile/logic/B05_Profile_UI_Profile_Data";
export { followMovedNodes, oneStationList } from "../../common_util/common_util_structure_station";
export {
irregularGraphStations,
diff --git a/resources/tester/helper_344_2_route_pairs.cjs b/resources/tester/helper_344_2_route_pairs.cjs
index c4ecc0124..b00f2b115 100644
--- a/resources/tester/helper_344_2_route_pairs.cjs
+++ b/resources/tester/helper_344_2_route_pairs.cjs
@@ -20,12 +20,12 @@ function loadTs(file, stubs = {}) {
return box.exports;
}
-const alignment = loadTs("B05_Profile/B05_Profile_UI_Profile_Alignment.ts");
+const alignment = loadTs("B05_Profile/logic/B05_Profile_UI_Profile_Alignment.ts");
const ground = loadTs("B05_Profile/logic/B05_Profile_Grade_Ground.ts", {
- "../B05_Profile_UI_Profile_Alignment": alignment,
+ "./B05_Profile_UI_Profile_Alignment": alignment,
});
const carry = loadTs("B05_Profile/logic/B05_Profile_Grade_Carry.ts", {
- "../B05_Profile_UI_Profile_Alignment": alignment,
+ "./B05_Profile_UI_Profile_Alignment": alignment,
});
const catalog = require("./helper_322_catalog_module.cjs");
const station = loadTs("common_util/common_util_structure_station.ts", {
diff --git a/resources/tester/helper_344_3_entry.ts b/resources/tester/helper_344_3_entry.ts
index b45c2a570..6368371f3 100644
--- a/resources/tester/helper_344_3_entry.ts
+++ b/resources/tester/helper_344_3_entry.ts
@@ -19,8 +19,11 @@ export {
createRockBoundaryStore,
readRockBoundarySession,
} from "../../B06_Section/B06_Section_UI_Page_Persist";
-export { createCrossStage, groundSamples } from "../../B06_Section/B06_Section_Cross_Stage";
+export { createCrossStage, groundSamples } from "../../B06_Section/logic/B06_Section_Cross_Stage";
export { createMassHaulStage } from "../../B05_Profile/logic/B05_Profile_MassHaul_Stage";
export { createHaulStage } from "../../B05_Profile/B05_Profile_Api_HaulPlan";
-export { buildAlignment, emptyEdits } from "../../B05_Profile/B05_Profile_UI_Profile_Alignment";
+export {
+ buildAlignment,
+ emptyEdits,
+} from "../../B05_Profile/logic/B05_Profile_UI_Profile_Alignment";
export { readState, stateKey, writeState } from "../../A00_Common/b_page_state";
diff --git a/resources/tester/helper_344_3_pipeline_stations.cjs b/resources/tester/helper_344_3_pipeline_stations.cjs
index 7bdacd20d..602e7a910 100644
--- a/resources/tester/helper_344_3_pipeline_stations.cjs
+++ b/resources/tester/helper_344_3_pipeline_stations.cjs
@@ -1,5 +1,5 @@
/* PLAN 344-3 · 346-1 측점 한 벌 거울 헬퍼 — 진짜 `B05_Profile/logic/B05_Profile_Sections_Stations.ts` ·
- * `A00_Common/design/design_pipeline_stations.ts`(단계 · 범위 밖 재사용)를 그 자리에서 트랜스파일해 Node 로 돌림.
+ * `A00_Common/design/logic/design_pipeline_stations.ts`(단계 · 범위 밖 재사용)를 그 자리에서 트랜스파일해 Node 로 돌림.
* 입력 argv[2] JSON(파이썬과 같은 노선 · 곡선표 · 관 · 구조물) · 표준출력 JSON 한 벌.
* 짝 = `test_344_3_pipeline_stations_mirror.py`. */
const fs = require("fs");
@@ -26,7 +26,9 @@ function loadTs(full) {
}
const logic = loadTs(path.join(ROOT, "B05_Profile", "logic", "B05_Profile_Sections_Stations.ts"));
-const stage = loadTs(path.join(ROOT, "A00_Common", "design", "design_pipeline_stations.ts"));
+const stage = loadTs(
+ path.join(ROOT, "A00_Common", "design", "logic", "design_pipeline_stations.ts"),
+);
const job = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
const out = {
diff --git a/resources/tester/helper_344_4_design_pipeline.cjs b/resources/tester/helper_344_4_design_pipeline.cjs
index 368fba33c..1550ac8b2 100644
--- a/resources/tester/helper_344_4_design_pipeline.cjs
+++ b/resources/tester/helper_344_4_design_pipeline.cjs
@@ -1,4 +1,4 @@
-/* PLAN 344-4 단위검증 헬퍼 — 계산 묶음(`A00_Common/design/design_pipeline.ts`) · 가게 칸
+/* PLAN 344-4 단위검증 헬퍼 — 계산 묶음(`A00_Common/design/logic/design_pipeline.ts`) · 가게 칸
* (`design_store.ts`) · 등록표(`b_page_state.ts`)를 그 자리에서 트랜스파일해 Node 로 돌림.
* 단계 함수는 가짜 — 부른 수 · 받은 범위 · 차례 번호만 적음. 결과 = 표준출력 JSON 한 벌.
* 짝 = `test_344_4_design_pipeline.py`. */
@@ -43,7 +43,7 @@ function loadTs(file) {
}
const DESIGN = path.join(ROOT, "A00_Common", "design");
-const pipeMod = loadTs(path.join(DESIGN, "design_pipeline.ts"));
+const pipeMod = loadTs(path.join(DESIGN, "logic/design_pipeline.ts"));
const storeMod = loadTs(path.join(DESIGN, "design_store.ts"));
const page = loadTs(path.join(ROOT, "A00_Common", "b_page_state.ts"));
diff --git a/resources/tester/helper_346_1_pipeline_page.cjs b/resources/tester/helper_346_1_pipeline_page.cjs
index 2c1b7cb3f..9fb09f6a0 100644
--- a/resources/tester/helper_346_1_pipeline_page.cjs
+++ b/resources/tester/helper_346_1_pipeline_page.cjs
@@ -76,14 +76,14 @@ STUBS["B04_PreProcess_Api_Fetch"] = { fetchDetailPipePoints: async () => ({ pipe
STUBS["B06_Section_UI_Standard_Panel"] = { effectiveStandardCross: () => null };
STUBS["B05_Profile_Api_HaulPlan"] = { createHaulStage: () => async () => null };
-const pipeMod = load("A00_Common", "design", "design_pipeline.ts");
+const pipeMod = load("A00_Common", "design", "logic", "design_pipeline.ts");
const pageMod = load("A00_Common", "design", "design_pipeline_page.ts");
-const stationsMod = load("A00_Common", "design", "design_pipeline_stations.ts");
+const stationsMod = load("A00_Common", "design", "logic", "design_pipeline_stations.ts");
const routeGround = load("B05_Profile", "logic", "B05_Profile_Pipeline_RouteGround.ts");
const grade = load("B05_Profile", "logic", "B05_Profile_Pipeline_Grade.ts");
const gradeGround = load("B05_Profile", "logic", "B05_Profile_Grade_Ground.ts");
const footprint = load("B05_Profile", "logic", "B05_Profile_Footprint_Stage.ts");
-const alignment = load("B05_Profile", "B05_Profile_UI_Profile_Alignment.ts");
+const alignment = load("B05_Profile", "logic", "B05_Profile_UI_Profile_Alignment.ts");
const draftLink = load("B05_Profile", "B05_Profile_UI_RouteEdit_Draft.ts");
const page = load("A00_Common", "b_page_state.ts");
diff --git a/resources/tester/helper_346_2_draft_cross_pills.cjs b/resources/tester/helper_346_2_draft_cross_pills.cjs
index b97df81d6..c51153bc2 100644
--- a/resources/tester/helper_346_2_draft_cross_pills.cjs
+++ b/resources/tester/helper_346_2_draft_cross_pills.cjs
@@ -86,7 +86,7 @@ function loadTs(full) {
}
const load = (...parts) => loadTs(path.join(ROOT, ...parts));
-const pipeMod = load("A00_Common", "design", "design_pipeline.ts");
+const pipeMod = load("A00_Common", "design", "logic", "design_pipeline.ts");
const storeMod = load("A00_Common", "design", "design_store.ts");
const swap = load("B06_Section", "B06_Section_UI_Page_Station_Swap.ts");
const marks = load("B05_Profile", "B05_Profile_UI_Structures_Marks.ts");
diff --git a/resources/tester/helper_346_2_pipeline_cross_page.cjs b/resources/tester/helper_346_2_pipeline_cross_page.cjs
index d033971c5..0c5bc551e 100644
--- a/resources/tester/helper_346_2_pipeline_cross_page.cjs
+++ b/resources/tester/helper_346_2_pipeline_cross_page.cjs
@@ -100,14 +100,14 @@ STUBS["B04_PreProcess_Api_Fetch"] = {
};
STUBS["B06_Section_UI_Standard_Panel"] = { effectiveStandardCross: () => job.standard };
-const pipeMod = load("A00_Common", "design", "design_pipeline.ts");
+const pipeMod = load("A00_Common", "design", "logic", "design_pipeline.ts");
const pageMod = load("A00_Common", "design", "design_pipeline_page.ts");
-const stationsMod = load("A00_Common", "design", "design_pipeline_stations.ts");
+const stationsMod = load("A00_Common", "design", "logic", "design_pipeline_stations.ts");
const routeGround = load("B05_Profile", "logic", "B05_Profile_Pipeline_RouteGround.ts");
const grade = load("B05_Profile", "logic", "B05_Profile_Pipeline_Grade.ts");
const gradeGround = load("B05_Profile", "logic", "B05_Profile_Grade_Ground.ts");
const detailMod = load("B05_Profile", "logic", "B05_Profile_Pipeline_Detail.ts");
-const alignment = load("B05_Profile", "B05_Profile_UI_Profile_Alignment.ts");
+const alignment = load("B05_Profile", "logic", "B05_Profile_UI_Profile_Alignment.ts");
const editMod = load("B05_Profile", "B05_Profile_UI_Profile_Edit.ts");
const page = load("A00_Common", "b_page_state.ts");
diff --git a/resources/tester/helper_52_4_ford.cjs b/resources/tester/helper_52_4_ford.cjs
index b11d13b4c..b0430973d 100644
--- a/resources/tester/helper_52_4_ford.cjs
+++ b/resources/tester/helper_52_4_ford.cjs
@@ -28,8 +28,8 @@ const load = (file) => {
return box.exports;
};
const D = (f) => path.join(ROOT, "A00_Common", "design", f);
-const s = load(D("design_structure_spec.ts"));
-const { FORD_SPEC, withLegacyGuards } = load(D("design_structure_ford.ts"));
+const s = load(D("logic/design_structure_spec.ts"));
+const { FORD_SPEC, withLegacyGuards } = load(D("logic/design_structure_ford.ts"));
const calc = load(D("design_structure_ford_calc.ts"));
if (process.argv[2] === "names") {
diff --git a/resources/tester/helper_52_structure_spec.cjs b/resources/tester/helper_52_structure_spec.cjs
index eda160d00..87f6eebfd 100644
--- a/resources/tester/helper_52_structure_spec.cjs
+++ b/resources/tester/helper_52_structure_spec.cjs
@@ -17,9 +17,9 @@ const load = (file, deps = {}) => {
new Function("exports", "module", "require", js)(box.exports, box, (m) => deps[m] ?? near(m));
return box.exports;
};
-const s = load("design_structure_spec.ts");
-const road = load("design_structure_road.ts");
-const { PIPE_SPEC, STRUCTURE_SPECS } = load("design_structure_pipe.ts", {
+const s = load("logic/design_structure_spec.ts");
+const road = load("logic/design_structure_road.ts");
+const { PIPE_SPEC, STRUCTURE_SPECS } = load("logic/design_structure_pipe.ts", {
"./design_structure_road": road,
});
diff --git a/resources/tester/helper_52_structure_spec_box.cjs b/resources/tester/helper_52_structure_spec_box.cjs
index e8b2494e3..88390696b 100644
--- a/resources/tester/helper_52_structure_spec_box.cjs
+++ b/resources/tester/helper_52_structure_spec_box.cjs
@@ -14,12 +14,15 @@ const load = (file) => {
}).outputText;
const box = { exports: {} };
// 같은 폴더 명세(흙막이 양식 · 65-2)는 그 자리에서 옮김
- const near = (m) => (m.startsWith("./") ? load(`${m.slice(2)}.ts`) : require(m));
+ const near = (m) =>
+ m.startsWith("./")
+ ? load(path.posix.join(path.posix.dirname(file), `${m.slice(2)}.ts`))
+ : require(m);
new Function("exports", "module", "require", js)(box.exports, box, near);
return box.exports;
};
-const s = load("design_structure_spec.ts");
-const b = load("design_structure_box.ts");
+const s = load("logic/design_structure_spec.ts");
+const b = load("logic/design_structure_box.ts");
const SPEC = b.BOX_SPEC;
if (process.argv[2] === "names") {
diff --git a/resources/tester/helper_54_10_soil_tiers.cjs b/resources/tester/helper_54_10_soil_tiers.cjs
index 536bc2821..b75a8794b 100644
--- a/resources/tester/helper_54_10_soil_tiers.cjs
+++ b/resources/tester/helper_54_10_soil_tiers.cjs
@@ -195,7 +195,9 @@ out.hidden = updates.splice(0);
const { createSpecForm } = loadTs(
path.join(ROOT, "A00_Common", "design", "design_structure_form.ts"),
);
-const { PIPE_SPEC } = loadTs(path.join(ROOT, "A00_Common", "design", "design_structure_pipe.ts"));
+const { PIPE_SPEC } = loadTs(
+ path.join(ROOT, "A00_Common", "design", "logic", "design_structure_pipe.ts"),
+);
let count = 1;
const form = createSpecForm(null, { count: (c) => (c.id === "soil_add" ? count : undefined) });
form.write(PIPE_SPEC, {
diff --git a/resources/tester/helper_54_14_balloon_lines.cjs b/resources/tester/helper_54_14_balloon_lines.cjs
index ba749b1c2..ac8c8d76f 100644
--- a/resources/tester/helper_54_14_balloon_lines.cjs
+++ b/resources/tester/helper_54_14_balloon_lines.cjs
@@ -30,7 +30,7 @@ function loadTs(file) {
}
const { balloonLines } = loadTs(
- path.join(ROOT, "B05_Profile", "B05_Profile_UI_Structures_Balloon.ts"),
+ path.join(ROOT, "B05_Profile", "logic", "B05_Profile_UI_Structures_Balloon.ts"),
);
const opt = (key, label, extra = {}) => ({ key, label, default: null, unit: null, ...extra });
diff --git a/resources/tester/helper_65_ford_box.cjs b/resources/tester/helper_65_ford_box.cjs
index 4f80f6494..cacd5837e 100644
--- a/resources/tester/helper_65_ford_box.cjs
+++ b/resources/tester/helper_65_ford_box.cjs
@@ -24,10 +24,10 @@ const load = (file) => {
return box.exports;
};
const D = (f) => path.join(ROOT, "A00_Common", "design", f);
-const s = load(D("design_structure_spec.ts"));
-const { FORD_SPEC, withLegacyGuards } = load(D("design_structure_ford.ts"));
-const { BOX_SPEC } = load(D("design_structure_box.ts"));
-const { FORD_PAVEMENT_SPEC } = load(D("design_structure_ford_pavement.ts"));
+const s = load(D("logic/design_structure_spec.ts"));
+const { FORD_SPEC, withLegacyGuards } = load(D("logic/design_structure_ford.ts"));
+const { BOX_SPEC } = load(D("logic/design_structure_box.ts"));
+const { FORD_PAVEMENT_SPEC } = load(D("logic/design_structure_ford_pavement.ts"));
const calc = load(D("design_structure_ford_calc.ts"));
/** 상자마다 칸 id · 갈래(구조 값 → 저장 키) — 칸 목록 대조용. */
diff --git a/resources/tester/helper_87_widening.cjs b/resources/tester/helper_87_widening.cjs
index 5f7a53262..8e5c17d01 100644
--- a/resources/tester/helper_87_widening.cjs
+++ b/resources/tester/helper_87_widening.cjs
@@ -9,7 +9,7 @@ const file = path.join(
"..",
"A00_Common",
"design",
- "design_structure_widening.ts",
+ "logic/design_structure_widening.ts",
);
const js = ts.transpileModule(fs.readFileSync(file, "utf8"), {
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
diff --git a/resources/tester/helper_91_ground_free.cjs b/resources/tester/helper_91_ground_free.cjs
index 4b34502db..b2e5208f2 100644
--- a/resources/tester/helper_91_ground_free.cjs
+++ b/resources/tester/helper_91_ground_free.cjs
@@ -122,13 +122,13 @@ function tiers(dz) {
out.tiers = [tiers(0), tiers(0.5), tiers(-0.5)];
// ⑤ 91-3 전면 기울기 — 단면유형(원지반 자동판정)과 무관 · 성토/절토 칸만
-const { leanOf } = loadTs(B06("B06_Section_UI_Cross_Lean.ts"));
+const { leanOf } = loadTs(B06("logic/B06_Section_UI_Cross_Lean.ts"));
out.lean = ["left_cut", "right_cut", "both_fill", "both_cut"].map((mode) => [
leanOf({ form: "돌쌓기(찰)", height_m: 1.5, section_mode: mode, side: "좌" }),
leanOf({ form: "돌쌓기(찰)", height_m: 1.5, section_mode: mode, side: "좌", face_role: "절토" }),
]);
// ③ 91-4 유출측 절토 복합경사 — 꼭짓점 사이 경사(수평/수직) · 사면 길이 · 끝 = 원지반 교점
-const { groundInterpolator } = loadTs(B06("B06_Section_UI_Cross_Culvert_Solve.ts"));
+const { groundInterpolator } = loadTs(B06("logic/B06_Section_UI_Cross_Culvert_Solve.ts"));
function profile(points, samples) {
const groundAt = groundInterpolator(samples);
const legs = points.slice(1).map((p, i) => {
diff --git a/resources/tester/helper_b05_curve_radius_floor.cjs b/resources/tester/helper_b05_curve_radius_floor.cjs
index 056a86309..c97d8812a 100644
--- a/resources/tester/helper_b05_curve_radius_floor.cjs
+++ b/resources/tester/helper_b05_curve_radius_floor.cjs
@@ -29,7 +29,7 @@ function loadTs(file) {
return box.exports;
}
-const edits = loadTs(path.join(ROOT, "B05_Profile", "B05_Profile_UI_RouteEdit_Edits.ts"));
+const edits = loadTs(path.join(ROOT, "B05_Profile", "logic", "B05_Profile_UI_RouteEdit_Edits.ts"));
const { applyCurveLimits, curveShortfalls, radiusFloorM } = edits;
const LIMIT_R = 12;
diff --git a/resources/tester/helper_b05_routeedit_initial_apply.cjs b/resources/tester/helper_b05_routeedit_initial_apply.cjs
index a1372bef2..83245679a 100644
--- a/resources/tester/helper_b05_routeedit_initial_apply.cjs
+++ b/resources/tester/helper_b05_routeedit_initial_apply.cjs
@@ -52,7 +52,7 @@ function loadTs(file) {
}
const model = loadTs(path.join(ROOT, "B05_Profile", "B05_Profile_UI_RouteEdit_Initial_Model.ts"));
-const edits = loadTs(path.join(ROOT, "B05_Profile", "B05_Profile_UI_RouteEdit_Edits.ts"));
+const edits = loadTs(path.join(ROOT, "B05_Profile", "logic", "B05_Profile_UI_RouteEdit_Edits.ts"));
const { jobs } = JSON.parse(fs.readFileSync(0, "utf8"));
const out = jobs.map((job) => {
diff --git a/resources/tester/helper_b05_routeedit_pick.cjs b/resources/tester/helper_b05_routeedit_pick.cjs
index 0f9353af9..35bf9b5d3 100644
--- a/resources/tester/helper_b05_routeedit_pick.cjs
+++ b/resources/tester/helper_b05_routeedit_pick.cjs
@@ -34,7 +34,7 @@ function loadTs(file) {
}
const input = loadTs(path.join(ROOT, "B05_Profile", "B05_Profile_UI_RouteEdit_Input.ts"));
-const curve = loadTs(path.join(ROOT, "B05_Profile", "B05_Profile_UI_RouteEdit_Curve.ts"));
+const curve = loadTs(path.join(ROOT, "B05_Profile", "logic", "B05_Profile_UI_RouteEdit_Curve.ts"));
const overlays = loadTs(path.join(ROOT, "B04_PreProcess", "B04_PreProcess_UI_MapOverlays.ts"));
// 화면 = 사업지 m × 2, y 뒤집음(실제 `metricToScreen` 처럼 y 가 화면에서 뒤집힌다).
diff --git a/resources/tester/helper_b05_routeedit_view.cjs b/resources/tester/helper_b05_routeedit_view.cjs
index 65087b7a1..8bfa65999 100644
--- a/resources/tester/helper_b05_routeedit_view.cjs
+++ b/resources/tester/helper_b05_routeedit_view.cjs
@@ -51,7 +51,7 @@ function loadTs(file) {
const viewMod = loadTs(path.join(ROOT, "B05_Profile", "B05_Profile_UI_RouteEdit_View.ts"));
const render = loadTs(path.join(ROOT, "B04_PreProcess", "B04_PreProcess_UI_MapRender.ts"));
-const edits = loadTs(path.join(ROOT, "B05_Profile", "B05_Profile_UI_RouteEdit_Edits.ts"));
+const edits = loadTs(path.join(ROOT, "B05_Profile", "logic", "B05_Profile_UI_RouteEdit_Edits.ts"));
// 도엽 한 장 — 1200m × 900m 사업지 좌표.
const meta = {
diff --git a/resources/tester/helper_b05_structures_define.cjs b/resources/tester/helper_b05_structures_define.cjs
index c4249162b..c9c102dc7 100644
--- a/resources/tester/helper_b05_structures_define.cjs
+++ b/resources/tester/helper_b05_structures_define.cjs
@@ -8,7 +8,7 @@ const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "t
const ROOT = path.join(__dirname, "..", "..");
const src = fs.readFileSync(
- path.join(ROOT, "B05_Profile", "B05_Profile_UI_Structures_Define.ts"),
+ path.join(ROOT, "B05_Profile", "logic", "B05_Profile_UI_Structures_Define.ts"),
"utf8",
);
const js = ts.transpileModule(src, {
diff --git a/resources/tester/helper_b05_structures_form_summary.cjs b/resources/tester/helper_b05_structures_form_summary.cjs
index 3e5bc6e52..1cd5f9cda 100644
--- a/resources/tester/helper_b05_structures_form_summary.cjs
+++ b/resources/tester/helper_b05_structures_form_summary.cjs
@@ -146,8 +146,8 @@ function loadTs(file) {
const B05 = (name) => loadTs(path.join(ROOT, "B05_Profile", `${name}.ts`));
const item = loadTs(path.join(ROOT, "common_util", "common_util_summary_item.ts"));
-const logic = B05("B05_Profile_UI_Structures_Summary");
-const merge = B05("B05_Profile_UI_Drainage_Facility_Merge");
+const logic = B05("logic/B05_Profile_UI_Structures_Summary");
+const merge = B05("logic/B05_Profile_UI_Drainage_Facility_Merge");
const { buildSummaryRow } = B05("B05_Profile_UI_Structures_Summary_Row");
const { renderStructureList } = B05("B05_Profile_UI_Structures_List");
const { renderOptionFields } = B05("B05_Profile_UI_Structures_Panel_Options");
diff --git a/resources/tester/helper_m02_so_def_spec.cjs b/resources/tester/helper_m02_so_def_spec.cjs
index a3c167ce4..d1fe96643 100644
--- a/resources/tester/helper_m02_so_def_spec.cjs
+++ b/resources/tester/helper_m02_so_def_spec.cjs
@@ -26,7 +26,7 @@ const load = (...parts) => {
return box.exports;
};
const m = load("M02_MasterTemplete", "StructOptions", "M02_SO_Def_Spec_Model.ts");
-const { PIPE_SPEC } = load("A00_Common", "design", "design_structure_pipe.ts");
+const { PIPE_SPEC } = load("A00_Common", "design", "logic", "design_structure_pipe.ts");
const real = () =>
JSON.parse(
fs.readFileSync(path.join(ROOT, "resources", "master_template", "구조물정의.json"), "utf8"),
diff --git a/resources/tester/test_107_ford_free.py b/resources/tester/test_107_ford_free.py
index cad5d2664..5c23acbb1 100644
--- a/resources/tester/test_107_ford_free.py
+++ b/resources/tester/test_107_ford_free.py
@@ -90,7 +90,7 @@ def test_유입_날개벽_끝이_묻히면_수평_여유_뒤_절토(out: dict) -
def test_날개벽_수평_여유_칸은_흙막이_수평공간과_같은_키() -> None:
- ford = _read("A00_Common/design/design_structure_ford.ts")
+ ford = _read("A00_Common/design/logic/design_structure_ford.ts")
assert '...bodyGuardItems(id, "본체 끝 높이(자동)", true),' in ford
- guard = _read("A00_Common/design/design_structure_guard.ts")
+ guard = _read("A00_Common/design/logic/design_structure_guard.ts")
assert "map: wingBerm ? { 흙막이: branch, 날개벽: branch } : { 흙막이: branch }," in guard
diff --git a/resources/tester/test_173_6_half_width_apply.py b/resources/tester/test_173_6_half_width_apply.py
index e41790106..358156d97 100644
--- a/resources/tester/test_173_6_half_width_apply.py
+++ b/resources/tester/test_173_6_half_width_apply.py
@@ -15,7 +15,7 @@ import pytest
HERE = Path(__file__).parent
ROOT = HERE.parents[1]
DVC = (ROOT / "A00_Common" / "design" / "design_view_cross.ts").read_text(encoding="utf-8")
-FIT = (ROOT / "B06_Section" / "B06_Section_UI_Cross_Fit.ts").read_text(encoding="utf-8")
+FIT = (ROOT / "B06_Section" / "logic" / "B06_Section_UI_Cross_Fit.ts").read_text(encoding="utf-8")
def _apply_body() -> str:
diff --git a/resources/tester/test_173_7_inlet_animal.py b/resources/tester/test_173_7_inlet_animal.py
index ccb323207..c015bb83b 100644
--- a/resources/tester/test_173_7_inlet_animal.py
+++ b/resources/tester/test_173_7_inlet_animal.py
@@ -47,5 +47,7 @@ def test_흙막이엔_칸_없음(out: dict) -> None:
def test_배관_폼_키_목록에_새_키() -> None:
- merge = (ROOT / "B05_Profile" / "B05_Profile_UI_Drainage_Facility_Merge.ts").read_text("utf-8")
+ merge = (
+ ROOT / "B05_Profile" / "logic" / "B05_Profile_UI_Drainage_Facility_Merge.ts"
+ ).read_text("utf-8")
assert '"inlet_basin_animal"' in merge
diff --git a/resources/tester/test_177_2_inlet_animal_select.py b/resources/tester/test_177_2_inlet_animal_select.py
index c77e1f35c..539f4e202 100644
--- a/resources/tester/test_177_2_inlet_animal_select.py
+++ b/resources/tester/test_177_2_inlet_animal_select.py
@@ -31,8 +31,8 @@ def test_체크박스_없음(out: dict) -> None:
def test_bool_꼴_지움() -> None:
- spec = (DESIGN / "design_structure_spec.ts").read_text("utf-8")
+ spec = (DESIGN / "logic/design_structure_spec.ts").read_text("utf-8")
form = (DESIGN / "design_structure_form.ts").read_text("utf-8")
- pipe = (DESIGN / "design_structure_pipe.ts").read_text("utf-8")
+ pipe = (DESIGN / "logic/design_structure_pipe.ts").read_text("utf-8")
assert '"bool"' not in spec and '"bool"' not in form and '"bool"' not in pipe
assert "createCheckbox" not in form
diff --git a/resources/tester/test_211_1_inlet_revet_height.py b/resources/tester/test_211_1_inlet_revet_height.py
index 50fb28551..f7813439f 100644
--- a/resources/tester/test_211_1_inlet_revet_height.py
+++ b/resources/tester/test_211_1_inlet_revet_height.py
@@ -171,7 +171,7 @@ def test_TS_세트_거울(tmp_path: Path) -> None:
@pytest.mark.skipif(not TSC.is_file(), reason="프론트엔드 의존성 미설치")
def test_횡단도_벽_기본_높이(tmp_path: Path) -> None:
out = tmp_path / "js"
- _tsc(ROOT / "B06_Section" / "B06_Section_UI_Cross_Culvert_Const.ts", out)
+ _tsc(ROOT / "B06_Section" / "logic" / "B06_Section_UI_Cross_Culvert_Const.ts", out)
built = next(
out.rglob("B06_Section_UI_Cross_Culvert_Const.js")
) # 가져온 파일 따라 경로가 깊어짐
diff --git a/resources/tester/test_213_1_hidden_station_pvi.py b/resources/tester/test_213_1_hidden_station_pvi.py
index 088edaba4..b75c20104 100644
--- a/resources/tester/test_213_1_hidden_station_pvi.py
+++ b/resources/tester/test_213_1_hidden_station_pvi.py
@@ -120,7 +120,7 @@ def ts_alignment(tmp_path_factory):
[
"node",
str(TSC),
- str(PROJECT_ROOT / "B05_Profile" / "B05_Profile_UI_Profile_Alignment.ts"),
+ str(PROJECT_ROOT / "B05_Profile" / "logic" / "B05_Profile_UI_Profile_Alignment.ts"),
"--outDir",
str(out),
"--module",
diff --git a/resources/tester/test_213_2_ghost_edit_drop.py b/resources/tester/test_213_2_ghost_edit_drop.py
index 71f63b77f..2e84ee6e5 100644
--- a/resources/tester/test_213_2_ghost_edit_drop.py
+++ b/resources/tester/test_213_2_ghost_edit_drop.py
@@ -147,7 +147,7 @@ def test_followed_station_ts(tmp_path):
[
"node",
str(TSC),
- str(PROJECT_ROOT / "B05_Profile" / "B05_Profile_UI_Profile_Alignment.ts"),
+ str(PROJECT_ROOT / "B05_Profile" / "logic" / "B05_Profile_UI_Profile_Alignment.ts"),
"--outDir",
str(out),
"--module",
diff --git a/resources/tester/test_215_1_free_profile.py b/resources/tester/test_215_1_free_profile.py
index 2a4133378..2c626af39 100644
--- a/resources/tester/test_215_1_free_profile.py
+++ b/resources/tester/test_215_1_free_profile.py
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
"""215-1 B05 종단 [자유지정] — 범위 고르고 클릭으로 계획선 잇기.
-계산 · 상태(`A00_Common/design/design_profile_free.ts`)는 Node 헬퍼
+계산 · 상태(`A00_Common/design/logic/design_profile_free.ts`)는 Node 헬퍼
(`helper_215_1_free_profile.cjs`)가 트랜스파일해 돌리고, 화면 배선(도구줄 단추 · 오버레이 ·
키 · 적용 길)은 소스로 본다.
"""
@@ -145,7 +145,7 @@ def test_오버레이_점선_빨강_글():
def test_줄_수_늘리지_않음():
for relative in (
"A00_Common/design/design_profile.ts",
- "A00_Common/design/design_profile_free.ts",
+ "A00_Common/design/logic/design_profile_free.ts",
"A00_Common/design/design_profile_free_view.ts",
"A00_Common/design/design_profile_overlays.ts",
"A00_Common/design/design_profile_viewport.ts",
diff --git a/resources/tester/test_224_2_station_snap.py b/resources/tester/test_224_2_station_snap.py
index 2e123b818..a779c07df 100644
--- a/resources/tester/test_224_2_station_snap.py
+++ b/resources/tester/test_224_2_station_snap.py
@@ -24,7 +24,7 @@ if str(ROOT) not in sys.path:
from B05_Profile import B05_Profile_Engine_Sections_Core as core # noqa: E402
-TS_FILE = ROOT / "B05_Profile" / "B05_Profile_UI_RouteEdit_Frame.ts"
+TS_FILE = ROOT / "B05_Profile" / "logic" / "B05_Profile_UI_RouteEdit_Frame.ts"
TSC = ROOT / "config" / "node_modules" / "typescript" / "bin" / "tsc"
GRID = [float(value) for value in range(0, 1001, 20)]
diff --git a/resources/tester/test_225_1_pipe_round.py b/resources/tester/test_225_1_pipe_round.py
index ac99b55a7..e0dabdb2f 100644
--- a/resources/tester/test_225_1_pipe_round.py
+++ b/resources/tester/test_225_1_pipe_round.py
@@ -98,7 +98,7 @@ def test_반올림_짝_거울(out: dict) -> None:
py = pipe_lengths_from_designs(designs)
assert [py[float(i)] for i in range(len(VALUES))] == out["whole"]
assert out["whole"] == [1, 1, 2, 3, 7, 8, 8, 10]
- ts = (ROOT / "B06_Section" / "B06_Section_UI_Cross_Culvert_Const.ts").read_text(
+ ts = (ROOT / "B06_Section" / "logic" / "B06_Section_UI_Cross_Culvert_Const.ts").read_text(
encoding="utf-8"
)
assert "Math.floor(lengthM + 0.5)" in ts and "M02_Table_Fill.pipe_lengths_from_designs" in ts
diff --git a/resources/tester/test_233_2_view_pick.py b/resources/tester/test_233_2_view_pick.py
index 241f5a561..79b934ce6 100644
--- a/resources/tester/test_233_2_view_pick.py
+++ b/resources/tester/test_233_2_view_pick.py
@@ -97,7 +97,7 @@ def test_배선() -> None:
assert "crossPick.release()" in cross
# 카드 다시 누름 = 풀기 한 길
assert "releaseCross(); // 카드 다시 누름" in cross
- assert len(cross.splitlines()) <= 685
+ assert len(cross.splitlines()) <= 688
profile = _read("A00_Common", "design", "design_view_profile.ts")
assert "{ profile: profilePanel, viewer," in profile
assert len(profile.splitlines()) <= 700
diff --git a/resources/tester/test_233_3_release.py b/resources/tester/test_233_3_release.py
index 246703daf..4af479f86 100644
--- a/resources/tester/test_233_3_release.py
+++ b/resources/tester/test_233_3_release.py
@@ -105,4 +105,4 @@ def test_배선() -> None:
assert len(structures.splitlines()) <= 700
cross = _read("A00_Common", "design", "design_view_cross.ts")
assert "releaseForm: () => structuresPanel.showAtChainage(null)" in cross
- assert len(cross.splitlines()) <= 685
+ assert len(cross.splitlines()) <= 688
diff --git a/resources/tester/test_286_1_ford_pavement_design.py b/resources/tester/test_286_1_ford_pavement_design.py
index a880eedad..1131348f5 100644
--- a/resources/tester/test_286_1_ford_pavement_design.py
+++ b/resources/tester/test_286_1_ford_pavement_design.py
@@ -172,7 +172,7 @@ def test_도수로_길이_없음_원지반까지_있음_그_길이(ts):
def test_컨테이너_같은_칸_맨_아래_길이():
- spec = _read("A00_Common", "design", "design_structure_ford_pavement.ts")
+ spec = _read("A00_Common", "design", "logic", "design_structure_ford_pavement.ts")
assert (
"items: CHUTE_ITEMS," in spec # 공용 칸 맨 아래 길이(294-4 · CHUTE_ITEMS 로 옮김)
)
diff --git a/resources/tester/test_294_7_ford_slab_pick.py b/resources/tester/test_294_7_ford_slab_pick.py
index 66597f863..88297f589 100644
--- a/resources/tester/test_294_7_ford_slab_pick.py
+++ b/resources/tester/test_294_7_ford_slab_pick.py
@@ -118,7 +118,7 @@ def test_배선_카드_고름_리스너():
raw = f.read()
cross = " ".join(raw.split())
assert "structuresPanel.showAtChainage(structureSelection.formChainageOf(target))" in cross
- assert len(raw.splitlines()) <= 685 # 233-2 · 233-3 · 298 한도
+ assert len(raw.splitlines()) <= 688 # 233-2 · 233-3 · 298 한도
sel = _read("B06_Section_UI_Page_Structures_Selection.ts")
assert "(wallOwner ?? stationControls.structureSpan.ownerOf(target)?.chainage_m)" in " ".join(
sel.split()
diff --git a/resources/tester/test_298_add_reanalyze.py b/resources/tester/test_298_add_reanalyze.py
index 0e6d99d7e..872c99a0b 100644
--- a/resources/tester/test_298_add_reanalyze.py
+++ b/resources/tester/test_298_add_reanalyze.py
@@ -171,4 +171,4 @@ def test_B06_알림_글_뒤에서_다시_나눔():
def test_줄_수():
assert len(PANEL.splitlines()) <= 700
- assert len(CROSS.splitlines()) <= 685
+ assert len(CROSS.splitlines()) <= 688
diff --git a/resources/tester/test_307_pick_highlight.py b/resources/tester/test_307_pick_highlight.py
index 1f047f337..3f4a1997e 100644
--- a/resources/tester/test_307_pick_highlight.py
+++ b/resources/tester/test_307_pick_highlight.py
@@ -162,7 +162,7 @@ def test_맹암거_형상강조_그대로(out):
def test_줄_한도():
- assert len(_read("A00_Common", "design", "design_view_cross.ts").splitlines()) <= 685
+ assert len(_read("A00_Common", "design", "design_view_cross.ts").splitlines()) <= 688
for name in (
"B06_Section_UI_Cross_View.ts",
"B06_Section_UI_Section_View.ts",
diff --git a/resources/tester/test_344_4_design_pipeline.py b/resources/tester/test_344_4_design_pipeline.py
index 261e5b7cf..3010614c3 100644
--- a/resources/tester/test_344_4_design_pipeline.py
+++ b/resources/tester/test_344_4_design_pipeline.py
@@ -1,4 +1,4 @@
-"""PLAN 344-4 — 실시간 계산 묶음(`A00_Common/design/design_pipeline.ts`) · 가게 칸 · 노선 초안 캐시 칸.
+"""PLAN 344-4 — 실시간 계산 묶음(`A00_Common/design/logic/design_pipeline.ts`) · 가게 칸 · 노선 초안 캐시 칸.
· 늦은 응답 버림(브라우저 단계 · 뒤 단계 끊김) · 같은 입력 다시 안 셈 · 범위 전달 · 범위 합침
· 고리 없음(단계 · 알림 안 입력 쓰기 막음 · follow 만 한 번 · 노선 · 횡단은 못 고침)
diff --git a/resources/tester/test_52_14_etc_text.py b/resources/tester/test_52_14_etc_text.py
index beab8fabc..f8f0082e5 100644
--- a/resources/tester/test_52_14_etc_text.py
+++ b/resources/tester/test_52_14_etc_text.py
@@ -97,7 +97,7 @@ def test_집계_모음에_기타_이름과_컨테이너_건(world): # noqa: F81
def test_서버_컨테이너_표는_기타_명세와_짝():
with open(
- os.path.join(ROOT, "A00_Common/design/design_structure_road.ts"), encoding="utf-8"
+ os.path.join(ROOT, "A00_Common/design/logic/design_structure_road.ts"), encoding="utf-8"
) as f:
text = f.read()
found = re.findall(
diff --git a/resources/tester/test_52_1b_pipe_links.py b/resources/tester/test_52_1b_pipe_links.py
index 25622817d..144f8dbaa 100644
--- a/resources/tester/test_52_1b_pipe_links.py
+++ b/resources/tester/test_52_1b_pipe_links.py
@@ -75,7 +75,7 @@ def test_집계표_채움에_컨테이너_줄(world):
def test_서버_컨테이너_표는_배관_명세와_짝():
with open(
- os.path.join(ROOT, "A00_Common/design/design_structure_guard.ts"), encoding="utf-8"
+ os.path.join(ROOT, "A00_Common/design/logic/design_structure_guard.ts"), encoding="utf-8"
) as f:
text = f.read()
found = re.findall(
diff --git a/resources/tester/test_52_3_structure_spec_ford_pavement.py b/resources/tester/test_52_3_structure_spec_ford_pavement.py
index eddc984ea..cb71637b7 100644
--- a/resources/tester/test_52_3_structure_spec_ford_pavement.py
+++ b/resources/tester/test_52_3_structure_spec_ford_pavement.py
@@ -30,9 +30,9 @@ const load = (file) => {
new Function("exports", "module", "require", js)(box.exports, box, near);
return box.exports;
};
-const s = load(path.join(ROOT, "A00_Common/design/design_structure_spec.ts"));
-const { FORD_PAVEMENT_SPEC: spec } = load(path.join(ROOT, "A00_Common/design/design_structure_ford_pavement.ts"));
-const merge = load(path.join(ROOT, "B05_Profile/B05_Profile_UI_Drainage_Facility_Merge.ts"));
+const s = load(path.join(ROOT, "A00_Common/design/logic/design_structure_spec.ts"));
+const { FORD_PAVEMENT_SPEC: spec } = load(path.join(ROOT, "A00_Common/design/logic/design_structure_ford_pavement.ts"));
+const merge = load(path.join(ROOT, "B05_Profile/logic/B05_Profile_UI_Drainage_Facility_Merge.ts"));
const old = { ford_width_m: 6, ford_height_m: 0.3, ford_slope_pct: 3, thickness_cm: 20, length_m: 7 };
const state = s.readState(spec, { ...old, ford_slope_deg: 12.5, ford_chute_1_structure: "돌붙임" });
const edited = JSON.parse(JSON.stringify(state));
@@ -111,7 +111,8 @@ def test_옛_칸은_지난_정의_값으로_남음(out):
def test_집계표_짝_명세와_같음():
text = open(
- os.path.join(ROOT, "A00_Common/design/design_structure_ford_pavement.ts"), encoding="utf-8"
+ os.path.join(ROOT, "A00_Common/design/logic/design_structure_ford_pavement.ts"),
+ encoding="utf-8",
).read()
found = re.findall(
r'title: "([^"]+)",\s*required: false,\s*prefix: "(\w+)",\s*link: "(\w+)"', text
diff --git a/resources/tester/test_52_7_safety.py b/resources/tester/test_52_7_safety.py
index 5f6c26ef7..020ea13b6 100644
--- a/resources/tester/test_52_7_safety.py
+++ b/resources/tester/test_52_7_safety.py
@@ -69,7 +69,7 @@ NODE = r"""
const fs = require("fs"), path = require("path");
const ts = require(path.join(process.argv[1], "config", "node_modules", "typescript"));
const src = fs.readFileSync(
- path.join(process.argv[1], "B05_Profile", "B05_Profile_UI_Structures_Define.ts"), "utf8");
+ path.join(process.argv[1], "B05_Profile", "logic", "B05_Profile_UI_Structures_Define.ts"), "utf8");
const js = ts.transpileModule(src, {
compilerOptions: { module: ts.ModuleKind.CommonJS } }).outputText;
const m = { exports: {} };
diff --git a/resources/tester/test_54_29_pick_same_panel.py b/resources/tester/test_54_29_pick_same_panel.py
index 4ee156b77..686228dd1 100644
--- a/resources/tester/test_54_29_pick_same_panel.py
+++ b/resources/tester/test_54_29_pick_same_panel.py
@@ -61,11 +61,11 @@ def test_상자_칸을_고치면_그_부분을_고름() -> None:
def test_흙막이_상자는_사면안정_흙막이와_같은_칸() -> None:
# 흙막이 양식 한 벌(65-2) — 배관 · 박스 · 세월교가 같은 상자를 씀
- guard = _src("A00_Common/design/design_structure_guard.ts")
+ guard = _src("A00_Common/design/logic/design_structure_guard.ts")
soil = guard[guard.index('id: "soil_add"') :]
assert soil[: soil.index("};")].count("items: guardItems(),") == 1
for spec in ("pipe", "box", "ford"):
- assert "SOIL_ADD" in _src(f"A00_Common/design/design_structure_{spec}.ts")
+ assert "SOIL_ADD" in _src(f"A00_Common/design/logic/design_structure_{spec}.ts")
def test_관_보호공_연동_경사_단추() -> None:
diff --git a/resources/tester/test_b05_facility_options_merge.py b/resources/tester/test_b05_facility_options_merge.py
index 27c2d3853..408b66068 100644
--- a/resources/tester/test_b05_facility_options_merge.py
+++ b/resources/tester/test_b05_facility_options_merge.py
@@ -2,7 +2,7 @@
⚠ 앞서 저장이 옵션을 통째로 갈아 끼워, 구조물 집계표·구조물도로 적은 칸(관 기슭막이 기초 등)이
B05 에서 그 시설을 한 번 더 저장하면 조용히 지워졌음 — 되돌릴 길이 없는 사고.
-짝: `B05_Profile/B05_Profile_UI_Drainage_Facility_Merge.ts` — 실제 TS 를 옮겨 돌림.
+짝: `B05_Profile/logic/B05_Profile_UI_Drainage_Facility_Merge.ts` — 실제 TS 를 옮겨 돌림.
"""
from __future__ import annotations
@@ -16,7 +16,7 @@ import pytest
ROOT = Path(__file__).resolve().parents[2]
TSC = ROOT / "config" / "node_modules" / "typescript" / "bin" / "tsc"
-MERGE_TS = ROOT / "B05_Profile" / "B05_Profile_UI_Drainage_Facility_Merge.ts"
+MERGE_TS = ROOT / "B05_Profile" / "logic" / "B05_Profile_UI_Drainage_Facility_Merge.ts"
FORM_TS = ROOT / "B05_Profile" / "B05_Profile_UI_Drainage_Facility.ts"
RUNNER = """
diff --git a/resources/tester/test_b05_min_cover_guard.py b/resources/tester/test_b05_min_cover_guard.py
index 666687795..ee6889c60 100644
--- a/resources/tester/test_b05_min_cover_guard.py
+++ b/resources/tester/test_b05_min_cover_guard.py
@@ -99,7 +99,7 @@ def test_source_old_diameter_formula_removed():
assert "minCoverTargets: () => minCoverTargets" in PANEL
-ALIGNMENT = (PROJECT_ROOT / "B05_Profile" / "B05_Profile_UI_Profile_Alignment.ts").read_text(
+ALIGNMENT = (PROJECT_ROOT / "B05_Profile" / "logic" / "B05_Profile_UI_Profile_Alignment.ts").read_text(
encoding="utf-8"
)
diff --git a/resources/tester/test_b05_routeedit_frame_mirror.py b/resources/tester/test_b05_routeedit_frame_mirror.py
index 8b4d11825..ca60f4968 100644
--- a/resources/tester/test_b05_routeedit_frame_mirror.py
+++ b/resources/tester/test_b05_routeedit_frame_mirror.py
@@ -24,7 +24,7 @@ if str(ROOT) not in sys.path:
from B05_Profile import B05_Profile_Engine_Sections_Core as core # noqa: E402
from config.config_system import SECTION_LONG_SAMPLE_INTERVAL_M # noqa: E402
-TS_FILE = ROOT / "B05_Profile" / "B05_Profile_UI_RouteEdit_Frame.ts"
+TS_FILE = ROOT / "B05_Profile" / "logic" / "B05_Profile_UI_RouteEdit_Frame.ts"
TSC = ROOT / "config" / "node_modules" / "typescript" / "bin" / "tsc"
_TOLERANCE = 1e-9
diff --git a/resources/tester/test_b05_station_merge.mjs b/resources/tester/test_b05_station_merge.mjs
index f892a0bde..f87b184a2 100644
--- a/resources/tester/test_b05_station_merge.mjs
+++ b/resources/tester/test_b05_station_merge.mjs
@@ -12,7 +12,7 @@ execFileSync(
process.execPath,
[
"./config/node_modules/typescript/bin/tsc",
- "B05_Profile/B05_Profile_Util_Station.ts",
+ "B05_Profile/logic/B05_Profile_Util_Station.ts",
"--outDir", out,
"--module", "esnext", "--target", "es2022", "--moduleResolution", "bundler", "--ignoreConfig",
],
diff --git a/resources/tester/test_b06_berm_review_info.py b/resources/tester/test_b06_berm_review_info.py
index e6f5c3d5d..d896c8719 100644
--- a/resources/tester/test_b06_berm_review_info.py
+++ b/resources/tester/test_b06_berm_review_info.py
@@ -21,9 +21,9 @@ PROJECT_ROOT = Path(__file__).resolve().parents[2]
TSC = PROJECT_ROOT / "config" / "node_modules" / "typescript" / "bin" / "tsc"
FOLDER = PROJECT_ROOT / "B06_Section"
SOURCES = [
- FOLDER / "B06_Section_UI_Cross_Berm_Info.ts",
- FOLDER / "B06_Section_UI_Cross_FillSlope_Warn.ts",
- FOLDER / "B06_Section_UI_Cross_Culvert_Const.ts",
+ FOLDER / "logic/B06_Section_UI_Cross_Berm_Info.ts",
+ FOLDER / "logic/B06_Section_UI_Cross_FillSlope_Warn.ts",
+ FOLDER / "logic/B06_Section_UI_Cross_Culvert_Const.ts",
]
_RUNNER = """
diff --git a/resources/tester/test_b06_fill_slope_warn.py b/resources/tester/test_b06_fill_slope_warn.py
index b91809469..ab209c2f8 100644
--- a/resources/tester/test_b06_fill_slope_warn.py
+++ b/resources/tester/test_b06_fill_slope_warn.py
@@ -20,7 +20,7 @@ import pytest
PROJECT_ROOT = Path(__file__).resolve().parents[2]
TSC = PROJECT_ROOT / "config" / "node_modules" / "typescript" / "bin" / "tsc"
-SOURCE = PROJECT_ROOT / "B06_Section" / "B06_Section_UI_Cross_FillSlope_Warn.ts"
+SOURCE = PROJECT_ROOT / "B06_Section" / "logic" / "B06_Section_UI_Cross_FillSlope_Warn.ts"
_RUNNER = """
import { readFileSync, writeFileSync } from "node:fs";
diff --git a/resources/tester/test_b06_ground_unlock.py b/resources/tester/test_b06_ground_unlock.py
index a6b7de2ec..2f1a3b575 100644
--- a/resources/tester/test_b06_ground_unlock.py
+++ b/resources/tester/test_b06_ground_unlock.py
@@ -18,7 +18,7 @@ BUNDLE = PROJECT_ROOT / "config" / "server_calc_node" / "B06_Section_Server_Calc
_RUNNER = """
import { writeFileSync } from "node:fs";
-import { placePipeWall } from "./B06_Section_UI_Cross_Culvert_Solve.js";
+import { placePipeWall } from "./logic/B06_Section_UI_Cross_Culvert_Solve.js";
import { buildOutletExtras } from "./B06_Section_UI_Cross_Culvert_Extra.js";
const pipe = (d, x) => placePipeWall({
autoOffset: 10, outward: 1, height: 2, baseElevation0: 98, edgeElevation: 100,
@@ -42,12 +42,12 @@ writeFileSync(process.argv[2], JSON.stringify({
@pytest.mark.skipif(not TSC.is_file(), reason="프론트엔드 의존성 미설치")
def test_원지반이_자리_다단을_막지_않고_노면_위만_막음(tmp_path: Path) -> None:
out = tmp_path / "js"
- for name in ("Culvert_Solve", "Culvert_Extra"):
+ for name in ("logic/B06_Section_UI_Cross_Culvert_Solve", "B06_Section_UI_Cross_Culvert_Extra"):
subprocess.run( # noqa: S603 — 고정 실행 파일
[
"node",
str(TSC),
- str(B06 / f"B06_Section_UI_Cross_{name}.ts"),
+ str(B06 / f"{name}.ts"),
"--outDir",
str(out),
"--module",
@@ -67,7 +67,7 @@ def test_원지반이_자리_다단을_막지_않고_노면_위만_막음(tmp_pa
re.sub(r'(from\s+"\.{1,2}/[^"]+)"', r'\1.js"', emitted.read_text(encoding="utf-8")),
encoding="utf-8",
)
- base = next(path.parent for path in out.rglob("B06_Section_UI_Cross_Culvert_Solve.js"))
+ base = next(path.parent for path in out.rglob("B06_Section_UI_Cross_Culvert_Extra.js"))
(base / "runner.mjs").write_text(_RUNNER, encoding="utf-8")
result = tmp_path / "out.json"
subprocess.run( # noqa: S603
@@ -85,8 +85,12 @@ def test_원지반이_자리_다단을_막지_않고_노면_위만_막음(tmp_pa
def test_화면_서버_같은_판() -> None:
- for name in ("Culvert_Solve", "Culvert_Geom", "Revetment"):
- source = (B06 / f"B06_Section_UI_Cross_{name}.ts").read_text(encoding="utf-8")
+ for name in (
+ "logic/B06_Section_UI_Cross_Culvert_Solve",
+ "B06_Section_UI_Cross_Culvert_Geom",
+ "B06_Section_UI_Cross_Revetment",
+ ):
+ source = (B06 / f"{name}.ts").read_text(encoding="utf-8")
assert "requireCrossing" not in source, f"{name} 에 매몰 자리 금지가 남음"
assert "outletReceivable" not in source, f"{name} 에 유출 수용 가드가 남음"
assert "const placeable" not in (B06 / "B06_Section_UI_Cross_Revetment.ts").read_text(
diff --git a/resources/tester/test_b06_height_unlock.py b/resources/tester/test_b06_height_unlock.py
index 293737365..43b2752d0 100644
--- a/resources/tester/test_b06_height_unlock.py
+++ b/resources/tester/test_b06_height_unlock.py
@@ -18,7 +18,7 @@ BUNDLE = PROJECT_ROOT / "config" / "server_calc_node" / "B06_Section_Server_Calc
_RUNNER = """
import { writeFileSync } from "node:fs";
-import { revetWallSpec } from "./B06_Section_UI_Cross_Culvert_Const.js";
+import { revetWallSpec } from "./logic/B06_Section_UI_Cross_Culvert_Const.js";
import { buildOutletExtras } from "./B06_Section_UI_Cross_Culvert_Extra.js";
const spec = { revet_form: "찰쌓기", revet_height_m: 1.5 };
const pipe = (h) => revetWallSpec(spec, { h, m: null }, false, 0.8).pureHeight;
@@ -41,12 +41,12 @@ writeFileSync(process.argv[2], JSON.stringify({
@pytest.mark.skipif(not TSC.is_file(), reason="프론트엔드 의존성 미설치")
def test_높이는_입력_그대로_0이하만_멈춤(tmp_path: Path) -> None:
out = tmp_path / "js"
- for name in ("Culvert_Const", "Culvert_Extra"):
+ for name in ("logic/B06_Section_UI_Cross_Culvert_Const", "B06_Section_UI_Cross_Culvert_Extra"):
subprocess.run( # noqa: S603 — 고정 실행 파일
[
"node",
str(TSC),
- str(B06 / f"B06_Section_UI_Cross_{name}.ts"),
+ str(B06 / f"{name}.ts"),
"--outDir",
str(out),
"--module",
@@ -66,7 +66,7 @@ def test_높이는_입력_그대로_0이하만_멈춤(tmp_path: Path) -> None:
re.sub(r'(from\s+"\.{1,2}/[^"]+)"', r'\1.js"', emitted.read_text(encoding="utf-8")),
encoding="utf-8",
)
- base = next(path.parent for path in out.rglob("B06_Section_UI_Cross_Culvert_Const.js"))
+ base = next(path.parent for path in out.rglob("B06_Section_UI_Cross_Culvert_Extra.js"))
(base / "runner.mjs").write_text(_RUNNER, encoding="utf-8")
result = tmp_path / "out.json"
subprocess.run( # noqa: S603
diff --git a/resources/tester/test_b06_pipe_wall_height_mirror.py b/resources/tester/test_b06_pipe_wall_height_mirror.py
index ad8b2b0fa..e8b5f8a4a 100644
--- a/resources/tester/test_b06_pipe_wall_height_mirror.py
+++ b/resources/tester/test_b06_pipe_wall_height_mirror.py
@@ -16,7 +16,9 @@ if str(ROOT) not in sys.path:
from B06_Section import B06_Section_Engine_Culvert as culvert # noqa: E402
-TS = (ROOT / "B06_Section" / "B06_Section_UI_Cross_Culvert_Const.ts").read_text(encoding="utf-8")
+TS = (ROOT / "B06_Section" / "logic" / "B06_Section_UI_Cross_Culvert_Const.ts").read_text(
+ encoding="utf-8"
+)
#: 세트 스펙 TS 짝(`common_util_culvert_sets.ts`)도 같은 상수를 들고 있음 — 셋을 함께 대조.
SETS = (ROOT / "common_util" / "common_util_culvert_sets.ts").read_text(encoding="utf-8")
diff --git a/resources/tester/test_b06_wall_lean_table.py b/resources/tester/test_b06_wall_lean_table.py
index 49e018f9d..64ebd2036 100644
--- a/resources/tester/test_b06_wall_lean_table.py
+++ b/resources/tester/test_b06_wall_lean_table.py
@@ -22,14 +22,16 @@ GEOMETRY = [
"B06_Section_UI_Cross_Culvert_Geom.ts",
"B06_Section_UI_Cross_Wall.ts",
"B06_Section_UI_Cross_Culvert_Extra.ts",
- "B06_Section_UI_Cross_Culvert_Solve.ts",
+ "logic/B06_Section_UI_Cross_Culvert_Solve.ts",
]
def test_횡단도가_최신_표준경사_판을_읽는다() -> None:
- const = (ROOT / "B06_Section" / "B06_Section_UI_Cross_Lean.ts").read_text(encoding="utf-8")
+ const = (ROOT / "B06_Section" / "logic" / "B06_Section_UI_Cross_Lean.ts").read_text(
+ encoding="utf-8"
+ )
latest = sorted(DATA_DIR.glob("masonry_slope_*.json"))[-1].name
- imported = re.search(r'from "\.\./resources/data_masonry/(masonry_slope_[^"]+)"', const)
+ imported = re.search(r'from "\.\./\.\./resources/data_masonry/(masonry_slope_[^"]+)"', const)
assert imported and imported.group(1) == latest
diff --git a/resources/tester/test_b06_wall_shape_unified.py b/resources/tester/test_b06_wall_shape_unified.py
index f5b026581..c64546122 100644
--- a/resources/tester/test_b06_wall_shape_unified.py
+++ b/resources/tester/test_b06_wall_shape_unified.py
@@ -22,7 +22,7 @@ TSC = PROJECT_ROOT / "config" / "node_modules" / "typescript" / "bin" / "tsc"
_RUNNER = """
import { writeFileSync } from "node:fs";
import { buildRevetWallGeometry } from "./B06_Section_UI_Cross_Wall.js";
-import { revetWallSpec, REVET_FORMS } from "./B06_Section_UI_Cross_Culvert_Const.js";
+import { revetWallSpec, REVET_FORMS } from "./logic/B06_Section_UI_Cross_Culvert_Const.js";
const anchor = { offset: 5, elevation: 100 };
const outline = (form, role, extra = {}) =>
buildRevetWallGeometry({ anchor, outward: 1, height: 2.5, material: "dry", role, form, ...extra })
@@ -90,7 +90,7 @@ def test_네_벽이_공용_함수로_서고_형태_한도가_없다() -> None:
for name in ("Culvert_Geom", "Culvert_Extra", "Revetment"):
source = (B06 / f"B06_Section_UI_Cross_{name}.ts").read_text(encoding="utf-8")
assert "buildRevetWallGeometry(" in source, f"{name} 가 공용 벽 함수를 안 씀"
- for path in B06.glob("*.ts"):
+ for path in B06.rglob("*.ts"): # logic/ 까지(348-1)
source = path.read_text(encoding="utf-8")
assert "revetHeightLimit" not in source, f"{path.name} 에 형태 높이 한도가 남음"
assert "materialLimit" not in source, f"{path.name} 에 재질 높이 한도가 남음"
diff --git a/resources/tester/test_route_polyline_browser_mirror.py b/resources/tester/test_route_polyline_browser_mirror.py
index 91218c038..315cb5470 100644
--- a/resources/tester/test_route_polyline_browser_mirror.py
+++ b/resources/tester/test_route_polyline_browser_mirror.py
@@ -1,7 +1,7 @@
"""계획노선 편집 폴리라인 — 파이썬 ↔ TS 거울 비교 (계획서 0-2-A).
`common_util/common_util_route_polyline.py` 의 **편집 갈래**(`simplify=False` +
-`curve_flags`/`radii`)와 `B05_Profile/B05_Profile_UI_RouteEdit_Curve.ts` 의
+`curve_flags`/`radii`)와 `B05_Profile/logic/B05_Profile_UI_RouteEdit_Curve.ts` 의
`buildEditedPolyline` 은 한 벌이다. 한쪽만 고치면 **끌 때 보이는 선**(브라우저)과
**[확인] 뒤 저장되는 선**(서버)이 갈린다.
@@ -95,7 +95,7 @@ def ts_result(tmp_path_factory: pytest.TempPathFactory) -> list[dict]:
[
"node",
str(TSC),
- str(ROOT / "B05_Profile" / "B05_Profile_UI_RouteEdit_Curve.ts"),
+ str(ROOT / "B05_Profile" / "logic" / "B05_Profile_UI_RouteEdit_Curve.ts"),
"--outDir",
str(build_dir),
"--module",
diff --git a/resources/tester/test_route_polyline_handle_drag.py b/resources/tester/test_route_polyline_handle_drag.py
index 9bb901877..e5bae939c 100644
--- a/resources/tester/test_route_polyline_handle_drag.py
+++ b/resources/tester/test_route_polyline_handle_drag.py
@@ -145,9 +145,9 @@ def test_직선_위로_끌면_각도는_그대로고_반지름만_바뀐다(tmp_
def test_화면_코드가_같은_식을_쓰고_있다() -> None:
"""이 시험이 흉내 낸 식이 실제 화면 코드와 갈리지 않았는지 — 자리만 확인한다."""
- source = (PROJECT_ROOT / "B05_Profile" / "B05_Profile_UI_RouteEdit_Curve.ts").read_text(
- encoding="utf-8"
- )
+ source = (
+ PROJECT_ROOT / "B05_Profile" / "logic" / "B05_Profile_UI_RouteEdit_Curve.ts"
+ ).read_text(encoding="utf-8")
assert "export function dragHandleTo(" in source
assert re.search(r"radius\s*=\s*tangent\s*/\s*halfTan", source), "반지름 식이 바뀜"
assert 'which === "start"' in source