From 292dfc9e37c6ac8070fd4bd84c3137aa7880cdd5 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sun, 25 Oct 2026 23:27:02 +0900 Subject: [PATCH] =?UTF-8?q?fix(528-6):=20D=20=C2=B7=20E=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EA=B0=80=EB=B3=8D=EA=B2=8C=20=E2=80=94=20B=20?= =?UTF-8?q?=EC=96=91=EC=8B=9D(10.76=20MB)=20=EB=B3=B5=EC=82=AC=20=C2=B7=20?= =?UTF-8?q?B0x=20=EB=B9=88=20=ED=8F=B4=EB=8D=94=20=EC=97=86=EC=9D=8C(D=20?= =?UTF-8?q?=3D=20D0x=20+=20B04=5FPreProcess=20=C2=B7=20E=20=3D=20E0x)=20?= =?UTF-8?q?=C2=B7=20=EA=B2=BD=EB=A1=9C=20=ED=92=80=EC=9D=B4=EA=B0=80=20D?= =?UTF-8?q?=20=C2=B7=20E=20=EB=A3=A8=ED=8A=B8=EC=97=90=20B=20=ED=8F=B4?= =?UTF-8?q?=EB=8D=94=EB=A5=BC=20=EB=8B=A4=EC=8B=9C=20=EB=A7=8C=EB=93=A4?= =?UTF-8?q?=EB=8D=98=20=EA=B2=83=20=EB=A7=89=EC=9D=8C=20=C2=B7=20ROAD=20?= =?UTF-8?q?=EA=B7=B8=EB=8C=80=EB=A1=9C=20=C2=B7=20=EC=8B=9C=ED=97=98(?= =?UTF-8?q?=EC=A2=85=EB=A5=98=20=EC=A0=80=EC=9E=A5=EC=86=8C=20=C2=B7=20ROA?= =?UTF-8?q?D=20=EB=B0=B0=EC=B9=98=20=C2=B7=20=ED=92=80=EC=9D=B4=20?= =?UTF-8?q?=EA=B1=B4=EB=84=88=EB=9C=80)(=EC=9A=94=EA=B5=AC=20351)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- common_util/common_util_project_kind.py | 21 +++++++------ common_util/common_util_storage.py | 9 +++++- resources/tester/test_528_project_groups.py | 35 +++++++++++++++++++++ 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/common_util/common_util_project_kind.py b/common_util/common_util_project_kind.py index 2ebca164c..e09facfbe 100644 --- a/common_util/common_util_project_kind.py +++ b/common_util/common_util_project_kind.py @@ -1,25 +1,24 @@ """종류별 프로젝트 행 만들기 — D 예정노선 · E 안정성평가(요구 345). -임도설계(ROAD)는 B02 그대로. 저장소 경로 · 초기 폴더는 B02 함수를 그대로 씀. +임도설계(ROAD)는 B02 그대로. 저장소 경로는 B02 함수를 씀 · 초기 폴더는 종류 단계만 +(B 양식 복사 · B0x 빈 폴더 없음 · D 는 지형 배치 B04_PreProcess 더함). """ from __future__ import annotations from datetime import datetime +from pathlib import Path from typing import Any from uuid import uuid4 -from B02_ProjRegister.B02_ProjRegister_Repository import ( - _build_project_storage, - _initialize_project_storage, -) +from B02_ProjRegister.B02_ProjRegister_Repository import _build_project_storage from common_util.common_util_audit import record_audit from common_util.common_util_storage import get_project_stage_path from common_util.common_util_workflow_state import initialize_project_stages from config.config_db import get_db_pool KIND_STAGE_DIRS = { - "PLAN": ("D02_PlanBase", "D03_PlanAnalysis", "D04_PlanConfirm"), + "PLAN": ("D02_PlanBase", "D03_PlanAnalysis", "D04_PlanConfirm", "B04_PreProcess"), "STABILITY": ( "E02_StabGround", "E03_StabSection", @@ -31,6 +30,12 @@ KIND_STAGE_DIRS = { } +def init_kind_storage(project_root: Path, kind: str) -> None: + """종류 단계 폴더만 — B 양식 · B0x 빈 폴더 · workflow · manifest 없음.""" + for stage_dir in KIND_STAGE_DIRS[kind]: + get_project_stage_path(str(project_root), stage_dir) + + async def create_kind_project( *, request: Any | None, @@ -99,9 +104,7 @@ async def create_kind_project( resource_ref=project_id, request=request, ) - _initialize_project_storage(project_root, project_id) - for stage_dir in KIND_STAGE_DIRS[kind]: - get_project_stage_path(str(project_root), stage_dir) + init_kind_storage(project_root, kind) await connection.commit() except Exception: await connection.rollback() diff --git a/common_util/common_util_storage.py b/common_util/common_util_storage.py index 59b65ffae..1d006136e 100644 --- a/common_util/common_util_storage.py +++ b/common_util/common_util_storage.py @@ -20,6 +20,8 @@ PROJECT_STORAGE_LAYOUT_V2 = ( ("B08_Quantity", "quantities"), ("B09_Estimation", "v1"), ) +#: D · E 프로젝트 표지 — 생성 때 만드는 단계 폴더(common_util_project_kind) +KIND_STAGE_MARKERS = tuple(sorted(s for s in PROJECT_STORAGE_STAGE_DIRS if s[0] in "DE")) def get_project_stage_path(project_root: str, stage: str) -> str: @@ -37,8 +39,13 @@ def get_project_stage_path(project_root: str, stage: str) -> str: def ensure_project_storage_layout(project_root: str) -> None: - """신규 워크플로우 저장소 하위 폴더를 누락분만 생성한다.""" + """신규 워크플로우 저장소 하위 폴더를 누락분만 생성한다. + + D · E 프로젝트(D0x · E0x 단계 폴더가 있는 루트)는 B 폴더를 만들지 않음 — 쓰는 곳이 스스로 만듦. + """ root = os.path.abspath(project_root) + if any(os.path.isdir(os.path.join(root, stage)) for stage in KIND_STAGE_MARKERS): + return for stage, subdir in PROJECT_STORAGE_LAYOUT_V2: if stage not in PROJECT_STORAGE_STAGE_DIRS: raise ValueError(f"허용되지 않은 프로젝트 저장 단계입니다: {stage}") diff --git a/resources/tester/test_528_project_groups.py b/resources/tester/test_528_project_groups.py index aedfd6fe7..62968e798 100644 --- a/resources/tester/test_528_project_groups.py +++ b/resources/tester/test_528_project_groups.py @@ -6,6 +6,7 @@ - 공유 판정 — 지정 회사 GET 200 · PUT 403 · 미지정 403 · 같은 회사 그대로 - 가입 — go.kr = 회사 「산림청」 · ACTIVE · 화면이 보낸 회사 값 무시 · 다른 메일 = NO_COMPANY - 종류별 단계 시드 · storage 허용 목록 +- 528-6 D · E 저장소 = 종류 단계만(B 양식 · B0x 빈 폴더 없음 · D 는 B04_PreProcess) · ROAD 그대로 """ import asyncio @@ -17,6 +18,7 @@ from A07_Register import A07_Register_Router as reg_router from A07_Register.A07_Register_Schema import RegisterRequest from common_util import common_util_auth as auth from common_util import common_util_auth_repository as auth_repo +from common_util.common_util_project_kind import KIND_STAGE_DIRS, init_kind_storage from common_util.common_util_workflow_state import initialize_project_stages from config.config_system import PROJECT_STORAGE_STAGE_DIRS from D01_PlanRegister import D01_PlanRegister_Router as d01 @@ -269,3 +271,36 @@ def test_stage_seed_by_kind(kind, count): def test_storage_dirs_allowed(): for name in ("D02_PlanBase", "D04_PlanConfirm", "E02_StabGround", "E05_StabReport"): assert name in PROJECT_STORAGE_STAGE_DIRS + + +@pytest.mark.parametrize("kind", ["PLAN", "STABILITY"]) +def test_kind_storage_light(tmp_path, kind): + init_kind_storage(tmp_path, kind) + names = {p.name for p in tmp_path.iterdir()} + assert names == set(KIND_STAGE_DIRS[kind]) + assert ("B04_PreProcess" in names) == (kind == "PLAN") + assert not [p for p in tmp_path.rglob("*") if p.is_file()] + + +def test_road_storage_unchanged(tmp_path, monkeypatch): + from B02_ProjRegister import B02_ProjRegister_Repository as b02 + + seeded = [] + monkeypatch.setattr(b02, "seed_project", seeded.append) + b02._initialize_project_storage(tmp_path, "p1") + assert seeded == [tmp_path] + assert (tmp_path / "B09_Estimation" / "v1").is_dir() + assert (tmp_path / "project_manifest.json").is_file() + + +@pytest.mark.parametrize("kind", ["PLAN", "STABILITY", None]) +def test_resolve_layout_skips_kind(tmp_path, kind): + from common_util.common_util_storage import ensure_project_storage_layout + + if kind: + init_kind_storage(tmp_path, kind) + before = {p.name for p in tmp_path.iterdir()} + ensure_project_storage_layout(str(tmp_path)) + after = {p.name for p in tmp_path.iterdir()} + assert (after == before) == bool(kind) + assert ("B09_Estimation" in after) == (kind is None)