10 KiB
10 KiB
[맥락노트] 품번 수동 접두어 채번 - 접두어별 독립 순번 생성
왜 이 작업을 하는가
- 기준정보 - 품목정보 등록 모달에서 품번 인풋에 사용자가 값을 입력해도 무시되고 "BULK1"로 저장됨
- 서로 다른 접두어("ㅁㅁㅁ", "ㅇㅇㅇ")를 입력해도 전부 같은 시퀀스 카운터를 공유함
- 카테고리 미선택 시
--제발-015-003처럼 연속 구분자가 발생함 - 사용자 입력이 반영되고, 접두어별로 독립된 순번이 부여되어야 함
핵심 결정 사항과 근거
1. 수동 값 추출을 buildPrefixKey 전으로 이동
- 결정:
allocateCode내부에서 수동 값 추출 → buildPrefixKey 순서로 변경 - 근거: 기존에는 buildPrefixKey(L1306)가 먼저 실행된 후 수동 값 추출(L1332)이 진행됨. 수동 값이 prefix_key에 포함되려면 추출이 먼저 되어야 함
- 대안 검토: buildPrefixKey 내부에서 직접 추출 → 기각 (역할 분리 위반, previewCode 호출에도 영향)
2. buildPrefixKey에 수동 파트 값 포함
- 결정:
manualValuesoptional 파라미터 추가, 전달되면 prefix_key에 포함 - 근거: 기존
continue(L85-87)로 수동 파트가 prefix_key에서 제외되어 모든 접두어가 같은 시퀀스를 공유함 - 하위호환: optional 파라미터이므로
previewCode(L1091) 등 기존 호출부는 영향 없음
3. 템플릿 파싱 실패 시 userInputCode 전체를 수동 값으로 사용
- 결정: 수동 파트가 1개이고 템플릿 기반 추출이 실패하면
userInputCode전체를 수동 값으로 사용 - 근거: 사용자가 "ㅁㅁㅁ"처럼 접두어 부분만 입력하면 템플릿 "카테고리값-____-XXX"와 불일치.
startsWith조건 실패로 추출이 안 됨. 이 경우 입력 전체가 수동 값임 - 제한: 수동 파트가 2개 이상이면 이 폴백 불가 (어디서 분리할지 알 수 없음)
4. 코드 조합에서 manualConfig.value 폴백 제거
- 결정:
extractedManualValues[i] || part.manualConfig?.value || ""→extractedManualValues[i] || "" - 근거:
manualConfig.value는 UI에서 입력/편집할 수 없는 유령 필드.ManualConfigPanel.tsx에value입력란이 없어 DB에 한번 저장되면 스프레드 연산자로 계속 보존됨 - 이중 조치: 코드에서 폴백 제거 + DB 마이그레이션으로 기존 "BULK1" 값 정리
5. DB 마이그레이션은 BULK1만 타겟팅
- 결정:
manual_config->>'value' = 'BULK1'조건으로 한정 - 근거: 다른 value가 의도적으로 설정된 경우가 있을 수 있음. 확인된 문제("BULK1")만 정리하여 부작용 방지
- 대안 검토: 전체
manual_config.value키 제거 → 보류 (운영 판단 필요)
6. extractManualValuesFromInput 헬퍼 분리
- 결정: 기존
allocateCode내부의 수동 값 추출 로직(L1332-1442)을 별도 private 메서드로 추출 - 근거: 추출 로직이 약 110줄로
allocateCode가 과도하게 비대함. 헬퍼로 분리하면 순서 변경도 자연스러움 - 원칙: 로직 자체는 변경 없음, 위치만 이동 (구조적 변경과 행위적 변경 분리)
7. 프론트엔드 변경 불필요
- 결정: 프론트엔드 코드 수정 없음
- 근거:
_numberingRuleId가 사용자 입력 시에도 유지되고 있음 확인.buttonActions.ts가 정상적으로allocateCode를 호출함. 문제는 백엔드 로직에만 있음
8. joinPartsWithSeparators 연속 구분자 방지
- 결정: 빈 파트 뒤에 이미 같은 구분자가 있으면 중복 추가하지 않음
- 근거: 카테고리가 비면 파트 값
""+ 구분자-가 반복되어--발생. 구분자 구조(-ㅁㅁㅁ-001)는 유지하되 연속(--)만 방지 - 조건:
if (val || !result.endsWith(sep))— 값이 있으면 항상 추가, 값이 없으면 이미 같은 구분자로 끝나면 스킵
9. 템플릿 카테고리/참조 플레이스홀더를 실제값으로 변경
- 결정:
extractManualValuesFromInput내부의 카테고리/참조 빈 값 반환을"CATEGORY"/"REF"→""로 변경 - 근거: 실제 코드 생성에서 빈 카테고리는
""인데 템플릿에서"CATEGORY"를 쓰면 구조 불일치로 추출 실패. 로그로 확인:userInputCode=-제발-015, previewTemplate=CATEGORY-____-XXX, extractedManualValues=[] - 카테고리 있을 때:
catMapping2?.format반환은 수정 전후 동일하여 영향 없음
관련 파일 위치
| 구분 | 파일 경로 | 설명 |
|---|---|---|
| 수정 대상 | backend-node/src/services/numberingRuleService.ts |
joinPartsWithSeparators(L36), buildPrefixKey(L75), extractManualValuesFromInput(신규), allocateCode(L1296) |
| 신규 생성 | db/migrations/1053_remove_bulk1_manual_config_value.sql |
BULK1 유령 값 정리 마이그레이션 |
| 변경 없음 | frontend/components/screen/widgets/TextInputComponent.tsx |
_numberingRuleId 유지 확인 완료 |
| 변경 없음 | frontend/lib/registry/components/numbering-rule/config.ts |
채번 설정 레지스트리 |
| 변경 없음 | frontend/components/screen/config-panels/NumberConfigPanel.tsx |
채번 규칙 설정 패널 |
| 참고 | backend-node/src/controllers/numberingRuleController.ts |
allocateNumberingCode 컨트롤러 |
기술 참고
allocateCode 실행 순서 (변경 전 → 후)
변경 전: buildPrefixKey(L1306) → 시퀀스 할당 → 수동 값 추출(L1332) → 코드 조합
변경 후: 수동 값 추출 → buildPrefixKey(수동 값 포함) → 시퀀스 할당 → 코드 조합
prefix_key 구성 (변경 전 → 후)
변경 전: "카테고리값" (수동 파트 무시, 모든 접두어가 같은 키)
변경 후: "카테고리값|ㅁㅁㅁ" (수동 파트 포함, 접두어별 독립 키)
폴백 체인 (변경 전 → 후)
변경 전: extractedManualValues[i] || manualConfig.value || ""
변경 후: extractedManualValues[i] || ""
joinPartsWithSeparators 연속 구분자 방지 (변경 전 → 후)
변경 전: "" + "-" + "" + "-" + "ㅁㅁㅁ" → "--ㅁㅁㅁ"
변경 후: "" + "-" (이미 "-"로 끝남, 스킵) + "ㅁㅁㅁ" → "-ㅁㅁㅁ"
템플릿 정합성 (변경 전 → 후)
변경 전: 카테고리 비었을 때 템플릿 = "CATEGORY-____-XXX" / 입력 = "-제발-015" → 불일치 → 추출 실패
변경 후: 카테고리 비었을 때 템플릿 = "-____-XXX" / 입력 = "-제발-015" → 일치 → 추출 성공
10. 실시간 순번 미리보기 구현 방식
- 결정: V2Input에서
manualInputValue변경 시 디바운스(300ms)로 preview API를 재호출하여 suffix(순번)를 갱신 - 근거: 기존 preview API는
manualInputValue없이 호출되어 모든 접두어가 같은 기본 순번을 표시함. 접두어별 정확한 순번을 보여주려면 preview 시점에도 수동 값을 전달하여 해당 prefix_key의 시퀀스를 조회해야 함 - 대안 검토: 프론트엔드에서 카운트 API를 별도 호출 → 기각 (기존
previewCode흐름 재사용이 프로젝트 관행에 부합) - 디바운스 300ms: 사용자 타이핑 중 과도한 API 호출 방지. 프로젝트 기존 패턴(검색 디바운스 등)과 동일
11. previewCode에 manualInputValue 전달
- 결정:
previewCode시그니처에manualInputValue?: string추가,buildPrefixKey에[manualInputValue]로 전달 - 근거:
buildPrefixKey가 이미manualValuesoptional 파라미터를 지원하므로 자연스럽게 확장 가능. 순번 조회 시 접두어별 독립 시퀀스를 정확히 반영함 - 하위호환: optional 파라미터이므로 기존 호출(
formData만 전달)에 영향 없음
12. 초기 상태에서 레거시 시퀀스 조회 방지
- 결정:
previewCode에서 수동 파트가 있는데manualInputValue가 없으면 시퀀스 조회를 건너뛰고currentSeq = 0사용 - 근거: 수정 전에는 모든 할당이 수동 파트 없는 공용 prefix_key를 사용했으므로 레거시 시퀀스가 누적되어 있음(예: 16). 모달 초기 상태에서 이 공용 키를 조회하면
-016이 표시됨. 아직 어떤 접두어인지 모르는 상태이므로startFrom기본값을 보여주는 것이 정확함 currentSeq = 0+startFrom:nextSequence = 0 + startFrom(5) = 5→-005표시. 사용자가 입력하면 디바운스 preview가 해당 접두어의 실제 시퀀스를 조회
13. 카테고리 변경 시 수동 입력값 포함하여 순번 재조회
- 결정: 초기 useEffect(카테고리 변경 트리거)에서
previewNumberingCode호출 시 현재manualInputValue도 함께 전달 - 근거: 카테고리를 바꾸거나 삭제하면 prefix_key가 달라지므로 순번도 달라져야 함. 기존에는 입력값 변경과 카테고리 변경이 별도 트리거여서 카테고리 변경 시 수동 값이 누락됨
- 빈 입력값 처리:
manualInputValue || undefined로 처리하여 빈 문자열일 때는 기존처럼skipSequenceLookup작동
14. 카테고리 해석 로직 resolveCategoryFormat 헬퍼 통합
- 결정:
previewCode,allocateCode,extractManualValuesFromInput3곳에 복붙된 카테고리 매핑 해석 로직을resolveCategoryFormatprivate 메서드로 추출 - 근거: 동일 로직 약 50줄이 3곳에 복사되어 있었음 (변수명만 pool2/ct2/cc2 등으로 다름). 한 곳을 수정하면 나머지도 동일하게 수정해야 하는 유지보수 위험
- 원칙: 구조적 변경만 수행 (로직 변경 없음)
BULK1이 DB에 남아있는 이유
ManualConfigPanel.tsx: placeholder 입력란만 존재 (value 입력란 없음)
플레이스홀더 수정 시: { ...existingConfig, placeholder: newValue }
→ 기존 config에 value: "BULK1"이 있으면 스프레드로 계속 보존됨
→ UI에서 제거 불가능한 유령 값