모음전 자동화 ⌂ 홈

모음전 · 내부 교육자료

데이터는 어떻게 수집·가공·전송되는가

소싱처에서 가격·재고를 긁어(수집), 저장·계산으로 다듬어(가공), 판매처로 내보내기(전송)까지의 전체 흐름과 — 각 단계가 코드 어디에 있고, 어떻게 불리고, 무엇에 쓰이는지를 한 곳에 정리했습니다.

읽는 법: 각 장의 줄글 설명으로 그림을 잡고, 코드 지도 표파일:라인으로 실제 위치를 찾습니다.

전체 그림 — 네 단계


소싱처 상품 하나의 값이 화면·판매처까지 가는 길은 수집 → 가공 → 전송 세 단계이고, 이 전부를 자동화 스케줄러가 주기적으로 돌립니다. 맨 아래 파란 줄은 "같은 값은 한 곳에서만 만든다"는 공유 원칙입니다.

그림 1. 세로 계층 흐름도 (자동화가 위에서 구동, 왼쪽 단계를 따라 아래로)

자동화 스케줄러 · full_cycle 반복 (수집 → 가공 → 전송) 수집 서버 크롤르무통 · SSF · SSG (무로그인) 크롬 확장 크롤무신사 · 스스 · 롯데온 (로그인) 가공 DB 저장재고·가격·혜택 계산 엔진표면가 − 혜택 화면 표시매트릭스·영수증 전송 가격 결정마켓별 포매팅스스·쿠팡 업로드드라이런 판매처전송 대기 단일 진실 원천 — 한 값을 여러 화면이 공유 표면가 = last_price 매입가 = compute_market_price 표시가 = 업로드가

1수집 — 소싱처에서 값을 긁는다


소싱처마다 로그인이 필요한지에 따라 크롤 경로가 둘로 갈립니다. 로그인이 필요 없는 곳은 서버가 직접, 로그인이 필요한 곳(회원가·회원할인)은 로그인된 크롬 확장이 긁습니다. 경로는 둘이어도 저장 종착지는 같은 테이블 하나입니다.

  • 서버 크롤 확장이 페이지 HTML만 떠서 서버로 보내면, 서버의 소싱처별 파서가 재고·표면가·혜택을 추출합니다.
  • 확장 크롤 로그인 세션이 있는 브라우저에서 확장이 직접 값을 뽑아 서버로 보냅니다(회원가가 보이는 이유).
노드코드 위치어떻게 불림쓰임
서버 크롤
르무통·SSF·SSG·현대H몰·롯데아이몰·스마트스토어
파서 crawlers/<소싱처>.py (parse_html)
서버 진입 api_sources_parse.py:38 parse_source_html
확장이 HTML 수집 → POST /api/sources/parse
(BG_PARSE_SOURCES background.js:825)
파서 추출 → service.py:707 save_crawl_result(=_ingest)로 저장
확장 크롤
무신사·롯데온
추출기 background.js:93 EXTRACTORS
crawlItemInTabBG:1112toItemBG:1181
로그인 페이지에서 JS 직접 추출 → POST /api/sources/crawl-result
(BG_JS_SOURCES :826)
api_pricing.py:1367 save_crawl_result + persist_crawled_options 저장

2가공 — 저장하고, 계산하고, 보여준다


긁어온 값은 그대로 쓰지 않습니다. 먼저 DB에 저장하고, 모든 소싱처 공통 공식 "표면 노출가 − 혜택 = 최종 매입가"로 계산한 뒤, 화면에는 두 값을 나눠 보여줍니다(셀의 큰 숫자=최종매입가, 작은 글씨=표면가).

