feat(M02): 46-2 구조물 옵션 그룹 — 종류마다 이름 붙은 묶음 편집 · 정본 · /structure-types groups

- 정본 `resources/master_template/구조물옵션그룹.json` = {type_id: [{id, 이름, 옵션[]}]} · 빈 그룹 됨
- 길 GET · PUT /api/m02/structure-option-groups(시스템 관리자) · 검사(없는 종류 · 키 · 겹침 · 옵션 두 그룹 422 · 낡은 판 409)
- /api/projects/structure-types 종류마다 groups(차례 · 이름 · 옵션) · 깨진 표 = 그룹 없음
- 옵션 보이기 화면 = 그룹 목록(이름 · 위로 · 아래로 · 지우기 · 추가) + 옵션 줄 「들어갈 자리」(본체 · 그룹)
- 좌측 「구조물 옵션 보이기」 = 시스템 관리자만
- 시험 test_m02_structure_option_groups.py

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MPcuokNm1ZR2kqgGGDfaJA
This commit is contained in:
2026-10-05 13:21:37 +09:00
co-authored by Claude Opus 5.5
parent bd3c48c525
commit 37634e2c26
12 changed files with 680 additions and 75 deletions
@@ -13,7 +13,7 @@ import json
import logging
from typing import Any
from pydantic import Field
from pydantic import BaseModel, Field
from B05_Profile.B05_Profile_Structures_Schema import (
StructureOptionField,
@@ -24,6 +24,7 @@ from B05_Profile.B05_Profile_Structures_Schema import (
)
from common_util.common_util_json import atomic_write_json
from M02_MasterTemplete import M02_MasterTemplete_Store as store
from M02_MasterTemplete.StructOptions.M02_SO_Groups import groups_of
FILE = "구조물옵션표시.json"
logger = logging.getLogger(__name__)
@@ -35,12 +36,21 @@ class OptionWithVisible(StructureOptionField):
visible: bool = True
class OptionGroup(BaseModel):
"""옵션 그룹 한 개(PLAN 46-2 · `M02_SO_Groups`) — 폼의 보조 컨테이너 하나 · 빈 옵션도 됨."""
id: str
name: str
options: list[str] = Field(default_factory=list)
class TypeWithVisible(StructureType):
options: list[OptionWithVisible] = Field(default_factory=list)
groups: list[OptionGroup] = Field(default_factory=list)
class TypesWithVisible(StructureTypesResponse):
"""`GET /structure-types` 응답 — 옵션마다 `visible` 칸."""
"""`GET /structure-types` 응답 — 옵션마다 `visible` 칸 · 종류마다 `groups`."""
types: list[TypeWithVisible]
@@ -86,12 +96,14 @@ def with_visible() -> TypesWithVisible:
except store.StoreError as e:
logger.warning("구조물 옵션 표시 표를 못 읽어 모두 보임으로 냄 — %s", e.detail)
doc = {}
groups = groups_of()
types = [
{
**t.model_dump(),
"options": [
{**o.model_dump(), "visible": _shown(doc, t.type_id, o.key)} for o in t.options
],
"groups": groups.get(t.type_id, []),
}
for t in load_structure_types()
]