feat(M02): 일위대가 조합 층 사이 복사 · 여러 개 옮기기 · 지우기 서버(PLAN 30-3)

- POST /api/m02/layers/{layer}/combos/paste — 원본 층(읽기) 조합 · 폴더 → 이 층(쓰기) 경로 폴더에 새 키(UA · UC · UP) · 본뜬키 = 원본(마스터는 UA 만) · 같은 이름 「이름 (2)」 · 폴더는 안 조합 · 빈 폴더까지 · 깊이 2 넘으면 422
- POST /api/m02/layers/{layer}/combos/tree-many — 나무 고침 여럿 차례대로 · 저장 한 번 · 하나라도 막히면 안 씀
- 새 M02_MasterTemplete_Combo_Copy · Combo_Store edit_tree 를 edit_tree_many · commit 한 길로
- Labor_Api 에 pasteCombos · editComboTreeMany
- 시험 test_m02_combo_layers 네 건 더함

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BU9gbNE3aWFUvE61pS2WGt
This commit is contained in:
2026-09-30 18:53:57 +09:00
co-authored by Claude Opus 5.5
parent 7ea8b75162
commit c0a76b844d
5 changed files with 272 additions and 7 deletions
@@ -19,6 +19,7 @@ from pydantic import BaseModel
from common_util.common_util_auth import verify_session
from M01_MasterData import M01_MasterData_Store as m01
from M02_MasterTemplete import M02_Layer_Access as access
from M02_MasterTemplete import M02_MasterTemplete_Combo_Copy as combo_copy
from M02_MasterTemplete import M02_MasterTemplete_Combo_Store as combos
from M02_MasterTemplete.M02_MasterTemplete_Router_Items import Layer, Session, _call, _root
@@ -41,6 +42,25 @@ class ComboTreeBody(BaseModel):
판: str
class TreeManyBody(BaseModel):
"""여러 개 옮기기 · 지우기(PLAN 30-3) — `ops` = 나무 고침(`ComboTreeBody` 모양) · 저장 한 번."""
판: str
ops: list[dict[str, Any]]
class PasteBody(BaseModel):
"""층 사이 복사(PLAN 30-3) — 원본 층(`from_layer` · `from_owner`)의 조합 `키` · 폴더 `폴더` →
이 층 `경로` 폴더에 새 키로. `판` = 이 층 조합 표 판."""
from_layer: Layer
from_owner: str | None = None
키: list[str] = []
폴더: list[list[str]] = []
경로: list[str] = []
판: str = ""
class PreviewBody(BaseModel):
"""저장 전 미리 보기 — `combo` 는 조합 줄 통째 또는 그 층 키 · `inputs` 는 로직마다."""
@@ -148,6 +168,30 @@ def post_tree(
return _call(folder, combos.edit_tree, body.model_dump())
@router.post("/layers/{layer}/combos/tree-many")
def post_tree_many(
layer: Layer,
body: TreeManyBody,
owner: str | None = None,
session: Session = Depends(verify_session),
):
folder = _root(session, layer, owner, write=True)
return _call(folder, combos.edit_tree_many, body.model_dump())
@router.post("/layers/{layer}/combos/paste")
def post_paste(
layer: Layer,
body: PasteBody,
owner: str | None = None,
session: Session = Depends(verify_session),
):
"""원본 층 읽기 권한 · 이 층 쓰기 권한(M02_Layer_Access) — 마스터 붙이기 = 시스템 관리자."""
source = _call(_root(session, body.from_layer, body.from_owner), lambda: combos._load()[0])
folder = _root(session, layer, owner, write=True)
return _call(folder, combo_copy.paste, source, body.model_dump())
@router.post("/layers/{layer}/combos/preview")
def post_preview(
layer: Layer,