노드코드 위치어떻게 불림쓰임
DB 저장 모델 sources/models.py:21 SourceProduct · :59 SourceOption
upsert service.py:104 / :159
혜택 화이트리스트 OPTION_DYNAMIC_KEYS service.py:605
두 수집 경로가 공통 호출 재고 current_stock·표면가 last_price·혜택 dynamic_benefits_json 영속
계산 엔진 api_benefits.py:417 compute_breakdown
final_price.py:236 compute_final_price
unified.py:257 compute_market_price
셀 fx·영수증 → /api/source-benefits/breakdown(s)
스케줄러·재고관리도 공유
혜택 키를 표면가에서 순서대로 차감 → 최종매입가
화면 표시 api_pricing.py:453 _option_matrix_data
:1230 GET /option-matrix · :231 _resolve_stock
템플릿 bundles/_matrix_v3.html
페이지 로드 시 1회 /option-matrix fetch → window.DATA 캐시 셀(표면가+최종매입가)·재고·영수증·크롤 로그 렌더
핵심 공식 — 페이지에 크게 적힌 값이 표면 노출가, 거기서 받을 수 있는 혜택(적립·할인·쿠폰·카드)을 순서대로 빼면 최종 매입가(우리가 실제로 사는 값). %혜택은 항상 베이스금액 기준.

3전송 — 판매처(쿠팡·스마트스토어)로 내보낸다


저장·계산된 값이 판매처로 나가는 길입니다. 가격 결정 → 포매팅 → 업로드 3단계이고, 이 전부를 자동화 스케줄러가 full_cycle로 묶어 돌립니다. 지금은 안전을 위해 실제 전송은 꺼둔 상태(드라이런)입니다 — 값 검증만 하고 마켓엔 아무것도 안 올립니다.

노드코드 위치어떻게 불림쓰임
가격 결정 (B) pricing/engine.py:11 run_pricing_engine
ss_decide.py:7 · coupang_decide.py:28
정책 templates/models.py PriceTemplate
full_cycle Phase B 원가+마진+수수료+반올림 → 마켓별 판매가
포매팅 (C) formatter/pipeline.py:10 run_formatter
build_smartstore_payload:8 · build_coupang_payload:7
full_cycle Phase C 결정가 → 마켓 API 페이로드(dict)
업로드 (D) uploader/orchestrator.py:59 run_uploader
런타임 uploader/runtime.py(select_adapters:40·build_sku_by_option:56·DryRun)
드라이런 dryrun.py:16 · 결과 uploader/models.py:10 MarketRegistration
연결 sets/models.py SetChannel:85 · SetChannelOption:113
full_cycle Phase D
안전 플래그 MOUM_LIVE_UPLOAD (기본 OFF→드라이런)
변동분만 마켓 PUT(현재 드라이런) → 성공 등록 / 실패 DLQ
자동화 스케줄러 scheduler/main.py:54 start_scheduler
scheduler/jobs.py:16 full_cycle
앱 부팅 시 시작, 60초 연속 반복 A수집 → B가격 → C포맷 → D업로드 오케스트레이션

4단일 진실 원천 — 같은 값은 한 곳에서만


가장 중요한 원칙입니다. 같은 값을 두 곳에서 따로 만들면 반드시 어긋나고, 어긋난 가격·재고는 곧 금전 손실입니다. 그래서 표면가·최종매입가·표시가를 각각 한 곳에서만 산출하고 나머지는 그걸 읽기만 합니다.

한 곳 원천공유처
표면가SourceProduct.last_price / SourceOption.current_price셀·크롤 로그·계산 입력
최종매입가compute_market_price / compute_breakdown매트릭스·스케줄러·재고관리·업로드 미리보기
프론트 캐시window.DATA + SM_BREAKDOWNS (/option-matrix 1회)셀·팝업(재호출 없음)
표시가 = 업로드가uploader/preview.py (parity 테스트로 보증)화면에 보이는 값 = 마켓에 올릴 값

⑤ 탭별 데이터 지도 — 각 화면의 데이터가 어디서 오고, 어디에 쓰이는가


