직거래(Direct Trade) 트랙

거래 · 2026년 8월 31일 기준

  • 실측
  • 2축 관계 판정
  • 대행 폴백 대신 차단
  • 트랙 순도 2단 가드
  • 주문 헤더 스냅샷 격리
  • 라인합계 청구 축
  • 초대 토큰 생명주기
목차 7
  1. 개요
  2. 왜 이 설계가 필요했는가 (Problem)
  3. 검토했던 판정 축 (Analyze)
  4. 핵심 설계 결정
  5. 설계가 만든 결과 (Result)
  6. 데이터 구조
  7. 역할 분담

개요

구매기업이 공급사와 직접 거래하는 트랙을, 이미 운영 중이던 대행(agency) 트랙 위에 얹은 기능. 신규 개발이 아니라 돌아가는 파이프라인에 대한 개조였다. 운영사가 거래 당사자에서 빠지므로, 판정 → 장바구니 → 주문 → 정산 → 클레임 → 통계까지 전 계층에서 운영사를 걷어내야 한다.

2축 판정 판정 3값 운영사 API 0개 잔차 0 청구 축 200개 테스트
고객사 연결 × 품목 소유자 직거래 / 대행 / 차단 격리를 필터가 아닌 부재로 라인합계를 그대로 청구 31개 파일 (단위·슬라이스)

왜 이 설계가 필요했는가 (Problem)


검토했던 판정 축 (Analyze)

“이 주문이 직거래인가”를 무엇으로 판정할지 — 이 선택이 나머지 전부를 결정했다.

대안 장점 기각 사유 선택
1. 상품 테이블에 직거래 여부 컬럼 조회 단순, 인덱스 1개면 끝 같은 상품이 기업마다 다른 트랙이다 — 표현 불능 ❌
2. 공급사 단위 플래그 쌍 단위라 관리 지점이 적음 같은 공급사도 품목별로 소유자가 갈린다 ❌
3. 주문 시점에 사용자가 선택 구현 최단, 판정 로직 불필요 오지정 한 번에 정산 축이 통째로 틀어지고 사후 감사가 불가능 ❌
4. (고객사 연결 × 표준품목 소유자) 2축 판정 기업별·품목별 차이를 정확히 표현, 원자료가 남아 감사 가능 조인 깊이 증가 · 목록 판정 시 N+1 위험 ✅ 선택

핵심 설계 결정

1. 2축 판정 — 6개 조건이 전부 AND

6개 조건은 어느 하나만 흘려도 판정이 반대로 뒤집힌다. 그래서 AND 묶음을 한 번에 검증하지 않고, 조건별로 쪼개 각각 독립 테스트로 고정했다.

2. 트랙 순도 — 2단 가드

3. 격리는 조인이 아니라 스냅샷 등호

4. 운영사용 직거래 API 를 0개로 둔 것

5. 공급사 청구 축 = 라인합계 (개당 축 금지)

6. 연결·초대 생명주기

상황 처리
사업자번호 일치 공급사 1곳 연결요청 + 사업자번호 스냅샷
복수 공급사와 일치 임의 선택하지 않고 초대로 전환 — 오연결 방지
미가입 사업자번호 초대 + 토큰 발급 → 가입 후 이메일 매칭으로 소진
연결 해제 행을 지우지 않고 사용 여부만 끈다 (다른 출처 행은 불변)
재연결 해제된 직거래 행을 다시 켠다 — 새 행을 만들지 않음
승인 시 수동 등록 행이 이미 있음 출처를 직거래로 승격 (목록·해제 토글 정합)

7. 예산 환원 — 직거래 원장만


설계가 만든 결과 (Result)

계층별 검증 분포

계층 대표 테스트 고정한 불변식
판정 자동승인 판정 쿼리 (15)
판정 서비스 (9)
6개 AND 조건 각각 독립 검증 · 고객사 소유 + 연결 없음 → 차단(대행 폴백 금지) · 목록 판정 쿼리 1회(N+1 금지) · 트랙이 비어 들어와도 예외 없이 대행
트랙 순도 주문 트랙 (22)
장바구니 순도 (6)
혼합 거부 · 차단 단독도 거부(스냅샷 역산 전제 보호) · 선택 해제는 미검사 · 1건 이하는 판정 미호출
운영사 격리 격리 가드 (4)
주문 목록 쿼리 · 카탈로그 숨김 (6)
직거래 라인 혼입 시 404(존재 미누설) · 대행 전용은 통과(positive control) · 목록·카운트·요약·엑셀 어디에도 노출 안 됨 · 카탈로그 self-map·0-노출은 숨기지 않음(공허참 방지)
정산 축 공급가 청구 축 (6)
공급사 정산 쿼리 (4)
잔차 0 · 전량 취소 시 최종 청구액 정확히 0 · 대행 주문에 닿지 않음(fail-closed) · 타 공급사 조회 0건
연결·초대 초대 수락 (10)
연결요청 생성 (10)
다른 이메일 수락 불가(링크 유출 방어) · 복수 후보는 초대로 · 기연결이면 초대도 차단 · 만료 초대는 상태·토큰 무변경
예산 환원 예산 환원 (8) 여신 원장 오복원 가드 · 순잔액 상한 · 전량 복원 후 재집행 멱등
통계·클레임 통계 차원 (2)
클레임 환불 (3)
적재 5문 전부가 차원을 싣는다 · 병합은 주문 헤더 조인(라인 축 금지) · 마이너스 PO 가 트랙을 승계

괄호 안 숫자는 대표 테스트의 개수다(합계 105개). 전체 200개 중 계층마다 대표만 추렸다.

회귀로 고정한 위험 지점

동시성 결함 — 연결요청 중복 가드 (미수정)

이 검증이 말하지 않는 것


데이터 구조

데이터 역할
연결요청 요청 / 초대 · 사업자번호 스냅샷
초대 토큰 미가입 공급사 초대 · 만료·소진 관리
정산 헤더·라인 고객사 × 과세형태로 그룹 분할
거래명세서 헤더·라인 당사자 스냅샷
명세서 상태 이력 상태 변경 이력
세금계산서 금액·당사자를 명세서에서 복사(수기 입력 아님)
입금 이력 헤더 입금상태를 합계 기준으로 재계산

이 외에 주문·발주·클레임·장바구니·기업 등 기존 테이블에 직거래 여부 스냅샷 컬럼을 추가했다.

역할 분담