feat(M02): 기본 층 = 개인 — 층 없는 주소 · 사전조합도 · 회사 없으면 마스터(134-4)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SE9MxeXTu2uaDZ55BJowAY
This commit is contained in:
2026-10-09 15:03:30 +09:00
co-authored by Claude Opus 5.5
parent bf9472d8f3
commit 2640fb4c60
4 changed files with 22 additions and 8 deletions
@@ -34,11 +34,17 @@ const ROOTS: Root[] = ["master", "company", "personal"];
export const layerOfRoot = (root: Root): ManageLayer => (root === "master" ? "system" : root);
/** 주소 인자에서 진입 — 모르는 값 · 없음 = 마스터 · 구조물 조합 */
export function entryFromHash(): Entry {
/** 주소 인자에서 진입 — 층 모르는 값 · 없음 = 기본 층(134-4 · 개인 · 회사 없으면 마스터 · 사용자를 안 주면
* 마스터) · 열 곳 없음 = 구조물 조합 */
export function entryFromHash(user?: SessionUser | null): Entry {
const query = currentQuery();
const raw = query.get("root") ?? query.get("layer");
const root: Root = raw === "company" || raw === "personal" ? raw : "master";
const root: Root =
raw === "master" || raw === "company" || raw === "personal"
? raw
: user === undefined
? "master"
: defaultRoot(user);
const open = OPENS.find((one) => one === query.get("open")) ?? "구조물조합";
const owner = root === "master" ? null : query.get("owner") || null;
const pre = ROOTS.find((one) => one === query.get("pre")) ?? null;
@@ -52,7 +52,7 @@ const NEW_ASK =
export async function renderM02MasterTemplate(root: HTMLElement): Promise<MountedPage> {
const user = await fetchSessionUser().catch(() => null);
const entry = entryFromHash();
const entry = entryFromHash(user); // 134-4 — 해시에 층 없음 = 개인(회사 없으면 마스터)
const company = viewCompany(entry, user); // 볼 회사(시스템 관리자는 고른 회사)
let layer = layerOfRoot(entry.root);
// 회사 층 주인 = 볼 회사 · 자기 층 주인을 적어도 자기 층 · 회사 없는 사람의 회사 · 개인 = 마스터(단추 자리에 안내)
+9 -3
View File
@@ -217,7 +217,8 @@ def test_회사_찾기_거르기():
@pytest.mark.skipif(shutil.which("node") is None, reason="node 가 없음")
def test_구조물_조합_기본_층_개인():
"""123-1 — 회사 있는 사람은 역할 무관 구조물 조합 = 개인 · 회사 없으면 지금 규칙 · 다른 곳 그대로."""
"""123-1 — 회사 있는 사람은 역할 무관 구조물 조합 = 개인 · 회사 없으면 지금 규칙 · 다른 곳 그대로 ·
134-4 — 층 없는 주소도 개인(회사 없으면 마스터) · 사전조합 기본 층도 같은 규칙."""
m = "B01_Dashboard_PermMasterWrite"
combo = f"{M02}?open=구조물조합&root=personal"
assert _cards({"role": "SYSTEM_ADMIN", "is_master": False, "company_id": 1}, 3) == [
@@ -238,7 +239,12 @@ def test_구조물_조합_기본_층_개인():
assert _cards({"role": "ADMIN", "is_master": False, "company_id": None})[0][2] == (
f"{M02}?open=구조물조합&root=company"
)
# 다른 곳 기본 그대로 — 고르기 탭(일위대가 · 복사 생성 · 복사해 가져오기) · 층 없는 주소
# 다른 곳 기본 그대로 — 고르기 탭(일위대가 · 복사 생성 · 복사해 가져오기)
layer = _text(ROOT / "M02_MasterTemplete" / "M02_MasterTemplete_Layer.ts")
assert 'return { tabs, first: isSystem || !own ? "master" : "personal" };' in layer
assert 'raw === "company" || raw === "personal" ? raw : "master";' in layer
# 134-4 — 층 없는 주소 = 기본 층(개인 · 회사 없으면 마스터) · 사전조합 층도 같은 기본
assert 'ownOwner("personal", user) ? "personal" : "master";' in layer
assert ': user === undefined\n ? "master"\n : defaultRoot(user);' in layer
page = _text(ROOT / "M02_MasterTemplete" / "M02_MasterTemplete_UI_Page.ts")
assert "const entry = entryFromHash(user);" in page
assert "let pre = preScope(entry.pre ?? defaultRoot(user));" in page
+3 -1
View File
@@ -86,7 +86,9 @@ def test_주소_인자를_라우트에서_뗌():
layer = _text(LAYER)
# 진입 해시 `?open=&root=&owner=`(PLAN 27-1d) · 옛 `?layer=` 도 root 로
assert 'query.get("root") ?? query.get("layer")' in layer
assert 'raw === "company" || raw === "personal" ? raw : "master"' in layer
assert (
'raw === "master" || raw === "company" || raw === "personal"' in layer
) # 없음 = 기본(134-4)
assert '["구조물조합", "옵션", "도면", "일위대가조합"]' in layer # 일위대가 조합 서고 = 50-3
picker = _text(ROOT / "ui_template" / "ui_template_item_picker.ts")
assert 'open: "구조물조합", root: "personal"' in picker and "layer=personal" not in picker