발행일

관리자 사이드바 그룹을 열흘 사이 세 번 옮겼다 — 메뉴 활성 판정이 경로 부분 문자열일 때

관리자 사이드바 그룹을 열흘 사이 세 번 옮겼다

9월 2일 작업을 중심으로, 그 뒤 10월 27일 메뉴 이름 정리까지 묶어 10월 말에 정리한 글입니다.

관리자 화면의 사이드바는 템플릿 하나(aside.html.j2) 안의 메뉴 목록으로 그려집니다. 그룹(main)마다 하위 항목(sub)이 있고, 지금 보고 있는 화면에 해당하는 그룹이 펼쳐지며 항목이 강조돼요.

이 사이드바의 신청·심사 메뉴가 열흘 사이에 세 번 자리를 옮겼습니다.

날짜커밋누가배치
8/2304730d40저도메인마다 한 그룹 — 표준데이터 관리·OID 관리 안에 각자의 신청·심사 목록
8/319c32af2a팀원신청·심사 목록 넷을 신청/심사 관리 한 그룹으로 모음
9/2abf6ed92저다시 도메인마다 한 그룹

이 글은 9월 2일 커밋을 중심으로 씁니다. 옮기는 일 자체보다, 옮길 때마다 같은 곳에서 걸렸다는 게 남길 만했어요.

활성 메뉴 판정은 부분 문자열 포함이다

그룹이 펼쳐질지는 이 함수가 정합니다.

def is_exist_word(content: str, words: list) -> bool:
    if not content or content == "":
        return False
    for word in words:
        if str(word) in content:
            return True
    return False

content는 현재 경로, words는 메뉴의 id 목록입니다. 경로에 id 중 하나라도 들어 있으면 켜져요. 접두어 비교도, URL 이름 비교도 아닙니다.

그래서 상위 경로를 id로 가진 메뉴가 하위 경로 화면까지 삼킵니다. 표준데이터 관리 그룹의 id는 std-data인데, OID 관리 화면의 경로는 /web-admin/std-data/oid/예요. OID 관리 항목을 OID 그룹으로 옮기면 두 그룹이 동시에 켜집니다.

8월 23일에 이걸 처음 밟았고, 그때 그룹에 "이 문자열이 들어 있으면 빼라"는 id_except를 더했습니다.

{% set is_active_main_menu = is_exist_word(encoded_url, main["id"])
     and not is_exist_word(encoded_url, main.get("id_except", [])) %}
"id": ["std-data", "wf-dataset"], "id_except": ["std-data/oid"], "title": _("표준데이터 관리")

판정 함수는 그대로 두고 예외 목록을 하나 얹은 겁니다. 이 함수는 사이드바 말고도 탭·목록 템플릿에서 쓰여서(9월 2일 시점, 사이드바 말고도 템플릿 9개), 사이드바 때문에 동작을 바꾸면 다른 화면이 같이 움직입니다.

8월 31일 — 팀원이 한 그룹으로 모으면서 하위 id를 좁혔다

8월 31일에 팀원이 신청·심사 목록 넷을 신청/심사 관리 한 그룹으로 모았습니다. 이때 팀원이 하위 항목 id를 qualify·request에서 wf-dataset/qualify·wf-oid/request처럼 도메인 경로를 붙인 형태로 바꿨어요. 커밋 메시지에 이유가 적혀 있습니다.

표준데이터와 OID 가 한 묶음에 들어오면서 qualify 만으로는 네 항목 중 둘이 동시에 활성으로 잡힘

같은 부분 문자열 함정이 하위 항목에서도 난 거고, 팀원은 id를 길게 적어서 피했습니다. 이 배치에서는 OID 목록이 다시 표준데이터 관리 그룹 안으로 들어가서 id_except는 필요 없어졌고요.

9월 2일 — 도메인 그룹으로 되돌렸다

9월 2일에 저는 이 배치를 다시 도메인 그룹으로 돌렸습니다.

  • 표준데이터 관리: 메타데이터 관리 · 표준데이터 관리 · 표준데이터 등록 신청 목록 · 표준데이터 등록 심사 목록
  • OID 관리: OID 관리 · OID 등록 신청 목록 · OID 등록 심사 목록

바꾼 건 템플릿 여섯 줄입니다. diff에서 볼 것은 두 가지예요.

팀원이 좁혀 둔 하위 id는 그대로 뒀습니다. 하위 항목은 그룹이 켜졌을 때만 판정하니, 도메인 그룹 안에서는 8월 23일처럼 짧은 qualify로도 동작합니다. 짧게 되돌려도 지금 배치에서는 동작합니다. 그래도 긴 id는 배치와 상관없이 맞아서, 다음에 그룹을 또 합쳐도 같은 함정을 밟지 않습니다.

