Repository: KimByeongKou/fastcampus-pay Branch: main Commit: e61875092c50 Files: 173 Total size: 138.2 KB Directory structure: gitextract_owzcci7l/ ├── .gitignore ├── .idea/ │ ├── .gitignore │ ├── compiler.xml │ ├── gradle.xml │ ├── jarRepositories.xml │ ├── misc.xml │ ├── modules/ │ │ ├── common/ │ │ │ └── fastcampus-pay.common.main.iml │ │ └── settlement-service/ │ │ └── fastcampus-pay.settlement-service.main.iml │ ├── modules.xml │ ├── uiDesigner.xml │ └── vcs.xml ├── Dockerfile ├── README.md ├── banking-service/ │ ├── build.gradle │ └── src/ │ └── main/ │ └── java/ │ └── com/ │ └── fastcampuspay/ │ └── banking/ │ ├── BankingApplication.java │ ├── BankingConfiguration.java │ ├── BankingConfigurationProperties.java │ ├── SwaggerConfig.java │ ├── adapter/ │ │ ├── in/ │ │ │ └── web/ │ │ │ ├── FindBankingAccountInfoController.java │ │ │ ├── RegisterBankingAccountInfoController.java │ │ │ ├── RegisterBankingAccountInfoRequest.java │ │ │ └── RequestTransferMoneyController.java │ │ └── out/ │ │ └── persistence/ │ │ ├── BankingAccountPersistenceAdapter.java │ │ ├── BankingAccountRegisterInfoJpaEntity.java │ │ ├── BankingAccountRegisterInfoMapper.java │ │ └── SpringDataBankingAccountRegisterInfoRepository.java │ ├── application/ │ │ ├── port/ │ │ │ ├── in/ │ │ │ │ ├── RegisterBankingAccountCommand.java │ │ │ │ └── RegisterBankingAccountUseCase.java │ │ │ └── out/ │ │ │ └── RegisterBankingAccountPort.java │ │ └── service/ │ │ └── RegisterBankingAccount.java │ └── domain/ │ ├── BankingAccountRegisterInfo.java │ └── TransferMoney.java ├── build.gradle ├── common/ │ ├── build.gradle │ └── src/ │ └── main/ │ └── java/ │ └── com/ │ └── fastcampuspay/ │ └── common/ │ ├── PersistenceAdapter.java │ ├── SelfValidating.java │ ├── UseCase.java │ ├── WebAdapter.java │ └── events/ │ └── RegisterAccountEvent.java ├── db/ │ ├── conf.d/ │ │ └── my.cnf │ └── initdb.d/ │ ├── create_table.sql │ └── load_data.sql ├── docker-compose.yaml ├── gradle/ │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── membership-service/ │ ├── build.gradle │ └── src/ │ └── main/ │ └── java/ │ └── com/ │ └── fastcampuspay/ │ └── membership/ │ ├── MembershipApplication.java │ ├── MembershipConfiguration.java │ ├── MembershipConfigurationProperties.java │ ├── SwaggerConfig.java │ ├── adapter/ │ │ ├── in/ │ │ │ └── web/ │ │ │ ├── FindMembershipController.java │ │ │ ├── FindMembershipRequest.java │ │ │ ├── LoginAuthMembershipController.java │ │ │ ├── RegisterMembershipController.java │ │ │ ├── RegisterMembershipRequest.java │ │ │ ├── UpdateMembershipController.java │ │ │ └── UpdateMembershipRequest.java │ │ └── out/ │ │ └── persistence/ │ │ ├── MembershipJpaEntity.java │ │ ├── MembershipMapper.java │ │ ├── MembershipPersistenceAdapter.java │ │ └── SpringDataMembershipRepository.java │ ├── application/ │ │ ├── port/ │ │ │ ├── in/ │ │ │ │ ├── FindMembershipCommand.java │ │ │ │ ├── FindMembershipUseCase.java │ │ │ │ ├── RegisterMembershipCommand.java │ │ │ │ ├── RegisterMembershipUseCase.java │ │ │ │ ├── UpdateMembershipCommand.java │ │ │ │ ├── UpdateMembershipEventCommand.java │ │ │ │ ├── UpdateMembershipUseCase.java │ │ │ │ └── aggregate/ │ │ │ │ └── MembershipAggregate.java │ │ │ └── out/ │ │ │ ├── FindMembershipPort.java │ │ │ ├── RegisterMembershipPort.java │ │ │ ├── UpdateMembershipPort.java │ │ │ └── query/ │ │ │ ├── FindMembershipQuery.java │ │ │ └── MembershipQueryHandler.java │ │ ├── saga/ │ │ │ ├── MembershipCreateEvent.java │ │ │ ├── MembershipUpdateEvent.java │ │ │ ├── Order.java │ │ │ ├── OrderCancelledEvent.java │ │ │ ├── OrderConfirmedEvent.java │ │ │ ├── OrderCreatedEvent.java │ │ │ ├── OrderPlacedEvent.java │ │ │ ├── OrderSaga.java │ │ │ ├── Payment.java │ │ │ ├── PaymentCancelledEvent.java │ │ │ ├── PaymentCompletedEvent.java │ │ │ └── PaymentRequestedCommand.java │ │ └── service/ │ │ ├── FindMembership.java │ │ ├── RegisterMembership.java │ │ └── UpdateMembership.java │ └── domain/ │ └── Membership.java ├── money-local-service/ │ ├── build.gradle │ └── src/ │ └── main/ │ └── java/ │ └── com/ │ └── fastcampuspay/ │ └── moneylocal/ │ ├── MoneyLocalApplication.java │ ├── MoneyLocalConfiguration.java │ ├── MoneyLocalConfigurationProperties.java │ ├── SwaggerConfig.java │ ├── adapter/ │ │ ├── in/ │ │ │ └── web/ │ │ │ └── CalculateLocalMoneyController.java │ │ └── out/ │ │ └── persistence/ │ │ ├── LocalMoneyJpaEntity.java │ │ ├── LocalMoneyMapper.java │ │ ├── LocalMoneyPersistenceAdapter.java │ │ └── SpringDataLocalMoneyRepository.java │ ├── application/ │ │ ├── port/ │ │ │ ├── in/ │ │ │ │ ├── RechargeMoneyCommand.java │ │ │ │ └── RechargeMoneyUseCase.java │ │ │ └── out/ │ │ │ └── RechargeMoneyPort.java │ │ └── service/ │ │ └── RechargeMoney.java │ └── domain/ │ └── MemberMoney.java ├── money-service/ │ ├── build.gradle │ └── src/ │ └── main/ │ └── java/ │ └── com/ │ └── fastcampuspay/ │ └── money/ │ ├── MoneyApplication.java │ ├── MoneyConfiguration.java │ ├── MoneyConfigurationProperties.java │ ├── SwaggerConfig.java │ ├── adapter/ │ │ ├── in/ │ │ │ └── web/ │ │ │ ├── FindMoneyController.java │ │ │ ├── RechargeMoneyController.java │ │ │ └── RequestTransferMoneyController.java │ │ └── out/ │ │ └── persistence/ │ │ ├── RechargeMoneyJpaEntity.java │ │ ├── RechargeMoneyMapper.java │ │ ├── RechargeMoneyPersistenceAdapter.java │ │ └── SpringDataRechargeMoneyRepository.java │ ├── application/ │ │ ├── port/ │ │ │ ├── in/ │ │ │ │ ├── RechargeMoneyCommand.java │ │ │ │ └── RechargeMoneyUseCase.java │ │ │ └── out/ │ │ │ └── RechargeMoneyPort.java │ │ └── service/ │ │ └── RechargeMoney.java │ └── domain/ │ └── MemberMoney.java ├── payment-service/ │ ├── build.gradle │ └── src/ │ └── main/ │ └── java/ │ └── com/ │ └── fastcampuspay/ │ └── payment/ │ ├── PaymentApplication.java │ ├── PaymentConfiguration.java │ ├── PaymentConfigurationProperties.java │ ├── SwaggerConfig.java │ ├── adapter/ │ │ ├── in/ │ │ │ └── web/ │ │ │ ├── FindPaymentController.java │ │ │ └── RequestTransferMoneyController.java │ │ └── out/ │ │ └── persistence/ │ │ ├── PaymentJpaEntity.java │ │ ├── PaymentMapper.java │ │ ├── RechargeMoneyPersistenceAdapter.java │ │ └── SpringDataPaymentRepository.java │ ├── application/ │ │ ├── port/ │ │ │ ├── in/ │ │ │ │ ├── RechargeMoneyCommand.java │ │ │ │ └── RechargeMoneyUseCase.java │ │ │ └── out/ │ │ │ └── RechargeMoneyPort.java │ │ └── service/ │ │ └── RechargeMoney.java │ └── domain/ │ └── MemberMoney.java ├── remittance-service/ │ ├── build.gradle │ └── src/ │ └── main/ │ └── java/ │ └── com/ │ └── fastcampuspay/ │ └── remittance/ │ ├── RemittanceApplication.java │ ├── RemittanceConfiguration.java │ ├── RemittanceConfigurationProperties.java │ ├── SwaggerConfig.java │ ├── adapter/ │ │ ├── in/ │ │ │ └── web/ │ │ │ ├── FindRemittanceController.java │ │ │ └── RequestRemittanceMoneyController.java │ │ └── out/ │ │ └── persistence/ │ │ ├── RemittanceMoneyJpaEntity.java │ │ ├── RemittanceMoneyMapper.java │ │ ├── RemittanceMoneyPersistenceAdapter.java │ │ └── SpringDataRemittanceMoneyRepository.java │ ├── application/ │ │ ├── port/ │ │ │ ├── in/ │ │ │ │ ├── RemittanceMoneyCommand.java │ │ │ │ └── RemittanceMoneyUseCase.java │ │ │ └── out/ │ │ │ └── RemittanceMoneyPort.java │ │ └── service/ │ │ └── RemittanceMoney.java │ └── domain/ │ └── RemittanceMoney.java ├── settings.gradle └── settlement-service/ ├── build.gradle └── src/ └── main/ └── java/ └── com/ └── fastcampuspay/ └── settlement/ ├── SettlementApplication.java ├── SettlementConfiguration.java ├── SettlementConfigurationProperties.java ├── SwaggerConfig.java ├── adapter/ │ ├── in/ │ │ └── web/ │ │ └── SettlementStartController.java │ └── out/ │ └── persistence/ │ ├── RechargeMoneyMapper.java │ ├── RechargeMoneyPersistenceAdapter.java │ ├── SettlementJpaEntity.java │ └── SpringDataSettlementRepository.java ├── application/ │ ├── port/ │ │ ├── in/ │ │ │ ├── RechargeMoneyCommand.java │ │ │ └── RechargeMoneyUseCase.java │ │ └── out/ │ │ └── RechargeMoneyPort.java │ └── service/ │ └── RechargeMoney.java └── domain/ └── MemberMoney.java ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ /*/build/ axon-server-se/*/* db/data/* ================================================ FILE: .idea/.gitignore ================================================ # 디폴트 무시된 파일 /shelf/ /workspace.xml # 에디터 기반 HTTP 클라이언트 요청 /httpRequests/ # Datasource local storage ignored files /dataSources/ /dataSources.local.xml # Zeppelin ignored files /ZeppelinRemoteNotebooks/ ================================================ FILE: .idea/compiler.xml ================================================ ================================================ FILE: .idea/gradle.xml ================================================ ================================================ FILE: .idea/jarRepositories.xml ================================================ ================================================ FILE: .idea/misc.xml ================================================ ================================================ FILE: .idea/modules/common/fastcampus-pay.common.main.iml ================================================ ================================================ FILE: .idea/modules/settlement-service/fastcampus-pay.settlement-service.main.iml ================================================ ================================================ FILE: .idea/modules.xml ================================================ ================================================ FILE: .idea/uiDesigner.xml ================================================ ================================================ FILE: .idea/vcs.xml ================================================ ================================================ FILE: Dockerfile ================================================ FROM openjdk:11-slim-stretch EXPOSE 8080 ARG JAR_FILE COPY ${JAR_FILE} app.jar #"-Djava.security.egd=file:/dev/./urandom", #"-Dspring.profiles.active=prod", ENTRYPOINT ["java", "-jar", "/app.jar"] ================================================ FILE: README.md ================================================ # FastCampus-Pay Project Overview ![Overall Architecture](md_resource/Overall_Architecture_Image.png) 일반적인 간편결제 도메인을 주제로, MSA 를 중점적으로 학습하기 위한 교육용 프로젝트입니다. 회원(Membership), 뱅킹(Banking), 머니(Money), 송금(Remittance), 결제(Payment), 정산(Settlement) 6개의 서비스로 구성되어 있으며, 각각의 독립적인 프로젝트로 구성되어 있어요. 각 서비스에서는 기본적인 기능을 먼저 Hexagonal Architecture 로 구현하고, 일부 기능들에 EDA, CQRS, Event Sourcing, Saga Pattern 등을 적용하며 진행해 보아요. 기본적으로 Springboot 와 Java 11 을 기준으로 프로젝트를 구성하고, EDA 구현을 위해서 Axon Framework v4.6.0 을 사용해요. 로깅 파이프라인은 따로 구성하진 않았지만, kafka 의 실습을 목적으로 하는 간단한 로깅 파이프라인을 구성할 예정이에요. 실제 간편 결제 도메인 시스템과는 복잡성 측면에서 차이가 있지만, 간단한 버전을 기준으로 MSA 를 구성하고, 각 서비스의 기능을 구현하며, EDA 를 적용해 보는 것을 목표로 진행해요. 아래 내용들은 수업 진행 방향 및 실습 진행 속도에 따라 유동적일 수 있어요. ## Overall Architecture for Monolithic System ![Monolithic System](md_resource/Overview2.png) ## Overall Architecture for MSA ![MSA System](md_resource/Overview1.png) ## Membership Service (Part. 2, 3, 6, 7) 고객의 회원 가입, 회원 정보 변경, 회원 정보 조회 등의 기능을 제공하는 서비스입니다. - Part 2. - Hexagonal Architecture 를 활용하여 기본적인 Membership Service 를 구현 (회원 가입) - Part 3. - gradle build tool 을 이용하여 Docker build 연동. 추가적인 Membership Service 를 구현 (회원 정보 변경) - Part 6. - Axon Framework 를 이용하여 Event Driven Architecture 로 리팩토링. - 고객 정보가 변경될 경우, 이벤트를 발행하고, 이를 구독하는 Money 서비스 에서 고객의 머니 정보를 변경하는 CQRS 패턴 구현 (with/ AWS DynamoDB) - Part 7. - 보안을 위해 JWT 를 이용한 간단한 API 인증 구현 ### API Lists - registerMembership - updateMembershipByMemberId (CQRS Trigger) - findMembershipByMemberId - loginByMembershipIdPw - authByToken #### Using Stack - Spring Boot, Java 11, Spring Data JPA, H2, Mysql, Lombok, Gradle, JWT, Axon Framework, Docker, Docker Compose, AWS DynamoDB ### Sequence Diagram Example (회원 가입, JWT 토큰 인증 프로세스) ![Membership Sequence Example](md_resource/Membership_Sequence_Example.png) ## Banking Service (Part. 3) 고객의 계좌 정보 등록, 등록된 계좌 정보 조회, 입/출금, 거래내역 조회 등의 기능을 제공하는 서비스입니다. - Part 3. - Hexagonal Architecture 를 활용하여 기본적인 Banking Service 를 구현 (가상의 법인 계좌 및 고객 계좌 정보 등록, 은행으로 입/출금 요청하기) ### API Lists - registerBankingAccount - requestTransferMoneyToBank - findRegisteredBankingAccountByMemberId - findTransferMoneyInfoByMemberId - findTransferMoneyInfoByBankingId #### Using Stack - Spring Boot, Java 11, Spring Data JPA, H2, Mysql, Lombok, Gradle, JWT, Axon Framework, Docker, Docker Compose ### Sequence Diagram Example (입/출금 요청 프로세스) ![Banking Sequence Example](md_resource/Banking_Sequence_Example.png) ## Money Service (Part. 3, 4, 5, 6) 고객의 충전 잔액(머니) CRUD, 충전 내역 조회 등의 기능을 제공하는 서비스입니다. - Part 3. - Hexagonal Architecture 를 활용하여 Membership 서비스 및 Banking 서비스를 이용하는 충전 잔액(머니)을 충전하는 기능 구현 - 충전 내역 조회 기능 구현 - Part 4. - kafka 을 이용한 간단 로깅 파이프라인 적용 (kafka 를 이용한 로깅 파이프라인은 실습을 위한 간단한 구현이며, 실제로는 ELK/EFK 등을 이용한 로깅 파이프라인을 구성하는 것을 추천합니다.) - 충전 잔액(머니) 충전 프로세스를 Async 방식으로 구현하고, Polling 을 통한 결과 조회 방식 구현 - Part 5. - 충전 잔액(머니)을 충전하는 기능은 Axon Framework 를 이용하여 Saga Pattern 적용 및 리팩토링 - Part 6. - Axon Framework 를 이용하여 Event Driven Architecture 로 리팩토링. - Membership 서비스로부터 고객 정보 변경 이벤트를 수신하고, 이를 기반으로 CQRS 패턴을 구현 (with/ AWS DynamoDB) - "지역별 고객들의 잔액 총합 View" 을 얻어오려면? ### API Lists - rechargeMoneyByMemberId - findMoneyInfoByRechargeMoneyId - findMoneyHistoryByMemberId - transferMoneyBetweenMembers ### MoneyLocal Service (for CQRS) - calculateMoneySumByLocal - MembershipUpdate (EventHandler) #### Using Stack - Spring Boot, Java 11, Spring Data JPA, H2, Mysql, Lombok, Gradle, JWT, Axon Framework, Docker, Docker Compose, Kafka, Kafka-ui, Zookeeper, AWS DynamoDB ### Sequence Diagram Example (충전 잔액(머니) 충전 프로세스) ![Money_Sequence_Example](md_resource/Money_Sequence_Example.png) ## Remittance Service (Part. 4, 5, 6) 고객 간 송금 기능 및 송금 내역 정보 조회 등의 기능을 제공하는 서비스입니다. - Part 4. - Hexagonal Architecture 를 활용하여 Membership 서비스, Banking 서비스, Money 서비스를 이용하는 고객 간 혹은 계좌 송금 기능 구현 - Part 5. - 고객 간 송금하는 기능은 기능은 Axon Framework 를 이용하여 Saga Pattern 적용 및 리팩토링 - Part 6. - 특정 송금 건을 기준으로, 머니의 충전 내역을 조회해보는 기능 구현을 위해 API Aggregation Pattern 적용 ### API Lists - requestRemittance - findRemittanceInfoByRemittanceId - findRemittanceHistoryByMemberId - findMoneyTransferringByRemittanceId (API Aggregation, Banking + Money) #### Using Stack - Spring Boot, Java 11, Spring Data JPA, H2, Mysql, Lombok, Gradle, JWT, Axon Framework, Docker, Docker Compose, AWS DynamoDB ### Sequence Diagram Example (송금 프로세스) ![Remittance_Sequence_Example](md_resource/Remittance_Sequence_Example.png) ## Payment Service (Part. 5) 가맹점에서 Fastcampus Pay 를 이용한 간편 결제 및 결제 내역 조회 등의 기능을 제공하는 서비스입니다. - Part 5. - Hexagonal Architecture 를 활용하여 Membership 서비스, Money 서비스를 이용하는 가맹점에서의 결제 기능 구현 - Membership Service 의 가맹점주 기능 확장 ### API Lists - requestPaymentAtMerchant - findPaymentByPaymentId - listPaymentsByPeriod #### Using Stack - Spring Boot, Java 11, Spring Data JPA, Mysql, Lombok, Gradle, Axon Framework, Docker, Docker Compose ### Sequence Diagram Example (결제 프로세스) ![Payment_Sequence_Example](md_resource/Payment_Sequence_Example.png) ## Settlement Service (Part. 6) 완료된 결제 내역을 기준으로 가맹점에 정산된 금액을 입금하고, 수수료 수취를 위한 기능을 제공하는 서비스입니다. - Part 6. - Hexagonal Architecture 를 활용하여 Payment 서비스를 이용하는 기간별 정산 기능 구현. - 수수료 수취 기능 구현, 가맹점주 계좌로 입금 기능 구현. ### API Lists - startSettlementByPeriod #### Using Stack - Spring Boot, Java 11, Spring Data JPA, Mysql, Lombok, Gradle, JWT, Axon Framework, Docker, Docker Compose ### Sequence Diagram Example (정산 프로세스) ![Settlement_Sequence_Example](md_resource/Settlement_Sequence_Example.png) ## Execution ``` ./gradlew docker docker-compose up -d ``` ## Service Endpoint & Swagger UI - Membership Service - http://localhost:8081/membership/ - http://localhost:8081/swagger-ui.html - Banking Service - http://localhost:8082/banking/ - http://localhost:8082/swagger-ui.html - Money Service - http://localhost:8083/money/ - http://localhost:8083/swagger-ui.html - Money Local Service (CQRS View Service) - http://localhost:8084/money-local/ - http://localhost:8084/swagger-ui.html - Remittance Service - http://localhost:8085/remittance/ - http://localhost:8085/swagger-ui.html - Payment Service - http://localhost:8086/payment/ - http://localhost:8086/swagger-ui.html - Settlement Service - http://localhost:8087/settlement/ - http://localhost:8087/swagger-ui.html - Mysql - http://localhost:3306 - root password: rootpassword - database: fastcampus_pay - User/PW : mysqluser / mysqlpw - Kafka UI - http://localhost:8989 - Axon Server Dashboard - http://localhost:8024 ## Trouble Shooting ### 1. gradle build(docker build) 시, dockerPrepare 단계에서 error 가 발생하는 경우 ``` ./gradlew --stop ./gradlew docker ``` ## Sample Screenshots ![Sample1](md_resource/sample_docker.png) ![Sample2](md_resource/sample_swagger.png) ![Sample3](md_resource/sample_kafkaui.png) ![Sample4](md_resource/sample_AxonServer.png) ![Sample5](md_resource/sample_mysql.png) ================================================ FILE: banking-service/build.gradle ================================================ plugins { id 'com.palantir.docker' version '0.25.0' } ext{ axonVersion = "4.6.0" } group = 'com.fastcampuspay.banking' version = '0.0.1-SNAPSHOT' dependencies { implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-web' implementation group: 'javax.persistence', name: 'javax.persistence-api', version: '2.2' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation group: 'org.axonframework', name: 'axon-configuration', version: "$axonVersion" implementation group: 'org.axonframework', name: 'axon-spring-boot-starter', version: "$axonVersion" implementation 'org.jetbrains:annotations:23.0.0' implementation project(path: ':common') // runtimeOnly 'com.h2database:h2' runtimeOnly 'mysql:mysql-connector-java' } docker { println(tasks.bootJar.outputs.files) name rootProject.name+'-'+project.name + ":" + version dockerfile file('../Dockerfile') files tasks.bootJar.outputs.files buildArgs(['JAR_FILE': tasks.bootJar.outputs.files.singleFile.name]) } ================================================ FILE: banking-service/src/main/java/com/fastcampuspay/banking/BankingApplication.java ================================================ package com.fastcampuspay.banking; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class BankingApplication { public static void main(String[] args) { SpringApplication.run(BankingApplication.class, args); } } ================================================ FILE: banking-service/src/main/java/com/fastcampuspay/banking/BankingConfiguration.java ================================================ package com.fastcampuspay.banking; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration @EnableConfigurationProperties(BankingConfigurationProperties.class) public class BankingConfiguration { } ================================================ FILE: banking-service/src/main/java/com/fastcampuspay/banking/BankingConfigurationProperties.java ================================================ package com.fastcampuspay.banking; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; @Data @ConfigurationProperties(prefix = "banking") public class BankingConfigurationProperties { private long transferThreshold = Long.MAX_VALUE; } ================================================ FILE: banking-service/src/main/java/com/fastcampuspay/banking/SwaggerConfig.java ================================================ package com.fastcampuspay.banking; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket restAPI() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.fastcampuspay.banking")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .build(); } } ================================================ FILE: banking-service/src/main/java/com/fastcampuspay/banking/adapter/in/web/FindBankingAccountInfoController.java ================================================ package com.fastcampuspay.banking.adapter.in.web; import com.fastcampuspay.common.WebAdapter; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @WebAdapter @RestController @RequiredArgsConstructor class FindBankingAccountInfoController { // private final RegisterBankingAccountUseCase registerBankingAccountUseCase; @GetMapping(path = "/banking/registered-banking-account/") ResponseEntity findRegisteredBankingAccountByMemberId(){ // RegisterMembershipRequest // name, address, email return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } @GetMapping(path = "/banking/transfer-money/") ResponseEntity findTransferMoneyInfoByMemberId(){ // RegisterMembershipRequest // name, address, email return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } @GetMapping(path = "/banking/transfer-money-info/") ResponseEntity findTransferMoneyInfoByBankingId(){ // RegisterMembershipRequest // name, address, email return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } } ================================================ FILE: banking-service/src/main/java/com/fastcampuspay/banking/adapter/in/web/RegisterBankingAccountInfoController.java ================================================ package com.fastcampuspay.banking.adapter.in.web; import com.fastcampuspay.banking.application.port.in.RegisterBankingAccountCommand; import com.fastcampuspay.banking.application.port.in.RegisterBankingAccountUseCase; import com.fastcampuspay.common.WebAdapter; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @WebAdapter @RestController @RequiredArgsConstructor class RegisterBankingAccountInfoController { private final RegisterBankingAccountUseCase registerBankingAccountUseCase; @PostMapping(path = "/banking/account/") void registerBankingAccount(@RequestBody RegisterBankingAccountInfoRequest request){ // RegisterMembershipRequest // name, address, email RegisterBankingAccountCommand command = RegisterBankingAccountCommand.builder() .name(request.getName()) .address(request.getAddress()) .email(request.getEmail()) .build(); registerBankingAccountUseCase.registerBankingAccount(command); } } ================================================ FILE: banking-service/src/main/java/com/fastcampuspay/banking/adapter/in/web/RegisterBankingAccountInfoRequest.java ================================================ package com.fastcampuspay.banking.adapter.in.web; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @Getter @Setter @AllArgsConstructor @NoArgsConstructor public class RegisterBankingAccountInfoRequest { private String name; private String address; private String email; } ================================================ FILE: banking-service/src/main/java/com/fastcampuspay/banking/adapter/in/web/RequestTransferMoneyController.java ================================================ package com.fastcampuspay.banking.adapter.in.web; import com.fastcampuspay.banking.domain.BankingAccountRegisterInfo; import com.fastcampuspay.common.WebAdapter; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; @WebAdapter @RestController @RequiredArgsConstructor class RequestTransferMoneyController { // private final RegisterBankingAccountUseCase registerBankingAccountUseCase; @PostMapping(path = "/banking/transfer-money") ResponseEntity requestTransferMoneyToBank(){ // RegisterMembershipRequest // name, address, email return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } } ================================================ FILE: banking-service/src/main/java/com/fastcampuspay/banking/adapter/out/persistence/BankingAccountPersistenceAdapter.java ================================================ package com.fastcampuspay.banking.adapter.out.persistence; import com.fastcampuspay.banking.application.port.out.RegisterBankingAccountPort; import com.fastcampuspay.banking.domain.BankingAccountRegisterInfo; import com.fastcampuspay.common.PersistenceAdapter; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @PersistenceAdapter class BankingAccountPersistenceAdapter implements RegisterBankingAccountPort { private final SpringDataBankingAccountRegisterInfoRepository bankingAccountRepository; private final BankingAccountRegisterInfoMapper bankingAccountRegisterInfoMapper; private Long orZero(Long value){ return value == null ? 0L : value; } @Override public void registerBankingAccount(BankingAccountRegisterInfo.BankingAccountRegisterInfoId bankingAccountRegisterInfoId) { bankingAccountRepository.save( new BankingAccountRegisterInfoJpaEntity( Long.parseLong(bankingAccountRegisterInfoId.getBankingAccountRegisterInfoId()) ) ); } } ================================================ FILE: banking-service/src/main/java/com/fastcampuspay/banking/adapter/out/persistence/BankingAccountRegisterInfoJpaEntity.java ================================================ package com.fastcampuspay.banking.adapter.out.persistence; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "banking_account_register_info") @Data @AllArgsConstructor @NoArgsConstructor class BankingAccountRegisterInfoJpaEntity { @Id @GeneratedValue private Long registerInfoId; // private String name; // // private String address; // // private String email; // // private boolean isValid; } ================================================ FILE: banking-service/src/main/java/com/fastcampuspay/banking/adapter/out/persistence/BankingAccountRegisterInfoMapper.java ================================================ package com.fastcampuspay.banking.adapter.out.persistence; import com.fastcampuspay.banking.domain.BankingAccountRegisterInfo; import org.springframework.stereotype.Component; @Component class BankingAccountRegisterInfoMapper { BankingAccountRegisterInfo mapToDomainEntity( BankingAccountRegisterInfoJpaEntity bankingAccountRegisterInfoJpaEntity) { System.out.println(bankingAccountRegisterInfoJpaEntity.toString()); return BankingAccountRegisterInfo.generateBankingAccountRegisterInfo( new BankingAccountRegisterInfo.BankingAccountRegisterInfoId(bankingAccountRegisterInfoJpaEntity.getRegisterInfoId()+"") ); } } ================================================ FILE: banking-service/src/main/java/com/fastcampuspay/banking/adapter/out/persistence/SpringDataBankingAccountRegisterInfoRepository.java ================================================ package com.fastcampuspay.banking.adapter.out.persistence; import org.springframework.data.jpa.repository.JpaRepository; interface SpringDataBankingAccountRegisterInfoRepository extends JpaRepository { } ================================================ FILE: banking-service/src/main/java/com/fastcampuspay/banking/application/port/in/RegisterBankingAccountCommand.java ================================================ package com.fastcampuspay.banking.application.port.in; import com.fastcampuspay.common.SelfValidating; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Value; import javax.validation.constraints.NotNull; @Value @Builder @EqualsAndHashCode(callSuper = false) public class RegisterBankingAccountCommand extends SelfValidating { @NotNull private final String name; @NotNull private final String email; @NotNull private final String address; @NotNull private final boolean isValid; public RegisterBankingAccountCommand(String name, String email, String address, boolean isValid) { this.name = name; this.email = email; this.address = address; this.isValid = isValid; } } ================================================ FILE: banking-service/src/main/java/com/fastcampuspay/banking/application/port/in/RegisterBankingAccountUseCase.java ================================================ package com.fastcampuspay.banking.application.port.in; public interface RegisterBankingAccountUseCase { void registerBankingAccount(RegisterBankingAccountCommand command); } ================================================ FILE: banking-service/src/main/java/com/fastcampuspay/banking/application/port/out/RegisterBankingAccountPort.java ================================================ package com.fastcampuspay.banking.application.port.out; import com.fastcampuspay.banking.domain.BankingAccountRegisterInfo; public interface RegisterBankingAccountPort { void registerBankingAccount( BankingAccountRegisterInfo.BankingAccountRegisterInfoId bankingAccountRegisterInfoId ); } ================================================ FILE: banking-service/src/main/java/com/fastcampuspay/banking/application/service/RegisterBankingAccount.java ================================================ package com.fastcampuspay.banking.application.service; import com.fastcampuspay.banking.application.port.in.RegisterBankingAccountCommand; import com.fastcampuspay.banking.application.port.in.RegisterBankingAccountUseCase; import com.fastcampuspay.banking.application.port.out.RegisterBankingAccountPort; import com.fastcampuspay.banking.domain.BankingAccountRegisterInfo; import com.fastcampuspay.common.UseCase; import lombok.RequiredArgsConstructor; import javax.transaction.Transactional; @RequiredArgsConstructor @UseCase @Transactional public class RegisterBankingAccount implements RegisterBankingAccountUseCase { private final RegisterBankingAccountPort rport; @Override public void registerBankingAccount(RegisterBankingAccountCommand command) { rport.registerBankingAccount(new BankingAccountRegisterInfo.BankingAccountRegisterInfoId(command.getEmail())); } } ================================================ FILE: banking-service/src/main/java/com/fastcampuspay/banking/domain/BankingAccountRegisterInfo.java ================================================ package com.fastcampuspay.banking.domain; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Value; @AllArgsConstructor(access = AccessLevel.PRIVATE) public class BankingAccountRegisterInfo { /** * The baseline balance of the account. This was the balance of the account before the first * activity in the activityWindow. */ @Getter private final String bankingAccountRegisterInfoId; // @Getter private final String name; // @Getter private final String email; // @Getter private final String address; // @Getter private final boolean isValid; public static BankingAccountRegisterInfo generateBankingAccountRegisterInfo( BankingAccountRegisterInfoId bankingAccountRegisterInfoId) { return new BankingAccountRegisterInfo( bankingAccountRegisterInfoId.bankingAccountRegisterInfoId ); } @Value public static class BankingAccountRegisterInfoId { public BankingAccountRegisterInfoId(String value) { this.bankingAccountRegisterInfoId = value; } String bankingAccountRegisterInfoId ; } } ================================================ FILE: banking-service/src/main/java/com/fastcampuspay/banking/domain/TransferMoney.java ================================================ package com.fastcampuspay.banking.domain; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Value; @AllArgsConstructor(access = AccessLevel.PRIVATE) public class TransferMoney { /** * The baseline balance of the account. This was the balance of the account before the first * activity in the activityWindow. */ @Getter private final String transferMoneyId; public static TransferMoney generateTransferMoney( TransferMoneyId transferMoneyId) { return new TransferMoney( transferMoneyId.transferMoneyId ); } @Value public static class TransferMoneyId { public TransferMoneyId(String value) { this.transferMoneyId = value; } String transferMoneyId ; } } ================================================ FILE: build.gradle ================================================ buildscript { dependencies { classpath "io.spring.gradle:dependency-management-plugin:0.5.1.RELEASE" } } plugins { id 'org.springframework.boot' version '2.5.2' id 'java' } subprojects { compileJava { sourceCompatibility = 11 targetCompatibility = 11 } apply plugin: 'java' apply plugin: 'java-library' apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' repositories { mavenCentral() } dependencies { compileOnly 'org.projectlombok:lombok' annotationProcessor 'org.projectlombok:lombok' annotationProcessor "org.springframework.boot:spring-boot-configuration-processor" implementation group: 'io.springfox', name: 'springfox-swagger-ui', version: '2.9.2' implementation group: 'io.springfox', name: 'springfox-swagger2', version: '2.9.2' testImplementation 'com.tngtech.archunit:archunit:1.0.1' testImplementation 'org.springframework.boot:spring-boot-starter-test' } test { useJUnitPlatform() maxHeapSize = "1024m" //원하는 만큼 변경 } } bootRun { enabled = false } bootJar { enabled = false } bootBuildImage{ enabled = false } ================================================ FILE: common/build.gradle ================================================ group 'org.mypay.common' repositories { mavenCentral() } dependencies { testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' implementation 'org.springframework.boot:spring-boot-starter-validation' } test { useJUnitPlatform() } ================================================ FILE: common/src/main/java/com/fastcampuspay/common/PersistenceAdapter.java ================================================ package com.fastcampuspay.common; import org.springframework.core.annotation.AliasFor; import org.springframework.stereotype.Component; import java.lang.annotation.*; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface PersistenceAdapter { /** * The value may indicate a suggestion for a logical component name, * to be turned into a Spring bean in case of an autodetected component. * @return the suggested component name, if any (or empty String otherwise) */ @AliasFor(annotation = Component.class) String value() default ""; } ================================================ FILE: common/src/main/java/com/fastcampuspay/common/SelfValidating.java ================================================ package com.fastcampuspay.common; import javax.validation.*; import java.util.Set; public abstract class SelfValidating { private Validator validator; public SelfValidating() { ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); validator = factory.getValidator(); } /** * Evaluates all Bean Validations on the attributes of this * instance. */ protected void validateSelf() { Set> violations = validator.validate((T) this); if (!violations.isEmpty()) { throw new ConstraintViolationException(violations); } } } ================================================ FILE: common/src/main/java/com/fastcampuspay/common/UseCase.java ================================================ package com.fastcampuspay.common; import org.springframework.core.annotation.AliasFor; import org.springframework.stereotype.Component; import java.lang.annotation.*; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface UseCase { /** * The value may indicate a suggestion for a logical component name, * to be turned into a Spring bean in case of an autodetected component. * @return the suggested component name, if any (or empty String otherwise) */ @AliasFor(annotation = Component.class) String value() default ""; } ================================================ FILE: common/src/main/java/com/fastcampuspay/common/WebAdapter.java ================================================ package com.fastcampuspay.common; import org.springframework.core.annotation.AliasFor; import org.springframework.stereotype.Component; import java.lang.annotation.*; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface WebAdapter { /** * The value may indicate a suggestion for a logical component name, * to be turned into a Spring bean in case of an autodetected component. * @return the suggested component name, if any (or empty String otherwise) */ @AliasFor(annotation = Component.class) String value() default ""; } ================================================ FILE: common/src/main/java/com/fastcampuspay/common/events/RegisterAccountEvent.java ================================================ package com.fastcampuspay.common.events; import java.util.Objects; public class RegisterAccountEvent { private final String accountId; public RegisterAccountEvent(){ this.accountId = "0000"; } public RegisterAccountEvent(String accountId) { this.accountId = accountId; } public String getAccountId() { return accountId; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } RegisterAccountEvent that = (RegisterAccountEvent) o; return Objects.equals(accountId, that.accountId); } @Override public int hashCode() { return Objects.hash(accountId); } @Override public String toString() { return "OrderCreatedEvent{" + "orderId='" + accountId + '\'' + '}'; } } ================================================ FILE: db/conf.d/my.cnf ================================================ ================================================ FILE: db/initdb.d/create_table.sql ================================================ CREATE DATABASE IF NOT EXISTS fastcampus_pay; USE fastcampus_pay; -- for Axon Framework (for Mismatching of Axon and Mysql) create table IF NOT EXISTS dead_letter_entry ( dead_letter_id varchar(255) not null, cause_message varchar(255), cause_type varchar(255), diagnostics longblob, enqueued_at datetime not null, `index` bigint not null, last_touched datetime, aggregate_identifier varchar(255), event_identifier varchar(255) not null, message_type varchar(255) not null, meta_data longblob, payload longblob not null, payload_revision varchar(255), payload_type varchar(255) not null, sequence_number bigint, time_stamp varchar(255) not null, token longblob, token_type varchar(255), type varchar(255), processing_group varchar(255) not null, processing_started datetime, sequence_identifier varchar(255) not null, primary key (dead_letter_id) ) engine=InnoDB ================================================ FILE: db/initdb.d/load_data.sql ================================================ ================================================ FILE: docker-compose.yaml ================================================ version: '3' services: zookeeper: image: 'arm64v8/zookeeper:3.8' networks: - fastcampuspay_network ports: - '2181:2181' environment: - ALLOW_ANONYMOUS_LOGIN=yes - ZOO_TLS_CLIENT_AUTH=none - ZOO_TLS_QUORUM_CLIENT_AUTH=none kafka: image: 'bitnami/kafka:3.4.0' networks: - fastcampuspay_network ports: - '9092:9092' environment: - KAFKA_BROKER_ID=1 - KAFKA_CFG_ZOOKEEPER_CONNECT=zookeeper:2181 - ALLOW_PLAINTEXT_LISTENER=yes - KAFKA_CFG_LISTENERS=LC://kafka:29092,LX://kafka:9092 - KAFKA_CFG_ADVERTISED_LISTENERS=LC://kafka:29092,LX://${DOCKER_HOST_IP:-localhost}:9092 - KAFKA_CFG_LISTENER_SECURITY_PROTOCOL_MAP=LC:PLAINTEXT,LX:PLAINTEXT - KAFKA_CFG_INTER_BROKER_LISTENER_NAME=LC depends_on: - zookeeper kafka-ui: image: provectuslabs/kafka-ui container_name: kafka-ui networks: - fastcampuspay_network ports: - "8989:8080" restart: always depends_on: - kafka - zookeeper environment: - KAFKA_CLUSTERS_0_NAME=local - KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS=kafka:29092 - KAFKA_CLUSTERS_0_ZOOKEEPER=zookeeper:2181 mysql: image: mysql:8.0 networks: - fastcampuspay_network volumes: - ./db/conf.d:/etc/mysql/conf.d - ./db/data:/var/lib/mysql - ./db/initdb.d:/docker-entrypoint-initdb.d env_file: .env ports: - "3306:3306" environment: - TZ=Asia/Seoul - MYSQL_ROOT_PASSWORD=rootpassword - MYSQL_USER=mysqluser - MYSQL_PASSWORD=mysqlpw axon-server: container_name: axon-server image: axoniq/axonserver:4.6.3-jdk-11-dev networks: - fastcampuspay_network ports: - "8024:8024" - "8124:8124" volumes: - axonserver-data:/axonserver/data - axonserver-events:/axonserver/events - axonserver-config:/axonserver/config:ro membership-service: image: fastcampus-pay-membership-service:0.0.1-SNAPSHOT networks: - fastcampuspay_network ports: - "8081:8080" depends_on: - axon-server - mysql environment: - AXON_AXONSERVER_SERVERS=axon-server:8124 - AXON_SERIALIZER_EVENTS=jackson - AXON_SERIALIZER_MESSAGES=jackson - AXON_SERIALIZER_GENERAL=xstream - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/fastcampus_pay?useSSL=false&allowPublicKeyRetrieval=true - SPRING_DATASOURCE_USERNAME=mysqluser - SPRING_DATASOURCE_PASSWORD=mysqlpw - SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT=org.hibernate.dialect.MySQL5InnoDBDialect - SPRING_JPA_HIBERNATE_DDL_AUTO=update banking-service: image: fastcampus-pay-banking-service:0.0.1-SNAPSHOT networks: - fastcampuspay_network ports: - "8082:8080" depends_on: - axon-server - mysql environment: - AXON_AXONSERVER_SERVERS=axon-server:8124 - AXON_SERIALIZER_EVENTS=jackson - AXON_SERIALIZER_MESSAGES=jackson - AXON_SERIALIZER_GENERAL=xstream - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/fastcampus_pay?useSSL=false&allowPublicKeyRetrieval=true - SPRING_DATASOURCE_USERNAME=mysqluser - SPRING_DATASOURCE_PASSWORD=mysqlpw - SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT=org.hibernate.dialect.MySQL5InnoDBDialect - SPRING_JPA_HIBERNATE_DDL_AUTO=update money-service: image: fastcampus-pay-money-service:0.0.1-SNAPSHOT networks: - fastcampuspay_network ports: - "8083:8080" depends_on: - axon-server - mysql environment: - AXON_AXONSERVER_SERVERS=axon-server:8124 - AXON_SERIALIZER_EVENTS=jackson - AXON_SERIALIZER_MESSAGES=jackson - AXON_SERIALIZER_GENERAL=xstream - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/fastcampus_pay?useSSL=false&allowPublicKeyRetrieval=true - SPRING_DATASOURCE_USERNAME=mysqluser - SPRING_DATASOURCE_PASSWORD=mysqlpw - SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT=org.hibernate.dialect.MySQL5InnoDBDialect - SPRING_JPA_HIBERNATE_DDL_AUTO=update money-local-service: image: fastcampus-pay-money-local-service:0.0.1-SNAPSHOT networks: - fastcampuspay_network ports: - "8084:8080" depends_on: - axon-server - mysql environment: - AXON_AXONSERVER_SERVERS=axon-server:8124 - AXON_SERIALIZER_EVENTS=jackson - AXON_SERIALIZER_MESSAGES=jackson - AXON_SERIALIZER_GENERAL=xstream - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/fastcampus_pay?useSSL=false&allowPublicKeyRetrieval=true - SPRING_DATASOURCE_USERNAME=mysqluser - SPRING_DATASOURCE_PASSWORD=mysqlpw - SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT=org.hibernate.dialect.MySQL5InnoDBDialect - SPRING_JPA_HIBERNATE_DDL_AUTO=update remittance-service: image: fastcampus-pay-remittance-service:0.0.1-SNAPSHOT networks: - fastcampuspay_network ports: - "8085:8080" depends_on: - axon-server - mysql environment: - AXON_AXONSERVER_SERVERS=axon-server:8124 - AXON_SERIALIZER_EVENTS=jackson - AXON_SERIALIZER_MESSAGES=jackson - AXON_SERIALIZER_GENERAL=xstream - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/fastcampus_pay?useSSL=false&allowPublicKeyRetrieval=true - SPRING_DATASOURCE_USERNAME=mysqluser - SPRING_DATASOURCE_PASSWORD=mysqlpw - SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT=org.hibernate.dialect.MySQL5InnoDBDialect - SPRING_JPA_HIBERNATE_DDL_AUTO=update payment-service: image: fastcampus-pay-payment-service:0.0.1-SNAPSHOT networks: - fastcampuspay_network ports: - "8086:8080" depends_on: - axon-server - mysql environment: - AXON_AXONSERVER_SERVERS=axon-server:8124 - AXON_SERIALIZER_EVENTS=jackson - AXON_SERIALIZER_MESSAGES=jackson - AXON_SERIALIZER_GENERAL=xstream - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/fastcampus_pay?useSSL=false&allowPublicKeyRetrieval=true - SPRING_DATASOURCE_USERNAME=mysqluser - SPRING_DATASOURCE_PASSWORD=mysqlpw - SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT=org.hibernate.dialect.MySQL5InnoDBDialect - SPRING_JPA_HIBERNATE_DDL_AUTO=update settlement-service: image: fastcampus-pay-settlement-service:0.0.1-SNAPSHOT networks: - fastcampuspay_network ports: - "8087:8080" depends_on: - axon-server - mysql environment: - AXON_AXONSERVER_SERVERS=axon-server:8124 - AXON_SERIALIZER_EVENTS=jackson - AXON_SERIALIZER_MESSAGES=jackson - AXON_SERIALIZER_GENERAL=xstream - SPRING_DATASOURCE_URL=jdbc:mysql://mysql:3306/fastcampus_pay?useSSL=false&allowPublicKeyRetrieval=true - SPRING_DATASOURCE_USERNAME=mysqluser - SPRING_DATASOURCE_PASSWORD=mysqlpw - SPRING_JPA_PROPERTIES_HIBERNATE_DIALECT=org.hibernate.dialect.MySQL5InnoDBDialect - SPRING_JPA_HIBERNATE_DDL_AUTO=update volumes: axonserver-data: driver: local driver_opts: o: bind type: none device: ${PWD}/axon-server-se/data axonserver-events: driver: local driver_opts: o: bind type: none device: ${PWD}/axon-server-se/events axonserver-config: driver: local driver_opts: o: bind type: none device: ${PWD}/axon-server-se/config networks: fastcampuspay_network: driver: bridge ================================================ FILE: gradle/wrapper/gradle-wrapper.properties ================================================ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists ================================================ FILE: gradle.properties ================================================ org.gradle.jvmargs=-Xmx2g org.gradle.caching=true org.gradle.configureondemand=true org.gradle.parallel=false ================================================ FILE: gradlew ================================================ #!/usr/bin/env sh # # Copyright 2015 the original author or authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # ############################################################################## ## ## Gradle start up script for UN*X ## ############################################################################## # Attempt to set APP_HOME # Resolve links: $0 may be a link PRG="$0" # Need this for relative symlinks. while [ -h "$PRG" ] ; do ls=`ls -ld "$PRG"` link=`expr "$ls" : '.*-> \(.*\)$'` if expr "$link" : '/.*' > /dev/null; then PRG="$link" else PRG=`dirname "$PRG"`"/$link" fi done SAVED="`pwd`" cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME="`pwd -P`" cd "$SAVED" >/dev/null APP_NAME="Gradle" APP_BASE_NAME=`basename "$0"` # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD="maximum" warn () { echo "$*" } die () { echo echo "$*" echo exit 1 } # OS specific support (must be 'true' or 'false'). cygwin=false msys=false darwin=false nonstop=false case "`uname`" in CYGWIN* ) cygwin=true ;; Darwin* ) darwin=true ;; MINGW* ) msys=true ;; NONSTOP* ) nonstop=true ;; esac CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar # Determine the Java command to use to start the JVM. if [ -n "$JAVA_HOME" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then # IBM's JDK on AIX uses strange locations for the executables JAVACMD="$JAVA_HOME/jre/sh/java" else JAVACMD="$JAVA_HOME/bin/java" fi if [ ! -x "$JAVACMD" ] ; then die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi else JAVACMD="java" which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." fi # Increase the maximum file descriptors if we can. if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then MAX_FD_LIMIT=`ulimit -H -n` if [ $? -eq 0 ] ; then if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD="$MAX_FD_LIMIT" fi ulimit -n $MAX_FD if [ $? -ne 0 ] ; then warn "Could not set maximum file descriptor limit: $MAX_FD" fi else warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" fi fi # For Darwin, add options to specify how the application appears in the dock if $darwin; then GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" fi # For Cygwin or MSYS, switch paths to Windows format before running java if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` SEP="" for dir in $ROOTDIRSRAW ; do ROOTDIRS="$ROOTDIRS$SEP$dir" SEP="|" done OURCYGPATTERN="(^($ROOTDIRS))" # Add a user-defined pattern to the cygpath arguments if [ "$GRADLE_CYGPATTERN" != "" ] ; then OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" fi # Now convert the arguments - kludge to limit ourselves to /bin/sh i=0 for arg in "$@" ; do CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` else eval `echo args$i`="\"$arg\"" fi i=`expr $i + 1` done case $i in 0) set -- ;; 1) set -- "$args0" ;; 2) set -- "$args0" "$args1" ;; 3) set -- "$args0" "$args1" "$args2" ;; 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; esac fi # Escape application args save () { for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done echo " " } APP_ARGS=`save "$@"` # Collect all arguments for the java command, following the shell quoting and substitution rules eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" exec "$JAVACMD" "$@" ================================================ FILE: gradlew.bat ================================================ @rem @rem Copyright 2015 the original author or authors. @rem @rem Licensed under the Apache License, Version 2.0 (the "License"); @rem you may not use this file except in compliance with the License. @rem You may obtain a copy of the License at @rem @rem https://www.apache.org/licenses/LICENSE-2.0 @rem @rem Unless required by applicable law or agreed to in writing, software @rem distributed under the License is distributed on an "AS IS" BASIS, @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem @if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Resolve any "." and ".." in APP_HOME to make it shorter. for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega ================================================ FILE: membership-service/build.gradle ================================================ plugins { id 'com.palantir.docker' version '0.25.0' } ext{ axonVersion = "4.6.0" } group = 'com.fastcampuspay.membership' version = '0.0.1-SNAPSHOT' dependencies { implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-web' implementation group: 'javax.persistence', name: 'javax.persistence-api', version: '2.2' implementation group: 'org.axonframework', name: 'axon-configuration', version: "$axonVersion" implementation group: 'org.axonframework', name: 'axon-spring-boot-starter', version: "$axonVersion" implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation project(path: ':common') implementation 'org.jetbrains:annotations:23.0.0' // runtimeOnly 'com.h2database:h2' runtimeOnly 'mysql:mysql-connector-java' } docker { println(tasks.bootJar.outputs.files) name rootProject.name+'-'+project.name + ":" + version dockerfile file('../Dockerfile') files tasks.bootJar.outputs.files buildArgs(['JAR_FILE': tasks.bootJar.outputs.files.singleFile.name]) } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/MembershipApplication.java ================================================ package com.fastcampuspay.membership; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MembershipApplication { public static void main(String[] args) { SpringApplication.run(MembershipApplication.class, args); } } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/MembershipConfiguration.java ================================================ package com.fastcampuspay.membership; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration @EnableConfigurationProperties(MembershipConfigurationProperties.class) public class MembershipConfiguration { } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/MembershipConfigurationProperties.java ================================================ package com.fastcampuspay.membership; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; @Data @ConfigurationProperties(prefix = "membership") public class MembershipConfigurationProperties { private long transferThreshold = Long.MAX_VALUE; } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/SwaggerConfig.java ================================================ package com.fastcampuspay.membership; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket restAPI() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.fastcampuspay.membership")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .build(); } } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/adapter/in/web/FindMembershipController.java ================================================ package com.fastcampuspay.membership.adapter.in.web; import com.fastcampuspay.common.WebAdapter; import com.fastcampuspay.membership.application.port.in.FindMembershipCommand; import com.fastcampuspay.membership.application.port.in.FindMembershipUseCase; import com.fastcampuspay.membership.domain.Membership; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; @WebAdapter @RestController @RequiredArgsConstructor class FindMembershipController { private final FindMembershipUseCase findMembershipUseCase; @GetMapping(path = "/membership/{membershipId}") ResponseEntity findMembershipByMemberId(@PathVariable String membershipId){ FindMembershipCommand command = FindMembershipCommand.builder() .membershipId(membershipId) .build(); return ResponseEntity.ok(findMembershipUseCase.findMembership(command)); } @GetMapping(path = "/membership/axon/{membershipId}") ResponseEntity findAxonMembershipByMemberId(@PathVariable String membershipId){ FindMembershipCommand command = FindMembershipCommand.builder() .membershipId(membershipId) .build(); return ResponseEntity.ok(findMembershipUseCase.findAxonMembership(command)); } } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/adapter/in/web/FindMembershipRequest.java ================================================ package com.fastcampuspay.membership.adapter.in.web; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @Getter @Setter @AllArgsConstructor @NoArgsConstructor public class FindMembershipRequest { private String membershipId; } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/adapter/in/web/LoginAuthMembershipController.java ================================================ package com.fastcampuspay.membership.adapter.in.web; import com.fastcampuspay.common.WebAdapter; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; @WebAdapter @RestController @RequiredArgsConstructor class LoginAuthMembershipController { @PostMapping(path = "/membership/login/") ResponseEntity loginByMembershipIdPw(){ return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } @PostMapping(path = "/membership/auth/") ResponseEntity authByToken(){ return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/adapter/in/web/RegisterMembershipController.java ================================================ package com.fastcampuspay.membership.adapter.in.web; import com.fastcampuspay.common.WebAdapter; import com.fastcampuspay.membership.application.port.in.RegisterMembershipCommand; import com.fastcampuspay.membership.application.port.in.RegisterMembershipUseCase; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @WebAdapter @RestController @RequiredArgsConstructor class RegisterMembershipController { private final RegisterMembershipUseCase registerMembershipUseCase; @PostMapping(path = "/membership/register/") void registerMembership(@RequestBody RegisterMembershipRequest request){ // RegisterMembershipRequest // name, address, email RegisterMembershipCommand command = RegisterMembershipCommand.builder() .name(request.getName()) .address(request.getAddress()) .email(request.getEmail()) .build(); registerMembershipUseCase.registerMembership(command); } @PostMapping(path = "/membership/axon-register/") void registerAxonMembership(@RequestBody RegisterMembershipRequest request){ RegisterMembershipCommand command = RegisterMembershipCommand.builder() .name(request.getName()) .address(request.getAddress()) .email(request.getEmail()) .build(); registerMembershipUseCase.registerAxonMembership(command); } } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/adapter/in/web/RegisterMembershipRequest.java ================================================ package com.fastcampuspay.membership.adapter.in.web; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @Getter @Setter @AllArgsConstructor @NoArgsConstructor public class RegisterMembershipRequest { private String name; private String address; private String email; } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/adapter/in/web/UpdateMembershipController.java ================================================ package com.fastcampuspay.membership.adapter.in.web; import com.fastcampuspay.common.WebAdapter; import com.fastcampuspay.membership.application.port.in.UpdateMembershipCommand; import com.fastcampuspay.membership.application.port.in.UpdateMembershipUseCase; import com.fastcampuspay.membership.domain.Membership; import lombok.RequiredArgsConstructor; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; @WebAdapter @RestController @RequiredArgsConstructor class UpdateMembershipController { private final UpdateMembershipUseCase updateMembershipUseCase; @PutMapping(path = "/membership/update") ResponseEntity updateMembershipByMemberId(@RequestBody UpdateMembershipRequest membershipToBeUpdated){ // updateMembership UpdateMembershipCommand command = UpdateMembershipCommand.builder() .membershipId(membershipToBeUpdated.getMembershipId()) .name(membershipToBeUpdated.getName()) .address(membershipToBeUpdated.getAddress()) .email(membershipToBeUpdated.getEmail()) .isValid(membershipToBeUpdated.isValid()) .build(); return ResponseEntity.ok(updateMembershipUseCase.updateMembership(command)); } @PutMapping(path = "/membership/axon-update") ResponseEntity updateAxonMembershipByMemberId(@RequestBody UpdateMembershipRequest membershipToBeUpdated){ System.out.println("axon update controller"); // updateMembership UpdateMembershipCommand command = UpdateMembershipCommand.builder() .membershipId(membershipToBeUpdated.getMembershipId()) .name(membershipToBeUpdated.getName()) .address(membershipToBeUpdated.getAddress()) .email(membershipToBeUpdated.getEmail()) .isValid(membershipToBeUpdated.isValid()) .build(); return ResponseEntity.ok(updateMembershipUseCase.updateAxonMembership(command)); } } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/adapter/in/web/UpdateMembershipRequest.java ================================================ package com.fastcampuspay.membership.adapter.in.web; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @Getter @Setter @AllArgsConstructor @NoArgsConstructor public class UpdateMembershipRequest { private String membershipId; private String name; private String address; private String email; private boolean isValid; } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/adapter/out/persistence/MembershipJpaEntity.java ================================================ package com.fastcampuspay.membership.adapter.out.persistence; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "membership") @Data @AllArgsConstructor @NoArgsConstructor class MembershipJpaEntity { @Id @GeneratedValue private Long membershipId; private String name; private String address; private String email; private boolean isValid; private String aggregateIdentifier; public MembershipJpaEntity(String name, String address, String email, boolean isValid, String aggregateIdentifier) { this.name = name; this.address = address; this.email = email; this.isValid = isValid; this.aggregateIdentifier = aggregateIdentifier; } @Override public String toString() { return "MembershipJpaEntity{" + "membershipId=" + membershipId + ", name='" + name + '\'' + ", address='" + address + '\'' + ", email='" + email + '\'' + ", isValid=" + isValid + ", aggregateIdentifier='" + aggregateIdentifier + '\'' + '}'; } } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/adapter/out/persistence/MembershipMapper.java ================================================ package com.fastcampuspay.membership.adapter.out.persistence; import com.fastcampuspay.membership.domain.Membership; import org.springframework.stereotype.Component; @Component class MembershipMapper { Membership mapToDomainEntity( MembershipJpaEntity membership) { System.out.println(membership.toString()); return Membership.generateMember( new Membership.MembershipId(membership.getMembershipId()+""), new Membership.MembershipName(membership.getName()), new Membership.MembershipEmail(membership.getEmail()), new Membership.MembershipAddress(membership.getAddress()), new Membership.MembershipIsValid(membership.isValid()), new Membership.MembershipAggregateIdentifier(membership.getAggregateIdentifier()) ); } } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/adapter/out/persistence/MembershipPersistenceAdapter.java ================================================ package com.fastcampuspay.membership.adapter.out.persistence; import com.fastcampuspay.common.PersistenceAdapter; import com.fastcampuspay.membership.application.port.out.FindMembershipPort; import com.fastcampuspay.membership.application.port.out.RegisterMembershipPort; import com.fastcampuspay.membership.application.port.out.UpdateMembershipPort; import com.fastcampuspay.membership.domain.Membership; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @PersistenceAdapter class MembershipPersistenceAdapter implements RegisterMembershipPort, FindMembershipPort, UpdateMembershipPort { private final SpringDataMembershipRepository membershipRepository; private final MembershipMapper membershipMapper; @Override public void createMembership(Membership.MembershipName membershipName , Membership.MembershipEmail membershipEmail , Membership.MembershipAddress membershipAddress , Membership.MembershipIsValid membershipIsValid , Membership.MembershipAggregateIdentifier membershipAggregateIdentifier ) { membershipRepository.save( new MembershipJpaEntity( membershipName.getNameValue(), membershipEmail.getEmailValue(), membershipAddress.getAddressValue(), membershipIsValid.isValidValue(), membershipAggregateIdentifier.getAggregateIdentifier() ) ); } @Override public Membership findMembership(Membership.MembershipId membershipId) { return membershipMapper.mapToDomainEntity( membershipRepository.getById(Long.parseLong(membershipId.getMembershipId())) ); } @Override public Membership updateMembership(Membership.MembershipId membershipId, Membership.MembershipName membershipName, Membership.MembershipEmail membershipEmail, Membership.MembershipAddress membershipAddress, Membership.MembershipIsValid membershipIsValid) { // update membership Info MembershipJpaEntity membershipJpaEntity = membershipRepository.getById(Long.parseLong(membershipId.getMembershipId())); membershipJpaEntity.setName(membershipName.getNameValue()); membershipJpaEntity.setEmail(membershipEmail.getEmailValue()); membershipJpaEntity.setAddress(membershipAddress.getAddressValue()); membershipJpaEntity.setValid(membershipIsValid.isValidValue()); // save MembershipJpaEntity updatedMembership = membershipRepository.save(membershipJpaEntity); // return return membershipMapper.mapToDomainEntity(updatedMembership); } } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/adapter/out/persistence/SpringDataMembershipRepository.java ================================================ package com.fastcampuspay.membership.adapter.out.persistence; import org.springframework.data.jpa.repository.JpaRepository; interface SpringDataMembershipRepository extends JpaRepository { } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/port/in/FindMembershipCommand.java ================================================ package com.fastcampuspay.membership.application.port.in; import com.fastcampuspay.common.SelfValidating; import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; @Data @Builder @EqualsAndHashCode(callSuper = false) public class FindMembershipCommand extends SelfValidating { private final String membershipId; } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/port/in/FindMembershipUseCase.java ================================================ package com.fastcampuspay.membership.application.port.in; import com.fastcampuspay.membership.domain.Membership; public interface FindMembershipUseCase { Membership findMembership(FindMembershipCommand command); Membership findAxonMembership(FindMembershipCommand command); } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/port/in/RegisterMembershipCommand.java ================================================ package com.fastcampuspay.membership.application.port.in; import com.fastcampuspay.common.SelfValidating; import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; import javax.validation.constraints.NotNull; @Builder @Data @EqualsAndHashCode(callSuper = false) public class RegisterMembershipCommand extends SelfValidating { @NotNull private final String name; @NotNull private final String email; @NotNull private final String address; @NotNull private final boolean isValid; public RegisterMembershipCommand(String name, String email, String address, boolean isValid) { this.name = name; this.email = email; this.address = address; this.isValid = isValid; } } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/port/in/RegisterMembershipUseCase.java ================================================ package com.fastcampuspay.membership.application.port.in; public interface RegisterMembershipUseCase { void registerMembership(RegisterMembershipCommand command); void registerAxonMembership(RegisterMembershipCommand command); } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/port/in/UpdateMembershipCommand.java ================================================ package com.fastcampuspay.membership.application.port.in; import com.fastcampuspay.common.SelfValidating; import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; import org.axonframework.modelling.command.TargetAggregateIdentifier; import javax.validation.constraints.NotNull; @Builder @Data @EqualsAndHashCode(callSuper = false) public class UpdateMembershipCommand extends SelfValidating { @NotNull @TargetAggregateIdentifier private String membershipId; private String name; private String address; private String email; private boolean isValid; } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/port/in/UpdateMembershipEventCommand.java ================================================ package com.fastcampuspay.membership.application.port.in; import com.fastcampuspay.common.SelfValidating; import lombok.*; import org.axonframework.modelling.command.TargetAggregateIdentifier; import javax.validation.constraints.NotNull; @Builder @Data @EqualsAndHashCode(callSuper = false) @AllArgsConstructor @NoArgsConstructor public class UpdateMembershipEventCommand extends SelfValidating { @NotNull @TargetAggregateIdentifier private String aggregateIdentifier; private String name; private String address; private String email; private boolean isValid; } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/port/in/UpdateMembershipUseCase.java ================================================ package com.fastcampuspay.membership.application.port.in; import com.fastcampuspay.membership.domain.Membership; public interface UpdateMembershipUseCase { Membership updateMembership(UpdateMembershipCommand command); Membership updateAxonMembership(UpdateMembershipCommand command); } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/port/in/aggregate/MembershipAggregate.java ================================================ package com.fastcampuspay.membership.application.port.in.aggregate; import com.fastcampuspay.membership.application.port.in.RegisterMembershipCommand; import com.fastcampuspay.membership.application.port.in.UpdateMembershipCommand; import com.fastcampuspay.membership.application.port.in.UpdateMembershipEventCommand; import com.fastcampuspay.membership.application.saga.MembershipCreateEvent; import com.fastcampuspay.membership.application.saga.MembershipUpdateEvent; import lombok.Data; import org.axonframework.commandhandling.CommandHandler; import org.axonframework.eventsourcing.EventSourcingHandler; import org.axonframework.modelling.command.AggregateIdentifier; import org.axonframework.spring.stereotype.Aggregate; import org.jetbrains.annotations.NotNull; import java.util.UUID; import static org.axonframework.modelling.command.AggregateLifecycle.apply; @Aggregate() @Data public class MembershipAggregate { @AggregateIdentifier private String id; private String name; private String email; private String address; @CommandHandler public MembershipAggregate(@NotNull RegisterMembershipCommand command) { System.out.println("RegisterMembershipCommand Handler"); // store event apply(new MembershipCreateEvent(command.getName(), command.getEmail(), command.getAddress())); } @CommandHandler public String handle(@NotNull UpdateMembershipEventCommand command) { System.out.println("UpdateMembershipEventCommand Handler"); id = command.getAggregateIdentifier(); // store event apply(new MembershipUpdateEvent(id, command.getName(), command.getEmail(), command.getAddress())); return id; } @CommandHandler public String handle (@NotNull UpdateMembershipCommand command) { System.out.println("UpdateMembershipCommand Handler"); String aggregateIdentifier = command.getMembershipId(); id = aggregateIdentifier; // store event apply(new MembershipUpdateEvent(aggregateIdentifier, command.getName(), command.getEmail(), command.getAddress())); return aggregateIdentifier; } @EventSourcingHandler public void on(MembershipCreateEvent event) { System.out.println("MembershipCreateEvent Sourcing Handler"); id = UUID.randomUUID().toString(); name = event.getName() ; email = event.getEmail(); address = event.getAddress(); } @EventSourcingHandler public void on(MembershipUpdateEvent event) { System.out.println("MembershipUpdateEvent Sourcing Handler"); name = event.getName() ; email = event.getEmail(); address = event.getAddress(); } public MembershipAggregate() { // Required by Axon to construct an empty instance to initiate Event Sourcing. } @Override public String toString() { return "MembershipAggregate{" + "id='" + id + '\'' + ", name='" + name + '\'' + ", email='" + email + '\'' + ", address='" + address + '\'' + '}'; } } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/port/out/FindMembershipPort.java ================================================ package com.fastcampuspay.membership.application.port.out; import com.fastcampuspay.membership.domain.Membership; public interface FindMembershipPort { Membership findMembership( Membership.MembershipId membershipId ); } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/port/out/RegisterMembershipPort.java ================================================ package com.fastcampuspay.membership.application.port.out; import com.fastcampuspay.membership.domain.Membership; public interface RegisterMembershipPort { void createMembership( Membership.MembershipName membershipName , Membership.MembershipEmail membershipEmail , Membership.MembershipAddress membershipAddress , Membership.MembershipIsValid membershipIsValid , Membership.MembershipAggregateIdentifier membershipAggregateIdentifier ); } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/port/out/UpdateMembershipPort.java ================================================ package com.fastcampuspay.membership.application.port.out; import com.fastcampuspay.membership.domain.Membership; public interface UpdateMembershipPort { Membership updateMembership( Membership.MembershipId membershipId , Membership.MembershipName membershipName , Membership.MembershipEmail membershipEmail , Membership.MembershipAddress membershipAddress , Membership.MembershipIsValid membershipIsValid ); } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/port/out/query/FindMembershipQuery.java ================================================ package com.fastcampuspay.membership.application.port.out.query; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @AllArgsConstructor @NoArgsConstructor @Data public class FindMembershipQuery { String membershipId; } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/port/out/query/MembershipQueryHandler.java ================================================ package com.fastcampuspay.membership.application.port.out.query; import com.fastcampuspay.membership.application.port.out.FindMembershipPort; import com.fastcampuspay.membership.domain.Membership; import lombok.RequiredArgsConstructor; import org.axonframework.queryhandling.QueryHandler; import org.springframework.stereotype.Component; @RequiredArgsConstructor @Component public class MembershipQueryHandler{ private final FindMembershipPort fport; @QueryHandler public Membership handle(FindMembershipQuery query) { System.out.println("MembershipQueryHandler Handler"); // Retrieve the event sourcing repository // EventSourcingRepository repository = EventSourcingRepository.builder(MembershipAggregate.class).eventStore(eventStore).build(); // MembershipAggregate user = repository.load(query.getMembershipId()).getWrappedAggregate().getAggregateRoot(); // System.out.println(user.toString()); return fport.findMembership(new Membership.MembershipId(query.getMembershipId())); // return Membership.generateMember( // new Membership.MembershipId(user.getId()+""), // new Membership.MembershipName(user.getName()), // new Membership.MembershipEmail(user.getEmail()), // new Membership.MembershipAddress(user.getAddress()), // new Membership.MembershipIsValid(true) // ); } } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/saga/MembershipCreateEvent.java ================================================ package com.fastcampuspay.membership.application.saga; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @AllArgsConstructor @NoArgsConstructor @Data public class MembershipCreateEvent { private String name; private String email; private String address; } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/saga/MembershipUpdateEvent.java ================================================ package com.fastcampuspay.membership.application.saga; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @AllArgsConstructor @NoArgsConstructor @Data public class MembershipUpdateEvent { private String membershipId; private String name; private String email; private String address; } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/saga/Order.java ================================================ package com.fastcampuspay.membership.application.saga; import lombok.Data; import org.axonframework.modelling.command.AggregateIdentifier; import org.axonframework.spring.stereotype.Aggregate; @Data @Aggregate() public class Order { @AggregateIdentifier private String orderId; } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/saga/OrderCancelledEvent.java ================================================ package com.fastcampuspay.membership.application.saga; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @AllArgsConstructor @NoArgsConstructor @Data public class OrderCancelledEvent { private String orderId; private String paymentId; private String name; } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/saga/OrderConfirmedEvent.java ================================================ package com.fastcampuspay.membership.application.saga; import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor public class OrderConfirmedEvent { private String orderId; } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/saga/OrderCreatedEvent.java ================================================ package com.fastcampuspay.membership.application.saga; public class OrderCreatedEvent { private String orderId; private String customerName; public OrderCreatedEvent(String orderId, String customerName) { this.orderId = orderId; this.customerName = customerName; } public String getOrderId() { return orderId; } public String getCustomerName() { return customerName; } } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/saga/OrderPlacedEvent.java ================================================ package com.fastcampuspay.membership.application.saga; import lombok.Data; @Data public class OrderPlacedEvent { private String orderId; private String name; public OrderPlacedEvent(){ orderId = "default-123"; } public OrderPlacedEvent(String orderId){ this.orderId = orderId; } public OrderPlacedEvent(String orderId, String name){ this.orderId = orderId; this.name = name; } } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/saga/OrderSaga.java ================================================ package com.fastcampuspay.membership.application.saga; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.NonNull; import org.axonframework.commandhandling.gateway.CommandGateway; import org.axonframework.eventhandling.EventBus; import org.axonframework.modelling.saga.SagaEventHandler; import org.axonframework.modelling.saga.SagaLifecycle; import org.axonframework.modelling.saga.StartSaga; import org.axonframework.spring.stereotype.Saga; import org.springframework.beans.factory.annotation.Autowired; import java.util.UUID; @Saga @Getter @NoArgsConstructor public class OrderSaga { private String orderId; private String paymentId; private double amount; @NonNull private transient EventBus eventBus; @NonNull private transient CommandGateway commandGateway; @Autowired public void setEventBus(EventBus eventBus) { this.eventBus = eventBus; } @Autowired public void setCommandGateway(CommandGateway commandGateway) { this.commandGateway = commandGateway; } @StartSaga @SagaEventHandler(associationProperty = "orderId") public void handle(OrderPlacedEvent event) { SagaLifecycle.associateWith("orderId", event.getOrderId()); System.out.println("Order placed"); orderId = event.getOrderId(); paymentId = UUID.randomUUID().toString(); amount = 100.0; // hardcoded for simplicity PaymentRequestedCommand command = new PaymentRequestedCommand(paymentId, orderId, amount); commandGateway.send(command).whenComplete((Object result, Throwable throwable) -> { // if (throwable == null) { System.out.println("Payment requested"); this.orderId = "finished"; SagaLifecycle.associateWith("paymentId", paymentId); // eventBus.publish(GenericEventMessage.asEventMessage(new PaymentCompletedEvent("1345", event.getOrderId()))); // } System.out.println("Payment failed"); SagaLifecycle.end(); }); } @SagaEventHandler(associationProperty = "orderId") public void handle(OrderConfirmedEvent event) { System.out.println("Payment completed"); SagaLifecycle.end(); // // OrderConfirmedEvent orderConfirmedEvent = new OrderConfirmedEvent(orderId); // if (this.orderId != null) { // System.out.println("Payment completed"); // // SagaLifecycle.associateWith("orderId", orderId); // // eventBus.publish(orderConfirmedEvent); // } else{ // System.out.println("Order Cancelled"); // // commandGateway.send(new OrderCancelledEvent(event.getOrderId())); // } // System.out.println("Payment completed"); } } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/saga/Payment.java ================================================ package com.fastcampuspay.membership.application.saga; import lombok.Data; import org.axonframework.modelling.command.AggregateIdentifier; import org.axonframework.spring.stereotype.Aggregate; @Data @Aggregate() public class Payment { private String orderId; @AggregateIdentifier private String paymentId; // getters and setters } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/saga/PaymentCancelledEvent.java ================================================ package com.fastcampuspay.membership.application.saga; import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor public class PaymentCancelledEvent { private String orderId; private String paymentId; } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/saga/PaymentCompletedEvent.java ================================================ package com.fastcampuspay.membership.application.saga; import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor public class PaymentCompletedEvent { private String paymentId; private String orderId; } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/saga/PaymentRequestedCommand.java ================================================ package com.fastcampuspay.membership.application.saga; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @AllArgsConstructor @NoArgsConstructor @Data public class PaymentRequestedCommand { private String paymentId; private String orderId; private double amount; // getters and setters } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/service/FindMembership.java ================================================ package com.fastcampuspay.membership.application.service; import com.fastcampuspay.common.UseCase; import com.fastcampuspay.membership.application.port.in.FindMembershipCommand; import com.fastcampuspay.membership.application.port.in.FindMembershipUseCase; import com.fastcampuspay.membership.application.port.out.FindMembershipPort; import com.fastcampuspay.membership.application.port.out.query.FindMembershipQuery; import com.fastcampuspay.membership.domain.Membership; import lombok.RequiredArgsConstructor; import org.axonframework.messaging.responsetypes.ResponseTypes; import org.axonframework.queryhandling.QueryGateway; import javax.transaction.Transactional; @RequiredArgsConstructor @UseCase @Transactional public class FindMembership implements FindMembershipUseCase { private final FindMembershipPort fport; private final QueryGateway queryGateway; @Override public Membership findMembership(FindMembershipCommand command) { return fport.findMembership(new Membership.MembershipId(command.getMembershipId())); } @Override public Membership findAxonMembership(FindMembershipCommand command) { FindMembershipQuery getQuery = new FindMembershipQuery(command.getMembershipId()); queryGateway.query(getQuery, ResponseTypes.instanceOf(Membership.class)) .whenComplete((Object result, Throwable throwable) -> { if (throwable == null) { System.out.println(result.toString()); } else { System.out.println("error : " + throwable.getMessage()); } }); return null; } } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/service/RegisterMembership.java ================================================ package com.fastcampuspay.membership.application.service; import com.fastcampuspay.common.UseCase; import com.fastcampuspay.membership.application.port.in.RegisterMembershipCommand; import com.fastcampuspay.membership.application.port.in.RegisterMembershipUseCase; import com.fastcampuspay.membership.application.port.out.RegisterMembershipPort; import com.fastcampuspay.membership.domain.Membership; import lombok.RequiredArgsConstructor; import org.axonframework.commandhandling.gateway.CommandGateway; import javax.transaction.Transactional; @RequiredArgsConstructor @UseCase @Transactional public class RegisterMembership implements RegisterMembershipUseCase { private final RegisterMembershipPort rport; private final CommandGateway commandGateway; @Override public void registerMembership(RegisterMembershipCommand command) { rport.createMembership( new Membership.MembershipName(command.getName()), new Membership.MembershipEmail(command.getEmail()), new Membership.MembershipAddress(command.getAddress()), new Membership.MembershipIsValid(command.isValid()), new Membership.MembershipAggregateIdentifier("default") ); } @Override public void registerAxonMembership(RegisterMembershipCommand command) { commandGateway.send(command) .whenComplete((Object result, Throwable throwable) -> { if (throwable == null) { System.out.println("Aggregate ID:" + result.toString()); rport.createMembership( new Membership.MembershipName(command.getName()), new Membership.MembershipEmail(command.getEmail()), new Membership.MembershipAddress(command.getAddress()), new Membership.MembershipIsValid(command.isValid()), new Membership.MembershipAggregateIdentifier(result.toString()) ); } else{ System.out.println("error : " + throwable.getMessage()); } }); } } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/application/service/UpdateMembership.java ================================================ package com.fastcampuspay.membership.application.service; import com.fastcampuspay.common.UseCase; import com.fastcampuspay.membership.application.port.in.UpdateMembershipCommand; import com.fastcampuspay.membership.application.port.in.UpdateMembershipEventCommand; import com.fastcampuspay.membership.application.port.in.UpdateMembershipUseCase; import com.fastcampuspay.membership.application.port.out.FindMembershipPort; import com.fastcampuspay.membership.application.port.out.UpdateMembershipPort; import com.fastcampuspay.membership.domain.Membership; import lombok.RequiredArgsConstructor; import org.axonframework.commandhandling.gateway.CommandGateway; import javax.transaction.Transactional; @RequiredArgsConstructor @UseCase @Transactional public class UpdateMembership implements UpdateMembershipUseCase { private final UpdateMembershipPort uport; private final FindMembershipPort fport; private final CommandGateway commandGateway; @Override public Membership updateMembership(UpdateMembershipCommand command) { return uport.updateMembership( new Membership.MembershipId(command.getMembershipId()), new Membership.MembershipName(command.getName()), new Membership.MembershipEmail(command.getEmail()), new Membership.MembershipAddress(command.getAddress()), new Membership.MembershipIsValid(command.isValid()) ); } @Override public Membership updateAxonMembership(UpdateMembershipCommand command) { System.out.println("update axon membership"); Membership membership = fport.findMembership(new Membership.MembershipId(command.getMembershipId())); UpdateMembershipEventCommand eventCommand = UpdateMembershipEventCommand.builder() .aggregateIdentifier(membership.getAggregateIdentifier()) .name(command.getName()) .email(command.getEmail()) .address(command.getAddress()) .isValid(command.isValid()) .build(); commandGateway.send(eventCommand).whenComplete((Object result, Throwable throwable) -> { if (throwable == null) { System.out.println("Aggregate ID:" + result); } else { System.out.println("error : " + throwable.getMessage()); } }); this.updateMembership(command); return null; } } ================================================ FILE: membership-service/src/main/java/com/fastcampuspay/membership/domain/Membership.java ================================================ package com.fastcampuspay.membership.domain; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Value; @AllArgsConstructor(access = AccessLevel.PRIVATE) public class Membership { /** * The baseline balance of the account. This was the balance of the account before the first * activity in the activityWindow. */ @Getter private final String membershipId; @Getter private final String name; @Getter private final String email; @Getter private final String address; @Getter private final boolean isValid; @Getter private final String aggregateIdentifier; public static Membership generateMember( MembershipId membershipId, MembershipName membershipName, MembershipEmail membershipEmail, MembershipAddress membershipAddress, MembershipIsValid membershipIsValid, MembershipAggregateIdentifier membershipAggregateIdentifier) { return new Membership( membershipId.membershipId, membershipName.nameValue, membershipEmail.emailValue, membershipAddress.addressValue, membershipIsValid.isValidValue, membershipAggregateIdentifier.aggregateIdentifier ); } @Value public static class MembershipId { public MembershipId(String value) { this.membershipId = value; } String membershipId ; } @Value public static class MembershipName { public MembershipName(String value) { this.nameValue = value; } String nameValue; } @Value public static class MembershipEmail { public MembershipEmail(String value) { this.emailValue = value; } String emailValue; } @Value public static class MembershipAddress { public MembershipAddress(String value) { this.addressValue = value; } String addressValue; } @Value public static class MembershipIsValid { public MembershipIsValid(boolean value) { this.isValidValue = value; } boolean isValidValue; } @Value public static class MembershipAggregateIdentifier { public MembershipAggregateIdentifier(String value) { this.aggregateIdentifier = value; } String aggregateIdentifier; } } ================================================ FILE: money-local-service/build.gradle ================================================ plugins { id 'com.palantir.docker' version '0.25.0' } ext{ axonVersion = "4.6.0" } group = 'com.fastcampuspay.moneylocal' version = '0.0.1-SNAPSHOT' dependencies { implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-web' implementation group: 'javax.persistence', name: 'javax.persistence-api', version: '2.2' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation group: 'org.axonframework', name: 'axon-configuration', version: "$axonVersion" implementation group: 'org.axonframework', name: 'axon-spring-boot-starter', version: "$axonVersion" implementation 'org.jetbrains:annotations:23.0.0' implementation project(path: ':common') // runtimeOnly 'com.h2database:h2' runtimeOnly 'mysql:mysql-connector-java' } docker { println(tasks.bootJar.outputs.files) name rootProject.name+'-'+project.name + ":" + version dockerfile file('../Dockerfile') files tasks.bootJar.outputs.files buildArgs(['JAR_FILE': tasks.bootJar.outputs.files.singleFile.name]) } ================================================ FILE: money-local-service/src/main/java/com/fastcampuspay/moneylocal/MoneyLocalApplication.java ================================================ package com.fastcampuspay.moneylocal; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MoneyLocalApplication { public static void main(String[] args) { SpringApplication.run(MoneyLocalApplication.class, args); } } ================================================ FILE: money-local-service/src/main/java/com/fastcampuspay/moneylocal/MoneyLocalConfiguration.java ================================================ package com.fastcampuspay.moneylocal; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration @EnableConfigurationProperties(MoneyLocalConfigurationProperties.class) public class MoneyLocalConfiguration { } ================================================ FILE: money-local-service/src/main/java/com/fastcampuspay/moneylocal/MoneyLocalConfigurationProperties.java ================================================ package com.fastcampuspay.moneylocal; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; @Data @ConfigurationProperties(prefix = "banking") public class MoneyLocalConfigurationProperties { private long transferThreshold = Long.MAX_VALUE; } ================================================ FILE: money-local-service/src/main/java/com/fastcampuspay/moneylocal/SwaggerConfig.java ================================================ package com.fastcampuspay.moneylocal; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket restAPI() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.fastcampuspay.money")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .build(); } } ================================================ FILE: money-local-service/src/main/java/com/fastcampuspay/moneylocal/adapter/in/web/CalculateLocalMoneyController.java ================================================ package com.fastcampuspay.moneylocal.adapter.in.web; import com.fastcampuspay.common.WebAdapter; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; // CQRS Controller @WebAdapter @RestController @RequiredArgsConstructor class CalculateLocalMoneyController { // private final RegisterBankingAccountUseCase registerBankingAccountUseCase; @GetMapping(path = "/money-local/calculate-money-sum") ResponseEntity calculateMoneySumByLocal(){ // RegisterMembershipRequest // name, address, email return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } // TODO // - MembershipUpdate EventHandler (EventHandler) } ================================================ FILE: money-local-service/src/main/java/com/fastcampuspay/moneylocal/adapter/out/persistence/LocalMoneyJpaEntity.java ================================================ package com.fastcampuspay.moneylocal.adapter.out.persistence; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "local_money") @Data @AllArgsConstructor @NoArgsConstructor class LocalMoneyJpaEntity { @Id @GeneratedValue private Long localMoneyId; // private String name; // // private String address; // // private String email; // // private boolean isValid; } ================================================ FILE: money-local-service/src/main/java/com/fastcampuspay/moneylocal/adapter/out/persistence/LocalMoneyMapper.java ================================================ package com.fastcampuspay.moneylocal.adapter.out.persistence; import com.fastcampuspay.moneylocal.domain.MemberMoney; import org.springframework.stereotype.Component; @Component class LocalMoneyMapper { MemberMoney mapToDomainEntity( LocalMoneyJpaEntity rechargeMoneyJpaEntity) { System.out.println(rechargeMoneyJpaEntity.toString()); return MemberMoney.generateMemberMoney( new MemberMoney.MemberMoneyId(rechargeMoneyJpaEntity.getLocalMoneyId()+"") ); } } ================================================ FILE: money-local-service/src/main/java/com/fastcampuspay/moneylocal/adapter/out/persistence/LocalMoneyPersistenceAdapter.java ================================================ package com.fastcampuspay.moneylocal.adapter.out.persistence; import com.fastcampuspay.common.PersistenceAdapter; import com.fastcampuspay.moneylocal.application.port.out.RechargeMoneyPort; import com.fastcampuspay.moneylocal.domain.MemberMoney; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @PersistenceAdapter class LocalMoneyPersistenceAdapter implements RechargeMoneyPort { // private final SpringDataRechargeMoneyRepository rechargeMoneyRepository; // private final RechargeMoneyMapper rechargeMoneyMapper; @Override public void rechargeMoney(MemberMoney.MemberMoneyId memberMoneyId) { } } ================================================ FILE: money-local-service/src/main/java/com/fastcampuspay/moneylocal/adapter/out/persistence/SpringDataLocalMoneyRepository.java ================================================ package com.fastcampuspay.moneylocal.adapter.out.persistence; import org.springframework.data.jpa.repository.JpaRepository; interface SpringDataLocalMoneyRepository extends JpaRepository { } ================================================ FILE: money-local-service/src/main/java/com/fastcampuspay/moneylocal/application/port/in/RechargeMoneyCommand.java ================================================ package com.fastcampuspay.moneylocal.application.port.in; import com.fastcampuspay.common.SelfValidating; import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; import javax.validation.constraints.NotNull; @Builder @Data @EqualsAndHashCode(callSuper = false) public class RechargeMoneyCommand extends SelfValidating { @NotNull private final String name; @NotNull private final String email; @NotNull private final String address; @NotNull private final boolean isValid; public RechargeMoneyCommand(String name, String email, String address, boolean isValid) { this.name = name; this.email = email; this.address = address; this.isValid = isValid; } } ================================================ FILE: money-local-service/src/main/java/com/fastcampuspay/moneylocal/application/port/in/RechargeMoneyUseCase.java ================================================ package com.fastcampuspay.moneylocal.application.port.in; public interface RechargeMoneyUseCase { void rechargeMoney(RechargeMoneyCommand command); } ================================================ FILE: money-local-service/src/main/java/com/fastcampuspay/moneylocal/application/port/out/RechargeMoneyPort.java ================================================ package com.fastcampuspay.moneylocal.application.port.out; import com.fastcampuspay.moneylocal.domain.MemberMoney; public interface RechargeMoneyPort { void rechargeMoney( MemberMoney.MemberMoneyId memberMoneyId ); } ================================================ FILE: money-local-service/src/main/java/com/fastcampuspay/moneylocal/application/service/RechargeMoney.java ================================================ package com.fastcampuspay.moneylocal.application.service; import com.fastcampuspay.common.UseCase; import com.fastcampuspay.moneylocal.application.port.in.RechargeMoneyCommand; import com.fastcampuspay.moneylocal.application.port.in.RechargeMoneyUseCase; import lombok.RequiredArgsConstructor; import javax.transaction.Transactional; @RequiredArgsConstructor @UseCase @Transactional public class RechargeMoney implements RechargeMoneyUseCase { @Override public void rechargeMoney(RechargeMoneyCommand command) { } } ================================================ FILE: money-local-service/src/main/java/com/fastcampuspay/moneylocal/domain/MemberMoney.java ================================================ package com.fastcampuspay.moneylocal.domain; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Value; @AllArgsConstructor(access = AccessLevel.PRIVATE) public class MemberMoney { /** * The baseline balance of the account. This was the balance of the account before the first * activity in the activityWindow. */ @Getter private final String memberMoneyId; // @Getter private final String name; // @Getter private final String email; // @Getter private final String address; // @Getter private final boolean isValid; public static MemberMoney generateMemberMoney( MemberMoneyId memberMoneyId) { return new MemberMoney( memberMoneyId.getMemberMoneyId() ); } @Value public static class MemberMoneyId { public MemberMoneyId(String value) { this.memberMoneyId = value; } String memberMoneyId ; } } ================================================ FILE: money-service/build.gradle ================================================ plugins { id 'com.palantir.docker' version '0.25.0' } ext{ axonVersion = "4.6.0" } group = 'com.fastcampuspay.money' version = '0.0.1-SNAPSHOT' dependencies { implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-web' implementation group: 'javax.persistence', name: 'javax.persistence-api', version: '2.2' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation group: 'org.axonframework', name: 'axon-configuration', version: "$axonVersion" implementation group: 'org.axonframework', name: 'axon-spring-boot-starter', version: "$axonVersion" implementation 'org.jetbrains:annotations:23.0.0' implementation project(path: ':common') // runtimeOnly 'com.h2database:h2' runtimeOnly 'mysql:mysql-connector-java' } docker { println(tasks.bootJar.outputs.files) name rootProject.name+'-'+project.name + ":" + version dockerfile file('../Dockerfile') files tasks.bootJar.outputs.files buildArgs(['JAR_FILE': tasks.bootJar.outputs.files.singleFile.name]) } ================================================ FILE: money-service/src/main/java/com/fastcampuspay/money/MoneyApplication.java ================================================ package com.fastcampuspay.money; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MoneyApplication { public static void main(String[] args) { SpringApplication.run(MoneyApplication.class, args); } } ================================================ FILE: money-service/src/main/java/com/fastcampuspay/money/MoneyConfiguration.java ================================================ package com.fastcampuspay.money; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration @EnableConfigurationProperties(MoneyConfigurationProperties.class) public class MoneyConfiguration { } ================================================ FILE: money-service/src/main/java/com/fastcampuspay/money/MoneyConfigurationProperties.java ================================================ package com.fastcampuspay.money; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; @Data @ConfigurationProperties(prefix = "banking") public class MoneyConfigurationProperties { private long transferThreshold = Long.MAX_VALUE; } ================================================ FILE: money-service/src/main/java/com/fastcampuspay/money/SwaggerConfig.java ================================================ package com.fastcampuspay.money; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket restAPI() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.fastcampuspay.money")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .build(); } } ================================================ FILE: money-service/src/main/java/com/fastcampuspay/money/adapter/in/web/FindMoneyController.java ================================================ package com.fastcampuspay.money.adapter.in.web; import com.fastcampuspay.common.WebAdapter; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @WebAdapter @RestController @RequiredArgsConstructor class FindMoneyController { // private final RegisterBankingAccountUseCase registerBankingAccountUseCase; @GetMapping(path = "/money/money-history") ResponseEntity findMoneyHistoryByMemberId(){ // RegisterMembershipRequest // name, address, email return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } @GetMapping(path = "/money/money-info") ResponseEntity findMoneyInfoByRechargeMoneyId(){ // RegisterMembershipRequest // name, address, email return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } } ================================================ FILE: money-service/src/main/java/com/fastcampuspay/money/adapter/in/web/RechargeMoneyController.java ================================================ package com.fastcampuspay.money.adapter.in.web; import com.fastcampuspay.common.WebAdapter; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; @WebAdapter @RestController @RequiredArgsConstructor class RechargeMoneyController { // private final RechargeMoneyUseCase registerBankingAccountUseCase; @PostMapping(path = "/money/recharge/") ResponseEntity rechargeMoney(){ return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } } ================================================ FILE: money-service/src/main/java/com/fastcampuspay/money/adapter/in/web/RequestTransferMoneyController.java ================================================ package com.fastcampuspay.money.adapter.in.web; import com.fastcampuspay.common.WebAdapter; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; @WebAdapter @RestController @RequiredArgsConstructor class RequestTransferMoneyController { // private final RegisterBankingAccountUseCase registerBankingAccountUseCase; @PostMapping(path = "/money/transfer") ResponseEntity requestTransferMoneyBetweenMembers(){ return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } } ================================================ FILE: money-service/src/main/java/com/fastcampuspay/money/adapter/out/persistence/RechargeMoneyJpaEntity.java ================================================ package com.fastcampuspay.money.adapter.out.persistence; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "recharge_money") @Data @AllArgsConstructor @NoArgsConstructor class RechargeMoneyJpaEntity { @Id @GeneratedValue private Long rechargeMoneyId; // private String name; // // private String address; // // private String email; // // private boolean isValid; } ================================================ FILE: money-service/src/main/java/com/fastcampuspay/money/adapter/out/persistence/RechargeMoneyMapper.java ================================================ package com.fastcampuspay.money.adapter.out.persistence; import com.fastcampuspay.money.domain.MemberMoney; import org.springframework.stereotype.Component; @Component class RechargeMoneyMapper { MemberMoney mapToDomainEntity( RechargeMoneyJpaEntity rechargeMoneyJpaEntity) { System.out.println(rechargeMoneyJpaEntity.toString()); return MemberMoney.generateMemberMoney( new MemberMoney.MemberMoneyId(rechargeMoneyJpaEntity.getRechargeMoneyId()+"") ); } } ================================================ FILE: money-service/src/main/java/com/fastcampuspay/money/adapter/out/persistence/RechargeMoneyPersistenceAdapter.java ================================================ package com.fastcampuspay.money.adapter.out.persistence; import com.fastcampuspay.common.PersistenceAdapter; import com.fastcampuspay.money.application.port.out.RechargeMoneyPort; import com.fastcampuspay.money.domain.MemberMoney; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @PersistenceAdapter class RechargeMoneyPersistenceAdapter implements RechargeMoneyPort { // private final SpringDataRechargeMoneyRepository rechargeMoneyRepository; // private final RechargeMoneyMapper rechargeMoneyMapper; @Override public void rechargeMoney(MemberMoney.MemberMoneyId memberMoneyId) { } } ================================================ FILE: money-service/src/main/java/com/fastcampuspay/money/adapter/out/persistence/SpringDataRechargeMoneyRepository.java ================================================ package com.fastcampuspay.money.adapter.out.persistence; import org.springframework.data.jpa.repository.JpaRepository; interface SpringDataRechargeMoneyRepository extends JpaRepository { } ================================================ FILE: money-service/src/main/java/com/fastcampuspay/money/application/port/in/RechargeMoneyCommand.java ================================================ package com.fastcampuspay.money.application.port.in; import com.fastcampuspay.common.SelfValidating; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Value; import javax.validation.constraints.NotNull; @Value @Builder @EqualsAndHashCode(callSuper = false) public class RechargeMoneyCommand extends SelfValidating { @NotNull private final String name; @NotNull private final String email; @NotNull private final String address; @NotNull private final boolean isValid; public RechargeMoneyCommand(String name, String email, String address, boolean isValid) { this.name = name; this.email = email; this.address = address; this.isValid = isValid; } } ================================================ FILE: money-service/src/main/java/com/fastcampuspay/money/application/port/in/RechargeMoneyUseCase.java ================================================ package com.fastcampuspay.money.application.port.in; public interface RechargeMoneyUseCase { void rechargeMoney(RechargeMoneyCommand command); } ================================================ FILE: money-service/src/main/java/com/fastcampuspay/money/application/port/out/RechargeMoneyPort.java ================================================ package com.fastcampuspay.money.application.port.out; import com.fastcampuspay.money.domain.MemberMoney; public interface RechargeMoneyPort { void rechargeMoney( MemberMoney.MemberMoneyId memberMoneyId ); } ================================================ FILE: money-service/src/main/java/com/fastcampuspay/money/application/service/RechargeMoney.java ================================================ package com.fastcampuspay.money.application.service; import com.fastcampuspay.common.UseCase; import com.fastcampuspay.money.application.port.in.RechargeMoneyCommand; import com.fastcampuspay.money.application.port.in.RechargeMoneyUseCase; import com.fastcampuspay.money.application.port.out.RechargeMoneyPort; import lombok.RequiredArgsConstructor; import javax.transaction.Transactional; @RequiredArgsConstructor @UseCase @Transactional public class RechargeMoney implements RechargeMoneyUseCase { private final RechargeMoneyPort rport; @Override public void rechargeMoney(RechargeMoneyCommand command) { } } ================================================ FILE: money-service/src/main/java/com/fastcampuspay/money/domain/MemberMoney.java ================================================ package com.fastcampuspay.money.domain; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Value; @AllArgsConstructor(access = AccessLevel.PRIVATE) public class MemberMoney { /** * The baseline balance of the account. This was the balance of the account before the first * activity in the activityWindow. */ @Getter private final String memberMoneyId; // @Getter private final String name; // @Getter private final String email; // @Getter private final String address; // @Getter private final boolean isValid; public static MemberMoney generateMemberMoney( MemberMoneyId memberMoneyId) { return new MemberMoney( memberMoneyId.getMemberMoneyId() ); } @Value public static class MemberMoneyId { public MemberMoneyId(String value) { this.memberMoneyId = value; } String memberMoneyId ; } } ================================================ FILE: payment-service/build.gradle ================================================ plugins { id 'com.palantir.docker' version '0.25.0' } ext{ axonVersion = "4.6.0" } group = 'com.fastcampuspay.payment' version = '0.0.1-SNAPSHOT' dependencies { implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-web' implementation group: 'javax.persistence', name: 'javax.persistence-api', version: '2.2' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation group: 'org.axonframework', name: 'axon-configuration', version: "$axonVersion" implementation group: 'org.axonframework', name: 'axon-spring-boot-starter', version: "$axonVersion" implementation 'org.jetbrains:annotations:23.0.0' implementation project(path: ':common') // runtimeOnly 'com.h2database:h2' runtimeOnly 'mysql:mysql-connector-java' } docker { println(tasks.bootJar.outputs.files) name rootProject.name+'-'+project.name + ":" + version dockerfile file('../Dockerfile') files tasks.bootJar.outputs.files buildArgs(['JAR_FILE': tasks.bootJar.outputs.files.singleFile.name]) } ================================================ FILE: payment-service/src/main/java/com/fastcampuspay/payment/PaymentApplication.java ================================================ package com.fastcampuspay.payment; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class PaymentApplication { public static void main(String[] args) { SpringApplication.run(PaymentApplication.class, args); } } ================================================ FILE: payment-service/src/main/java/com/fastcampuspay/payment/PaymentConfiguration.java ================================================ package com.fastcampuspay.payment; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration @EnableConfigurationProperties(PaymentConfigurationProperties.class) public class PaymentConfiguration { } ================================================ FILE: payment-service/src/main/java/com/fastcampuspay/payment/PaymentConfigurationProperties.java ================================================ package com.fastcampuspay.payment; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; @Data @ConfigurationProperties(prefix = "banking") public class PaymentConfigurationProperties { private long transferThreshold = Long.MAX_VALUE; } ================================================ FILE: payment-service/src/main/java/com/fastcampuspay/payment/SwaggerConfig.java ================================================ package com.fastcampuspay.payment; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket restAPI() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.fastcampuspay.money")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .build(); } } ================================================ FILE: payment-service/src/main/java/com/fastcampuspay/payment/adapter/in/web/FindPaymentController.java ================================================ package com.fastcampuspay.payment.adapter.in.web; import com.fastcampuspay.common.WebAdapter; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @WebAdapter @RestController @RequiredArgsConstructor class FindPaymentController { // private final RegisterBankingAccountUseCase registerBankingAccountUseCase; @GetMapping(path = "/payment/info") ResponseEntity findPaymentByPaymentId(){ // RegisterMembershipRequest // name, address, email return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } @GetMapping(path = "/payment/list-by-period") ResponseEntity listPaymentsByPeriod(){ // RegisterMembershipRequest // name, address, email return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } } ================================================ FILE: payment-service/src/main/java/com/fastcampuspay/payment/adapter/in/web/RequestTransferMoneyController.java ================================================ package com.fastcampuspay.payment.adapter.in.web; import com.fastcampuspay.common.WebAdapter; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; @WebAdapter @RestController @RequiredArgsConstructor class RequestTransferMoneyController { // private final RegisterBankingAccountUseCase registerBankingAccountUseCase; @PostMapping(path = "/payment/request") ResponseEntity requestPaymentAtMerchant(){ return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } } ================================================ FILE: payment-service/src/main/java/com/fastcampuspay/payment/adapter/out/persistence/PaymentJpaEntity.java ================================================ package com.fastcampuspay.payment.adapter.out.persistence; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "payment") @Data @AllArgsConstructor @NoArgsConstructor class PaymentJpaEntity { @Id @GeneratedValue private Long rechargeMoneyId; // private String name; // // private String address; // // private String email; // // private boolean isValid; } ================================================ FILE: payment-service/src/main/java/com/fastcampuspay/payment/adapter/out/persistence/PaymentMapper.java ================================================ package com.fastcampuspay.payment.adapter.out.persistence; import com.fastcampuspay.payment.domain.MemberMoney; import org.springframework.stereotype.Component; @Component class PaymentMapper { MemberMoney mapToDomainEntity( PaymentJpaEntity rechargeMoneyJpaEntity) { System.out.println(rechargeMoneyJpaEntity.toString()); return MemberMoney.generateMemberMoney( new MemberMoney.MemberMoneyId(rechargeMoneyJpaEntity.getRechargeMoneyId()+"") ); } } ================================================ FILE: payment-service/src/main/java/com/fastcampuspay/payment/adapter/out/persistence/RechargeMoneyPersistenceAdapter.java ================================================ package com.fastcampuspay.payment.adapter.out.persistence; import com.fastcampuspay.common.PersistenceAdapter; import com.fastcampuspay.payment.application.port.out.RechargeMoneyPort; import com.fastcampuspay.payment.domain.MemberMoney; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @PersistenceAdapter class PaymentPersistenceAdapter implements RechargeMoneyPort { // private final SpringDataRechargeMoneyRepository rechargeMoneyRepository; // private final RechargeMoneyMapper rechargeMoneyMapper; @Override public void rechargeMoney(MemberMoney.MemberMoneyId memberMoneyId) { } } ================================================ FILE: payment-service/src/main/java/com/fastcampuspay/payment/adapter/out/persistence/SpringDataPaymentRepository.java ================================================ package com.fastcampuspay.payment.adapter.out.persistence; import org.springframework.data.jpa.repository.JpaRepository; interface SpringDataPaymentRepository extends JpaRepository { } ================================================ FILE: payment-service/src/main/java/com/fastcampuspay/payment/application/port/in/RechargeMoneyCommand.java ================================================ package com.fastcampuspay.payment.application.port.in; import com.fastcampuspay.common.SelfValidating; import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; import javax.validation.constraints.NotNull; @Data @Builder @EqualsAndHashCode(callSuper = false) public class RechargeMoneyCommand extends SelfValidating { @NotNull private final String name; @NotNull private final String email; @NotNull private final String address; @NotNull private final boolean isValid; public RechargeMoneyCommand(String name, String email, String address, boolean isValid) { this.name = name; this.email = email; this.address = address; this.isValid = isValid; } } ================================================ FILE: payment-service/src/main/java/com/fastcampuspay/payment/application/port/in/RechargeMoneyUseCase.java ================================================ package com.fastcampuspay.payment.application.port.in; public interface RechargeMoneyUseCase { void rechargeMoney(RechargeMoneyCommand command); } ================================================ FILE: payment-service/src/main/java/com/fastcampuspay/payment/application/port/out/RechargeMoneyPort.java ================================================ package com.fastcampuspay.payment.application.port.out; import com.fastcampuspay.payment.domain.MemberMoney; public interface RechargeMoneyPort { void rechargeMoney( MemberMoney.MemberMoneyId memberMoneyId ); } ================================================ FILE: payment-service/src/main/java/com/fastcampuspay/payment/application/service/RechargeMoney.java ================================================ package com.fastcampuspay.payment.application.service; import com.fastcampuspay.common.UseCase; import com.fastcampuspay.payment.application.port.in.RechargeMoneyCommand; import com.fastcampuspay.payment.application.port.in.RechargeMoneyUseCase; import lombok.RequiredArgsConstructor; import javax.transaction.Transactional; @RequiredArgsConstructor @UseCase @Transactional public class RechargeMoney implements RechargeMoneyUseCase { @Override public void rechargeMoney(RechargeMoneyCommand command) { } } ================================================ FILE: payment-service/src/main/java/com/fastcampuspay/payment/domain/MemberMoney.java ================================================ package com.fastcampuspay.payment.domain; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Value; @AllArgsConstructor(access = AccessLevel.PRIVATE) public class MemberMoney { /** * The baseline balance of the account. This was the balance of the account before the first * activity in the activityWindow. */ @Getter private final String memberMoneyId; // @Getter private final String name; // @Getter private final String email; // @Getter private final String address; // @Getter private final boolean isValid; public static MemberMoney generateMemberMoney( MemberMoneyId memberMoneyId) { return new MemberMoney( memberMoneyId.getMemberMoneyId() ); } @Value public static class MemberMoneyId { public MemberMoneyId(String value) { this.memberMoneyId = value; } String memberMoneyId ; } } ================================================ FILE: remittance-service/build.gradle ================================================ plugins { id 'com.palantir.docker' version '0.25.0' } ext{ axonVersion = "4.6.0" } group = 'com.fastcampuspay.remittance' version = '0.0.1-SNAPSHOT' dependencies { implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-web' implementation group: 'javax.persistence', name: 'javax.persistence-api', version: '2.2' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation group: 'org.axonframework', name: 'axon-configuration', version: "$axonVersion" implementation group: 'org.axonframework', name: 'axon-spring-boot-starter', version: "$axonVersion" implementation 'org.jetbrains:annotations:23.0.0' implementation project(path: ':common') // runtimeOnly 'com.h2database:h2' runtimeOnly 'mysql:mysql-connector-java' } docker { println(tasks.bootJar.outputs.files) name rootProject.name+'-'+project.name + ":" + version dockerfile file('../Dockerfile') files tasks.bootJar.outputs.files buildArgs(['JAR_FILE': tasks.bootJar.outputs.files.singleFile.name]) } ================================================ FILE: remittance-service/src/main/java/com/fastcampuspay/remittance/RemittanceApplication.java ================================================ package com.fastcampuspay.remittance; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class RemittanceApplication { public static void main(String[] args) { SpringApplication.run(RemittanceApplication.class, args); } } ================================================ FILE: remittance-service/src/main/java/com/fastcampuspay/remittance/RemittanceConfiguration.java ================================================ package com.fastcampuspay.remittance; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration @EnableConfigurationProperties(RemittanceConfigurationProperties.class) public class RemittanceConfiguration { } ================================================ FILE: remittance-service/src/main/java/com/fastcampuspay/remittance/RemittanceConfigurationProperties.java ================================================ package com.fastcampuspay.remittance; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; @Data @ConfigurationProperties(prefix = "banking") public class RemittanceConfigurationProperties { private long transferThreshold = Long.MAX_VALUE; } ================================================ FILE: remittance-service/src/main/java/com/fastcampuspay/remittance/SwaggerConfig.java ================================================ package com.fastcampuspay.remittance; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket restAPI() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.fastcampuspay.remittance")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .build(); } } ================================================ FILE: remittance-service/src/main/java/com/fastcampuspay/remittance/adapter/in/web/FindRemittanceController.java ================================================ package com.fastcampuspay.remittance.adapter.in.web; import com.fastcampuspay.common.WebAdapter; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @WebAdapter @RestController @RequiredArgsConstructor class FindRemittanceController { // private final RegisterBankingAccountUseCase registerBankingAccountUseCase; @GetMapping(path = "/remittance/info") ResponseEntity findRemittanceInfoByRemittanceId(){ return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } @GetMapping(path = "/remittance/history") ResponseEntity findRemittanceHistoryByMemberId(){ return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } // (API Aggregation, Banking + Money) @GetMapping(path = "/remittance/transferred-money") ResponseEntity findMoneyTransferringByRemittanceId(){ return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } } ================================================ FILE: remittance-service/src/main/java/com/fastcampuspay/remittance/adapter/in/web/RequestRemittanceMoneyController.java ================================================ package com.fastcampuspay.remittance.adapter.in.web; import com.fastcampuspay.common.WebAdapter; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; @WebAdapter @RestController @RequiredArgsConstructor class RequestRemittanceMoneyController { // private final RechargeMoneyUseCase registerBankingAccountUseCase; @PostMapping(path = "/remittance/request/") ResponseEntity requestRemittance(){ return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } } ================================================ FILE: remittance-service/src/main/java/com/fastcampuspay/remittance/adapter/out/persistence/RemittanceMoneyJpaEntity.java ================================================ package com.fastcampuspay.remittance.adapter.out.persistence; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "remittance_money") @Data @AllArgsConstructor @NoArgsConstructor class RemittanceMoneyJpaEntity { @Id @GeneratedValue private Long remittanceMoneyId; // private String name; // // private String address; // // private String email; // // private boolean isValid; } ================================================ FILE: remittance-service/src/main/java/com/fastcampuspay/remittance/adapter/out/persistence/RemittanceMoneyMapper.java ================================================ package com.fastcampuspay.remittance.adapter.out.persistence; import com.fastcampuspay.remittance.domain.RemittanceMoney; import org.springframework.stereotype.Component; @Component class RemittanceMoneyMapper { RemittanceMoney mapToDomainEntity( RemittanceMoneyJpaEntity remittanceMoneyJpaEntity) { System.out.println(remittanceMoneyJpaEntity.toString()); return RemittanceMoney.generateRemittanceMoney( new RemittanceMoney.RemittanceMoneyId(remittanceMoneyJpaEntity.getRemittanceMoneyId()+"") ); } } ================================================ FILE: remittance-service/src/main/java/com/fastcampuspay/remittance/adapter/out/persistence/RemittanceMoneyPersistenceAdapter.java ================================================ package com.fastcampuspay.remittance.adapter.out.persistence; import com.fastcampuspay.common.PersistenceAdapter; import com.fastcampuspay.remittance.application.port.out.RemittanceMoneyPort; import com.fastcampuspay.remittance.domain.RemittanceMoney; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @PersistenceAdapter class RemittanceMoneyPersistenceAdapter implements RemittanceMoneyPort { private final SpringDataRemittanceMoneyRepository remittanceMoneyRepository; private final RemittanceMoneyMapper remittanceMoneyMapper; private Long orZero(Long value){ return value == null ? 0L : value; } @Override public void remittanceMoney(RemittanceMoney.RemittanceMoneyId remittanceMoneyId) { } } ================================================ FILE: remittance-service/src/main/java/com/fastcampuspay/remittance/adapter/out/persistence/SpringDataRemittanceMoneyRepository.java ================================================ package com.fastcampuspay.remittance.adapter.out.persistence; import org.springframework.data.jpa.repository.JpaRepository; interface SpringDataRemittanceMoneyRepository extends JpaRepository { } ================================================ FILE: remittance-service/src/main/java/com/fastcampuspay/remittance/application/port/in/RemittanceMoneyCommand.java ================================================ package com.fastcampuspay.remittance.application.port.in; import com.fastcampuspay.common.SelfValidating; import lombok.Builder; import lombok.EqualsAndHashCode; import lombok.Value; import javax.validation.constraints.NotNull; @Value @Builder @EqualsAndHashCode(callSuper = false) public class RemittanceMoneyCommand extends SelfValidating { @NotNull private final String name; @NotNull private final String email; @NotNull private final String address; @NotNull private final boolean isValid; public RemittanceMoneyCommand(String name, String email, String address, boolean isValid) { this.name = name; this.email = email; this.address = address; this.isValid = isValid; } } ================================================ FILE: remittance-service/src/main/java/com/fastcampuspay/remittance/application/port/in/RemittanceMoneyUseCase.java ================================================ package com.fastcampuspay.remittance.application.port.in; public interface RemittanceMoneyUseCase { void remittanceMoney(RemittanceMoneyCommand command); } ================================================ FILE: remittance-service/src/main/java/com/fastcampuspay/remittance/application/port/out/RemittanceMoneyPort.java ================================================ package com.fastcampuspay.remittance.application.port.out; import com.fastcampuspay.remittance.domain.RemittanceMoney; public interface RemittanceMoneyPort { void remittanceMoney( RemittanceMoney.RemittanceMoneyId remittanceMoneyId ); } ================================================ FILE: remittance-service/src/main/java/com/fastcampuspay/remittance/application/service/RemittanceMoney.java ================================================ package com.fastcampuspay.remittance.application.service; import com.fastcampuspay.common.UseCase; import com.fastcampuspay.remittance.application.port.in.RemittanceMoneyCommand; import com.fastcampuspay.remittance.application.port.in.RemittanceMoneyUseCase; import com.fastcampuspay.remittance.application.port.out.RemittanceMoneyPort; import lombok.RequiredArgsConstructor; import javax.transaction.Transactional; @RequiredArgsConstructor @UseCase @Transactional public class RemittanceMoney implements RemittanceMoneyUseCase { private final RemittanceMoneyPort rport; @Override public void remittanceMoney(RemittanceMoneyCommand command) { } } ================================================ FILE: remittance-service/src/main/java/com/fastcampuspay/remittance/domain/RemittanceMoney.java ================================================ package com.fastcampuspay.remittance.domain; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Value; @AllArgsConstructor(access = AccessLevel.PRIVATE) public class RemittanceMoney { /** * The baseline balance of the account. This was the balance of the account before the first * activity in the activityWindow. */ @Getter private final String memberMoneyId; // @Getter private final String name; // @Getter private final String email; // @Getter private final String address; // @Getter private final boolean isValid; public static RemittanceMoney generateRemittanceMoney( RemittanceMoneyId memberMoneyId) { return new RemittanceMoney( memberMoneyId.getRemittanceMoney() ); } @Value public static class RemittanceMoneyId { public RemittanceMoneyId(String value) { this.remittanceMoney = value; } String remittanceMoney ; } } ================================================ FILE: settings.gradle ================================================ rootProject.name = 'fastcampus-pay' include 'common' include 'membership-service' include 'banking-service' include 'money-service' include 'money-local-service' include 'remittance-service' include 'payment-service' include 'settlement-service' ================================================ FILE: settlement-service/build.gradle ================================================ plugins { id 'com.palantir.docker' version '0.25.0' } ext{ axonVersion = "4.6.0" } group = 'com.fastcampuspay.settlement' version = '0.0.1-SNAPSHOT' dependencies { implementation 'org.springframework.boot:spring-boot-starter-validation' implementation 'org.springframework.boot:spring-boot-starter-actuator' implementation 'org.springframework.boot:spring-boot-starter-web' implementation group: 'javax.persistence', name: 'javax.persistence-api', version: '2.2' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation group: 'org.axonframework', name: 'axon-configuration', version: "$axonVersion" implementation group: 'org.axonframework', name: 'axon-spring-boot-starter', version: "$axonVersion" implementation 'org.jetbrains:annotations:23.0.0' implementation project(path: ':common') // runtimeOnly 'com.h2database:h2' runtimeOnly 'mysql:mysql-connector-java' } docker { println(tasks.bootJar.outputs.files) name rootProject.name+'-'+project.name + ":" + version dockerfile file('../Dockerfile') files tasks.bootJar.outputs.files buildArgs(['JAR_FILE': tasks.bootJar.outputs.files.singleFile.name]) } ================================================ FILE: settlement-service/src/main/java/com/fastcampuspay/settlement/SettlementApplication.java ================================================ package com.fastcampuspay.settlement; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class SettlementApplication { public static void main(String[] args) { SpringApplication.run(SettlementApplication.class, args); } } ================================================ FILE: settlement-service/src/main/java/com/fastcampuspay/settlement/SettlementConfiguration.java ================================================ package com.fastcampuspay.settlement; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; @Configuration @EnableConfigurationProperties(SettlementConfigurationProperties.class) public class SettlementConfiguration { } ================================================ FILE: settlement-service/src/main/java/com/fastcampuspay/settlement/SettlementConfigurationProperties.java ================================================ package com.fastcampuspay.settlement; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; @Data @ConfigurationProperties(prefix = "banking") public class SettlementConfigurationProperties { private long transferThreshold = Long.MAX_VALUE; } ================================================ FILE: settlement-service/src/main/java/com/fastcampuspay/settlement/SwaggerConfig.java ================================================ package com.fastcampuspay.settlement; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket restAPI() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("com.fastcampuspay.money")) .paths(PathSelectors.any()) .build(); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .build(); } } ================================================ FILE: settlement-service/src/main/java/com/fastcampuspay/settlement/adapter/in/web/SettlementStartController.java ================================================ package com.fastcampuspay.settlement.adapter.in.web; import com.fastcampuspay.common.WebAdapter; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; @WebAdapter @RestController @RequiredArgsConstructor class SettlementStartController { // private final RegisterBankingAccountUseCase registerBankingAccountUseCase; @PostMapping(path = "/settlement/start") ResponseEntity startSettlementByPeriod(){ return ResponseEntity.status(HttpStatus.NOT_IMPLEMENTED).build(); } } ================================================ FILE: settlement-service/src/main/java/com/fastcampuspay/settlement/adapter/out/persistence/RechargeMoneyMapper.java ================================================ package com.fastcampuspay.settlement.adapter.out.persistence; import com.fastcampuspay.settlement.domain.MemberMoney; import org.springframework.stereotype.Component; @Component class SettlementMapper { MemberMoney mapToDomainEntity( SettlementJpaEntity rechargeMoneyJpaEntity) { System.out.println(rechargeMoneyJpaEntity.toString()); return MemberMoney.generateMemberMoney( new MemberMoney.MemberMoneyId(rechargeMoneyJpaEntity.getRechargeMoneyId()+"") ); } } ================================================ FILE: settlement-service/src/main/java/com/fastcampuspay/settlement/adapter/out/persistence/RechargeMoneyPersistenceAdapter.java ================================================ package com.fastcampuspay.settlement.adapter.out.persistence; import com.fastcampuspay.common.PersistenceAdapter; import com.fastcampuspay.settlement.application.port.out.RechargeMoneyPort; import com.fastcampuspay.settlement.domain.MemberMoney; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @PersistenceAdapter class RechargeMoneyPersistenceAdapter implements RechargeMoneyPort { // private final SpringDataRechargeMoneyRepository rechargeMoneyRepository; // private final RechargeMoneyMapper rechargeMoneyMapper; @Override public void rechargeMoney(MemberMoney.MemberMoneyId memberMoneyId) { } } ================================================ FILE: settlement-service/src/main/java/com/fastcampuspay/settlement/adapter/out/persistence/SettlementJpaEntity.java ================================================ package com.fastcampuspay.settlement.adapter.out.persistence; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "settlement") @Data @AllArgsConstructor @NoArgsConstructor class SettlementJpaEntity { @Id @GeneratedValue private Long rechargeMoneyId; // private String name; // // private String address; // // private String email; // // private boolean isValid; } ================================================ FILE: settlement-service/src/main/java/com/fastcampuspay/settlement/adapter/out/persistence/SpringDataSettlementRepository.java ================================================ package com.fastcampuspay.settlement.adapter.out.persistence; import org.springframework.data.jpa.repository.JpaRepository; interface SpringDataSettlementRepository extends JpaRepository { } ================================================ FILE: settlement-service/src/main/java/com/fastcampuspay/settlement/application/port/in/RechargeMoneyCommand.java ================================================ package com.fastcampuspay.settlement.application.port.in; import com.fastcampuspay.common.SelfValidating; import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.Value; import javax.validation.constraints.NotNull; @Data @Builder @EqualsAndHashCode(callSuper = false) public class RechargeMoneyCommand extends SelfValidating { @NotNull private final String name; @NotNull private final String email; @NotNull private final String address; @NotNull private final boolean isValid; public RechargeMoneyCommand(String name, String email, String address, boolean isValid) { this.name = name; this.email = email; this.address = address; this.isValid = isValid; } } ================================================ FILE: settlement-service/src/main/java/com/fastcampuspay/settlement/application/port/in/RechargeMoneyUseCase.java ================================================ package com.fastcampuspay.settlement.application.port.in; public interface RechargeMoneyUseCase { void rechargeMoney(RechargeMoneyCommand command); } ================================================ FILE: settlement-service/src/main/java/com/fastcampuspay/settlement/application/port/out/RechargeMoneyPort.java ================================================ package com.fastcampuspay.settlement.application.port.out; import com.fastcampuspay.settlement.domain.MemberMoney; public interface RechargeMoneyPort { void rechargeMoney( MemberMoney.MemberMoneyId memberMoneyId ); } ================================================ FILE: settlement-service/src/main/java/com/fastcampuspay/settlement/application/service/RechargeMoney.java ================================================ package com.fastcampuspay.settlement.application.service; import com.fastcampuspay.common.UseCase; import com.fastcampuspay.settlement.application.port.in.RechargeMoneyCommand; import com.fastcampuspay.settlement.application.port.in.RechargeMoneyUseCase; import lombok.RequiredArgsConstructor; import javax.transaction.Transactional; @RequiredArgsConstructor @UseCase @Transactional public class RechargeMoney implements RechargeMoneyUseCase { @Override public void rechargeMoney(RechargeMoneyCommand command) { } } ================================================ FILE: settlement-service/src/main/java/com/fastcampuspay/settlement/domain/MemberMoney.java ================================================ package com.fastcampuspay.settlement.domain; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Value; @AllArgsConstructor(access = AccessLevel.PRIVATE) public class MemberMoney { /** * The baseline balance of the account. This was the balance of the account before the first * activity in the activityWindow. */ @Getter private final String memberMoneyId; // @Getter private final String name; // @Getter private final String email; // @Getter private final String address; // @Getter private final boolean isValid; public static MemberMoney generateMemberMoney( MemberMoneyId memberMoneyId) { return new MemberMoney( memberMoneyId.getMemberMoneyId() ); } @Value public static class MemberMoneyId { public MemberMoneyId(String value) { this.memberMoneyId = value; } String memberMoneyId ; } }