rimo030 / nestjs-e-commerce-frame

✏️ NestJS로 구현한 Commerce API
46 stars 1 forks source link

커머스 ERD 설계하기 #28

Open kakasoo opened 9 months ago

kakasoo commented 9 months ago

다른 분께 커머스 구조를 설명하다보니 님께 설명드린 내용을 다시 말하게 되었어요. 그래서 이번에는 텍스트로 정리했습니다. 기억을 되새길 겸 같이 보시면 더 좋을 거 같아요.

kakasoo commented 9 months ago

여기서 설명하는 커머스 ERD는 가장 대표적인 커머스들의 공통 특징을 묶으려고 하는 것이고, 디테일한 부분까지 챙기지는 못합니다. 하지만 대충 판매자, 구매자, 주문결제에 대한 각각 6개씩의 테이블만 트리로 잘 만들어둬도 웬만한 커머스 구조를 모방할 수 있습니다. 재밌는 점은 판매자, 구매자, 주문결제로 이어지는 이 세 가지 트리의 구조가 서로 똑같고, 시간 순으로 진행된다는 점이에요. 그럼 한 번 시작해보죠.

ERD 작성의 기본 이해

정규화에 대한 설명은 하지 않을 거고요, 여기서는 간단하게 하나의 원칙만 설명하겠습니다. 더 많은 쪽이 더 적은 쪽의 ID를 가진다. 커머스를 봐요, 판매자는 여러 개의 상품을 업로드하고 판매할 겁니다. 만약 더 적은 쪽인 판매자가 상품의 아이디를 가진다면 아래처럼 판매자의 정보가 계속 중복될 수 밖에 없을 겁니다. 그러면 이건 굉장히 비효율적인 구조가 되기 때문에 차라리 반대로 아이디를 주는 게 더 낫다는 겁니다.

판매자의 아이디 판매자의 이름 상품의 아이디
1 카카수 1
1 카카수 2
1 카카수 3

판매자 도메인

설명을 다시 하죠, 일단 구매자에 대한 거는 일절 생각하지 맙시다.

모든 걸 1:M의 계층 구조를 가지면 마치 트리와 같은 모습이 될 겁니다.

판매자 묶음 배송

하지만 위 설명에는 하나가 빠져 있는데 바로 묶음 배송입니다. 왜냐하면 커머스에는 배송비가 무료가 되는 조건이 있는데요, 그걸 표현하기 위해서는 판매자가 묶음 배송을 먼저 만들어야 합니다. 같은 박스에 담아서 배송할 수 있는 상품을 기준으로 한다고 생각하면 이해가 쉬운데요, 이 묶음 배송이 다시 상품을 여러 개 가지게 해야 합니다. 다시 설명하면 아래와 같은 구조가 될 겁니다.

다시 말하지만, 묶음 배송은 판매자가 배송비를 1번만 부과한다던가 하는, 배송비 기준을 정하기 위한 테이블입니다. 추가로 상품 옵션은 신발을 구매할 때 '신발끈'처럼 상품에서 선택적으로 구매 가능한 대상이며 절대 별도로 구매할 수 없는 것을 말합니다.

판매자 도메인 테이블에 추가되어야 하는 정보들

간단하지만 어쨌든 물건을 담고 전시할 수 있는 판매자의 도메인이 완성되었습니다. 이 구조가 이해되었다면 다음은 간단합니다.

구매자 도메인

구매자 도메인은 판매자 도메인에 있던 6개의 테이블, 그리고 그 트리 구조를 그대로 복사해서 옆에 그려주면 됩니다.

그대로 옮기고 아이디들도 다시 엮어주기만 하면 됩니다. 하지만 구매자 도메인에서는 가격을 계산하기 위한 각종 칼럼이 없습니다. 왜 일까요?

구매자 도메인의 계산 방법은 판매자의 영향을 받는다

장바구니 옵션, 장바구니 선택 옵션 등에는 가격 칼럼이 없습니다. 구매자가 장바구니에 물건을 담았다고 해도 판매자가 가격을 조정했다면 거기에 따라가야 합니다. 아직 구매를 한 건 아니기 때문에 구매자 도메인의 가격 관련 칼럼들은 모두 판매자 쪽으로부터 와야 합니다. 반대로 새로 추가되는 칼럼이 있는데 장바구니에 담은 상품의 수, 즉 수량에 대한 칼럼이 필요합니다.

주문 결제 도메인

주문도 똑같이 트리 구조를 그대로 옮겨보면 됩니다.

판매자 구매자 영수증
묶음 배송 장바구니 묶음 박스 단위 묶음
상품 장바구니 상품 결제된 상품
상품 옵션 장바구니 상품 옵션 결제된 상품 옵션
상품 선택 옵션 장바구니 상품 선택 옵션 결제된 상품 선택 옵션
상품 입력 옵션 장바구니 상품 입력 옵션 결제된 상품 입력 옵션

다만 추가된 게 있다면, 이번에는 결제가 된 것이기 때문에 결제된 당시의 가격과 수량을 저장해야 합니다. 판매자가 가격을 바꾸든 말든, 배송비 부과 정책을 바꾸든 말든, 이미 확정된 금액은 그대로여야 하고 취소와 환불도 당시의 가격대로 이루어져야 하기 때문입니다. 다시 강조하건대, 이번에는 바뀌면 안 되기 때문에 저장하는 겁니다.

부분 취소를 하면?

해당 상품이 없다고 가정하고 전체 가격을 다시 계산하면 됩니다. 이 때, 재계산은 주문 결제 도메인의 정보로만 이루어져야 하고 다른 테이블을 사용해서는 안 됩니다. 그렇게 해서 전체 계산을 다시 했다면, 이전과 이후의 가격을 빼는 것만으로 환불 금액, 취소 금액을 구할 수 있습니다.

배송비 무료 기준

꼭 번들 단위여야 하는가?

그런 건 아니고, 쿠팡처럼 유저의 등급, 회원에 따라 또 가격이 달라지는 경우가 있습니다. 이 또한 배송비를 일괄적으로 무료로 하는 경우도 있지만, 퍼센테이지를 달리 주는 등 차등이 있을 수 있습니다.

장바구니 아이디를 가지는 결제된 상품?

주문서 쪽의 결제된 상품상품 아이디를 가지는 거는 이해가 될 거에요. 상품이 여러 번 결제될 수 있기 때문에, 상품은 여러 개의 결제된 상품을 가지고, 그러면 당연히 상품의 아이디를 필요로 하겠죠? 그런데 장바구니 상품이 여러 개의 결제된 상품을 가진다고 한다면 그건 좀 이상해요. 결제가 여러 번 될 수 있는 장바구니가 있나? 놀랍게도 있습니다.

비즈니스적인 관점

설계는 항상 비즈니스적인 관점이 고려가 되어야 해요. 데이터가 많은 테이블은 수정 자체만으로도 많은 리소스를 쓰기 때문에, 설계에 많은 시간을 써야 하고, 당연히 그 기준은 비즈니스가 됩니다. 때로는 설계에 미친 개발자가 있을 것이고, 당장 급한 것만 처리하자고 말하는 개발자가 있을 텐데요 둘 다 공통점이 있습니다. 바로 입니다. 정상적인 개발자라면 돈에 대한 고민을 안할 수가 없고, 따라서 서로 다른 의견을 말하는 두 개발자는 같은 얘기를 하고 있을 겁니다.

개발자끼리 말이 다를 때는 어느 것이 돈을 더 버는지로 얘기하면 됩니다.

kakasoo commented 9 months ago

여기에도 동일한 텍스트를 옮겨둡니다.