MD-11공급·매입 / MD🆕 신규 기능

공급사 상품 업로드 자동 그룹핑

공급사 상품 엑셀을 업로드하면 매칭엔진이 행별 top3 후보를 제시하고, MD가 건별로 같음/수정/제외를 확정하는 어드민 기능.

🎯 한눈 결론

  • 무엇을 공급사 상품 엑셀 업로드 → 매칭엔진(이름+중량+원산지+카테고리)이 행별 top3 후보 생성
  • 핵심 원칙 정확도 임계 99.9% 도달 전까지 전건 사람 확인 (top-1 자동확정 없음)
  • MD 조작 건별 같음 / 수정 / 제외 3버튼 · 제외분은 엑셀 재다운로드
  • 오그룹핑 1건이 그룹 매입 단가 기준선을 오염 → 최저가·비교 왜곡 방지가 목표
  • 신규 seller_product_request_item ALTER + 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. 잘못된 그룹핑이 그룹 단가 기준선을 오염(핵심 방지 대상).

정책 규칙

  1. 임계 99.9% 도달 전까지 전건 수동 검수. review_decision 기본값 PENDING.
  2. 신선/수산 카테고리는 정확도와 무관하게 강제 수동. auto_confirm_blocked=true. 🆕
  3. 같음(SAME) → 후보 그룹 확정, group_id·hero_product_code 적용, 감사로그(reviewed_by·reviewed_at) 기록.
  4. 수정(EDIT) → 다른 히어로코드 부여 또는 신규 그룹 생성. review_decision=EDIT.
  5. 제외(EXCLUDE) → 제외 행 엑셀 재다운로드, 공급사 재작업/재견적 표시.
  6. 후보 0건 → 신규 상품 등록 플로우로 라우팅. review_decision=NEW.
  7. 매칭엔진은 공급사 등록 로직 재사용(char n-gram 코사인). 런칭 게이트 = 다중필드(이름+중량+원산지+카테고리) top3 정확도 스파이크 테스트.
  8. 단가 기준선 오염 방지가 1차 목표.
  9. 행별 감사로그 + 배치(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다음 단계

  1. 런칭 게이트: 다중필드(이름+중량+원산지+카테고리) top3 정확도 스파이크 테스트 — 실데이터로 top-1/top-3 정확도 실측. 담당: MD·데이터
  2. 미정의 확정: 위 06 항목, 특히 MD-15 그룹3 흡수/분리 규칙 결정. 담당: 기획
  3. DDL 리뷰: _item ALTER · _match_candidate 신설 스키마 확정 + 인덱스(request_item_id, rank). 담당: BE
  4. 제외 엑셀 양식 확정: 컬럼·파일명·재업로드 흐름. 담당: 기획·MD
  5. 화면 상세: 검수 테이블 필터·정렬·대량처리(전체 같음 등) 스펙 보강. 담당: 기획·FE