모음전 · 내부 교육자료
데이터는 어떻게 수집·가공·전송되는가
소싱처에서 가격·재고를 긁어(수집), 저장·계산으로 다듬어(가공), 판매처로 내보내기(전송)까지의 전체 흐름과 — 각 단계가 코드 어디에 있고, 어떻게 불리고, 무엇에 쓰이는지를 한 곳에 정리했습니다.
읽는 법: 각 장의 줄글 설명으로 그림을 잡고, 코드 지도 표의 파일:라인으로 실제 위치를 찾습니다.
전체 그림 — 네 단계
소싱처 상품 하나의 값이 화면·판매처까지 가는 길은 수집 → 가공 → 전송 세 단계이고, 이 전부를 자동화 스케줄러가 주기적으로 돌립니다. 맨 아래 파란 줄은 "같은 값은 한 곳에서만 만든다"는 공유 원칙입니다.
그림 1. 세로 계층 흐름도 (자동화가 위에서 구동, 왼쪽 단계를 따라 아래로)
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:1112 → toItemBG: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 SourceOptionupsert service.py:104 / :159혜택 화이트리스트 OPTION_DYNAMIC_KEYS service.py:605 |
두 수집 경로가 공통 호출 | 재고 current_stock·표면가 last_price·혜택 dynamic_benefits_json 영속 |
| 계산 엔진 | api_benefits.py:417 compute_breakdownfinal_price.py:236 compute_final_priceunified.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_schedulerscheduler/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_json | D1 드로워 경고 카드 |
상품관리 · 신규 등록 → 목록 → 상세(옵션 매트릭스)
| 탭 | 상세 데이터 항목 | 출처(모델·파일) | 어디에 쓰이나 |
|---|---|---|---|
| 신규 등록 /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_at | stale 경고(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 · 예제 스크린샷 · 크롤러 확장 ZIP | crawl_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.