Skip to content

Commit 4d24eb8

Browse files
authored
Merge pull request #54 from JeonJe/round2
[volume-2] 이커머스 설계 문서 작성
2 parents 4cd0580 + 44411ba commit 4d24eb8

File tree

4 files changed

+1386
-0
lines changed

4 files changed

+1386
-0
lines changed

docs/week2/01-requirements.md

Lines changed: 320 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
# 01-requirements.md - 요구사항 명세
2+
3+
## 📑 목차
4+
5+
- [0. 전제 조건 및 제약사항](#0-전제-조건-및-제약사항)
6+
- [1. 전체 유저 시나리오](#1-전체-유저-시나리오)
7+
- [2. 도메인별 상세 요구사항](#2-도메인별-상세-요구사항)
8+
- [2.1 상품](#21-상품)
9+
- [2.1.1 상품 목록 조회](#211-상품-목록-조회)
10+
- [2.1.2 상품 상세 조회](#212-상품-상세-조회)
11+
- [2.1.3 상품 좋아요](#213-상품-좋아요)
12+
- [2.2 브랜드](#22-브랜드)
13+
- [2.3 주문](#23-주문)
14+
15+
---
16+
17+
## 0. 전제 조건 및 제약사항
18+
19+
### 0.1 설계 범위
20+
- **포함**: 상품 조회, 브랜드 조회, 좋아요, 주문 생성 및 결제 (재고/포인트 차감)
21+
- **제외**: 회원가입, 포인트 충전 (1주차 구현 완료)
22+
23+
### 0.2 인증/인가
24+
- 모든 API는 별도의 인증없이 X-USER-ID 헤더로 사용자 식별
25+
- 토큰이 없으면 비회원 사용자
26+
- 회원가입 API는 1주차 완료 (설계 범위 제외)
27+
28+
### 0.3 포인트 시스템
29+
- 포인트 충전 API는 1주차 완료 (설계 범위 제외)
30+
- 포인트 조회 및 차감/사용은 주문 과정에서 처리 (설계 필요)
31+
32+
### 0.4 데이터 사전 등록
33+
- 상품 데이터는 사전 등록되어 있다고 가정
34+
- 브랜드 데이터는 사전 등록되어 있다고 가정
35+
36+
---
37+
38+
## 1. 전체 유저 시나리오
39+
40+
사용자의 서비스 이용 여정:
41+
42+
1. **브랜드 탐색**: 관심있는 브랜드를 조회하여 브랜드 정보를 확인한다.
43+
44+
2. **상품 탐색**: 브랜드별 필터링, 다양한 정렬 조건(최신순/가격순/좋아요순)으로 상품 목록을 탐색하고, 관심 상품의 상세 정보를 확인한다.
45+
46+
3. **관심 표현**: 마음에 드는 상품에 좋아요를 등록하거나 취소하며, 나중에 좋아요한 상품 목록을 다시 확인할 수 있다.
47+
48+
4. **구매 및 확인**: 여러 상품을 한 번에 주문하고, 보유한 포인트로 결제한다. 재고와 포인트가 차감되며, 주문 정보는 외부 시스템으로 전송된다. 나중에 주문 이력을 조회하여 과거 주문 내역을 확인할 수 있다.
49+
50+
---
51+
52+
## 2. 도메인별 상세 요구사항
53+
54+
### 2.1 상품
55+
56+
#### 2.1.1 상품 목록 조회
57+
58+
##### 유저 시나리오
59+
60+
사용자 김철수는 새로운 상품을 찾아 쇼핑을 시작한다.
61+
62+
1. 김철수는 상품 목록을 열어 최신순으로 정렬된 상품들을 확인한다.
63+
2. 특정 브랜드의 상품만 보고 싶어 브랜드를 선택하여 필터링한다.
64+
3. 가격이 저렴한 순서로 보고 싶어 가격 낮은 순으로 정렬한다.
65+
4. 한 페이지에 20개씩 상품을 확인하며, 다음 페이지로 이동하여 더 많은 상품을 탐색한다.
66+
67+
##### 기능 요구사항
68+
69+
- **엔드포인트**: `GET /api/v1/products`
70+
- **쿼리 파라미터**:
71+
- `brandId`: 특정 브랜드의 상품만 필터링 (선택)
72+
- `sort`: 정렬 기준 (기본값: `latest`, 선택: `price_asc`, `likes_desc`)
73+
- `page`: 페이지 번호 (기본값: 0)
74+
- `size`: 페이지당 상품 수 (기본값: 20)
75+
- **응답 데이터**:
76+
- 상품 ID, 상품명, 가격
77+
- 브랜드 정보: ID, 이름
78+
- 총 좋아요 수
79+
- 현재 사용자의 좋아요 여부
80+
- 페이지네이션 정보: 총 개수, 현재 페이지, 전체 페이지 수, 페이지당 개수, 정렬 조건
81+
82+
##### 제약사항
83+
84+
- 정렬 기능: 최신순(`latest`), 가격 오름차순(`price_asc`), 좋아요순(`likes_desc`) 구현
85+
- 페이지네이션은 반드시 지원해야 함
86+
87+
---
88+
89+
#### 2.1.2 상품 상세 조회
90+
91+
##### 유저 시나리오
92+
93+
김철수는 상품 목록에서 관심있는 상품을 발견하고 상세 정보를 확인한다.
94+
95+
1. 김철수는 상품을 클릭하여 상세 페이지로 이동한다.
96+
2. 상품의 이름, 가격, 설명, 브랜드 정보, 재고 수량, 총 좋아요 수를 확인한다.
97+
3. 해당 상품이 마음에 들어 구매를 결정한다.
98+
99+
##### 기능 요구사항
100+
101+
- **엔드포인트**: `GET /api/v1/products/{productId}`
102+
- **경로 파라미터**:
103+
- `productId`: 조회할 상품의 ID
104+
- **응답 데이터**:
105+
- 상품 ID, 상품명, 가격, 상세 설명
106+
- 브랜드 정보: ID, 이름
107+
- 재고 수량
108+
- 총 좋아요 수
109+
- 현재 사용자의 좋아요 여부
110+
111+
##### 제약사항
112+
113+
- 존재하지 않는 상품 ID 조회 시 적절한 에러 응답 필요
114+
- 재고 수량은 정확히 반영되어야 함
115+
116+
---
117+
118+
#### 2.1.3 상품 좋아요
119+
120+
##### 유저 시나리오
121+
122+
김철수는 마음에 드는 상품에 좋아요를 누르고 관리한다.
123+
124+
1. 김철수는 상품 상세 페이지에서 좋아요 버튼을 클릭한다.
125+
2. 같은 상품에 실수로 다시 좋아요를 눌렀지만, 중복 등록되지 않는다.
126+
3. 나중에 생각이 바뀌어 좋아요 취소 버튼을 클릭한다.
127+
4. 이미 취소된 상태에서 다시 취소 버튼을 눌러도 에러 없이 정상 처리된다.
128+
5. 관심 상품을 다시 보기 위해 좋아요 목록 페이지로 이동한다.
129+
130+
##### ✅ 정상 흐름
131+
132+
**좋아요 등록**:
133+
1. 로그인한 사용자가 상품 상세 페이지에서 좋아요 버튼 클릭
134+
2. 시스템이 상품 존재 확인
135+
3. 시스템이 좋아요 저장
136+
4. 상품의 좋아요 수 증가
137+
5. 200 OK 응답
138+
139+
**좋아요 취소**:
140+
1. 로그인한 사용자가 좋아요한 상품에서 취소 버튼 클릭
141+
2. 시스템이 좋아요 삭제
142+
3. 상품의 좋아요 수 감소
143+
4. 200 OK 응답
144+
145+
##### 🔄 경계 케이스
146+
147+
- **이미 좋아요한 상품에 재등록**: 중복 저장하지 않고 200 OK (멱등성)
148+
- **이미 취소한 좋아요 재취소**: 에러 없이 200 OK (멱등성)
149+
- **네트워크 재시도**: 첫 요청 처리 후 재시도 시 멱등하게 동작
150+
151+
##### ❌ 에러 케이스
152+
153+
- **상품 없음**: 404 Not Found
154+
- **미인증 사용자**: 401 Unauthorized
155+
- **시스템 오류**: 500 Internal Server Error
156+
157+
##### 기능 요구사항
158+
159+
- **좋아요 등록**: `POST /api/v1/like/products/{productId}`
160+
- 사용자는 각 상품에 한 번만 좋아요 가능
161+
- 중복 등록 시도는 무시
162+
- **응답 데이터**: 200 OK
163+
164+
- **좋아요 취소**: `DELETE /api/v1/like/products/{productId}`
165+
- 이미 취소된 상태에서 재시도 시 정상 응답
166+
- **응답 데이터**: 200 OK
167+
168+
- **좋아요 목록 조회**: `GET /api/v1/like/products`
169+
- **쿼리 파라미터**:
170+
- `sort`: 정렬 기준 (기본값: `latest` - 최근 좋아요 순, 선택: `product_name`, `price_asc`, `price_desc`)
171+
- `page`: 페이지 번호 (기본값: 0)
172+
- `size`: 페이지당 상품 수 (기본값: 20)
173+
- **응답 데이터**:
174+
- 현재 사용자가 좋아요한 상품 목록
175+
- 상품 기본 정보: ID, 상품명, 가격, 총 좋아요 수
176+
- 브랜드 정보: ID, 이름
177+
- 페이지네이션 정보: 총 개수, 현재 페이지, 전체 페이지 수, 페이지당 개수, 정렬 조건
178+
179+
##### 제약사항
180+
181+
- **멱등성 보장**: 동일한 요청을 여러 번 호출해도 결과는 동일해야 함
182+
- 좋아요 등록: 이미 등록된 경우 중복 등록하지 않음
183+
- 좋아요 취소: 이미 취소된 경우 에러 없이 정상 응답
184+
- **구현 방식**:
185+
- DB 제약: `UNIQUE(ref_user_id, ref_product_id)` 제약으로 중복 방지
186+
- 예외 처리: DB 제약 위반 시 애플리케이션에서 200 OK로 변환
187+
- 동시성 보장: 동시 요청에도 DB 제약이 데이터 일관성 보장
188+
- 좋아요 수는 상품 목록/상세 조회 시 정확히 반영
189+
- X-USER-ID 헤더로 사용자 식별
190+
- **대규모 트래픽 고려**: 충분히 많은 사용자가 좋아요를 사용하는 상황을 가정하여 조회 성능 최적화 필요
191+
192+
---
193+
194+
### 2.2 브랜드
195+
196+
#### 2.2.1 브랜드 조회
197+
198+
##### 유저 시나리오
199+
200+
김철수는 특정 브랜드에 관심이 생겨 브랜드 정보를 확인한다.
201+
202+
1. 김철수는 상품 목록에서 본 브랜드 이름을 클릭하여 브랜드 페이지로 이동한다.
203+
2. 브랜드의 이름과 설명을 확인한다.
204+
3. 해당 브랜드가 마음에 들어 해당 브랜드의 상품만 필터링하여 탐색한다.
205+
206+
##### 기능 요구사항
207+
208+
- **엔드포인트**: `GET /api/v1/brands/{brandId}`
209+
- **경로 파라미터**:
210+
- `brandId`: 조회할 브랜드의 ID
211+
- **응답 데이터**:
212+
- 브랜드 ID, 브랜드명
213+
- 브랜드 설명
214+
215+
##### 제약사항
216+
217+
- 존재하지 않는 브랜드 ID 조회 시 적절한 에러 응답 필요
218+
219+
---
220+
221+
### 2.3 주문
222+
223+
#### 2.3.1 주문 생성 및 결제
224+
225+
##### 유저 시나리오
226+
227+
김철수는 여러 상품을 선택하여 주문한다.
228+
229+
1. 김철수는 구매하려는 상품들을 선택하고 주문하기 버튼을 클릭한다.
230+
- 상품 A: 2개
231+
- 상품 B: 1개
232+
233+
2. 시스템은 재고를 확인하고, 포인트를 차감하여 주문을 완료한다.
234+
235+
3. 주문 완료 페이지에서 주문 번호와 주문 내역을 확인한다.
236+
237+
4. 김철수는 나중에 자신의 주문 목록을 조회한다.
238+
239+
5. 특정 주문을 선택하여 상세 내역을 다시 확인할 수 있다.
240+
241+
##### ✅ 정상 흐름
242+
243+
1. 로그인한 사용자가 주문할 상품과 수량 선택
244+
2. 시스템이 각 상품 재고 확인
245+
3. 시스템이 총 결제 금액 계산
246+
4. 시스템이 사용자 포인트 잔액 확인
247+
5. 시스템이 재고 차감
248+
6. 시스템이 포인트 차감
249+
7. 시스템이 주문 정보 저장
250+
8. 시스템이 주문 정보를 외부 시스템에 전송
251+
9. 201 Created 응답
252+
253+
##### 🔄 경계 케이스
254+
255+
- **결제 처리 실패**: 재시도 또는 상태 마킹 후 수동 처리
256+
- **주문 수량 0 또는 음수**: 400 Bad Request
257+
258+
##### ❌ 에러 케이스
259+
260+
- **재고 부족**: 400 Bad Request
261+
- **포인트 부족**: 400 Bad Request
262+
- **상품 없음**: 404 Not Found
263+
- **미인증 사용자**: 401 Unauthorized
264+
- **시스템 오류**: 500 Internal Server Error, 트랜잭션 롤백
265+
- **결제 처리 실패**:
266+
- 주문은 이미 DB에 저장 완료 (재고/포인트 차감 완료, 트랜잭션 커밋됨)
267+
- 자동 재시도 3회 (1초, 2초, 4초 간격, 지수 백오프)
268+
- 재시도 실패 시 주문 상태를 '결제 대기'로 마킹
269+
- 500 Internal Server Error 응답
270+
271+
##### 기능 요구사항
272+
273+
- **주문 생성**: `POST /api/v1/orders`
274+
- **요청 바디**:
275+
```json
276+
{
277+
"items": [
278+
{ "productId": 1, "quantity": 2 },
279+
{ "productId": 3, "quantity": 1 }
280+
]
281+
}
282+
```
283+
- **처리 흐름**:
284+
1. 각 상품의 재고 확인
285+
2. 총 결제 금액 계산
286+
3. 사용자 포인트 확인
287+
4. 재고 차감
288+
5. 포인트 차감
289+
6. 주문 정보 저장
290+
7. 외부 시스템 전송 (Mock 가능)
291+
- **응답 데이터**:
292+
- 주문 ID, 주문 일시
293+
- 주문 상품 목록: 상품 ID, 상품명, 수량, 가격
294+
- 총 결제 금액
295+
296+
- **주문 목록 조회**: `GET /api/v1/orders`
297+
- **쿼리 파라미터**:
298+
- `page`: 페이지 번호 (기본값: 0)
299+
- `size`: 페이지당 주문 수 (기본값: 20)
300+
- **응답 데이터**:
301+
- 주문 ID, 주문 일시, 총 금액
302+
- 주문 상품 수
303+
- 페이지네이션 정보: 총 개수, 현재 페이지, 전체 페이지 수, 페이지당 개수
304+
305+
- **주문 상세 조회**: `GET /api/v1/orders/{orderId}`
306+
- **응답 데이터**:
307+
- 주문 ID, 주문 일시
308+
- 주문 상품 목록: 상품 ID, 상품명, 수량, 가격
309+
- 총 결제 금액
310+
311+
##### 제약사항
312+
313+
- **트랜잭션 보장**: 재고 차감과 포인트 차감은 원자적으로 처리되어야 함
314+
- 둘 중 하나라도 실패하면 전체 롤백
315+
316+
- **재고 부족**: 주문 수량이 재고보다 많을 경우 주문 실패
317+
318+
- **포인트 부족**: 사용자의 보유 포인트가 총 결제 금액보다 적을 경우 주문 실패
319+
320+
- **외부 시스템 연동**: 주문 정보 전송은 Mock으로 처리 가능

0 commit comments

Comments
 (0)