앞의 ①~④가 값 하나가 흐르는 길이라면, 여기서는 화면(탭) 하나하나가 그 길의 어느 지점인지를 봅니다. 프로그램은 두 모드 — 모음전 모드(값을 만들고·매핑하고·판매처로 내보냄)와 재고관리 모드(실물 재고를 입·출고하고 분석)로 나뉩니다. 각 탭은 데이터를 보여주기만 하는 게 아니라, 그 데이터가 다른 탭·계산·전송으로 흘러갑니다. 표의 "어디에 쓰이나" 열이 이 자료의 핵심입니다.

읽는 법: (왼쪽 세로 병합) → 그 탭의 상세 데이터 항목 → 값의 출처(모델·파일) → 그 값이 흘러가는 쓰임 순으로 읽습니다. 코드 위치는 모델/파일:함수로 찾습니다.

모음전 모드 — 값을 만들고 · 매핑하고 · 내보낸다

· 대시보드

상세 데이터 항목출처(모델·파일)어디에 쓰이나
/ 4대 KPI — 모음전 수 · 미맵핑 큐 · 24h 가격변동 · 업로드 실패 Model · DiscoveryQueueItem · PriceTrackHistory · MarketRegistration (home.py _get_kpis) 각 탭 바로가기 진입 + 경고 배지(미맵핑·DLQ)
자동화 ON/OFF 비율Model.auto_enabled홈 카드 토글 컨트롤
최근 모음전 5개 (updated_at DESC))Model카드 클릭 → /bundles/<code> 상세
무신사 비회원가 경고SourceOption.dynamic_benefits_jsonD1 드로워 경고 카드

상품관리 · 신규 등록 → 목록 → 상세(옵션 매트릭스)

상세 데이터 항목출처(모델·파일)어디에 쓰이나
신규 등록 /bundles/new 코드 · 모델명 · 브랜드 · 카테고리(입력) Model INSERT (bundles.py) 모음전 1건 생성 → 자동으로 상세 진입
카테고리 목록(드롭다운)_all_categories() DISTINCT기존 사용값 + 기본(신발·의류·가방)
상품관리 목록 /bundles 코드 · 표시명 · 상태 배지(신규/마이그레이션/정규) Model · BundleGroup (_bundle_summary) 행 클릭 → 상세, 배지로 작업 우선순위
옵션 카운트(색×사이즈)Option.canonical_sku COUNT모음전 규모 표시
소싱처 분포(이름·URL 수)OptionSourceUrl + SourceRegistry매핑 진행도(" N · N URL")
마켓 매칭 상태(스스/쿠팡)Option.naver_option_id·coupang_option_id업로드 준비도(N/M 매칭 칩)
크롤·업로드 최근 시각Model.last_crawled_at·last_uploaded_atstale 경고(12h+) · DLQ 배지
상세 · 옵션 매트릭스 /bundles/<id> 옵션(색·사이즈·SKU) Option · BundleOptionStep(축) 매트릭스 셀 렌더(표면가+최종매입가)
소싱처 URL 다중 등록BundleSourceUrl①수집의 크롤 대상이 됨
옵션 ↔ URL 매핑OptionSourceUrlLink옵션별 자동 크롤 대상 지정
템플릿 적용(가격/색/사이즈)Model.price_template_id 등 → PriceTemplate②가공의 자동 계산 트리거
마켓 활성 플래그 · 실행 이력 20건market_active_ss/coupang · run_history③전송 여부 결정 · 크롤/업로드 로그
기존 마켓 연동 /bundles/migrate 이전 마켓 상품ID(originProductNo) + 카테고리 외부 마켓 API fetch 기존 상품 → Model/Option 자동 생성

매핑 현황 · 소싱처 운영센터 → 미맵핑 큐 → 맵핑

