주문 품목이 이름과 값을 복사한다
대안은 지난 주문을 그릴 때 products 와 조인하는 것인데, 그러면 가게를 손댈 때마다 영수증이 바뀝니다 — 이름 변경, 가격 인하, 옵션 삭제. 복사는 품목당 컬럼 두 개가 들고, 주문이 스스로 완결됩니다. 외래키는 집계용으로 남겨 두므로 둘 다 가져서 잃는 것이 없습니다.
온라인 쇼핑몰 및 마켓플레이스를 위해 설계된 포괄적인 이커머스 데이터베이스 스키마입니다. 카테고리가 포함된 상품 카탈로그, 고객 관리, 주문 처리 및 품목 관리, 결제 추적, 배송지 주소 및 재고 관리를 포함합니다. Shopify와 같은 플랫폼, WooCommerce 대안 또는 맞춤형 이커머스 솔루션 구축에 적합합니다.
이 스키마의 중심은 카탈로그와 주문 사이의 선입니다. products·categories·product_images 는 지금 팔고 있는 것을 설명하고 가게를 손질할 때마다 바뀝니다. orders·order_items 는 실제로 팔린 것을 기록하며, 카탈로그가 바뀌어도 바뀌면 안 됩니다.
그래서 order_items 가 product_name 과 unit_price 를 자기 것으로 들고 있습니다. 집계를 위해 상품을 여전히 가리키지만, 영수증에 적힌 이름과 값은 결제 시점에 뜬 사본입니다. 상품 이름을 바꾸거나 할인을 걸어도 지난달 주문은 그대로 읽힙니다.
장바구니는 그 선 앞에 있고 일부러 느슨합니다. carts 에 user_id 와 session_id 가 둘 다 있어서 로그인 전에도 담을 수 있고, expires_at 이 있어 버려진 장바구니가 끝없이 쌓이지 않습니다. 장바구니의 무엇도 약속이 아닙니다 — 재고를 잡아 두지 않고 값은 products 에서 그때그때 읽습니다.
대안은 지난 주문을 그릴 때 products 와 조인하는 것인데, 그러면 가게를 손댈 때마다 영수증이 바뀝니다 — 이름 변경, 가격 인하, 옵션 삭제. 복사는 품목당 컬럼 두 개가 들고, 주문이 스스로 완결됩니다. 외래키는 집계용으로 남겨 두므로 둘 다 가져서 잃는 것이 없습니다.
stock_quantity 가 입출고 원장이 아니라 숫자 하나입니다. 창고를 겸하지 않는 가게에는 맞는 선택입니다 — 읽기가 상수 시간이고 차감이 갱신 한 번입니다. "왜 지금 이 수량인가" 를 알아야 하는 순간 — 반품, 파손, 입고 — 부족해지고, 그때 이 컬럼은 진실이 아니라 이동 테이블에 대한 캐시가 됩니다.
max_uses 에 대한 coupons.current_uses 는 가장 단순한 형태이고, 약점도 분명합니다 — 같은 순간의 두 결제가 같은 수를 읽을 수 있습니다. 한도를 절대 넘으면 안 된다면 쿠폰 행을 잠그는 트랜잭션 안에서 검사하거나, 사용 이력을 사용자별 유니크 제약이 걸린 자기 테이블로 빼야 합니다.
shipping_address_id 가 addresses 를 참조하므로, 고객이 주소를 고치면 지난 기록이 바뀝니다. 카탈로그에서 얻은 교훈이 여기만 적용되지 않은 자리입니다 — 배송하는 가게라면 값을 복사하듯 주소도 주문에 복사하세요. 흔한 출발 형태라 그대로 두었지만, 가장 먼저 손봐야 할 곳이라는 것은 알고 계시는 편이 좋습니다.