PLD-900 · MD-05·06·07·08 · 그룹3
조건별 판매 옵션 — 이벤트 엔진 흡수
히어로 단품 판매가에 수량·업종·업장·지역 조건을 걸어 타겟 업장에게 할인가로 노출합니다. 별도 엔진을 새로 만들지 않고 이벤트 상품 관리(PLD-548) 위에 흡수합니다. 08/13 회의(버기·미스틱) 반영판.
한눈 결론
개요 — 왜 새 엔진이 아니라 흡수인가
그룹3의 미해결 2개를 이벤트 엔진이 이미 풀고 있어, 3~4개만 더하면 완성됩니다.
MD가 요청한 것은 “히어로 단품 판매가를 업장·업종·지역 대상으로 다르게 세팅”입니다(버기). 이는 오늘 배포된 이벤트 상품 관리의 세그먼트 타겟팅과 대부분 겹칩니다. 별도 엔진을 새로 짜면 소스가 이원화되므로, 미스틱 제안대로 이미 개발된 이벤트 엔진 위에 얹습니다(진입점 통합 = 안정성).
정책 / 정의
조건 축 · 유형 · 값/기간 · 최종가 정책 · 상태.
조건 축 → 세그먼트 매핑
| 조건 축(MD 요청) | 이벤트 엔진에서 | 비고 |
|---|---|---|
| 수량 | 🆕 수량 구간 N개 이상 → 추가 할인율 | 가산 · 겹치면 최저가 |
| 업종 | 세그먼트 › 업종 단위 (1차 · 세부) | biz_type 재사용 |
| 업장 | 세그먼트 › 고객 단위(업장 ID) · 엑셀/직접입력 | 기존 판매가 설정과 동일 개념 |
| 지역 | 세그먼트 › 센터 단위(복수) | MFC 과도기 → 센터 매핑 |
이벤트 유형
| 유형 | 내용 | 상태 |
|---|---|---|
| Type A · 판매가 할인 | 단품 하나에 이벤트 판매가(정액/정률). “990원 딜”·“−12%”. 여러 상품을 각각 만들 수 있음. | 이번 차수 |
| Type B · 결합 할인 | 최대 10개 묶음 세트 할인(구성 상품을 모두 담아야 적용). 박스/세트 = 여기서 대체. | 다음 플래닝 |
| Type C · 증정 | N개 구매 시 증정품. (초기 abc 중 c) | 폐기 |
값 · 기간
| 항목 | 옵션 | 계산 / 규칙 |
|---|---|---|
| 할인 값 | 정액(원) / 정률(%) 🆕 | 정액=고정가 · 정률=현재판매가×(1−r/100). 차액=현재가−이벤트가(개당 자사부담). |
| 기간 | 기간 지정 / 상시(무기한) 🆕 | 상시=end_at NULL·상태 always·언제든 즉시 중단. |
| 수량 구간 | 🆕 on/off | N개↑ → 추가 할인율(%) 가산. 앱에 “3개↑ −5%” 안내. |
| 대상 공급사 | 🆕 전체 / 특정 | 같은 상품(그룹코드) 내 공급사별 차등. 특정=supplier_id. |
🆕 쿠폰 · 프라이싱 최종가 정책 08/13 회의 핵심
이벤트 판매가는 이미 상품 마진을 태워 정한 값입니다. 위에 쿠폰·VIP프라이싱·사이렌(신규회원가)·영업 개별가가 겹치면 실결제가 원가·시장가 밑으로 빠질 수 있습니다(바이럴·경쟁사 노출 리스크). 그래서 기본은 추가 할인을 막아 이 판매가를 최종·최상위가로 고정합니다.
| 옵션 | 기본값 | 의미 |
|---|---|---|
coupon_allowed 쿠폰 적용 | false (제외) | 이 상품엔 쿠폰 사용 불가. |
pricing_included 프라이싱 포함 | false (제외) | VIP 프라이싱 · 사이렌 · 영업 개별가 미적용. |
상태 머신
승인 완료 시 노출. 기간 지정=예정→진행중→종료 자동. 상시=승인 후 always 유지, 수량 소진 또는 수동 중단으로 종료.
데이터 모델 (ERD)
신규 5테이블(1 결합은 다음 차수) + 기존 참조.
DDL
Postgres 기준 초안. 🆕 = 그룹3 추가 컬럼/테이블.
-- 조건별 판매(이벤트) 마스터 CREATE TABLE event_sale ( id BIGINT PRIMARY KEY, name VARCHAR(120) NOT NULL, type VARCHAR(1) NOT NULL DEFAULT 'A', -- A:판매가할인, B:결합(다음) value_mode VARCHAR(3) NOT NULL DEFAULT 'amt', -- 🆕 amt:정액, pct:정률 value NUMERIC(12,2), -- 정액=원, 정률=% period_mode VARCHAR(6) NOT NULL DEFAULT 'range',-- 🆕 range/always(상시) start_at TIMESTAMP, end_at TIMESTAMP, -- always면 NULL per_store_limit INT, -- 업장당 구매 한도 total_qty INT, -- 총 판매 수량 auto_end_soldout BOOLEAN DEFAULT TRUE, budget_cap NUMERIC(14,0), -- 자사부담 예산 상한 coupon_allowed BOOLEAN NOT NULL DEFAULT FALSE, -- 🆕 08/13: 기본 제외 pricing_included BOOLEAN NOT NULL DEFAULT FALSE, -- 🆕 VIP/사이렌/영업가 기본 제외 status VARCHAR(12) NOT NULL DEFAULT 'draft', approved_by BIGINT, approved_at TIMESTAMP, created_by BIGINT, created_at TIMESTAMP DEFAULT now() ); -- 대상 상품 · 이벤트 판매가 (단품 기준, 1:N) CREATE TABLE event_sale_product ( id BIGINT PRIMARY KEY, event_sale_id BIGINT NOT NULL REFERENCES event_sale(id), hero_code VARCHAR(20) NOT NULL, -- 단품 group_code VARCHAR(20), -- 같은 상품의 공급사 그룹(식별) base_price NUMERIC(12,2), -- 현재 판매가 스냅샷 event_price NUMERIC(12,2), -- 계산·저장된 이벤트가 supplier_scope VARCHAR(3) DEFAULT 'all',-- 🆕 all/one supplier_id BIGINT -- 🆕 one일 때 특정 공급사 ); -- 🆕 수량(볼륨) 구간 CREATE TABLE event_sale_volume_tier ( id BIGINT PRIMARY KEY, event_sale_id BIGINT NOT NULL REFERENCES event_sale(id), min_qty INT NOT NULL, -- N개 이상 discount_rate NUMERIC(5,2) NOT NULL -- 추가 할인율 % ); -- 타겟 세그먼트 (1:N, seg_type별) CREATE TABLE event_sale_segment ( id BIGINT PRIMARY KEY, event_sale_id BIGINT NOT NULL REFERENCES event_sale(id), seg_type VARCHAR(10) NOT NULL, -- all/customer/biz/center segment_ref_id BIGINT, -- 세그먼트 관리 FK(불러오기) value_json JSONB -- cust:[store_id] / biz:{first,sub[]} / center:[id] );
event_sale_combo_item(Type B 결합)은 다음 차수라 생략. 노출 조회 시 coupon_allowed=false면 장바구니·결제 단계에서 쿠폰/프라이싱 스택을 차단.
화면 흐름 — 등록 모달 (라이브 프로토)
오른쪽 번호가 왼쪽 프로토의 각 블록 설명입니다. 🆕 = 그룹3 추가 · 회색 번호 = 기존 엔진.
- 상품·유형 선택 — 단품 검색 → Type A · 정액/정률 · 기간(지정/상시).
- 조건 설정 — 대상 공급사 · 수량 구간 · 타겟 세그먼트(업종/업장/지역).
- 정책 확인 — 쿠폰/프라이싱 제외(기본) · 예산 상한 · 겹침 경고 확인.
- 승인 요청 → 승인 완료 시 타겟 업장에 최종가로 노출.
정책 · 예외
| 상황 | 처리 |
|---|---|
| 같은 상품에 이벤트 겹침 | 최저가 적용(가장 큰 할인). 동일 유형 겹침은 등록 시 경고. |
| 공급사 여러 + 센터 세그먼트 | 공급사 매칭 센터 ∩ 타겟 센터 교집합에만 노출. |
| 쿠폰 / VIP프라이싱 / 사이렌 / 영업 개별가 | 기본 제외(최종가 고정). 옵션으로 개별 허용. |
| 공급가 · 공급사 정산 | 불변. 할인 차액 = 당사 비용(뒷단). |
| 수량 소진 | auto_end_soldout면 자동 종료. |
| 승인 전 | 노출 안 됨(임시저장/승인대기). 승인 완료 후 노출. |
| Type B(결합) / Type C(증정) | B=다음 플래닝 · C=폐기. |
원본 대비 변경점 — 이벤트 목업 v3.0 → 그룹3 흡수
원본(이벤트 상품 관리 v3.0, 미스틱)이 이미 갖고 있던 것 위에, 그룹3에서 없던 것만 얹었습니다.
화면 나란히 (Before / After)
왼쪽=원본, 오른쪽=흡수판. 오른쪽에만 있는 ②③⑤⑥⑧(보라 🆕)이 이번 추가분입니다. 번호는 프로토 우측 설명 패널과 동일.
A. 원본 그대로 재사용 vs 🆕 흡수판 추가
| 영역 | 원본 v3.0 (재사용) | 🆕 흡수판에서 추가 |
|---|---|---|
| 이벤트 유형 | Type A(판매가 할인) / Type B(결합) | 상태 명확화 — A=이번 차수 · B=다음 · C(증정)=폐기 |
| 할인 값 | 정액(원)만 — 예 990원 | 🆕 정률(%) 토글 (현재가×(1−r/100)) |
| 기간 | 기간 지정(시작~종료, 필수) | 🆕 상시(무기한) 모드 (end 없음·즉시 중단) |
| 대상 상품 | +상품 선택 · 이벤트 판매가 · 현재가→차액 | 단품 명시("그룹 아님") |
| 대상 공급사 | — (없음) | 🆕 전체 / 특정 공급사 + 매칭 센터 교집합 |
| 수량 | 업장당 구매 한도만 | 🆕 수량(볼륨) 구간 — N개↑ 추가 할인율 |
| 타겟 세그먼트 | 전체 / 고객(업장ID) / 업종 / 센터 + 세그먼트 관리 불러오기 + 구매이력·등급 결합 | 그대로 (그룹3의 업종·업장·지역이 이걸로 해결) |
| 가격 정책 | — (없음) | 🆕 쿠폰·프라이싱 최종가 정책 토글 2개 (08/13) |
| 당사부담 모델 | 공급가·정산 불변 · 차액 당사 뒷단 | 그대로 (그룹3의 "부담 주체" 미해결을 이게 해결) |
| 예산 시뮬 · 미리보기 · 승인 · 겹침 경고 | 전부 있음 | 미리보기에 "🔒 최종가" 표기 · 겹침=최저가 문구 |
B. 그룹3(MD-05·06·07·08) 요구 → 어디에 어떻게 녹였나
| 그룹3 요구 | 녹인 위치 | 방식 |
|---|---|---|
| 업장 대상 판매가 세팅 | 타겟 세그먼트 › 고객 단위(업장 ID) | 원본 재사용 |
| 업종 대상 판매가 | 타겟 세그먼트 › 업종 단위 | 원본 재사용 |
| 지역 대상 판매가 | 타겟 세그먼트 › 센터 단위 | 원본 재사용 |
| 수량 조건 (10개↑ %) | 🆕 수량(볼륨) 구간 | 추가 |
| 정률 할인 (%) | 🆕 할인 방식 · 정률 | 추가 |
| 상시 판매 | 🆕 기간 · 상시(무기한) | 추가 |
| 공급사별 차등 | 🆕 적용 대상 공급사 + 교집합 | 추가 |
| 박스/세트 묶음 (복제코드 대체) | Type B · 결합 할인 | 다음 차수 |
| 판매가 / 부담 주체 | 당사부담 모델 | 원본이 이미 해결 |
| 겹치면 최저가 | 겹침 경고 + 최저가 규칙 | 원본+강화 |
| 쿠폰·프라이싱 배제 | 🆕 최종가 정책 토글 | 추가 · 08/13 |
개발 노트
적용/노출 계산 순서 · 승인 권한 · 인덱스 · 롤아웃.
노출 · 가격 적용 순서 (앱 조회 시)
- 대상 상품·공급사 매칭 — event_sale_product의 hero_code(+supplier_scope/supplier_id) 기준 후보 산출.
- 세그먼트 교집합 — 업장이 타겟 세그먼트(고객/업종/센터)에 속하는지 + 공급사 매칭 센터 ∩ 타겟 센터 교집합 확인.
- 기간·상태 필터 — status ∈ {진행중, 상시} 이고 기간 내(상시는 무기한).
- 가격 계산 — 정액=value / 정률=base×(1−value/100). 수량 구간이 켜져 있으면 담은 수량으로 tier 매칭해 추가 할인 가산.
- 겹침 해소 — 같은 상품에 복수 이벤트가 걸리면 최저가 선택.
- 추가 할인 차단 —
coupon_allowed=false/pricing_included=false면 장바구니·결제 단계에서 쿠폰·VIP프라이싱·사이렌·영업개별가 스택을 제외(최종가 고정).
승인 · 권한 · 상태 전이
| 행위 | 권한 | 결과 |
|---|---|---|
| 등록/수정 · 임시저장 | MD | status=draft (노출 안 됨) |
| 승인 요청 | MD | draft → pending |
| 승인 | 승인권자(전략/책임) | pending → scheduled/running(또는 always) |
| 즉시 중단 | MD/승인권자 | running/always → stopped (노출 즉시 내림) |
인덱스 · 마이그레이션 · 롤아웃
- 인덱스 —
event_sale(status, start_at, end_at)·event_sale_product(hero_code, supplier_id)·event_sale_segment(event_sale_id, seg_type). 앱 조회는 hero_code→활성 이벤트 역인덱스가 핵심. - 마이그레이션 — 신규 테이블만 추가(기존 스키마 무변경). 이벤트 엔진(PLD-548) 위 확장이라 파괴적 마이그레이션 없음.
- 롤아웃 — 이번 차수 Type A만. 겹침=최저가·정책 기본 제외로 배포 → 데이터 관찰 후 Type B(결합)·조건축 세그먼트 완전 통합은 다음 플래닝.
- API 개요 — 목록/상세/생성/수정/승인/중단 + 앱 노출조회(hero_code·업장 컨텍스트 → 적용가·정책 플래그).
오픈 이슈 · 다음 단계
- 판매가 = 그룹 단위 하나인지, 공급사별로 다른지 최종 확인.
- 월 구매량별 조건은 다음 차수로 미뤄도 되는지(현재 수량=단건 볼륨).
- 권역(센터 묶음) 정의 기준 — MFC 과도기 반영.
- 공급사 협의 범위 — DC 매입 상품 한정 여부.
라이브 프로토: md-group3-absorb.pages.dev · 원본(05·06·08): md-group3-app.pages.dev