상세 데이터 항목출처(모델·파일)어디에 쓰이나
소싱처 운영센터 /sources KPI(전체·정상·에러·미수집·크롤러미지원) service.kpi_summary() 크롤 건강도 한눈에
SourceProduct 상세(URL·상품명·상태·fetch시각·가격·재고·사용 모음전 수)SourceProduct (sources/models.py)크롤 값 중앙 관리 · ②계산의 입력
미맵핑 큐 /queue 분류(신규모델·신규색상·옵션매핑·URL미등록) + 원문·제안코드 DiscoveryQueueItem (_classify()) 수동 해결 → 맵핑 학습으로 전달
맵핑 /mapping/ 차원(모델·색상·사이즈) · 캐노니컬 값 · 동의어(alias, manual/learned) AliasDimension·AliasCanonical·AliasMapping 정규화 기준 → 다음 크롤에서 자동 매칭

크롤링&업로드 · 가이드 · 사전 · 실패함 · 계정

상세 데이터 항목출처(모델·파일)어디에 쓰이나
크롤링 가이드 /sourcing-guide/ 소싱처별 크롤 가이드(단계 ①②③④ · 가격 포함/제외 게이트) SourceRegistry.crawl_guide (JSON) ①수집 파서 검증 · 최종매입가 계산 근거
검증 saved_checks · 예제 스크린샷 · 크롤러 확장 ZIPcrawl_guide['verification'] · _EXT_DIR정확도 근거 누적 · /install 배포
소싱처 사전 /source-registry 소싱처(이름·메인URL·정렬·사용 카운트) SourceRegistry + OptionSourceUrl COUNT 옵션 매핑 드롭다운 순서·라벨 결정
업로드 실패함 /dlq 실패 등록(마켓·SKU·마지막 시도·에러·시도횟수) MarketRegistration (status='failed') 수동 재시도 · 빈발 에러 패턴 통계
판매처 계정 /accounts/upload 업로드 계정 · 시크릿 상태 · 로그인 쿠키 영속성 UploadAccount + .env + Chrome 프로파일 ③전송의 업로드·자동로그인 가능 여부

구매 · 판매 · 기타

상세 데이터 항목출처(모델·파일)어디에 쓰이나
가격·재고 추적 /track 소싱처별 가격 시계열 · 최저가 PriceTrackHistory (Option 크롤 누적) 소싱처별 라인 차트 · "최저가 N원" 배지
템플릿 /templates 가격 템플릿(마진·수수료·가드레일) · 색상/사이즈 템플릿 · 적용 모음전 수 PriceTemplate·ColorTemplate·SizeTemplate ③전송 가격 결정 · 색·사이즈 정규화 규칙
주문 내역 · 마진 계산기 /orders 6마켓 주문·정산 통합 조회 · 항목별 마켓 API 코드 매핑 lemouton/markets/order_export.py (combined_order_rows) · margin/sell_source.py 구현 두 탭 단일 원천. 항목×마켓 코드·호출전략·업로드 제한은 → 판매처 데이터 코드 지도의 「 프로그램 주문조회 · ⬆️ 마켓별 업로드」 탭
휴지통·변경 이력 /trash · /audit 삭제 로그 · 변경 전/후(before/after) · 변경자·시각 AuditLog (audit/models.py) soft-delete 복구 · 감사 diff 검토
알림 채널 설정 /alerts Telegram/Slack 연결 상태 · 알림 종류 4종 · 라우팅 .env (TOKEN 존재 여부) 채널 연결 표시 (라우팅은 현재 보기 전용)

재고관리 모드 — 실물 재고를 입·출고하고 분석한다

이 모드의 단일 진실 원천 = InventoryTx 거래 원장. 화면에 보이는 모든 "재고 수량"은 저장된 스냅샷이 아니라 shared/inventory_stock.py get_stock_batch()가 입고(+)−출고(−)−이동을 매번 실시간 합산한 값입니다. (Option.boxhero_stock_total 스냅샷은 사용 금지)

제품목록 · 거래 — 입고·출고·조정·이동·히스토리·임시저장

