공급사 상품 업로드 자동 그룹핑
공급사 상품 엑셀을 업로드하면 매칭엔진이 행별 top3 후보를 제시하고, MD가 건별로 같음/수정/제외를 확정하는 어드민 기능.
🎯 한눈 결론
- 무엇을 공급사 상품 엑셀 업로드 → 매칭엔진(이름+중량+원산지+카테고리)이 행별 top3 후보 생성
- 핵심 원칙 정확도 임계 99.9% 도달 전까지 전건 사람 확인 (top-1 자동확정 없음)
- MD 조작 건별 같음 / 수정 / 제외 3버튼 · 제외분은 엑셀 재다운로드
- 왜 오그룹핑 1건이 그룹 매입 단가 기준선을 오염 → 최저가·비교 왜곡 방지가 목표
- 신규
seller_product_request_itemALTER +seller_product_match_candidate신설 - 영구 수동 신선/수산은 임계 도달과 무관하게 자동확정 차단
01개요
공급사가 취급하는 상품을 오더히어로 운영 그룹(히어로코드)에 연결하는 작업은 지금까지 수작업 매칭에 의존한다. 이 티켓은 공급사 상품 엑셀을 올리면 1차 자동 그룹핑이 돌아 행별 후보를 제시하고, MD가 검수 화면에서 건별로 확정하는 흐름을 만든다.
단, 매칭엔진의 현재 top-1 정확도(이름만 ≈75%, 이름+중량 ≈86%)는 자동확정 기준(99.9%)에 못 미친다. 따라서 이번 릴리즈의 기본 정책은 후보 제시 + 전건 사람 확인이며, 자동확정은 정확도 스파이크 테스트 통과 후 카테고리별로 단계 개방한다.
⚠️ 이 기능의 존재 이유: 오그룹핑 1건이 그룹의 매입 단가(net supplier price) 기준선을 오염시켜 그룹 최저가·가격 비교를 왜곡한다. 잘못 묶인 단가 1개가 전체 그룹 판단을 흐리므로, 임계 전 전건 확인이 1차 방어선이다.
02정책 · 정의
용어
| 용어 | 정의 |
|---|---|
| 자동 그룹핑 | 업로드 공급사 행을 운영 그룹에 매핑. 임계 전까지는 후보 제시만 하고 확정은 MD가 한다. |
| 히어로코드 | 표준 상품 ID(hero_product_code). 여러 공급사를 한 그룹으로 묶어 가격 비교 기준선을 만든다. |
| 매칭 후보 top3 | 엔진이 순위화한 최대 3개 그룹 후보. top-1도 ≈86%라 자동확정 불가. |
| 임계 99.9% | 이 아래면 MD 수동 검수 필수. 현재 엔진은 미달 → 전건 수동이 기본 표준. |
| 매입 단가 | net supplier price. 잘못된 그룹핑이 그룹 단가 기준선을 오염(핵심 방지 대상). |
정책 규칙
- 임계 99.9% 도달 전까지 전건 수동 검수.
review_decision기본값PENDING. - 신선/수산 카테고리는 정확도와 무관하게 강제 수동.
auto_confirm_blocked=true. 🆕 - 같음(SAME) → 후보 그룹 확정,
group_id·hero_product_code적용, 감사로그(reviewed_by·reviewed_at) 기록. - 수정(EDIT) → 다른 히어로코드 부여 또는 신규 그룹 생성.
review_decision=EDIT. - 제외(EXCLUDE) → 제외 행 엑셀 재다운로드, 공급사 재작업/재견적 표시.
- 후보 0건 → 신규 상품 등록 플로우로 라우팅.
review_decision=NEW. - 매칭엔진은 공급사 등록 로직 재사용(char n-gram 코사인). 런칭 게이트 = 다중필드(이름+중량+원산지+카테고리) top3 정확도 스파이크 테스트.
- 단가 기준선 오염 방지가 1차 목표.
- 행별 감사로그 + 배치(
seller_product_request) 성공/실패 카운트 갱신.
review_decision 상태값
| 값 | 의미 | 후속 |
|---|---|---|
PENDING | 기본 · 검수 대기 | — |
SAME | 후보 확정 · 그룹핑 완료 | group_id·hero코드 적용 |
EDIT | 다른/신규 코드 부여 | hero_code_mapping 동기화 |
EXCLUDE | 보류 · 재다운로드 대상 | 공급사 재작업 |
NEW | 후보 0건 · 신규등록 | 신규 등록 플로우 |
03데이터 모델 🆕
seller_product_request (READ · 기존)
id PK · seller_id · status · total_count · success_count · fail_count
│
│ 1 ─< N
▼
seller_product_request_item (ALTER · 컬럼 추가)
id PK · request_id FK · group_id · hero_product_code · main_product_name
weight · net_price
+ review_decision varchar(20) default 'PENDING'
+ top_match_score numeric(5,2)
+ auto_confirm_blocked boolean default false
+ reviewed_by varchar(50)
+ reviewed_at timestamp
│
│ 1 ─< N (max 3)
▼
seller_product_match_candidate (NEW · 신설)
id PK bigserial · request_item_id FK · rank(1~3)
group_id · hero_product_code · candidate_name · weight
score numeric(5,2) · match_field(NAME|NAME_WEIGHT|FULL) · created_at
READ 참조: hero_code_mapping(히어로코드 ↔ 4종 관리코드) · seller_product(후보 생성 소스)
🆕 이번 티켓 변경분:
seller_product_request_item에 검수 컬럼 5개 ALTER, seller_product_match_candidate 테이블 신설. seller_product_request는 기존 컬럼 재사용(추가 없음).ALTER / DDL (초안)
-- seller_product_request_item : 검수 컬럼 추가 ALTER TABLE seller_product_request_item ADD COLUMN review_decision varchar(20) DEFAULT 'PENDING', ADD COLUMN top_match_score numeric(5,2), ADD COLUMN auto_confirm_blocked boolean DEFAULT false, ADD COLUMN reviewed_by varchar(50), ADD COLUMN reviewed_at timestamp; -- seller_product_match_candidate : 신설 (행별 top3) CREATE TABLE seller_product_match_candidate ( id bigserial PRIMARY KEY, request_item_id bigint NOT NULL REFERENCES seller_product_request_item(id), rank smallint NOT NULL, -- 1~3 group_id bigint, hero_product_code varchar(50), candidate_name varchar(255), weight varchar(50), score numeric(5,2) NOT NULL, match_field varchar(20) NOT NULL, -- NAME | NAME_WEIGHT | FULL created_at timestamp DEFAULT now() );
04데이터 흐름
1
엑셀 업로드 → 배치 생성
업로드 1건 =
seller_product_request 1건. 행은 _item으로 적재, 필수 열 검증.2
1차 자동 그룹핑 (비동기)
매칭엔진이 행별 top3 산출 →
_match_candidate 저장, top-1 점수를 item.top_match_score에 기록. 신선/수산 행은 auto_confirm_blocked=true.3
검수 화면 진입
MD가 업로드 행·후보·신뢰도를 확인. 차단 행 배지 노출.
4
건별 확인 (같음/수정/제외)
같음=후보 확정·코드 적용·감사로그. 수정=다른/신규 코드. 제외=보류. 후보 0건=신규등록.
5
제외분 재다운로드 · 배치 마감
EXCLUDE 행 엑셀 내보내기, 배치 success/fail 카운트 갱신.
05화면 흐름 · 프로토타입
아래는 어드민 셸 안에서 이 티켓 화면(업로드 → 검수·그룹핑 → 결과·제외분)을 배치한 클릭 프로토타입이다. 우측 번호 핀(①~⑧)이 "여기서 개발할 것"과 연결된다.
↑ 프로토타입 임베드. 업로드 드롭존 클릭 → 검수 탭 → 행별 같음/수정/제외 조작 가능. (넓은 화면에서 우측 설명 패널 표시)
06⭐ 미정의 항목
스펙에 정해지지 않은 항목. 프로토는 아래 가정으로 구성했으며, 실제 확정 값은 별도 결정이 필요하다. (추측을 확정으로 쓰지 않음)
MD-15 연계그룹3 흡수 / 분리 규칙 (핵심 미정의)
자동 그룹핑 결과가 그룹3(행사·판매 그룹)에 어떻게 흡수/분리되는지가 MD-15의 핵심 미정의다. 그룹핑된 히어로코드가 그룹3 정책과 어떤 관계를 갖는지 확정 전까지, 이 프로토는 그룹핑=히어로코드 매핑까지만 다루고 그룹3 연동은 표시하지 않았다.
프로토 가정: 그룹3 연동은 범위 밖 (MD-15에서 결정)
임계자동확정 단계 개방 순서
99.9% 도달 후 자동확정을 카테고리별 단계적으로 풀지, 전체 일괄로 풀지 미정.
프로토 가정: 카테고리별 단계 개방, 신선/수산은 영구 수동
차단신선/수산 영구 차단 여부
신선/수산의
auto_confirm_blocked이 영구인지, 별도 임계 도달 시 해제되는지 미정.프로토 가정: 영구 수동 (단가 오염 리스크)
엑셀제외분 재다운로드 양식
EXCLUDE 엑셀의 컬럼 구성(원본 열만? 제외 사유·후보 점수 포함?)과 파일명 규칙 미정.
프로토 가정: 원본 열 + 제외 사유 열, 다운로드 버튼만 제공
라우팅신규등록 플로우 연결 지점
review_decision=NEW / 수정-신규 생성이 어느 등록 화면으로 연결되는지, 같은 배치 내 처리인지 별도 화면인지 미정.프로토 가정: 상태 표시만, 실제 화면 이동은 미연결
엔진매칭 필드 가중치
이름/중량/원산지/카테고리 각 가중치와
match_field 판정 컷오프(어느 점수부터 FULL인지) 미정. 스파이크 테스트로 결정 예정.프로토 가정: 점수는 예시값, match_field는 필드 조합으로 라벨
권한검수자 권한 범위
reviewed_by에 기록될 검수 가능 역할(MD 전원? 특정 권한?)과 재검수/되돌리기 권한 미정.프로토 가정: morty(MD) 단일, 되돌리기 허용
배치동시성 · 중복 업로드
같은 공급사 상품을 중복 업로드했을 때 처리(덮어쓰기/병합/차단)와 검수 중 재업로드 동시성 미정.
프로토 가정: 다루지 않음
07다음 단계
- 런칭 게이트: 다중필드(이름+중량+원산지+카테고리) top3 정확도 스파이크 테스트 — 실데이터로 top-1/top-3 정확도 실측. 담당: MD·데이터
- 미정의 확정: 위 06 항목, 특히 MD-15 그룹3 흡수/분리 규칙 결정. 담당: 기획
- DDL 리뷰:
_itemALTER ·_match_candidate신설 스키마 확정 + 인덱스(request_item_id, rank). 담당: BE - 제외 엑셀 양식 확정: 컬럼·파일명·재업로드 흐름. 담당: 기획·MD
- 화면 상세: 검수 테이블 필터·정렬·대량처리(전체 같음 등) 스펙 보강. 담당: 기획·FE