Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions docs/erd-diagram.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
```mermaid
erDiagram
USERS {
BIGINT id PK
DATETIME created_at "생성일자"
}

WALLET {
BIGINT id PK
BIGINT user_id FK "유저 식별자"
BIGINT balance "잔액"
DATETIME created_at "생성일자"
DATETIME updated_at "수정일시"
}

USER_POINT_HISTORY {
BIGINT id PK
BIGINT user_id FK "유저 식별자"
BIGINT wallet_id FK "지갑 식별자"
BIGINT amount "금액"
STRING type "CHARGE, USE"
DATETIME created_at "생성일자"
}

PRODUCT {
BIGINT id PK
STRING name "상품이름"
BIGINT price "금액"
INT stock_quantity "수량"
DATETIME created_at "생성일시"
DATETIME update_at "수정일시"
}

ORDER {
BIGINT id PK
STRING nonce UK "주문키"
BIGINT user_id FK "유저식별자"
BIGINT total_amount "주문금액"
BIGINT discount_amount "할인 금액"
BIGINT paid_amount "지불 금액"
DATETIME created_at "생성일시"
}

ORDER_ITEM {
BIGINT id PK
BIGINT order_id FK "주문식별자"
BIGINT product_id FK "상품식별자"
BIGINT unit_price "상품 가격"
INT quantity "주문수량"
BIGINT total_price "주문금액"
DATETIME created_at "생성일시"
}

COUPON {
BIGINT id PK
STRING name "쿠폰이름"
BIGINT discount_amount "할인금액"
STRING discount_type "PERCENT, AMOUNT"
BIGINT days "발급후 사용 가능 일자"
INT total_quantity "총 수량"
DATETIME created_at "생성일시"
}

COUPON_OWNED {
BIGINT id PK
BIGINT user_id FK "유저식별자"
BIGINT coupon_id FK "쿠폰식별자"
BIGINT discount_amount "할인금액"
STRING discount_type "PERCENT, AMOUNT"
DATETIME issued_at "발급일"
DATETIME started_at "사용시작"
DATETIME end_at "사용마감"
STRING state "ISSUED, USED"
BIGINT order_id FK "사용한 주문식별자"
}

%% 관계 정의
USERS ||--|| WALLET : "보유한다"
USERS ||--o{ ORDER : "주문한다"
USERS ||--o{ USER_POINT_HISTORY : "충전/사용한다"
WALLET ||--o{ USER_POINT_HISTORY : "충전/사용한다"
USERS ||--o{ COUPON_OWNED : "쿠폰보유"

ORDER ||--o{ ORDER_ITEM : "포함한다"
PRODUCT ||--o{ ORDER_ITEM : "구성된다"

COUPON ||--o{ COUPON_OWNED : "발급된다"
COUPON_OWNED ||--|| ORDER : "적용된다"
```
107 changes: 107 additions & 0 deletions docs/requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
## 이커머스 도메인 분석

---
### 주체

| 주체 | 역할 |
| ----------- |---------------------------------|
| **사용자(고객)** | 상품을 보고, 결제함 |
| 판매자(또는 관리자) | 상품 등록, 재고 관리, 주문 확인 |
| **시스템** | 상품 노출, 주문/결제 처리, 재고 차감, 쿠폰 발급 등 |

- 이번 프로젝트는 동시성과 TDD에 집중하기 위함으로 **판매자 주체는 크게 고려하지 않는다.**

### 도메인 주요 고려 사항
- **이벤트로 인해 트래픽 폭주 상황이 발생할 우려**
- → 서버 수평 확장성 고려 필요
- → 빠른 트랜잭션 처리 고려 필요

## API 고려 사항 정리

---

## 1. 잔액
### 1.1. 잔액 조회 API
#### 1.1.1. **기능적 요구사항**
- 사용자는 사용자 식별값을 보내어 자신의 잔액을 조회할 수 있다.
- 사용자가 유효하지 않으면 오류를 반환한다.
- 사용자는 반드시 하나의 지갑을 가지고 있다.
- 포인트 정보가 없으면 오류를 반환한다.

### 1.2. 잔액 충전 API
#### 1.2.1. **기능적 요구사항**
- 사용자는 사용자 식별값과 충전금액을 보내어 자신의 잔액을 충전할 수 있다.
- 충전 전 요청에 대한 유효성을 검증해야한다.
- 유효하지 않은 유저라면 오류를 반환한다.
- 충전 정책을 만족하지 않으면 오류를 반환한다.
- 충전에 성공하면 충전 후 사용자에게 잔액정보(`사용자ID`, `잔액`)를 응답한다.
- 충전에 성공하면 충전에 대한 로그를 저장한다.
- 충전 정책
- 최소 충전 금액: 1,000원