상세 데이터 항목출처(모델·파일)어디에 쓰이나
제품목록 /inventory/ SKU · 모델 · 색 · 사이즈 · 이미지 Option + Model 목록 · 검색 필터
실시간 재고 · 위치별 재고InventoryTx 집계 (get_stock_batch)통계 · 상세 패널 · 부족 알림
평균매입가Option.boxhero_avg_purchase_price행 표시 · 판매가 계산 기초
거래 /inbound · /outbound
/adjust · /move
/history · /pending
입고 — 수량·매입가·거래처·메모 InventoryTx(in) (transactions.py) 평균매입가 누적 갱신(inbound.py)
출고 — 수량·판매가·묶음 자동차감InventoryTx(out)재고 차감 + COGS 스냅샷(unit_purchase_price_at_tx)
조정 — 절대값/± (delta_mode)InventoryTx(adjust)재고 재설정·분실·습득
이동 — 위치 → 위치InventoryTx(move)위치 간 재고 이동
히스토리 — 전체 거래 역순InventoryTx.created_at DESC감사 추적
임시저장 — 작성 중 폼(payload_json)InventoryPending나중에 완료 처리

★ 모음전 차별점 · 구매/판매/반품

상세 데이터 항목출처(모델·파일)어디에 쓰이나
옵션 매트릭스 /matrix 옵션 행 · 실시간 재고 · 평균매입가 · 사입 마진 3계층 · 오버라이드 Option+get_stock_batch+PriceTemplate (boxhero_margin.py) 자체/외부 판매가 계산 (compute_sale_price)
SKU 매핑 /sku-mapping 미매핑 옵션(boxhero_sku NULL) · 매핑 진행률 Option.boxhero_sku 박스히어로 재고 동기화 기초
입고 검사 /inspection 대기 PO · 라인별 예상 vs 실제 수량 PurchaseOrder (status='pending') 차이 기록 → 자동 입고 생성 · PO 상태 갱신
발주 /purchase PO번호·거래처·라인·즉시입고 플래그 PurchaseOrder (purchase_sale.py) immediate_inbound → 자동 InventoryTx(in)
판매 /sale SO번호·거래처·라인·즉시출고 플래그 SalesOrder immediate_outbound → 자동 출고 + 묶음 expand
반품 /return RO번호·원 판매주문(FK)·라인 ReturnOrder 자동 입고 환원(평균매입가 기준)

분석 · 데이터 관리 · 설정