id_except를 되살렸습니다. OID 관리 항목이 다시 OID 그룹으로 나갔으니, std-data가 /std-data/oid/를 삼키는 문제가 그대로 돌아오거든요.

"id": ["std-data", "wf-dataset"], "id_except": ["std-data/oid"], "title": _("표준데이터 관리")
"id": ["wf-oid", "std-data/oid"],                          "title": _("OID 관리")

그리고 UI 관례 문서의 메뉴 표를 새 이름으로 바꾸고, 뒤집힌 경위를 표시로 남겼습니다.

🔄 2026-09-02 — 한동안 신청·심사만 신청/심사 관리 한 그룹으로 묶어 뒀다가 위 도메인 그룹으로 되돌렸다. 하위 항목 이름에서 도메인 단어를 빼지는 않는다 — 두 그룹에 등록 신청 목록 이 똑같이 있으면 세션에 펼침이 남은 상태에서 어느 쪽 항목인지 구분이 안 된다.

사이드바는 펼친 그룹을 sessionStorage에 저장해 페이지를 옮겨도 유지합니다. 두 그룹을 다 펼쳐 둔 채면 등록 신청 목록이 두 줄 보이고, 그룹 머리가 화면 밖에 있으면 어느 쪽인지 알 수 없어요.

그 뒤 — 이름 규칙이 세 번 바뀌었다

부끄러운 쪽도 적어 둡니다. 하위 메뉴 이름에 도메인 단어를 넣느냐는 규칙이 세 번 바뀌었고, 세 번 모두 제 커밋이었어요. 다만 8월 23일의 "뺀다"는 문서에만 있었고 코드의 이름은 그때도 길었으니, 9월 2일은 사실상 문서를 코드에 맞춘 것입니다.

날짜규칙
8/23그룹명이 이미 말하는 단어는 하위 항목에서 뺀다 (등록 심사 목록)
9/2하위 항목 이름에서 도메인 단어를 빼지 않는다 (표준데이터 등록 신청 목록)
10/27그룹명에서 관리를 빼고, 하위 항목의 도메인 접두어도 다시 뺀다 (등록 신청 관리)

10월 27일 커밋(11d14549)은 물리 아키텍처·Open API까지 사이드바 전체에서 관리를 일괄로 뺀 메뉴 이름 정리였고, 문서에 "9월 2일 메모의 '도메인 단어를 빼지 않는다'는 이 결정으로 뒤집혔다"고 적었습니다. 그런데 9월 2일에 근거로 든 문제, 곧 두 그룹을 다 펼쳤을 때 같은 이름이 두 줄 보이는 문제를 어떻게 했는지는 적지 않았어요. 펼침 상태를 sessionStorage에 여러 개 저장하는 코드는 그대로라, 두 그룹 모두 등록 신청 관리가 보이는 상태는 지금도 만들 수 있습니다. 문제가 풀린 게 아니라, 이름을 짧게 하는 쪽을 택하면서 그 문제를 다시 남긴 겁니다.

판단과 한계

  • 9월 2일에 팀원의 배치를 되돌린 사유를 커밋에도 문서에도 남기지 않았습니다. 8월 23일에 적은 "도메인마다 한 그룹"이 근거였지만, 팀원이 8일 만에 바꾼 배치를 다시 뒤집으면서 그 말을 다시 쓰지 않았어요. 문서에는 "되돌렸다"만 있습니다. 같은 자리를 두 사람이 번갈아 바꿀 때는 왜 바꾸는지가 diff보다 중요한데, 그걸 빠뜨렸습니다.
  • 판정 함수는 고치지 않았습니다. 세 번 모두 id를 길게 적거나 id_except를 얹어 피했어요. 같은 파일 머리 주석에는 팀원이 조직 관리 화면에서 반대쪽 함정(id가 빠져 메뉴가 안 켜짐)을 피한 기록도 있습니다. 메뉴를 경로 문자열 대신 URL 이름(namespace:name)으로 판정하면 이 종류의 문제가 사라지지만, 함수를 쓰는 다른 템플릿까지 같이 바꿔야 해서 아직 손대지 않은 부채입니다.
  • 회귀 테스트는 이 커밋에 없습니다. 표준데이터 그룹의 항목 수를 단언하는 테스트는 있지만(9월 29일 커밋에서 네 항목 → 다섯 항목으로 기대값을 고침), OID 화면에서 두 그룹이 동시에 켜지지 않는지를 보는 테스트는 지금 저장소에서 찾지 못했습니다. id_except 한 줄이 빠지면 조용히 다시 둘 다 켜집니다.