#### 1.2.2. **비기능적 요구사항**
- 성능: 로그 적재는 충전 트랜잭션에 포함하지 않고, 비동기로 요청하여 성능을 올린다.
- 동시성: 다수의 요청이 동시에 들어와도 충전 금액이 정확하게 반영되도록 처리해야 한다.
- 멱등성: 사용자에게 동일한 충전 요청이 여러번 들어와도, 같은 충전 요청임을 확인할 수 있어야한다.
- 정합성: 충전에 대한 처리와 로그가 일치하게 적재되어야한다.

## 2. 상품
### 2.1. 상품조회 API
#### 2.1.1 **기능적 요구사항**
- 사용자는 인증 없이 상품을 조회할 수 있다.
- 조회되는 상품이 없으면 오류를 반환한다.
- 조회되는 상품이 있으면 상품 정보(`상품ID`,`상품이름`, `가격`, `수량`)을 응답한다.

## 3. 주문/결제
### 3.1. 주문/결제 API
#### 3.1.1 **기능적 요구사항**
- 사용자는 사용자 식별값을 보내어 주문 요청을 보낼 수 있다.
- 주문 당 쿠폰 1개만 사용 가능하다.
- 결제 전 요청을 검증하여 유효성을 판단해야한다.
- 유효하지 않은 유저라면 오류를 반환한다.
- 사용자의 잔액이 부족한 경우 주문은 오류를 반환한다.
- 상품의 수량이 주문 수량보다 적은 경우 주문은 오류를 반환한다.
- 사용자가 쿠폰 정보를 보낸다면 결제 금액을 계산할 떄 적용되어야한다.
- 쿠폰은 유효성 검사는 아래 내용이 포함된다.
- 쿠폰 사용자
- 쿠폰 사용 기간
- 주문/결제가 성공하면 사용자에게 결과정보(`주문ID`, `결제금액`, `할인금액`, `지불금액`, `생성일시`)을 전달한다.
- 주문/결제가 성공하면 포인트 사용에 대한 로그를 저장되어야한다.


#### 3.1.2 **비기능적 요구사항**
- 원자성: 요청 처리 중 오류가 발생하면 요청 전 상태로 돌아가야한다.
- 동시성: 주문 과정에서 쿠폰 사용, 잔액과 재고 차감, 롤백 중에 레이스 컨디션이 발생하지 않아야한다.
- 안정성: 요청된 결제 정보는 네트워크 오류 등의 문제로 누락되지 않아야한다.
- 성능: 로그 적재는 충전 트랜잭션에 포함하지 않고, 비동기로 요청하여 성능을 올린다.
- 멱등성: 사용자에게 동일한 사용 요청이 여러번 들어와도, 같은 사용 요청임을 확인할 수 있어야한다.
- 정합성: 사용에 대한 처리와 로그가 일치하게 적재되어야한다.


## 4. 쿠폰
### 4.1. 선착순 쿠폰 발급 API
#### 4.1.1 **기능적 요구사항**
- 사용자는 사용자 식별값과 발급받을 쿠폰 정보를 보내어 쿠폰을 발급받을 수 있다.
- 쿠폰은 발급 수량이 제한된다.
- 선착순 방식으로 제공된다.
- 쿠폰 발급 전 유효한 요청인지 검증해야한다.
- 유효한 사용자가 아니면 오류를 반환한다.
- 요청된 쿠폰 정보가 존재하지 않으면 오류를 반환한다.
- 쿠폰 수량을 초과하면 오류를 반환한다.
- 이미 해당 쿠폰을 발급된 유저라면 오류를 반환한다.
- 유효한 요청이면 발급된 쿠폰 정보를 응답한다.


#### 4.1.2 **비기능적 요구사항**
- 동시성: 쿠폰 수량 차감은 중 레이스 컨디션이 발생하지 않아야한다.
- 성능: 선착순 쿠폰이므로 큰 트래픽을 견뎌야한다.
- 정합성: 쿠폰이 발급 응답과 저장된 데이터가 일치해야한다.

## 5. 인기 상품 조회
### 5.1. 인기 판매 상품 조회 API
#### 5.1.1 **기능적 요구사항**
- 사용자는 인증 없이 최근 3일간 가장 많이 팔린 상위 5개 상품 정보를 조회할 수 있다.
- 해당 상품을 주문한 횟수를 고려한다 (수량 고려 X)
- 정보가 없으면 빈 값을 응답한다.
#### 5.1.2 **비기능적 요구사항**
- 성능: 다수의 사용자가 동시에 조회할 수 있으므로 조회 속도를 고려한다.
Loading