# [맥락노트] 카테고리 드롭다운 - 3단계 깊이 구분 표시 > 관련 문서: [계획서](./CTI[계획]-카테고리-깊이구분.md) | [체크리스트](./CTI[체크]-카테고리-깊이구분.md) --- ## 왜 이 작업을 하는가 - 품목정보 등록 모달의 "재고단위" 등 카테고리 드롭다운에서 3단계 계층이 시각적으로 구분되지 않음 - 예: "신22"가 "신2"의 하위인데, "신3", "신4"와 같은 레벨로 보임 - 사용자가 대분류/중분류/소분류 관계를 파악할 수 없어 잘못된 항목을 선택할 위험 --- ## 핵심 결정 사항과 근거 ### 1. 원인: HTML 공백 축소(collapse) - **현상**: `flattenTree`에서 `" ".repeat(depth)`로 들여쓰기를 만들지만, HTML이 연속 공백을 하나로 합침 - **결과**: depth 1(`" └ "`)과 depth 2(`" └ "`)가 동일하게 렌더링됨 - **확인**: `SelectItem`, `CommandItem` 모두 `white-space: pre` 미적용 상태 ### 2. 해결: Non-Breaking Space(`\u00A0`) 사용 - **결정**: 일반 공백 `" "`를 `"\u00A0"`로 교체 - **근거**: `\u00A0`는 HTML에서 축소되지 않아 depth별 들여쓰기가 정확히 유지됨 - **대안 검토**: - `white-space: pre` CSS 적용 → 기각 (SelectItem, CommandItem 양쪽 모두 수정 필요, shadcn 기본 스타일 오버라이드 부담) - CSS `padding-left` 사용 → 기각 (label 문자열 기반 옵션 구조에서 개별 아이템에 스타일 전달 어려움) - 트리 문자(`│`, `├`, `└`) 조합 → 기각 (과도한 시각 정보, 단순 들여쓰기면 충분) ### 3. depth당 3칸 `\u00A0` - **결정**: `"\u00A0\u00A0\u00A0".repeat(depth)` (depth당 3칸) - **근거**: 기존 2칸은 `\u00A0`로 바꿔도 depth간 차이가 작음. 3칸이 시각적 구분에 적절 ### 4. 두 파일 동시 수정 - **결정**: `V2Select.tsx`와 `UnifiedSelect.tsx` 모두 수정 - **근거**: 동일한 `flattenTree` 패턴이 두 컴포넌트에 존재. 하나만 수정하면 불일치 발생 ### 5. 기존 prefix strip 정규식 호환 - **확인**: V2Select.tsx 979행의 `o.label.replace(/^[\s└]+/, "").trim()` - **근거**: JavaScript `\s`는 `\u00A0`를 포함하므로 추가 수정 불필요 --- ## 구현 중 발견한 사항 ### CAT_ vs CATEGORY_ 접두사 불일치 테스트 과정에서 최고 관리자 계정으로 리스트 조회 시 `CAT_MMLL6U02_QH2V` 같은 코드가 그대로 표시되는 현상 발견. - **원인**: 카테고리 값 생성 함수가 두 곳에 존재하며 접두사가 다름 - `CategoryValueAddDialog.tsx`: `CATEGORY_` 접두사 - `CategoryValueManagerTree.tsx`: `CAT_` 접두사 - **영향**: 리스트 해석 로직(`V2Repeater`, `InteractiveDataTable`, `UnifiedRepeater`)이 `CATEGORY_` 접두사만 인식하여 `CAT_` 코드는 라벨 변환 실패 - **판단**: 일반 회사 계정에서는 정상 동작 확인. 본 작업(들여쓰기 표시) 범위 외로 별도 이슈로 분리 --- ## 관련 파일 위치 | 구분 | 파일 경로 | 설명 | |------|----------|------| | 수정 완료 | `frontend/components/v2/V2Select.tsx` | flattenTree 함수 (904행) | | 수정 완료 | `frontend/components/unified/UnifiedSelect.tsx` | flattenTree 함수 (632행) | | 백엔드 (변경 없음) | `backend-node/src/services/tableCategoryValueService.ts` | buildHierarchy 메서드 | | UI 컴포넌트 (변경 없음) | `frontend/components/ui/select.tsx` | SelectItem 렌더링 | | UI 컴포넌트 (변경 없음) | `frontend/components/ui/command.tsx` | CommandItem 렌더링 | --- ## 기술 참고 ### flattenTree 동작 흐름 ``` 백엔드 API 응답 (트리 구조): { valueCode: "CAT_001", valueLabel: "신예철", children: [ { valueCode: "CAT_002", valueLabel: "신2", children: [ { valueCode: "CAT_003", valueLabel: "신22", children: [] } ]}, { valueCode: "CAT_004", valueLabel: "신3", children: [] }, { valueCode: "CAT_005", valueLabel: "신4", children: [] } ] } → flattenTree 변환 후 (SelectOption 배열): [ { value: "CAT_001", label: "신예철" }, { value: "CAT_002", label: "\u00A0\u00A0\u00A0└ 신2" }, { value: "CAT_003", label: "\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0└ 신22" }, { value: "CAT_004", label: "\u00A0\u00A0\u00A0└ 신3" }, { value: "CAT_005", label: "\u00A0\u00A0\u00A0└ 신4" } ] ``` ### value vs label 분리 - `value` (저장값): `valueCode` — DB에 저장되는 값, 들여쓰기 없음 - `label` (표시값): prefix + `valueLabel` — 화면에만 보이는 값, 들여쓰기 포함 - 데이터 무결성에 영향 없음