[230319] readme 수정, 패키지 구조 변경

This commit is contained in:
appleg
2022-03-19 22:37:00 +09:00
parent 28c84888d1
commit 5b25d23578
5 changed files with 39 additions and 15 deletions

View File

@@ -1,48 +1,70 @@
# Payment System with DDD
## Project Settings
### 1. Module Guide
본 프로젝트는 CQRS 패턴을 이용하여 구현되어 있다.
이에 따라 gradle을 이용하여 모듈이 둘로 나뉘어져 있는 디렉토리 구조를 확인할 수 있다.
서비스를 위해서는 `payment-command` 모듈과 `payment-query` 모듈을 각각 실행해야 한다.
본 프로젝트는 CQRS 패턴을 이용하여 구현되어 있다. 이에 따라 gradle을 이용하여 모듈이 둘로 나뉘어져 있는 디렉토리 구조를 확인할 수 있다. 서비스를 위해서는 `payment-command` 모듈과 `payment-query` 모듈을 각각 실행해야 한다.
#### payment-command 모듈
CRUD 중에서 CUD 만을 담당하는 모듈이다.
본인의 테이블에 DB를 저장하며, 해당 이벤트를 Kafka에 발행하여 Query 모듈에 알려준다.
DDD의 핵심 도메인들은 이곳에 구현이 된다.
CRUD 중에서 CUD 만을 담당하는 모듈이다. 본인의 테이블에 DB를 저장하며, 해당 이벤트를 Kafka에 발행하여 Query 모듈에 알려준다. DDD의 핵심 도메인들은 이곳에 구현이 된다.
#### payment-query 모듈
CRUD 중에서 R 만을 담당하는 모듈이다.
payment-command에서 발행한 이벤트를 Kafka로부터 consume하여 본인의 DB를 업데이트 한다.
이 모듈은 DDD의 핵심 도메인 중심이 아닌, 클라이언트에게 필요한 정보를 제공한다. 위의 command 모듈과는 다르게 조회의 효율성, 클라이언트의 호출과 관련하여 조회에 유연하게 구성해야 한다.
CRUD 중에서 R 만을 담당하는 모듈이다. payment-command에서 발행한 이벤트를 Kafka로부터 consume하여 본인의 DB를 업데이트 한다. 이 모듈은 DDD의 핵심 도메인 중심이 아닌, 클라이언트에게 필요한 정보를 제공한다. 위의 command
모듈과는 다르게 조회의 효율성, 클라이언트의 호출과 관련하여 조회에 유연하게 구성해야 한다.
### 2. Infra Used
```
1. MySQL 8.0.21 for Command
2. MySQL 8.0.21 for Query
3. Kafka(Zookeeper)
```
위의 인프라는 로컬 실행을 위해서 docker-compose를 이용하였다.
> :warning: m1 맥북의 경우 docker-compose.yaml 파일에서 platform 관련 주석을 해제하고 실행할 것
위의 인프라는 로컬 실행을 위해서 docker-compose를 이용하였다.
> :warning: m1 맥북의 경우 docker-compose.yaml 파일에서 platform 관련 주석을 해제하고 실행할 것
- CQRS에서 DB를 분리하는 방법은 여러가지가 있지만, 가장 보편적인(?) 방식인 물리 DB를 나누는 방식을 이용하였다.
command와 query 모듈은 각각 다른 DB를 보게된다.
command와 query 모듈은 각각 다른 DB를 보게된다.
- kafka의 경우 application.yaml에 특별한 설정 없이도 kafka에 자동으로 붙게 설정이 되어 있다.(autoconfigure 덕분에)
이외의 운영을 위한 상세 설정은 생략했다.
이외의 운영을 위한 상세 설정은 생략했다.
## Domain 소개
이 프로젝트에서는 '결제' 컨텍스트를 예시로하는 간단한 DDD 프로젝트다.
1. 유저는 결제창에서 결제를 진행하여, 본인의 계정에 서비스 전용 재화(캐시)를 획득하게 된다. 게임이나 스타벅스 앱의 페이와 같이 충전과 관련된 시스템 대부분의 유형을 따르면 된다.
2. 결제는 결제 대행사를 이용해서 처리하기 때문에 결제창에서 유저가 결제를 완료하면 본 도메인에서 제공하는 api로 결제 금액 정보가 담긴 결제 완료 요청을 보낸다. 결제창은 웹의 영역이므로 해당 도메인에서 다루지 않아도 무방하다.
3. 서비스에는 특정 아이템이 있으며, 서비스 전용 재화를 이용해서 구매할 수 있다.(게임이라면 아이템, 스타벅스라면 구매한 식음료) 다만 아이템은 본 컨텍스트에서는 관리하지 않는다.
도메인은 대략 다음과 같은 구조를 따른다.
1. User: 유저는 캐시를 소유할 수 있어 내부 엔터티로 구현. 유저 계정 관리 서비스가 따로 있다고 가정한다. 여기에서는 자체적으로 생성한다.
2. Payment: 캐시를 획득하는 행위
3. Cash: Payment로부터 생성된 User에게 할당되는 Cash
4. Purchase: 캐시를 사용하는 행위. 캐시를 차감한다.
![img_1.png](img_1.png)
## Use Case
### i. Command
- 외부 결제 시스템 결제로 인한 캐시 증가
```
1. 유저 캐시 추가 및 잔액 업데이트
2. 결제 기록 추가
3. 해당 이벤트를 consumer로 publish
```
- 각종 이유(구매 등)에 대한 캐시 사용
### ii. Query
- 유저의 결제 내역 단건/기간별 조회
- 유저의 사용 내역 단건/기간별 조회

BIN
img_1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -1,5 +1,6 @@
package com.example.user.domain;
package com.example.cash.domain;
import com.example.user.domain.User;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;

View File

@@ -1,6 +1,6 @@
package com.example.payment.application;
import com.example.user.domain.Cash;
import com.example.cash.domain.Cash;
import com.example.event.EventPublisher;
import com.example.payment.domain.Payment;
import com.example.payment.domain.PaymentRepository;

View File

@@ -1,5 +1,6 @@
package com.example.user.domain;
import com.example.cash.domain.Cash;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;