9c658ffd36
4개 도메인 병렬 분석 결과 + 통합 요약 + 시나리오 중심 정리.
총 25개 버그 (CRITICAL 3 / HIGH 11 / MEDIUM 7 / LOW 4) 식별.
실제 수정은 별도 커밋 (commit 68c1cb5b).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6.1 KiB
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_date 가 new 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