Files
invyone/notes/johngreen/2026-05-08-부서관리-버그헌팅-요약.md
T
johngreen 9c658ffd36 docs(notes): 부서관리 버그 헌팅 분석 리포트 (frontend/backend/sql/ux)
4개 도메인 병렬 분석 결과 + 통합 요약 + 시나리오 중심 정리.
총 25개 버그 (CRITICAL 3 / HIGH 11 / MEDIUM 7 / LOW 4) 식별.
실제 수정은 별도 커밋 (commit 68c1cb5b).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 17:08:23 +09:00

6.1 KiB

부서관리 버그 헌팅 통합 요약 (2026-05-08)

4개 도메인 병렬 분석 결과. 상세 리포트는 별도 파일 참조.


🔴 CRITICAL (즉시 수정)

# 위치 한 줄
C1 DepartmentService.java:356-370 setPrimaryDept 데이터 손상 — 사용자가 소속되지 않은 부서로 호출 시 다른 부서 primary 만 해제되고 새 primary 미설정 → 사용자가 어떤 부서도 primary 가 아닌 invariant 깨진 상태로 commit
C2 DepartmentController.java:234-245 searchUsers 회사 격리 누락userCompanyCode 가드 없음. 임의 사용자가 다른 회사 사용자 목록 검색 가능 → 멀티테넌시 침해
C3 DepartmentService.java:107 + :251 parent_dept_code cross-tenant — 존재/회사/삭제 검증 전혀 없음. update 의 verifyParentCycle 도 회사 격리 검증 없음. 다른 회사 부서를 부모로 지정 가능

🟠 HIGH

# 위치 한 줄
H1 page.tsx:658 (회사 Select) 회사 변경 시 selectedCode/draft/isNewMode 초기화 안 됨 → 다른 회사 부서가 우측 패널에 stale 노출 + 잘못된 회사 코드로 저장 위험
H2 page.tsx:403 handleMove Promise.all 로 N개 PUT — 일부 실패 시 부분 업데이트 영구 잔존 (catch 에서 loadDepartments 미호출). 트랜잭션 없음
H3 page.tsx:231-246 검색 필터 자식 매칭/부모 미매칭 시 트리 구조가 깨져 부서 안 보임 (broken tree)
H4 department.xml:160-179 updateDepartment 의 WHERE 에 DELETED_AT IS NULL 누락 — 삭제된 부서도 update 통과 후 controller 가 404 반환 → DB 는 변경되었는데 사용자는 실패로 인식 (silent corruption)
H5 DepartmentService.java:131 updateDepartment 부서명 중복 검증 없음 — create 에는 있지만 update 에 없어 동일 이름 active 부서 두 개 공존 가능
H6 DepartmentService.java:210 restoreDepartment 복구 시 동일 이름 active 부서 충돌 검증 없음 → 100% 재현되는 중복 이름 공존
H7 DepartmentController.java:135 deleteDepartment COMPANY_ADMIN 이 글로벌 부서 (*) 삭제 가능 → SUPER_ADMIN 전용 가드 필요
H8 DepartmentService.java:85-99 createDepartment 사용자 명시 dept_code 가 정규식 위반 시 silent fallback → 자동 코드로 발행되지만 사용자는 알지 못함
H9 DepartmentController.java:234 searchUsers role 검사 없음 — 일반 USER 가 회사 내 사용자 enumeration 가능
H10 page.tsx:113 emptyDraft start_datenew Date().toISOString().slice(0,10) 으로 고정 — UI 에서 hidden 인데도 today 가 강제 저장됨. 일괄등록도 동일
H11 DEPT_INFO 스키마 (mapper 외 확인 필요) (COMPANY_CODE, dept_name) partial UNIQUE 인덱스 부재 가능성 → race 시 중복 부서명 공존 (#H5/H6 의 근본 방어선)

🟡 MEDIUM

# 위치 한 줄
M1 page.tsx:219-228 멤버 fetch AbortController/cancellation flag 없음 → 빠른 부서 전환 시 stale 멤버 데이터 표시
M2 page.tsx:503 handleDelete selectedCode 를 클로저로 캡처 안 함 → 다이얼로그 열린 상태에서 다른 부서 선택되면 엉뚱한 부서 삭제 위험
M3 page.tsx:299 handleClearDetail isDirty 무시. X 버튼 클릭 시 미저장 변경 즉시 폐기
M4 page.tsx:997 변경이력 모달 API 호출 없음 — 항상 "이력 없음" 표시. 기능 미구현
M5 DepartmentService.java:96 selectNextDeptNumber MAX+1 비원자적 → 동시 생성 시 PK 충돌 5xx (catch 누락)
M6 DepartmentService.java:181 deleteDepartment 활성 자식만 카운트 → 자식 단독 복구 시 부모 deleted 차단되는 UX trap
M7 DepartmentService.java:283 searchUsers LIKE 와일드카드 %/_ 미이스케이프 → 동작 이상 + enumeration
M8 DepartmentService.java:107+ nullIfBlank 만 적용. 선행/후행 공백 보존 → DB 에 공백 포함 코드 저장 가능
M9 department.xml:150-174 #{date}::date cast 시 잘못된 형식 → SQLException 5xx
M10 DEPT_INFO * 회사 정책 글로벌 부서 read 일반 user 허용 / write 권한 정책 모호
M11 DepartmentController.java:353 super 식별 company_code='*' 우연 충돌 시 super 권한 부여 — provisioning 가드 필수

🟢 LOW

# 위치 한 줄
L1 DepartmentController.java:271-272 dead code (동일 키 두 번 lookup)
L2 DepartmentService.java:324 removeDeptMember primary 자동 승격 race 가능성 (낮음)
L3 page.tsx:920 picker "최상위로" 선택 UX 미구현 — handleConfirmMoveTo(null) 트리거 경로 없음
L4 page.tsx:957 bulk register 실패 부서 코드/사유 표시 없음 (성공/실패 카운트만)
L5 page.tsx:1469 멤버 패널 멤버 추가/제거 UI 미구현. API 만 존재
L6 page.tsx:249 expandAll + 검색 검색 후 expandAll → 검색 해제 시 부분 펼침 상태
L7 department.xml:213 selectDeptMembers INNER JOIN USER_INFO 삭제 시 orphan 멤버 표시 안 됨
L8 department.xml:192 deleteUserDeptByDeptCode dead query
L9 department.xml:266 selectFirstUserDept 동일 NOW() 다중 row 시 비결정적

추천 수정 순서

Phase 1 (긴급/보안): C1, C2, C3, H7 Phase 2 (데이터 무결성): H4, H5, H6, H11, H1 Phase 3 (UX/안정성): H2, H3, H8, H10, M1M3 Phase 4 (기능 보강): M4, L4, L5, L3 Phase 5 (정리): L1, L7L9, M5~M11

도메인별 통계

  • Frontend: 진짜 8 / 잠재 6 / 오탐 1
  • Backend: CRITICAL 3 + HIGH 7 + MEDIUM 7 + LOW 4
  • SQL: HIGH 2 + MEDIUM 4 + LOW 4 + OK 4
  • UX: 진짜 6 + 잠재 10 + OK 4