샐러드랩
경력근거: 알파앱스는 리뷰 관리(알파리뷰), 상품 추천(알파업셀), CRM(알파푸시) 등 커머스 마케팅 전 과정을 아우르는 통합 프로덕트를 제공합니다.
※ 실제 산출물이 아닌 AI 예측 시안입니다.
공고는 알파앱스를 리뷰 관리(알파리뷰)와 상품 추천(알파업셀), CRM(알파푸시)을 아우르는 통합 제품이라 소개하고 고객사 35,000곳을 확보했다고 적습니다. 리뷰가 낮게 깔린 이유를 상품 상세의 어느 줄에서 찾으려면 리뷰와 상품 상세가 한 계정 안에 같이 있어야 하는데, 그 두 데이터를 함께 쥔 곳이 알파리뷰입니다. 리뷰 위젯만 파는 도구는 별점 평균까지만 말하고 어느 표기를 고치라는 말은 못 합니다. 다만 이 포트폴리오는 두 데이터를 규칙으로 잇고 화면으로 세우는 프런트·백엔드 설계를 보여줍니다. 이커머스 상세 페이지 운영 실무나 반품 정책 전문성은 주장하지 않습니다. 모르는 깊이는 면접에서 모른다고 말하는 편이 낫습니다.
주요 업무에 고객과 실시간으로 소통하는 양방향 채팅·AI 챗봇 개발과 사내 운영 효율을 높이는 인터널 대시보드 설계가 나란히 적혀 있습니다. 판매자가 보는 화면과 사내가 보는 화면을 같은 사람이 만드는 자리입니다.
프론트엔드를 중심으로 필요에 따라 백엔드 영역까지 다루며 프로덕트 전체의 완결성을 책임진다고 적고, 우대사항에 Python 기반 Django·Flask·FastAPI 를 답니다. 화면만 그리고 끝나는 자리가 아닙니다.
우대사항에 LLM API를 활용한 AI 프로덕트 개발 경험과 WebSocket·SSE·폴링 같은 실시간 양방향 통신 구현 경험이 함께 있습니다. 모델을 붙이는 자리와 결과를 흘려보내는 자리를 둘 다 만져 본 사람을 찾습니다.
판매자가 알파리뷰에 쌓인 리뷰와 자사몰 상품 상세, 반품 집계를 함께 올리면 상품마다 무엇을 고쳐야 하는지 판정이 붙습니다. 리뷰가 말한 치수·배송일·옵션·색상을 상세에 적힌 값과 견주는 계산과, 불만 갈래를 반품 사유에 잇는 대응표가 갈래를 정합니다. 모델은 상세의 어느 줄을 어떤 값으로 바꾸면 되는지 판매자가 그대로 옮겨 붙일 수정 문구만 씁니다.
알파리뷰를 붙여 자사몰을 운영하는 이커머스 판매자 — 리뷰는 하루에도 수백 건씩 쌓이지만 화면에는 별점 평균만 보이고, 어떤 상품의 어떤 표기 때문에 낮은 별점이 나오는지는 리뷰를 한 장씩 열어 봐야 알 수 있다
같은 불만이 되풀이되는 이유는 리뷰가 나빠서가 아니라 상세에 적힌 값이 실제와 어긋난 채 오래 남아 있기 때문입니다. 리뷰가 말한 값과 상세에 적힌 값을 상품 단위로 맞춰 두면 판매자는 리뷰를 한 장씩 열지 않고도 고칠 상품과 고칠 줄을 먼저 봅니다.
판매자가 쓰는 화면 하나가 돕니다. 리뷰 내려받기 파일과 상품 상세, 반품 집계를 올리면 상품마다 판정이 붙고 판정별 묶음과 근거가 한 화면에 뜹니다. 1주차는 알파리뷰 API 를 붙이지 않고 관리자 화면에서 내려받은 파일을 그대로 읽는 것으로 시작합니다.
판매자가 손으로 정한 60건으로 판정 일치율을 자동으로 내고, 어긋난 건이 치수 파싱에서 갈라졌는지 반품률 계산에서 갈라졌는지 나눠 리포트로 냅니다. 상세에 그대로 붙일 수정 문구를 모델이 쓰고, 인용한 컬럼이 입력에 없으면 그 응답을 버립니다.
리뷰가 새로 달릴 때마다 받아 오는 수집기를 붙여 사람이 올리지 않아도 매일 아침 판정이 새로 돌고, 판정이 바뀐 상품은 서버가 보낸 이벤트로 화면에 바로 뜹니다.
판매자가 리뷰 파일과 상품 상세를 올리면 고칠 상품이 판정별로 뜨고, 어느 리뷰의 어느 값이 그 판정을 만들었는지 그 자리에서 펼쳐집니다.
받은 날이 안 적힌 리뷰, 치수표가 비어 있는 잡화, 지금 옵션 목록에 없는 옵션명을 섞은 입력 30종을 넣어도 화면이 죽지 않고 그 상품이 왜 판정 없이 남았는지 읽힙니다.
열 이름이 빠지거나 별점 칸이 비거나 인코딩이 깨진 파일 12종을 올려도 목록 대신 어느 줄이 왜 걸렸는지 이슈로 뜨고 나머지 상품은 그대로 판정됩니다.
판매자가 손으로 정한 60건으로 판정 일치율을 냅니다. 단, 리뷰와 정답을 모두 작성자가 만든 합성 기준이라 성능 검증이 아니라 데모 조건 동작입니다.
위 수치는 더미데이터 자가채점이며 실제 적중률은 알파리뷰에 쌓인 실 리뷰와 판매자의 상세 수정 이력이 있어야 측정됩니다. 이 포트폴리오는 그 검증을 바로 돌릴 수 있는 상태로 만듭니다.
판정 일치율은 제가 만든 리뷰에 제가 정답을 붙여 낸 숫자라 성능 증명이 아닙니다. 면접에서는 알파리뷰 실 리뷰를 넣었을 때 치수 파싱이 어디서부터 깨질지로 이야기하겠습니다.
정답을 단 사람과 리뷰를 지어낸 사람이 같아서 잘 맞는 것은 당연합니다. 받은 날이 비어 있는 리뷰, 반품이 0건인 상품, 치수표가 없는 잡화, 지금 옵션 목록에 없는 옵션명으로 달린 리뷰를 더미에 일부러 섞어 쉬운 상품만 골라 푸는 함정을 피합니다.
리뷰가 말한 실측값이 곧 상세가 틀렸다는 뜻은 아닙니다. 재는 자리가 사람마다 다르고 세탁 뒤 줄어든 옷도 섞이므로, 판정을 결론으로 읽지 않게 근거가 된 리뷰 문장을 항상 같이 보여줍니다.
반품률이 높다는 사실과 그 상품의 표기가 틀렸다는 사실은 다른 말입니다. 시즌이 끝나 가는 상품은 표기와 무관하게 반품이 늘므로, 대응표가 겹침으로 이어 준 갈래이면서 반품률이 같은 카테고리 평균의 두 배를 넘을 때만 걸리게 두었습니다.
실제 도입에서는 카테고리마다 상세 양식이 다르고 치수표를 이미지로만 올린 상품이 섞입니다. 이미지 안 표기를 읽는 일은 1주차 범위 밖이라 그 상품은 판정 없이 따로 모아 두고, 읽기 기능은 도입 단계 과제로 분리합니다.
상세 수정 자체는 판매자 계정 권한이 있어야 하므로 이 포트폴리오의 범위 밖입니다. 여기서는 무엇을 어떻게 고칠지 적은 목록을 내는 데까지만 다룹니다.
① 인라인 샘플 · ② seed.json 다운로드 · ③ 증강 프롬프트. 세 층 모두 동일한 schema 에서 파생.
알파리뷰에 쌓인 상품 리뷰입니다. 판정 대상이며, 받은 날이 비어 있는 리뷰와 별점이 최소인 1점 리뷰, 지금 옵션 목록에 없는 옵션명으로 달린 리뷰를 일부러 섞었습니다.
| review_id | product_id | option_name | rating | body | complaint_tag | claimed_value | delivered_days |
|---|---|---|---|---|---|---|---|
| RV-88201 | PRD-10412 | 블랙/M | 2 | 허리가 한 치수 작아요. 재보니 72cm 정도 나옵니다. | 치수 | 허리 72cm | 3 |
| RV-88214 | PRD-10412 | 블랙/M | 2 | 상세에 적힌 허리 76은 아닌 것 같아요. 73밖에 안 됩니다. | 치수 | 허리 73cm | 4 |
| RV-88230 | PRD-10412 | 차콜/L | 3 | 기장은 괜찮은데 허리가 74cm라 좁습니다. | 치수 | 허리 74cm | 2 |
| RV-88238 | PRD-10412 | 차콜/L | 2 | 실측 허리 73cm입니다. 상세 치수와 안 맞습니다. | 치수 | 허리 73cm | 3 |
| RV-88246 | PRD-10412 | 블랙/M | 5 | 핏이 예쁘고 배송도 빨랐습니다. | — | — | 2 |
아래 JSON Schema 에 맞는 리뷰 행을 더 만들어 주세요. {"type":"object","properties":{"review_id":{"type":"string"},"product_id":{"type":"string"},"option_name":{"type":["string","null"]},"rating":{"type":"integer","minimum":1,"maximum":5},"body":{"type":"string"},"complaint_tag":{"type":["string","null"],"enum":["치수","배송","소재","색상","포장",null]},"claimed_value":{"type":["string","null"]},"delivered_days":{"type":["integer","null"],"minimum":0}},"required":["review_id","product_id","option_name","rating","body","complaint_tag","claimed_value","delivered_days"]} 쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: (1) delivered_days 가 null 인 리뷰(받은 날을 안 적음), (2) rating 이 1 또는 5 인 극단 리뷰, (3) 상품의 지금 옵션 목록에 없는 option_name 으로 달린 리뷰, (4) complaint_tag 가 치수인데 claimed_value 에 숫자 대신 '한 치수 작아요' 처럼 말로만 적은 리뷰. 생성한 행은 반드시 위 스키마를 통과해야 하며, 형식을 깨뜨리는 시도는 별도로 3건만 표시해 두세요.{"type":"object","properties":{"review_id":{"type":"string"},"product_id":{"type":"string"},"option_name":{"type":["string","null"]},"rating":{"type":"integer","minimum":1,"maximum":5},"body":{"type":"string"},"complaint_tag":{"type":["string","null"],"enum":["치수","배송","소재","색상","포장",null]},"claimed_value":{"type":["string","null"]},"delivered_days":{"type":["integer","null"],"minimum":0}},"required":["review_id","product_id","option_name","rating","body","complaint_tag","claimed_value","delivered_days"]}자사몰 상품 상세에 지금 적혀 있는 값입니다. 대조의 다른 쪽 축이며, 치수표가 비어 있는 잡화와 옵션이 빠진 뒤로 오래 고치지 않은 상품을 함께 담았습니다.
| product_id | product_name | category | option_list | size_table | material_text | color_text | delivery_days | updated_at |
|---|---|---|---|---|---|---|---|---|
| PRD-10412 | 린넨 와이드팬츠 | 하의 | ["블랙/M","블랙/L","차콜/M","차콜/L"] | M 허리 76 총장 98 / L 허리 80 총장 99 | 겉감 린넨 55% 레이온 45% | 블랙, 차콜 | 3 | 2026-08-21T11:20:00 |
| PRD-10488 | 코튼 오버셔츠 | 상의 | ["아이보리/M","아이보리/L","네이비/M","네이비/L"] | M 어깨 46 총장 74 / L 어깨 48 총장 76 | 면 100% | 아이보리, 네이비 | 2 | 2026-07-02T16:05:00 |
| PRD-10530 | 베이직 니트 | 니트 | ["차콜/FREE","블랙/FREE"] | FREE 어깨 44 총장 60 | 아크릴 70% 울 30% | 차콜, 블랙 | 3 | 2026-03-06T09:40:00 |
| PRD-10577 | 숏패딩 | 아우터 | ["카키/M","카키/L","블랙/M"] | M 어깨 45 총장 62 / L 어깨 47 총장 64 | 겉감 나일론 100% 충전재 오리털 80% | 카키(밝은 올리브), 블랙 | 3 | 2026-08-30T10:15:00 |
| PRD-10604 | 기모 트레이닝팬츠 | 하의 | ["그레이/M","그레이/L","블랙/L"] | M 허리 74 총장 96 / L 허리 78 총장 98 | 면 60% 폴리에스터 40% | 그레이, 블랙 | 3 | 2026-08-12T14:30:00 |
아래 JSON Schema 에 맞는 상품 상세 행을 더 만들어 주세요. {"type":"object","properties":{"product_id":{"type":"string"},"product_name":{"type":"string"},"category":{"type":"string","enum":["상의","하의","아우터","니트","이너","잡화"]},"option_list":{"type":"array","items":{"type":"string"}},"size_table":{"type":["string","null"]},"material_text":{"type":"string"},"color_text":{"type":"string"},"delivery_days":{"type":"integer","minimum":0},"updated_at":{"type":"string"}},"required":["product_id","product_name","category","option_list","size_table","material_text","color_text","delivery_days","updated_at"]} 쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: (1) size_table 이 null 인 잡화 상품, (2) option_list 가 한 값뿐인 단일 옵션 상품, (3) updated_at 이 반년 넘게 지난 상품, (4) size_table 의 구분자가 슬래시·쉼표·줄바꿈으로 서로 다른 상품. 생성한 행은 반드시 위 스키마를 통과해야 하며, 형식을 깨뜨리는 시도는 별도로 3건만 표시해 두세요.{"type":"object","properties":{"product_id":{"type":"string"},"product_name":{"type":"string"},"category":{"type":"string","enum":["상의","하의","아우터","니트","이너","잡화"]},"option_list":{"type":"array","items":{"type":"string"}},"size_table":{"type":["string","null"]},"material_text":{"type":"string"},"color_text":{"type":"string"},"delivery_days":{"type":"integer","minimum":0},"updated_at":{"type":"string"}},"required":["product_id","product_name","category","option_list","size_table","material_text","color_text","delivery_days","updated_at"]}상품별 주문 수와 반품 수, 반품 사유 1위입니다. 리뷰 불만이 실제 반품으로도 이어졌는지 견주는 자리이며, 반품이 0건이라 사유가 비어 있는 상품을 담았습니다.
| product_id | return_reason | return_count | order_count |
|---|---|---|---|
| PRD-10412 | 치수 | 8 | 420 |
| PRD-10488 | 배송지연 | 9 | 310 |
| PRD-10530 | 단순변심 | 6 | 260 |
| PRD-10577 | 색상 | 21 | 250 |
| PRD-10604 | 단순변심 | 7 | 340 |
아래 JSON Schema 에 맞는 반품 집계 행을 더 만들어 주세요. {"type":"object","properties":{"product_id":{"type":"string"},"return_reason":{"type":["string","null"],"enum":["치수","배송지연","색상","소재","단순변심","불량",null]},"return_count":{"type":"integer","minimum":0},"order_count":{"type":"integer","minimum":1}},"required":["product_id","return_reason","return_count","order_count"]} 쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: (1) return_count 가 0 이라 return_reason 이 null 인 상품, (2) order_count 가 세 자리에 못 미치는 소량 판매 상품, (3) 같은 카테고리 안에서 반품률이 평균의 두 배를 넘는 상품, (4) 반품 사유가 단순변심이라 리뷰 불만과 갈래가 다른 상품. 생성한 행은 반드시 위 스키마를 통과해야 하며, 형식을 깨뜨리는 시도는 별도로 3건만 표시해 두세요.{"type":"object","properties":{"product_id":{"type":"string"},"return_reason":{"type":["string","null"],"enum":["치수","배송지연","색상","소재","단순변심","불량",null]},"return_count":{"type":"integer","minimum":0},"order_count":{"type":"integer","minimum":1}},"required":["product_id","return_reason","return_count","order_count"]}리뷰 불만 갈래(complaint_tag)와 반품 사유(return_reason)가 같은 이야기를 하는지 적어 둔 대응표입니다. 두 표가 쓰는 말이 달라서(「배송」과 「배송지연」) 글자로는 이어지지 않고, 「포장」처럼 반품 사유에는 같은 이름이 아예 없는 갈래도 있습니다. 지원자는 두 enum 의 짝을 하나씩 놓고 겹치는지 아닌지를 판매자와 정해 이 표를 만듭니다.
| complaint_tag | return_reason | overlap |
|---|---|---|
| 치수 | 치수 | 겹침 |
| 배송 | 배송지연 | 겹침 |
| 소재 | 소재 | 겹침 |
| 색상 | 색상 | 겹침 |
| 포장 | 불량 | 겹침 |
아래 JSON Schema 에 맞는 대응표 행을 더 만들어 주세요. {"type":"object","properties":{"complaint_tag":{"type":"string","enum":["치수","배송","소재","색상","포장"]},"return_reason":{"type":"string","enum":["치수","배송지연","색상","소재","단순변심","불량"]},"overlap":{"type":"string","enum":["겹침","안 겹침"]}},"required":["complaint_tag","return_reason","overlap"]} 쉬운 데이터만 만들지 말 것 — 다음 하드 케이스를 의도적으로 섞어라: (1) 이름이 다른데 같은 갈래인 짝(배송↔배송지연·포장↔불량)을 반드시 넣습니다, (2) 단순변심처럼 어느 불만과도 겹치지 않는 사유는 모든 complaint_tag 와의 짝을 안 겹침으로 한 줄씩 적어 빠진 짝이 없게 합니다, (3) 이름이 비슷해 헷갈리는 짝(색상↔소재)을 안 겹침으로 넣습니다. 같은 (complaint_tag, return_reason) 짝이 두 번 나오지 않게 합니다.{"type":"object","properties":{"complaint_tag":{"type":"string","enum":["치수","배송","소재","색상","포장"]},"return_reason":{"type":"string","enum":["치수","배송지연","색상","소재","단순변심","불량"]},"overlap":{"type":"string","enum":["겹침","안 겹침"]}},"required":["complaint_tag","return_reason","overlap"]}| TypeScript | 대조 규칙부터 화면까지 한 언어로 씁니다. 치수 문자열에서 뽑은 수치와 일수·비율이 섞이지 않도록 계산 함수마다 단위를 타입으로 박습니다. |
| React | 판매자가 보는 상세 점검 화면입니다. 판정별 묶음과 근거 표를 한 화면에 둡니다. |
| SPA | 상품 목록과 근거를 오가며 다시 그리는 구간이라 페이지 이동 없이 한 화면 안에서 상태를 바꿉니다. |
| FastAPI | 리뷰·상세·반품 파일을 받아 대조를 돌리는 API 서버입니다. 규칙 실행은 이쪽 한 곳에만 둡니다. |
| Python | 치수표 문자열을 옵션별 수치로 쪼개는 파서와 반품률 계산이 여기 있습니다. |
| PostgreSQL | 리뷰·상품 상세·반품 집계를 담는 저장소입니다. 상품 코드에 건 인덱스가 하루치 대조 시간을 좌우합니다. |
| SSE | 3주차에 판정이 바뀐 상품을 화면으로 밀어 보냅니다. 판매자가 새로고침하지 않아도 목록이 갱신됩니다. |
| WebSocket | 여러 사람이 같은 상품을 동시에 볼 때 누가 어떤 상품을 처리 중인지 표시하는 데 씁니다. |
| 디자인 시스템 | 판정 카드와 근거 표를 컴포넌트로 떼어 두고 목록·상세·리포트 세 화면이 같은 부품을 씁니다. |
| LLM | 판정이 정해진 뒤 상세에서 고칠 줄과 바꿔 넣을 값을 한 문장으로 씁니다. 여섯 판정 값에는 손대지 못합니다. |
| Claude | 수정 문구를 쓰는 기본 모델입니다. |
| Claude Code | 치수 파서 시험과 더미데이터 증강 스크립트를 쓰는 데 씁니다. 생성한 코드는 시험을 돌려 확인한 뒤 넣습니다. |
✓ pass → 그대로 멈춰도 완결입니다. 더 키우려면 판매자가 손으로 정한 60건과 판정을 맞춰 보는 단계로 넘어갑니다.
✓ pass → 여기까지도 완결입니다. 더 키우려면 리뷰를 자동으로 받아 오고 판정이 바뀐 상품을 화면으로 밀어 보내는 단계로 확장합니다.
위 예측 UI 는 3주차까지 완주했을 때의 화면입니다. 1주차에 실제로 만드는 것은 아래 표시된 화면 하나입니다.
verdict사유 라벨 · product_id + 한 줄 요약(근거 수치 포함)화면·코드·면접에서 이 단어를 그대로 씁니다. 키는 출력 스키마의 enum 과 같습니다.
표기 맞음표기 맞음치수 표기 어긋남치수 어긋남배송일 표기 초과배송일 초과목록에 없는 옵션없는 옵션소재·색상 표기와 다름소재·색상 다름반품 사유와 겹침반품 사유 겹침상품 하나에 대해 상세에서 무엇을 고칠지 정한 판정과 그 판정을 만든 값을 남기는 형식입니다. 판정 여섯 값은 대조 규칙이 정하고 수정 문구만 모델이 씁니다.
{"type":"object","properties":{"product_id":{"type":"string"},"product_name":{"type":"string"},"verdict":{"type":"string","enum":["표기 맞음","치수 표기 어긋남","배송일 표기 초과","목록에 없는 옵션","소재·색상 표기와 다름","반품 사유와 겹침"]},"complaint_review_count":{"type":["integer","null"],"minimum":0,"description":"그 판정을 만든 리뷰 수입니다. 판정마다 세는 대상이 달라 validation_notes 13번에 갈래별로 적어 두었습니다"},"return_rate_pct":{"type":["number","null"],"minimum":0,"maximum":100,"description":"order_return.return_count ÷ order_count × 100 을 소수 한 자리로 반올림한 값입니다"},"peer_return_rate_pct":{"type":["number","null"],"minimum":0,"maximum":100,"description":"같은 category 의 다른 상품 반품률을 반올림하지 않은 채 평균 낸 뒤 그 평균만 소수 한 자리로 반올림한 값입니다"},"fix_line":{"type":["string","null"],"description":"상세에서 고칠 줄과 바꿔 넣을 값입니다"},"evidence":{"type":"array","items":{"type":"object","properties":{"dataset":{"type":"string"},"field":{"type":"string"},"agg":{"type":["string","null"]},"value":{"type":["string","number","null"]}},"required":["dataset","field","value"]}},"summary":{"type":"string"},"hedge":{"type":["string","null"]}},"required":["product_id","product_name","verdict","evidence","summary"]}[
{
"product_id": "PRD-10604",
"product_name": "기모 트레이닝팬츠",
"verdict": "표기 맞음",
"complaint_review_count": 0,
"return_rate_pct": 2.1,
"peer_return_rate_pct": 2.3,
"fix_line": null,
"evidence": [
{
"dataset": "review",
"field": "rating",
"value": 5
},
{
"dataset": "review",
"field": "complaint_tag",
"value": null
},
{
"dataset": "product_detail",
"field": "size_table",
"value": "M 허리 74 총장 96 / L 허리 78 총장 98"
},
{
"dataset": "order_return",
"field": "return_count",
"value": 7
},
{
"dataset": "order_return",
"field": "order_count",
"value": 340
}
],
"summary": "불만이 달린 리뷰가 없고 반품률 2.1%도 같은 하의 상품 평균 2.3% 아래입니다. 상세에서 고칠 줄이 없습니다.",
"hedge": null
},
{
"product_id": "PRD-10631",
"product_name": "실버 링 귀걸이",
"verdict": "표기 맞음",
"complaint_review_count": 0,
"return_rate_pct": 0,
"peer_return_rate_pct": null,
"fix_line": null,
"evidence": [
{
"dataset": "product_detail",
"field": "size_table",
"value": null
},
{
"dataset": "order_return",
"field": "return_count",
"value": 0
},
{
"dataset": "order_return",
"field": "return_reason",
"value": null
},
{
"dataset": "review",
"field": "rating",
"value": 4
}
],
"summary": "치수표가 비어 있는 잡화라 치수 판정을 건너뜁니다. 반품이 0건이고 같은 잡화 상품이 하나뿐이라 반품률 비교도 하지 않아 그대로 둡니다.",
"hedge": null
},
{
"product_id": "PRD-10412",
"product_name": "린넨 와이드팬츠",
"verdict": "치수 표기 어긋남",
"complaint_review_count": 4,
"return_rate_pct": 1.9,
"peer_return_rate_pct": 2.4,
"fix_line": "상세 치수표 M 허리 76 → 실측 중앙값 72.5, L 허리 80 → 실측 중앙값 73.5 로 다시 재고 고칩니다",
"evidence": [
{
"dataset": "review",
"field": "claimed_value",
"value": "허리 72cm"
},
{
"dataset": "review",
"field": "claimed_value",
"value": "허리 73cm"
},
{
"dataset": "review",
"field": "option_name",
"value": "블랙/M"
},
{
"dataset": "product_detail",
"field": "size_table",
"value": "M 허리 76 총장 98 / L 허리 80 총장 99"
},
{
"dataset": "review",
"field": "review_id",
"agg": "count",
"value": 4
},
{
"dataset": "order_return",
"field": "return_count",
"value": 8
}
],
"summary": "M 리뷰 두 건의 실측 중앙값이 허리 72.5cm, L 두 건이 73.5cm 인데 상세 치수표는 M 76cm·L 80cm 입니다. 반품률 1.9%는 같은 하의 평균 2.4%의 두 배에 못 미쳐 치수 표기 쪽이 먼저 걸립니다.",
"hedge": "리뷰의 실측값은 재는 자리마다 달라질 수 있어 상세를 고치기 전에 판매자가 한 벌을 직접 재 보는 편이 낫습니다."
},
{
"product_id": "PRD-10488",
"product_name": "코튼 오버셔츠",
"verdict": "배송일 표기 초과",
"complaint_review_count": 3,
"return_rate_pct": 2.9,
"peer_return_rate_pct": null,
"fix_line": "상세 배송 안내 '2일 이내' → 최근 리뷰 기준 5일 이상으로 고칩니다",
"evidence": [
{
"dataset": "review",
"field": "delivered_days",
"value": 6
},
{
"dataset": "review",
"field": "delivered_days",
"value": 7
},
{
"dataset": "review",
"field": "delivered_days",
"value": 5
},
{
"dataset": "product_detail",
"field": "delivery_days",
"value": 2
},
{
"dataset": "review",
"field": "review_id",
"agg": "count",
"value": 3
}
],
"summary": "배송일이 적힌 리뷰 3건이 모두 상세에 적힌 2일을 넘겼습니다. 받은 날을 안 적은 리뷰 RV-88288 은 분모에서 뺐고, 같은 상의 상품이 하나뿐이라 반품률 비교는 건너뛰었습니다.",
"hedge": null
},
{
"product_id": "PRD-10530",
"product_name": "베이직 니트",
"verdict": "목록에 없는 옵션",
"complaint_review_count": 2,
"return_rate_pct": 2.3,
"peer_return_rate_pct": 2.7,
"fix_line": "아이보리/FREE 를 옵션에 되살리거나 품절 안내를 상세에 답니다",
"evidence": [
{
"dataset": "review",
"field": "option_name",
"value": "아이보리/FREE"
},
{
"dataset": "product_detail",
"field": "option_list",
"agg": "count",
"value": 2
},
{
"dataset": "product_detail",
"field": "updated_at",
"value": "2026-03-06T09:40:00"
},
{
"dataset": "review",
"field": "review_id",
"agg": "count",
"value": 2
}
],
"summary": "리뷰 2건이 아이보리/FREE 로 달렸는데 지금 옵션은 차콜과 블랙 둘뿐입니다. 상세를 마지막으로 고친 3월 6일 뒤로 아이보리가 빠진 채 리뷰만 남아 있습니다.",
"hedge": null
},
{
"product_id": "PRD-10703",
"product_name": "램스울 가디건",
"verdict": "소재·색상 표기와 다름",
"complaint_review_count": 2,
"return_rate_pct": 2.7,
"peer_return_rate_pct": 2.3,
"fix_line": "상세 소재 '울 100%' 를 실제 혼용률로 다시 적고 보풀 안내를 답니다",
"evidence": [
{
"dataset": "review",
"field": "claimed_value",
"value": "아크릴 느낌"
},
{
"dataset": "review",
"field": "claimed_value",
"value": "보풀 심함"
},
{
"dataset": "product_detail",
"field": "material_text",
"value": "울 100%"
},
{
"dataset": "order_return",
"field": "return_reason",
"value": "단순변심"
},
{
"dataset": "tag_map",
"field": "overlap",
"value": "안 겹침"
},
{
"dataset": "review",
"field": "review_id",
"agg": "count",
"value": 2
}
],
"summary": "소재를 말한 리뷰 2건이 상세의 울 100% 와 어긋납니다. 반품 사유는 단순변심이고 대응표가 그 짝을 안 겹침으로 두어 소재 표기 쪽으로 걸립니다.",
"hedge": "촉감으로 적은 리뷰라 실제 혼용률은 판매자가 소싱처 라벨로 확인해야 갈라집니다."
},
{
"product_id": "PRD-10577",
"product_name": "숏패딩",
"verdict": "반품 사유와 겹침",
"complaint_review_count": 2,
"return_rate_pct": 8.4,
"peer_return_rate_pct": 3.1,
"fix_line": "상세 색상 '카키(밝은 올리브)' 를 실제 촬영본 색으로 바꾸고 조명 안내를 답니다",
"evidence": [
{
"dataset": "review",
"field": "complaint_tag",
"value": "색상"
},
{
"dataset": "order_return",
"field": "return_reason",
"value": "색상"
},
{
"dataset": "tag_map",
"field": "overlap",
"value": "겹침"
},
{
"dataset": "order_return",
"field": "return_count",
"value": 21
},
{
"dataset": "order_return",
"field": "order_count",
"value": 250
},
{
"dataset": "review",
"field": "claimed_value",
"value": "어두운 카키"
}
],
"summary": "리뷰 불만도 색상, 반품 사유도 색상이라 대응표가 두 갈래를 겹침으로 잇고, 반품률 8.4%가 같은 아우터 평균 3.1%의 두 배를 넘습니다. 고쳐서 되돌아오는 금액이 가장 큰 상품이라 먼저 손댑니다.",
"hedge": null
}
][자동 검증 · 코드가 판정합니다] 1. verdict 가 enum 여섯 값(표기 맞음·치수 표기 어긋남·배송일 표기 초과·목록에 없는 옵션·소재·색상 표기와 다름·반품 사유와 겹침) 중 하나인지 확인합니다. 판정은 대조 규칙이 정하므로 모델이 다른 값을 쓰면 그 응답을 버립니다. 2. product_id·product_name·verdict·evidence·summary 다섯 필드가 모두 있는지 확인합니다. 3. return_rate_pct 와 peer_return_rate_pct 가 0 이상 100 이하인지, complaint_review_count 가 0 이상인지 범위를 확인합니다. 4. return_rate_pct 를 order_return.return_count ÷ order_count × 100 으로 다시 계산해 값이 같은지 확인합니다. 반올림은 소수 둘째 자리에서 하고 딱 절반이면 위로 올립니다. 5. peer_return_rate_pct 는 같은 category 의 다른 상품 반품률을 **반올림하지 않은 값 그대로** 평균 낸 뒤, 그 평균만 소수 한 자리로 반올림합니다. 상품마다 먼저 반올림하고 평균을 내면 아우터 평균이 3.1 이 아니라 3.0 이 나와 같은 데이터에서 판정이 갈립니다. 6. evidence 의 field 가 review·product_detail·order_return·tag_map 에 실재하는 컬럼 이름인지 대조합니다. 없는 이름을 인용하면 수정 문구가 지어낸 문장이라는 뜻이라 규칙이 만든 기본 문구로 되돌립니다. 7. agg 가 없는 evidence 값이 그 컬럼에 실제로 수록된 값과 같은지 대조합니다. 여러 리뷰에서 센 수치에는 agg 를 함께 적습니다. 8. summary 와 fix_line 이 존댓말로 끝나는 한국어 문장인지 확인합니다. 9. review.delivered_days 가 비어 있으면 그 리뷰는 배송일 판정의 분모에서 뺍니다. RV-88288 이 조건이 성립한 경우이고, 같은 상품의 RV-88259 는 받은 날이 적혀 있어 성립하지 않은 경우입니다. 10. product_detail.size_table 이 비어 있으면 그 상품의 치수 판정을 건너뜁니다. PRD-10631 이 조건이 성립한 경우이고, PRD-10412 는 치수표가 있어 성립하지 않은 경우입니다. 11. 같은 category 에 다른 상품이 없으면 peer_return_rate_pct 를 비우고 반품 사유 판정을 건너뜁니다. 잡화가 하나뿐인 PRD-10631 과 상의가 하나뿐인 PRD-10488 이 성립한 경우이고, 아우터 셋이 함께 있는 PRD-10577 은 성립하지 않은 경우입니다. 12. 판정 순서는 목록에 없는 옵션, 반품 사유와 겹침, 치수 표기 어긋남, 배송일 표기 초과, 소재·색상 표기와 다름, 표기 맞음 순으로 앞에서 걸리면 뒤를 보지 않습니다. 되돌아오는 금액이 큰 쪽을 앞에 둔 순서입니다. 13. 갈래마다 걸리는 조건과 complaint_review_count 가 세는 대상은 아래와 같습니다. · 목록에 없는 옵션 — option_name 이 그 상품 option_list 에 없는 리뷰가 1건이라도 있으면 걸리고, 그런 리뷰 수를 셉니다. · 반품 사유와 겹침 — 그 상품 리뷰의 complaint_tag 최빈값과 order_return.return_reason 을 tag_map 에서 찾아 overlap 이 「겹침」이고, return_rate_pct 가 peer_return_rate_pct 의 두 배를 넘을 때 걸립니다. 최빈값이 동수면 tag_map 에 먼저 실린 갈래를 씁니다. peer 가 비어 있으면 이 갈래는 건너뜁니다. 그 최빈 갈래로 달린 리뷰 수를 셉니다. · 치수 표기 어긋남 — complaint_tag 가 치수인 리뷰의 claimed_value 에서 부위 이름과 숫자를 뽑고, option_name 의 「/」 뒤 사이즈 키로 size_table 의 같은 사이즈·같은 부위 값과 견줍니다. 값이 다른 리뷰가 3건을 넘을 때 걸리고, 그런 리뷰 수를 셉니다. 사이즈 키가 size_table 에 없는 리뷰는 건너뜁니다. · 배송일 표기 초과 — delivered_days 가 적힌 리뷰 가운데 product_detail.delivery_days 를 넘긴 리뷰가 절반을 넘을 때 걸리고, 넘긴 리뷰 수를 셉니다. · 소재·색상 표기와 다름 — complaint_tag 가 소재 또는 색상인 리뷰가 2건 이상일 때 걸리고, 그 리뷰 수를 셉니다. · 표기 맞음 — 위 다섯 갈래에 하나도 걸리지 않은 상품이며 complaint_review_count 는 0 입니다. 14. fix_line 의 치수 값은 옵션(사이즈)별로 따로 냅니다. 같은 사이즈 리뷰의 실측값 중앙값을 쓰고, 리뷰가 짝수 건이면 가운데 두 값의 평균을 소수 한 자리로 적습니다. 사이즈를 섞어 한 값으로 내면 상세의 어느 줄을 고칠지가 다시 흐려집니다. [평가 러너 · 2주차] 1. 판매자가 손으로 정한 60건으로 판정 일치율을 냅니다. 어긋난 건은 치수 파싱에서 갈라졌는지 반품률 계산에서 갈라졌는지 나눠 리포트에 답니다. [수동 검증 · 사람이 봅니다] 1. 치수 표기 어긋남으로 뜬 상품을 판매자가 실제로 다시 재는지 표본 20건을 따라가 봅니다. 리뷰의 실측값은 재는 자리가 사람마다 달라 상세보다 넓게 나오기도 합니다. 2. tag_map 의 짝을 분기마다 판매자와 다시 봅니다. 포장 불만을 불량 반품으로 볼지 따로 둘지는 몰의 반품 정책에 따라 갈립니다. 3. 배송일 표기를 늘리는 것이 판매에 어떤 영향을 주는지 판매자에게 듣고 판정 기준을 조정할지 정합니다.