Project
오즈의 이상한 상점
Django 기반 쇼핑몰 백엔드 API
Screenshots
Overview
오즈의 이상한상점은 의류 상품 판매를 위한 쇼핑몰 백엔드 API 프로젝트입니다. Django와 Django REST Framework를 기반으로 회원 인증, 소셜 로그인, 상품/카테고리/옵션 재고, 장바구니, 주문, Toss Payments 결제, 리뷰, 위시리스트, 배송 추적, 관리자 API를 구현했습니다. 프론트엔드와 연동 가능한 REST API 구조와 Swagger 기반 API 문서화를 함께 구성했습니다.
Problem
쇼핑몰 서비스는 상품 옵션, 재고, 장바구니, 주문, 결제, 배송 상태가 하나의 구매 흐름 안에서 연결되기 때문에 데이터 정합성 관리가 중요했습니다. 특히 동일 상품의 옵션별 재고를 정확히 차감하고, 결제 승인 전후의 주문 상태와 결제 상태를 동기화하며, 실패 상황에서는 재고와 주문 데이터를 되돌릴 수 있어야 했습니다. 또한 프론트엔드와 협업하기 위해 인증, 권한, 예외 응답, API 문서가 일관된 구조로 제공될 필요가 있었습니다.
Solution
도메인을 accounts, catalog, carts, orders, payments, shipments, reviews, wishlists, staff 앱으로 분리하고 DRF 기반 REST API로 구현했습니다. 상품 옵션은 option_key 기준으로 정규화해 장바구니, 재고, 주문 항목이 동일한 기준을 사용하도록 구성했습니다. 주문 생성과 재고 차감은 transaction.atomic과 select_for_update를 활용해 원자적으로 처리하고, 결제 승인 실패나 주문 생성 실패 상황에 대비한 보상 흐름을 추가했습니다. 배송은 SweetTracker 연동 결과를 내부 ShipmentEvent 형식으로 변환해 저장하고, Celery worker/beat를 통해 배송 상태 폴링 작업을 API 요청 흐름과 분리했습니다.
Core Features
- 이메일/소셜 로그인 및 JWT 인증
- 상품/카테고리 조회 및 옵션별 재고 관리
- 장바구니 기반 체크아웃
- 주문 생성, 취소, 환불 상태 관리
- Toss Payments 결제 승인/취소 연동
- 리뷰 및 위시리스트
- SweetTracker 기반 배송 추적 API
- Celery 기반 배송 상태 폴링
- Swagger API 문서화
Tech Stack
Backend
Database
Auth
Async
External API
Infra
Docs & Test
My Role
- Django와 DRF 기반 API 구조 설계
- 커스텀 User 모델, JWT 인증, 소셜 로그인 흐름 구현
- 상품 옵션과 재고를 option_key 기준으로 정규화하는 구조 설계
- 장바구니에서 주문과 결제로 이어지는 체크아웃 흐름 구현
- transaction.atomic과 select_for_update를 활용한 재고 차감/복구 로직 구성
- Toss Payments 결제 승인, 취소, 이벤트 저장 흐름 구현
- 배송 추적 데이터 모델링 및 SweetTracker 연동 구조 설계
- Celery worker/beat 기반 배송 상태 폴링 작업 구성
Technical Decisions
- 쇼핑몰 주요 기능을 accounts, catalog, carts, orders, payments, shipments 등 도메인 앱으로 분리
- 상품 옵션 조합을 option_key로 정규화해 장바구니, 재고, 주문 항목에서 일관되게 관리
- transaction.atomic과 select_for_update로 체크아웃 시 주문 생성과 재고 차감을 원자적으로 처리
- Purchase와 Payment를 분리해 주문 상태와 결제 상태를 독립적으로 관리
- Shipment와 ShipmentEvent를 분리해 현재 배송 상태와 배송 이력을 함께 저장
- Celery worker/beat로 배송 상태 동기화를 백그라운드 작업으로 분리
- JWT Refresh Token Rotation/Blacklist로 인증 토큰 생명주기 관리
- Docker Compose로 Web, DB, Redis, Celery 실행 환경 구성
Challenges
- 옵션 조합이 있는 상품의 재고를 장바구니, 주문, 결제 단계에서 동일한 기준으로 추적하는 문제
- 결제 승인 성공 이후 주문 항목 생성과 재고 차감이 실패하지 않도록 트랜잭션 단위를 설계하는 문제
- 결제 실패나 취소 상황에서 주문 상태, 결제 상태, 재고 복구를 일관되게 처리하는 문제
- 외부 배송 API 응답을 내부 배송 이벤트 스키마로 변환하고 중복 이벤트를 방지하는 문제
- 배송 상태 폴링처럼 오래 걸리거나 반복되는 작업을 API 요청 흐름과 분리하는 문제
- 사용자, 관리자, 주문 소유자 권한을 API별로 다르게 적용하는 문제
- 프론트엔드가 예측 가능하게 사용할 수 있도록 응답 구조와 Swagger 문서를 정리하는 문제
Troubleshooting
Case 1외부 배송 API 리전 지연으로 인한 타임아웃 문제
- 이슈
- SweetTracker 배송 조회 API 호출 과정에서 타임아웃과 SSL handshake 실패가 발생했습니다. 국내 서버에서 외부 배송 API 엔드포인트까지의 네트워크 경로가 불안정해 배송 상태 동기화 작업의 안정성이 떨어졌습니다.
- 해결
- 외부 배송 API 호출 구간을 백엔드 핵심 로직과 분리하고, 도쿄 리전의 프록시 EC2를 통해 요청을 우회하도록 구성했습니다. 외부 API 장애가 전체 서비스 흐름에 직접 영향을 주지 않도록 네트워크 의존 구간을 분리했습니다.
- 결과
- 배송 조회 요청의 실패 가능성을 줄이고, 외부 API 의존 구간에 대한 장애 대응과 운영 안정성을 개선했습니다.
Case 2배송 상태 동기화와 이벤트 이력 관리 구조 설계
- 이슈
- 사용자 요청마다 외부 API를 직접 호출하면 응답 지연, 외부 API 장애, 반복 호출 비용이 발생할 수 있었습니다. 현재 상태만 저장하는 방식으로는 배송 과정의 변경 이력을 추적하기도 어려웠습니다.
- 해결
- Shipment와 ShipmentEvent를 분리해 현재 배송 상태와 이벤트 이력을 함께 관리하도록 설계했습니다. Celery worker와 beat로 진행 중인 배송을 주기적으로 동기화해 사용자 요청과 외부 배송 조회 작업을 분리했습니다.
- 결과
- 외부 API 호출이 사용자 요청에 직접 영향을 주지 않는 백그라운드 동기화 구조를 구성하고, 배송 상태 변경 이력을 추적할 수 있도록 개선했습니다.
Case 3배송 등록 요청과 내부 주문 모델의 매핑 문제
- 이슈
- 배송 도메인의 Shipment는 내부적으로 Purchase 주문 모델을 참조하지만 클라이언트는 purchase_id를 전달해야 했습니다. 요청 필드와 내부 FK 구조가 섞이면 잘못된 주문 참조, 권한 검증 누락, 배송 데이터 생성 오류가 발생할 수 있었습니다.
- 해결
- API에서는 purchase_id를 받고, 서비스 계층에서 요청 사용자와 purchase_id를 기준으로 Purchase 객체를 조회한 뒤 Shipment.order FK에 연결했습니다. View, Service, Repository의 책임을 분리해 요청 처리와 도메인 저장 흐름을 명확히 했습니다.
- 결과
- 클라이언트 API 사용성을 유지하면서 내부 모델 정합성과 주문 소유자 검증을 안정적으로 처리하고, 배송 데이터 생성 흐름의 유지보수성을 개선했습니다.
Case 4결제 승인 이후 주문 생성과 재고 정합성 문제
- 이슈
- Toss Payments 결제 승인 이후 주문 항목 생성이나 재고 차감이 실패하면 결제 상태, 주문 상태, 재고 수량이 서로 불일치할 수 있었습니다. 특히 장바구니 기반 체크아웃에서는 여러 상품의 재고를 한 번에 처리해야 해 부분 실패에 대한 대응이 필요했습니다.
- 해결
- 결제 승인 전 장바구니 재고를 검증하고, 주문 항목 생성과 재고 차감은 transaction.atomic 안에서 처리했습니다. 상품 옵션은 option_key로 정규화해 장바구니, 재고, 주문 항목이 같은 기준을 사용하도록 맞췄습니다. 주문 생성 실패 시에는 Toss 결제 취소를 시도하고 Payment 상태를 되돌리는 보상 흐름을 추가했습니다.
- 결과
- 결제, 주문, 재고 상태가 어긋날 가능성을 줄였고, 결제 성공 후 주문 데이터 생성 실패 상황에 대응할 수 있는 구조를 마련했습니다.
Improvements
- 이메일 기반 JWT 인증과 Refresh Token Blacklist 구조 적용
- option_key 기반 상품 옵션/재고 관리 구조로 개선
- 트랜잭션 기반 체크아웃으로 주문 생성과 재고 차감 정합성 강화
- Toss 결제 상태와 주문 상태를 연결해 결제 이력 추적 가능
- SweetTracker 배송 응답을 내부 이벤트 모델로 변환해 저장
- Celery 기반 배송 상태 폴링 작업 분리
- Docker Compose 기반 개발 환경 구성
Next Improvements
- 결제 실패/취소 보상 로직과 운영 로그 강화
- 배송 추적 응답 포맷 및 예외 케이스 정리
- 관리자 상태 변경 감사 로그 추가
- Toss 웹훅 기반 결제 상태 동기화
- 구매 흐름 E2E 테스트 보강
- Docker 실행 문서와 환경변수 예시 개선