상세 데이터 항목출처(모델·파일)어디에 쓰이나
분석 /dashboard
/reports/*
대시보드 — 총 옵션·총 재고·입출고 건수 Option·InventoryTx count (reports.py) 운영 개요
매출 분석 — 수익·원가(COGS)·마진InventoryTx(out) + unit_purchase_price_at_tx마진 = 수익 − COGS 리포트
재고/수량/요약 리포트Option·InventoryTx·PO/SO모델별 재고·매핑률·시계열·KPI
데이터 관리 /data/* 제품 · 묶음제품 · 위치 · 속성 · 거래처 Option·bundles.json·InventoryLocation·ItemAttribute 거래·매트릭스의 마스터 데이터
묶음제품(bundles.json)JSON 파일(DB 스키마 회피)출고/SO 시 구성 SKU 자동 확장
가격 템플릿 · 엑셀 업로드PriceTemplate · 엑셀 파싱매트릭스 마진 계산 · 대량 import
설정 /settings 팀 정보 · 구매/판매 규칙(접두사·자동번호·세금) · 연동 · 알림 JSON 파일(team_settings.json 등) PO/SO/RO 생성 규칙 · 동기화 · 알림 필터 제어
탭을 가로지르는 데이터 흐름(핵심 연쇄).
모음전 모드 — 신규 등록(Model) → 상세에서 소싱처 URL 등록(BundleSourceUrl) → 소싱처 운영센터에서 크롤(SourceProduct) → 새 색상·모델은 미맵핑 큐(DiscoveryQueueItem) → 맵핑 학습(AliasMapping) → 다음 크롤 자동 매칭. 템플릿·계정 설정은 ③전송 가격·업로드로 합류.
재고관리 모드 — 제품(Option) → 입고(평균매입가↑) → 출고(재고↓ + COGS 스냅샷) → 매출 분석(마진 = 수익 − COGS). 발주·판매·반품 완료는 각각 InventoryTx를 자동 생성.

검증 현황 — 이 지도를 무엇으로 · 어디까지 확인했나


검증 주제 — 이 지도의 탭 → 데이터 매핑이 실제 코드에 근거하는지 확인한 기록입니다. 가격·재고·라이브 동작 검증이 아니라 문서 정확도(코드 근거) 검증이며, 정직성 원칙에 따라 확정·추정·미확인을 구분합니다.

1. 발견 항목

#발견 / 확인확신도상태근거(파일·검사)
1⑤ 탭별 지도 추가 후 HTML 태그 균형 정상확정수정완료정적 검사 table 14/14 · tr 97/97 · rowspan 10
2현재상태·리스크·부록 삭제 후 태그 균형·죽은 앵커 제거확정수정완료table 12/12, #status·#risk·#views 부재 확인
3모음전 모드 탭 데이터 매핑이 실코드 근거 보유확정문서화home.py _get_kpis·bundles.py _bundle_summary·sources kpi_summary·DiscoveryQueueItem·AliasMapping
4재고관리 SSOT=InventoryTx, 재고는 실시간 합산(스냅샷 아님)확정문서화shared/inventory_stock.py get_stock_batch()
5주문 내역·마진 계산기(/orders)는 6마켓 구현 완료 (구 "스켈레톤" 서술 정정)확정구현·문서반영order_export.combined_order_rows(두 탭 단일 원천) · 항목×마켓 코드는 /marketplace-guide/map 「프로그램 주문조회」 탭
6알림 채널 설정(/alerts) 라우팅은 보기 전용(미영속)추정미수정(열림)settings.py — 에이전트 조사, 라이브 미확인
7일부 매핑 항목 근거 미확보미확인미확인inbound.py 라인·DLQ 재시도·run_history 스키마·match_options_batch

2. 확정 버그 (지금 고쳐야 함))

없음. 이 세션은 문서 편집·구조 검증만 수행 — 확신도=확정 & 상태=미수정인 코드 버그를 발견/검증한 바 없음. (/orders는 이후 6마켓 구현 완료 — 위 ⑤ 표·5번 항목 정정 반영)

3. 오판 · 거짓경보 (버그 아니었음)

없음. 이 세션에서 버그로 의심했다가 뒤집은 항목 없음.

4. 아직 확인 못 한 것

  • 새 표의 브라우저 실렌더 스크린샷 — 태그 균형만 확인, 시각 캡처 미실행.
  • 7번 미확인: inbound.py 평균매입가 갱신 정확 라인 · DLQ 재시도 로직 · run_history 스키마 · match_options_batch 구현.
  • /alerts 라우팅이 실제로 미영속인지 라이브 미확인(6번, 추정 단계).
  • 문서의 파일:라인이 워킹트리 기준 — origin/main과 대조 안 함.

5. 다른 검증과 충돌 가능성

  • 삭제된 리스크 지도 주의 — 지난 편집에서 지운 "HIGH 리스크 13" 서술은 이 세션이 검증한 결과가 아님(원 문서 서술을 옮겼다 삭제). 다른 세션이 "이 세션 발견"으로 취합하면 안 됨.
  • 파일:라인은 Explore 에이전트가 읽은 값 — 항목마다 직접 재확인하진 않음. 코드 검증 세션의 라인과 다를 수 있음.
  • 메모리의 가격·재고 버그 이력은 이 세션에서 재검증하지 않음 — 이 세션에 검증 크레딧을 붙이지 말 것.

파일:라인은 origin/main 기준(작성 시점). 코드가 바뀌면 이 표도 함께 갱신하세요. 인앱 정본: docs/크롤링-가이드.md · /sourcing-guide/data-flow.