├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── doc-service ├── doc-web │ └── src │ │ ├── main │ │ ├── resources │ │ │ ├── application-app-kafka-single.yaml │ │ │ ├── application-datastore-h2.yaml │ │ │ ├── application-datastore-mysql.yaml │ │ │ ├── application.yaml │ │ │ ├── application-app-inmem.yaml │ │ │ ├── application-broker-kafka-single.yaml │ │ │ └── application-common.yaml │ │ └── java │ │ │ └── com │ │ │ └── pubsubdoc │ │ │ └── doc │ │ │ └── service │ │ │ └── web │ │ │ ├── http │ │ │ ├── models │ │ │ │ ├── common │ │ │ │ │ ├── ErrorModel.java │ │ │ │ │ └── ErrorsResponse.java │ │ │ │ ├── docs │ │ │ │ │ ├── post │ │ │ │ │ │ ├── DocsPostRequest.java │ │ │ │ │ │ └── DocsPostResponse.java │ │ │ │ │ └── put │ │ │ │ │ │ └── DocsPutRequest.java │ │ │ │ └── effectives │ │ │ │ │ ├── post │ │ │ │ │ └── EffectivesPostRequest.java │ │ │ │ │ └── delete │ │ │ │ │ └── EffectivesDeleteRequest.java │ │ │ └── controllers │ │ │ │ ├── root │ │ │ │ └── RootController.java │ │ │ │ ├── advice │ │ │ │ └── AxonExceptionAdvice.java │ │ │ │ ├── effectives │ │ │ │ └── EffectivesController.java │ │ │ │ └── docs │ │ │ │ └── DocsController.java │ │ │ ├── app │ │ │ ├── application │ │ │ │ └── domain │ │ │ │ │ └── models │ │ │ │ │ ├── effective │ │ │ │ │ ├── exceptions │ │ │ │ │ │ ├── EffectiveException.java │ │ │ │ │ │ ├── EffectiveMarkedException.java │ │ │ │ │ │ └── EffectiveUnmarkedException.java │ │ │ │ │ └── Effective.java │ │ │ │ │ └── doc │ │ │ │ │ └── Doc.java │ │ │ └── adaptor │ │ │ │ └── aggregates │ │ │ │ ├── effective │ │ │ │ ├── commands │ │ │ │ │ ├── EffectiveCommand.java │ │ │ │ │ ├── EffectiveMark.java │ │ │ │ │ └── EffectiveUnmark.java │ │ │ │ └── EffectiveAggregate.java │ │ │ │ └── doc │ │ │ │ ├── commands │ │ │ │ ├── DocCommand.java │ │ │ │ └── create │ │ │ │ │ ├── DocCreate.java │ │ │ │ │ └── DocUpdate.java │ │ │ │ └── DocAggregate.java │ │ │ ├── DocServiceWebApplication.java │ │ │ └── config │ │ │ ├── OpenApiConfiguration.java │ │ │ └── axon │ │ │ ├── AxonKafkaTrackingConfiguration.java │ │ │ ├── SecureXStreamSerializer.java │ │ │ ├── AxonConfiguration.java │ │ │ └── AxonKafkaConfiguration.java │ │ └── test │ │ └── java │ │ └── com │ │ └── pubsubdoc │ │ └── doc │ │ └── service │ │ └── web │ │ └── Demo1ApplicationTests.java ├── doc-api │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── pubsubdoc │ │ └── doc │ │ └── service │ │ └── api │ │ └── domain │ │ └── models │ │ ├── effective │ │ ├── EffectiveEvent.java │ │ ├── EffectiveMarked.java │ │ └── EffectiveUnmarked.java │ │ └── doc │ │ ├── DocEvent.java │ │ ├── DocUpdated.java │ │ └── DocCreated.java └── doc-shared │ └── src │ └── main │ └── java │ └── com │ └── pubsubdoc │ └── doc │ └── service │ └── shared │ └── application │ └── doc │ └── models │ ├── doc │ └── DocId.java │ └── effective │ └── EffectiveId.java ├── pubsubdoc-service ├── back │ └── src │ │ ├── main │ │ ├── resources │ │ │ ├── application-app-kafka-single.yaml │ │ │ ├── application-datastore-h2.yaml │ │ │ ├── application-datastore-mysql.yaml │ │ │ ├── application.yaml │ │ │ ├── application-app-inmem.yaml │ │ │ ├── application-broker-kafka-single.yaml │ │ │ └── application-common.yaml │ │ └── java │ │ │ └── com │ │ │ └── pubsubdoc │ │ │ └── service │ │ │ └── back │ │ │ ├── http │ │ │ ├── models │ │ │ │ ├── common │ │ │ │ │ ├── ErrorModel.java │ │ │ │ │ └── ErrorsResponse.java │ │ │ │ ├── users │ │ │ │ │ ├── post │ │ │ │ │ │ ├── UsersPostRequest.java │ │ │ │ │ │ └── UsersPostResponse.java │ │ │ │ │ └── get │ │ │ │ │ │ ├── UsersGetResponse.java │ │ │ │ │ │ └── UsersResponseModel.java │ │ │ │ └── docs │ │ │ │ │ └── get │ │ │ │ │ └── DocsGetResponse.java │ │ │ └── controllers │ │ │ │ ├── root │ │ │ │ └── RootController.java │ │ │ │ ├── advice │ │ │ │ ├── AxonExceptionAdvice.java │ │ │ │ └── ExpectedExceptionAdvice.java │ │ │ │ ├── docs │ │ │ │ └── DocsController.java │ │ │ │ └── users │ │ │ │ └── UsersController.java │ │ │ ├── app │ │ │ ├── application │ │ │ │ ├── query │ │ │ │ │ ├── doc │ │ │ │ │ │ ├── queries │ │ │ │ │ │ │ ├── GetDoc.java │ │ │ │ │ │ │ └── GetDocResult.java │ │ │ │ │ │ ├── DocQueryService.java │ │ │ │ │ │ └── DocProjection.java │ │ │ │ │ └── user │ │ │ │ │ │ ├── queries │ │ │ │ │ │ ├── FindUser.java │ │ │ │ │ │ └── FindUserResult.java │ │ │ │ │ │ ├── UserQueryService.java │ │ │ │ │ │ └── UserProjection.java │ │ │ │ └── process │ │ │ │ │ └── user │ │ │ │ │ └── requestcreation │ │ │ │ │ ├── UserProcessRequestCreation.java │ │ │ │ │ └── UserProcessRequestCreationStep.java │ │ │ └── infrastructure │ │ │ │ └── jpa │ │ │ │ ├── doc │ │ │ │ ├── DocRepository.java │ │ │ │ └── DocDataModel.java │ │ │ │ └── user │ │ │ │ ├── UserRepository.java │ │ │ │ └── UserDataModel.java │ │ │ ├── PubSubDocServiceBackApplication.java │ │ │ └── config │ │ │ ├── infrastructure │ │ │ ├── InMemoryConfiguration.java │ │ │ ├── LocalConfiguration.java │ │ │ └── KafkaSingleConfiguration.java │ │ │ ├── OpenApiConfiguration.java │ │ │ └── axon │ │ │ ├── SecureXStreamSerializer.java │ │ │ ├── AxonConfiguration.java │ │ │ ├── AxonKafkaTrackingConfiguration.java │ │ │ └── AxonKafkaConfiguration.java │ │ └── test │ │ └── java │ │ └── com │ │ └── pubsubdoc │ │ └── doc │ │ └── service │ │ └── web │ │ └── Demo1ApplicationTests.java └── back-api │ └── src │ └── main │ └── java │ └── com │ └── pubsubdoc │ └── back │ └── service │ └── api │ └── process │ └── user │ └── requestcreation │ ├── UserProcessRequestCreationEvent.java │ └── UserProcessRequestCreationRequested.java ├── user-service ├── user-web │ └── src │ │ ├── main │ │ ├── resources │ │ │ ├── application-app-kafka-single.yaml │ │ │ ├── application-datastore-h2.yaml │ │ │ ├── application-datastore-mysql.yaml │ │ │ ├── application.yaml │ │ │ ├── application-app-inmem.yaml │ │ │ ├── application-broker-kafka-single.yaml │ │ │ └── application-common.yaml │ │ └── java │ │ │ └── com │ │ │ └── pubsubdoc │ │ │ └── user │ │ │ └── service │ │ │ └── web │ │ │ ├── http │ │ │ ├── models │ │ │ │ ├── common │ │ │ │ │ ├── ErrorModel.java │ │ │ │ │ └── ErrorsResponse.java │ │ │ │ ├── users │ │ │ │ │ ├── get │ │ │ │ │ │ └── UserGetResponse.java │ │ │ │ │ ├── post │ │ │ │ │ │ ├── UsersPostRequest.java │ │ │ │ │ │ └── UsersPostResponse.java │ │ │ │ │ └── find │ │ │ │ │ │ └── UserFindResponse.java │ │ │ │ └── teams │ │ │ │ │ └── post │ │ │ │ │ ├── TeamsPostResponse.java │ │ │ │ │ └── TeamsPostRequest.java │ │ │ └── controllers │ │ │ │ ├── teams │ │ │ │ ├── exceptions │ │ │ │ │ └── TeamsControllerOwnerUserNotFoundException.java │ │ │ │ ├── TeamsControllerAdvice.java │ │ │ │ └── TeamsController.java │ │ │ │ ├── teamsmemberships │ │ │ │ ├── exceptions │ │ │ │ │ └── TeamsMembersControllerMemberFullException.java │ │ │ │ ├── TeamsMembershipsControllerAdvice.java │ │ │ │ └── TeamsMembershipsController.java │ │ │ │ ├── root │ │ │ │ └── RootController.java │ │ │ │ └── advice │ │ │ │ ├── AxonExceptionAdvice.java │ │ │ │ └── ExpectedExceptionAdvice.java │ │ │ ├── app │ │ │ ├── application │ │ │ │ ├── domain │ │ │ │ │ └── models │ │ │ │ │ │ ├── team │ │ │ │ │ │ ├── errors │ │ │ │ │ │ │ ├── TeamError.java │ │ │ │ │ │ │ └── TeamMemberFullError.java │ │ │ │ │ │ └── Team.java │ │ │ │ │ │ └── user │ │ │ │ │ │ └── User.java │ │ │ │ ├── query │ │ │ │ │ └── user │ │ │ │ │ │ ├── queries │ │ │ │ │ │ ├── FindUserDataModel.java │ │ │ │ │ │ ├── GetUserDataModel.java │ │ │ │ │ │ ├── FindUserDataModelResult.java │ │ │ │ │ │ └── GetUserDataModelResult.java │ │ │ │ │ │ ├── UserDataModelProjection.java │ │ │ │ │ │ └── UserDataModelQueryService.java │ │ │ │ └── process │ │ │ │ │ ├── team │ │ │ │ │ └── addmember │ │ │ │ │ │ └── notification │ │ │ │ │ │ └── TeamProcessAddMemberNotificationStep.java │ │ │ │ │ └── user │ │ │ │ │ └── create │ │ │ │ │ └── creation │ │ │ │ │ └── UserProcessCreateCreationStep.java │ │ │ ├── adaptor │ │ │ │ └── aggregates │ │ │ │ │ ├── user │ │ │ │ │ ├── commands │ │ │ │ │ │ ├── UserUpgrade.java │ │ │ │ │ │ ├── UserCreate.java │ │ │ │ │ │ └── UserCommand.java │ │ │ │ │ └── UserAggregate.java │ │ │ │ │ └── team │ │ │ │ │ ├── commands │ │ │ │ │ ├── TeamAddMember.java │ │ │ │ │ ├── TeamCommand.java │ │ │ │ │ └── TeamCreate.java │ │ │ │ │ ├── TeamAggregateException.java │ │ │ │ │ └── TeamAggregate.java │ │ │ ├── external │ │ │ │ └── notification │ │ │ │ │ ├── protocol │ │ │ │ │ └── sendmemberadded │ │ │ │ │ │ ├── NotificationMemberAddedSent.java │ │ │ │ │ │ └── NotificationSendMemberAdded.java │ │ │ │ │ └── NotificationService.java │ │ │ └── infrastructure │ │ │ │ └── jpa │ │ │ │ └── user │ │ │ │ ├── UserDataModel.java │ │ │ │ └── UserDataRepository.java │ │ │ ├── UserServiceWebApplication.java │ │ │ ├── config │ │ │ ├── OpenApiConfiguration.java │ │ │ └── axon │ │ │ │ ├── SecureXStreamSerializer.java │ │ │ │ ├── AxonConfiguration.java │ │ │ │ ├── AxonKafkaTrackingConfiguration.java │ │ │ │ └── AxonKafkaConfiguration.java │ │ │ └── listener │ │ │ └── paymentservice │ │ │ └── PaymentServiceListener.java │ │ └── test │ │ └── java │ │ └── com │ │ └── pubsubdoc │ │ └── doc │ │ └── service │ │ └── web │ │ └── Demo1ApplicationTests.java ├── user-sdk │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── pubsubdoc │ │ └── user │ │ └── service │ │ └── sdk │ │ └── api │ │ ├── protocol │ │ ├── UsersFindResponse.java │ │ ├── UserModel.java │ │ └── UsersGetResponse.java │ │ ├── UserServiceApi.java │ │ ├── InMemoryUserServiceApi.java │ │ └── UserServiceApiApiImpl.java ├── user-api │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── pubsubdoc │ │ └── user │ │ └── service │ │ └── api │ │ └── domain │ │ └── models │ │ ├── team │ │ ├── TeamEvent.java │ │ ├── TeamMemberAdded.java │ │ ├── TeamCreated.java │ │ └── TeamOperationFailed.java │ │ └── user │ │ ├── UserEvent.java │ │ ├── UserUpgraded.java │ │ └── UserCreated.java └── user-shared │ └── src │ └── main │ └── java │ └── com │ └── pubsubdoc │ └── user │ └── service │ └── shared │ └── application │ └── doc │ └── models │ ├── team │ └── TeamId.java │ └── user │ └── UserId.java ├── payment-service ├── payment-web │ └── src │ │ ├── main │ │ ├── resources │ │ │ ├── application-app-kafka-single.yaml │ │ │ ├── application.yaml │ │ │ ├── application-app-inmem.yaml │ │ │ ├── application-broker-kafka-single.yaml │ │ │ ├── application-datastore-h2.yaml │ │ │ ├── application-common.yaml │ │ │ └── application-datastore-mysql.yaml │ │ └── java │ │ │ └── com │ │ │ └── pubsubdoc │ │ │ └── payment │ │ │ └── service │ │ │ └── web │ │ │ ├── http │ │ │ ├── models │ │ │ │ ├── common │ │ │ │ │ ├── ErrorModel.java │ │ │ │ │ └── ErrorsResponse.java │ │ │ │ ├── users │ │ │ │ │ └── post │ │ │ │ │ │ ├── UsersPostRequest.java │ │ │ │ │ │ └── UsersPostResponse.java │ │ │ │ ├── teams │ │ │ │ │ └── post │ │ │ │ │ │ ├── TeamsPostResponse.java │ │ │ │ │ │ └── TeamsPostRequest.java │ │ │ │ └── payments │ │ │ │ │ └── post │ │ │ │ │ ├── PaymentsPostResponse.java │ │ │ │ │ └── PaymentsPostRequest.java │ │ │ └── controllers │ │ │ │ ├── root │ │ │ │ └── RootController.java │ │ │ │ ├── advice │ │ │ │ └── AxonExceptionAdvice.java │ │ │ │ └── payments │ │ │ │ └── PaymentsController.java │ │ │ ├── app │ │ │ ├── application │ │ │ │ ├── query │ │ │ │ │ ├── user │ │ │ │ │ │ ├── queries │ │ │ │ │ │ │ ├── GetUser.java │ │ │ │ │ │ │ ├── UserModel.java │ │ │ │ │ │ │ └── GetUserResult.java │ │ │ │ │ │ └── UserQueryService.java │ │ │ │ │ └── transferrequest │ │ │ │ │ │ ├── datamodel │ │ │ │ │ │ ├── TransferRequestStatus.java │ │ │ │ │ │ └── TransferRequestDataModel.java │ │ │ │ │ │ ├── TransferRequestRepository.java │ │ │ │ │ │ └── TransferRequestProjection.java │ │ │ │ ├── domain │ │ │ │ │ └── models │ │ │ │ │ │ ├── paymentprocess │ │ │ │ │ │ ├── errors │ │ │ │ │ │ │ ├── PaymentProcessError.java │ │ │ │ │ │ │ └── PaymentProcessInvalidError.java │ │ │ │ │ │ └── PaymentProcess.java │ │ │ │ │ │ └── transferrequest │ │ │ │ │ │ └── TransferRequest.java │ │ │ │ ├── external │ │ │ │ │ ├── credit │ │ │ │ │ │ ├── protocol │ │ │ │ │ │ │ └── sendpaymentexecution │ │ │ │ │ │ │ │ ├── CreditMakePaymentCriticalErrorOccurred.java │ │ │ │ │ │ │ │ ├── CreditMakePaymentFailed.java │ │ │ │ │ │ │ │ ├── CreditAccepted.java │ │ │ │ │ │ │ │ ├── CreditRejected.java │ │ │ │ │ │ │ │ └── CreditApply.java │ │ │ │ │ │ └── CreditService.java │ │ │ │ │ └── notification │ │ │ │ │ │ ├── protocol │ │ │ │ │ │ └── sendpaymentexecution │ │ │ │ │ │ │ ├── NotificationSendPaymentExecution.java │ │ │ │ │ │ │ └── NotificationPaymentExecutionSent.java │ │ │ │ │ │ └── NotificationService.java │ │ │ │ └── process │ │ │ │ │ └── paymentprocess │ │ │ │ │ └── request │ │ │ │ │ ├── request │ │ │ │ │ └── PaymentProcessRequestCompensation.java │ │ │ │ │ ├── complete │ │ │ │ │ └── PaymentProcessCompleteStep.java │ │ │ │ │ ├── notification │ │ │ │ │ └── PaymentProcessNotificationStep.java │ │ │ │ │ ├── creditpayment │ │ │ │ │ └── PaymentProcessCreditPaymentStep.java │ │ │ │ │ └── transferrequest │ │ │ │ │ └── PaymentProcessTransferRequestStep.java │ │ │ ├── infrastructure │ │ │ │ ├── api │ │ │ │ │ └── credit │ │ │ │ │ │ ├── makepayment │ │ │ │ │ │ ├── CreditMakePaymentResponse.java │ │ │ │ │ │ └── CreditMakePaymentRequest.java │ │ │ │ │ │ ├── CreditApi.java │ │ │ │ │ │ └── CreditApiImpl.java │ │ │ │ └── inmem │ │ │ │ │ └── api │ │ │ │ │ └── credit │ │ │ │ │ └── InMemoryCreditApi.java │ │ │ └── adaptor │ │ │ │ └── aggregates │ │ │ │ ├── paymentprocess │ │ │ │ ├── commands │ │ │ │ │ ├── PaymentProcessFail.java │ │ │ │ │ ├── PaymentProcessComplete.java │ │ │ │ │ ├── PaymentProcessCommand.java │ │ │ │ │ └── PaymentRequest.java │ │ │ │ ├── PaymentProcessAggregateException.java │ │ │ │ └── PaymentProcessAggregate.java │ │ │ │ └── transferrequest │ │ │ │ ├── commands │ │ │ │ ├── TransferRequestCommand.java │ │ │ │ └── TransferRequestCreate.java │ │ │ │ └── TransferRequestAggregate.java │ │ │ ├── PaymentServiceWebApplication.java │ │ │ └── config │ │ │ ├── OpenApiConfiguration.java │ │ │ ├── axon │ │ │ ├── AxonKafkaTrackingConfiguration.java │ │ │ ├── SecureXStreamSerializer.java │ │ │ ├── AxonConfiguration.java │ │ │ └── AxonKafkaConfiguration.java │ │ │ └── infrastructure │ │ │ ├── InMemoryConfiguration.java │ │ │ ├── LocalConfiguration.java │ │ │ └── KafkaSingleConfiguration.java │ │ └── test │ │ └── java │ │ └── com │ │ └── pubsubdoc │ │ └── doc │ │ └── service │ │ └── web │ │ └── Demo1ApplicationTests.java ├── payment-shared │ └── src │ │ └── main │ │ └── java │ │ └── com │ │ └── pubsubdoc │ │ └── payment │ │ └── service │ │ └── shared │ │ └── application │ │ └── doc │ │ └── models │ │ ├── paymentprocess │ │ ├── PaymentMethod.java │ │ └── PaymentProcessId.java │ │ └── transferrequest │ │ └── TransferRequestId.java └── payment-api │ └── src │ └── main │ └── java │ └── com │ └── pubsubdoc │ └── payment │ └── service │ └── api │ └── domain │ └── models │ ├── paymentprocess │ ├── PaymentProcessEvent.java │ ├── PaymentProcessFailed.java │ ├── PaymentProcessCompleted.java │ └── PaymentProcessRequested.java │ └── transferrequest │ ├── TransferRequestEvent.java │ └── TransferRequestStarted.java ├── axon └── application │ └── src │ └── main │ ├── resources │ └── META-INF │ │ └── spring │ │ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports │ └── java │ └── com │ └── example │ └── axon │ └── application │ ├── external │ └── retry │ │ ├── RetryableCommand.java │ │ ├── CommandMeta.java │ │ ├── ExternalRetryRequested.java │ │ ├── ExternalRetryRequestedHandler.java │ │ └── RetryScheduler.java │ └── config │ ├── AxonExtendsProperties.java │ └── AxonExtendsAutoConfiguration.java ├── appkit └── application-basic │ └── src │ └── main │ └── java │ └── com │ └── example │ └── appkit │ ├── application │ └── basic │ │ ├── IdObject.java │ │ └── EventDrivenAggregateRoot.java │ ├── backoff │ └── Backoff.java │ └── http │ └── exceptions │ └── NotFoundException.java ├── README.md ├── settings.gradle.kts ├── .run ├── inmem.run.xml ├── dockerKafkaSIngle.run.xml ├── PaymentServiceWebApplication.run.xml ├── dockerKafkaSingleUserServiceWebApplication.run.xml ├── dockerKafkaSinglePaymentServiceWebApplication.run.xml ├── UserServiceWebApplication.run.xml ├── DocServiceWebApplication.run.xml ├── PubSubDocServiceBackApplication.run.xml ├── dockerKafkaSingleDocServiceWebApplication.run.xml └── dockerKafkaSinglePubSubDocServiceBackApplication.run.xml └── .gitignore /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nrslib/pubsubdoc/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/resources/application-app-kafka-single.yaml: -------------------------------------------------------------------------------- 1 | application: 2 | disable-kafka: false 3 | axon: 4 | axonserver: 5 | enabled: false 6 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/resources/application-app-kafka-single.yaml: -------------------------------------------------------------------------------- 1 | application: 2 | disable-kafka: false 3 | axon: 4 | axonserver: 5 | enabled: false 6 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/resources/application-app-kafka-single.yaml: -------------------------------------------------------------------------------- 1 | application: 2 | disable-kafka: false 3 | axon: 4 | axonserver: 5 | enabled: false 6 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/resources/application-app-kafka-single.yaml: -------------------------------------------------------------------------------- 1 | application: 2 | disable-kafka: false 3 | axon: 4 | axonserver: 5 | enabled: false 6 | -------------------------------------------------------------------------------- /axon/application/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports: -------------------------------------------------------------------------------- 1 | com.example.axon.application.config.AxonExtendsAutoConfiguration -------------------------------------------------------------------------------- /appkit/application-basic/src/main/java/com/example/appkit/application/basic/IdObject.java: -------------------------------------------------------------------------------- 1 | package com.example.appkit.application.basic; 2 | 3 | public interface IdObject { 4 | String asString(); 5 | } 6 | -------------------------------------------------------------------------------- /doc-service/doc-api/src/main/java/com/pubsubdoc/doc/service/api/domain/models/effective/EffectiveEvent.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.api.domain.models.effective; 2 | 3 | public interface EffectiveEvent { 4 | } 5 | -------------------------------------------------------------------------------- /axon/application/src/main/java/com/example/axon/application/external/retry/RetryableCommand.java: -------------------------------------------------------------------------------- 1 | package com.example.axon.application.external.retry; 2 | 3 | public interface RetryableCommand { 4 | int count(); 5 | } 6 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/http/models/common/ErrorModel.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.http.models.common; 2 | 3 | public record ErrorModel(Object code, String message) { 4 | } 5 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/http/models/common/ErrorModel.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.http.models.common; 2 | 3 | public record ErrorModel(Object code, String message) { 4 | } 5 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/http/models/docs/post/DocsPostRequest.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.http.models.docs.post; 2 | 3 | public record DocsPostRequest(String body) { 4 | } 5 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/http/models/users/post/UsersPostRequest.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.http.models.users.post; 2 | 3 | public record UsersPostRequest(String userName) { 4 | } 5 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/http/models/common/ErrorModel.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.http.models.common; 2 | 3 | public record ErrorModel(Object code, String message) { 4 | } 5 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/http/models/docs/put/DocsPutRequest.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.http.models.docs.put; 2 | 3 | public record DocsPutRequest( 4 | String body 5 | ) { 6 | } -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/http/models/common/ErrorModel.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.http.models.common; 2 | 3 | public record ErrorModel(Object code, String message) { 4 | } 5 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/application/domain/models/team/errors/TeamError.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.application.domain.models.team.errors; 2 | 3 | public interface TeamError { 4 | } 5 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/resources/application-datastore-h2.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:h2:mem:test 4 | driver-class-name: org.h2.Driver 5 | username: sa 6 | password: 7 | h2: 8 | console: 9 | enabled: true -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/resources/application-datastore-h2.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:h2:mem:test 4 | driver-class-name: org.h2.Driver 5 | username: sa 6 | password: 7 | h2: 8 | console: 9 | enabled: true -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/http/models/users/get/UserGetResponse.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.http.models.users.get; 2 | 3 | public record UserGetResponse(String userId, String userName) { 4 | } 5 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/http/models/users/post/UsersPostRequest.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.http.models.users.post; 2 | 3 | public record UsersPostRequest( 4 | String name 5 | ) { 6 | } 7 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/resources/application-datastore-h2.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:h2:mem:test 4 | driver-class-name: org.h2.Driver 5 | username: sa 6 | password: 7 | h2: 8 | console: 9 | enabled: true -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/http/models/users/get/UsersGetResponse.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.http.models.users.get; 2 | 3 | public record UsersGetResponse( 4 | UsersResponseModel user 5 | ) { 6 | } 7 | -------------------------------------------------------------------------------- /user-service/user-sdk/src/main/java/com/pubsubdoc/user/service/sdk/api/protocol/UsersFindResponse.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.sdk.api.protocol; 2 | 3 | import java.util.List; 4 | 5 | public record UsersFindResponse(List users) { 6 | } 7 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/http/models/docs/post/DocsPostResponse.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.http.models.docs.post; 2 | 3 | import java.util.UUID; 4 | 5 | public record DocsPostResponse(UUID docId) { 6 | } 7 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/app/application/query/doc/queries/GetDoc.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.app.application.query.doc.queries; 2 | 3 | import java.util.UUID; 4 | 5 | public record GetDoc(UUID docId) { 6 | } 7 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/http/models/users/post/UsersPostResponse.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.http.models.users.post; 2 | 3 | import java.util.UUID; 4 | 5 | public record UsersPostResponse(UUID userId) { 6 | } 7 | -------------------------------------------------------------------------------- /axon/application/src/main/java/com/example/axon/application/external/retry/CommandMeta.java: -------------------------------------------------------------------------------- 1 | package com.example.axon.application.external.retry; 2 | 3 | import java.util.Map; 4 | 5 | public record CommandMeta(String className, Map properties) { 6 | } 7 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/http/models/users/post/UsersPostRequest.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.http.models.users.post; 2 | 3 | public record UsersPostRequest( 4 | String name 5 | ) { 6 | } 7 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/app/application/query/user/queries/FindUser.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.app.application.query.user.queries; 2 | 3 | import java.util.UUID; 4 | 5 | public record FindUser(UUID userId) { 6 | } 7 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/application/query/user/queries/FindUserDataModel.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.application.query.user.queries; 2 | 3 | public record FindUserDataModel(String userName) { 4 | } 5 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/http/models/teams/post/TeamsPostResponse.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.http.models.teams.post; 2 | 3 | import java.util.UUID; 4 | 5 | public record TeamsPostResponse(UUID teamId) { 6 | } 7 | -------------------------------------------------------------------------------- /pubsubdoc-service/back-api/src/main/java/com/pubsubdoc/back/service/api/process/user/requestcreation/UserProcessRequestCreationEvent.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.back.service.api.process.user.requestcreation; 2 | 3 | 4 | public interface UserProcessRequestCreationEvent { 5 | } 6 | -------------------------------------------------------------------------------- /appkit/application-basic/src/main/java/com/example/appkit/application/basic/EventDrivenAggregateRoot.java: -------------------------------------------------------------------------------- 1 | package com.example.appkit.application.basic; 2 | 3 | public interface EventDrivenAggregateRoot { 4 | EventDrivenAggregateRoot applyEvent(Event event); 5 | } 6 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/http/models/teams/post/TeamsPostResponse.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.http.models.teams.post; 2 | 3 | import java.util.UUID; 4 | 5 | public record TeamsPostResponse(UUID teamId) { 6 | } 7 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/query/user/queries/GetUser.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.query.user.queries; 2 | 3 | import java.util.UUID; 4 | 5 | public record GetUser(UUID userId) { 6 | } 7 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/query/user/queries/UserModel.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.query.user.queries; 2 | 3 | import java.util.UUID; 4 | 5 | public record UserModel(UUID userId) { 6 | } 7 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/http/models/docs/get/DocsGetResponse.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.http.models.docs.get; 2 | 3 | import java.util.UUID; 4 | 5 | public record DocsGetResponse(UUID docsId, String body, int effectiveCount) { 6 | } 7 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/application/domain/models/team/errors/TeamMemberFullError.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.application.domain.models.team.errors; 2 | 3 | public class TeamMemberFullError implements TeamError { 4 | } 5 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/http/models/teams/post/TeamsPostRequest.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.http.models.teams.post; 2 | 3 | import java.util.UUID; 4 | 5 | public record TeamsPostRequest(String teamName, UUID ownerUserId) { 6 | } 7 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/application/query/user/queries/GetUserDataModel.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.application.query.user.queries; 2 | 3 | import java.util.UUID; 4 | 5 | public record GetUserDataModel(UUID userId) { 6 | } 7 | -------------------------------------------------------------------------------- /doc-service/doc-api/src/main/java/com/pubsubdoc/doc/service/api/domain/models/doc/DocEvent.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.api.domain.models.doc; 2 | 3 | import com.pubsubdoc.doc.service.shared.application.doc.models.doc.DocId; 4 | 5 | public interface DocEvent { 6 | DocId docId(); 7 | } 8 | -------------------------------------------------------------------------------- /payment-service/payment-shared/src/main/java/com/pubsubdoc/payment/service/shared/application/doc/models/paymentprocess/PaymentMethod.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess; 2 | 3 | public enum PaymentMethod { 4 | CREDIT, 5 | BANK_TRANSFER, 6 | } 7 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/domain/models/paymentprocess/errors/PaymentProcessError.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.domain.models.paymentprocess.errors; 2 | 3 | public interface PaymentProcessError { 4 | } 5 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/http/models/payments/post/PaymentsPostResponse.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.http.models.payments.post; 2 | 3 | import java.util.UUID; 4 | 5 | public record PaymentsPostResponse(UUID paymentProcessId) { 6 | } 7 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/http/models/teams/post/TeamsPostRequest.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.http.models.teams.post; 2 | 3 | import java.util.UUID; 4 | 5 | public record TeamsPostRequest(String teamName, UUID ownerUserId) { 6 | } 7 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/app/application/domain/models/effective/exceptions/EffectiveException.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.app.application.domain.models.effective.exceptions; 2 | 3 | public abstract class EffectiveException extends RuntimeException { 4 | } 5 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /user-service/user-api/src/main/java/com/pubsubdoc/user/service/api/domain/models/team/TeamEvent.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.api.domain.models.team; 2 | 3 | import com.pubsubdoc.user.service.shared.application.doc.models.team.TeamId; 4 | 5 | public interface TeamEvent { 6 | TeamId teamId(); 7 | } 8 | -------------------------------------------------------------------------------- /user-service/user-api/src/main/java/com/pubsubdoc/user/service/api/domain/models/user/UserEvent.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.api.domain.models.user; 2 | 3 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 4 | 5 | public interface UserEvent { 6 | UserId userId(); 7 | } 8 | -------------------------------------------------------------------------------- /user-service/user-sdk/src/main/java/com/pubsubdoc/user/service/sdk/api/protocol/UserModel.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.sdk.api.protocol; 2 | 3 | import java.util.UUID; 4 | 5 | public record UserModel( 6 | UUID userId, 7 | String userName, 8 | String teamId) { 9 | } 10 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/app/application/domain/models/effective/exceptions/EffectiveMarkedException.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.app.application.domain.models.effective.exceptions; 2 | 3 | public class EffectiveMarkedException extends EffectiveException { 4 | } 5 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/http/models/users/post/UsersPostResponse.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.http.models.users.post; 2 | 3 | import java.util.UUID; 4 | 5 | public record UsersPostResponse( 6 | UUID id, 7 | String name 8 | ) { 9 | } 10 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/app/application/domain/models/effective/exceptions/EffectiveUnmarkedException.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.app.application.domain.models.effective.exceptions; 2 | 3 | public class EffectiveUnmarkedException extends EffectiveException { 4 | } 5 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/infrastructure/api/credit/makepayment/CreditMakePaymentResponse.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.infrastructure.api.credit.makepayment; 2 | 3 | public record CreditMakePaymentResponse(boolean accepted, int statusCode) { 4 | } 5 | -------------------------------------------------------------------------------- /axon/application/src/main/java/com/example/axon/application/config/AxonExtendsProperties.java: -------------------------------------------------------------------------------- 1 | package com.example.axon.application.config; 2 | 3 | import org.springframework.boot.context.properties.ConfigurationProperties; 4 | 5 | @ConfigurationProperties(prefix = "axon.extends") 6 | public class AxonExtendsProperties { 7 | } 8 | -------------------------------------------------------------------------------- /doc-service/doc-api/src/main/java/com/pubsubdoc/doc/service/api/domain/models/doc/DocUpdated.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.api.domain.models.doc; 2 | 3 | import com.pubsubdoc.doc.service.shared.application.doc.models.doc.DocId; 4 | 5 | public record DocUpdated(DocId docId, String body) implements DocEvent { 6 | } 7 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/resources/application-datastore-mysql.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:mysql://localhost:3306/db 4 | driver-class-name: com.mysql.cj.jdbc.Driver 5 | username: docker 6 | password: mysql 7 | jpa: 8 | database: mysql 9 | hibernate: 10 | ddl-auto: update -------------------------------------------------------------------------------- /user-service/user-sdk/src/main/java/com/pubsubdoc/user/service/sdk/api/protocol/UsersGetResponse.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.sdk.api.protocol; 2 | 3 | import java.util.UUID; 4 | 5 | public record UsersGetResponse( 6 | UUID userId, 7 | String userName, 8 | String teamId 9 | ) { 10 | } -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/http/models/users/post/UsersPostResponse.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.http.models.users.post; 2 | 3 | import java.util.UUID; 4 | 5 | public record UsersPostResponse( 6 | UUID id, 7 | String name 8 | ) { 9 | } 10 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/resources/application-datastore-mysql.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:mysql://localhost:3326/db 4 | driver-class-name: com.mysql.cj.jdbc.Driver 5 | username: docker 6 | password: mysql 7 | jpa: 8 | database: mysql 9 | hibernate: 10 | ddl-auto: update -------------------------------------------------------------------------------- /user-service/user-web/src/main/resources/application-datastore-mysql.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:mysql://localhost:3336/db 4 | driver-class-name: com.mysql.cj.jdbc.Driver 5 | username: docker 6 | password: mysql 7 | jpa: 8 | database: mysql 9 | hibernate: 10 | ddl-auto: update -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/http/models/effectives/post/EffectivesPostRequest.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.http.models.effectives.post; 2 | 3 | import java.util.UUID; 4 | 5 | public record EffectivesPostRequest( 6 | UUID docId, 7 | UUID userId 8 | ) { 9 | } 10 | -------------------------------------------------------------------------------- /axon/application/src/main/java/com/example/axon/application/external/retry/ExternalRetryRequested.java: -------------------------------------------------------------------------------- 1 | package com.example.axon.application.external.retry; 2 | 3 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 4 | 5 | public record ExternalRetryRequested(@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) RetryableCommand command) { 6 | } 7 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/http/models/effectives/delete/EffectivesDeleteRequest.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.http.models.effectives.delete; 2 | 3 | import java.util.UUID; 4 | 5 | public record EffectivesDeleteRequest( 6 | UUID docId, 7 | UUID userId 8 | ) { 9 | } 10 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/domain/models/paymentprocess/errors/PaymentProcessInvalidError.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.domain.models.paymentprocess.errors; 2 | 3 | public class PaymentProcessInvalidError implements PaymentProcessError { 4 | } 5 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/query/transferrequest/datamodel/TransferRequestStatus.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.query.transferrequest.datamodel; 2 | 3 | public enum TransferRequestStatus { 4 | CREATED, 5 | COMPLETED, 6 | FAILED 7 | } 8 | -------------------------------------------------------------------------------- /user-service/user-api/src/main/java/com/pubsubdoc/user/service/api/domain/models/user/UserUpgraded.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.api.domain.models.user; 2 | 3 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 4 | 5 | public record UserUpgraded(UserId userId, String body) implements UserEvent { 6 | } 7 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/http/models/users/get/UsersResponseModel.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.http.models.users.get; 2 | 3 | import java.util.UUID; 4 | 5 | public record UsersResponseModel( 6 | UUID userId, 7 | String userName, 8 | String teamId 9 | ) { 10 | } 11 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/external/credit/protocol/sendpaymentexecution/CreditMakePaymentCriticalErrorOccurred.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.external.credit.protocol.sendpaymentexecution; 2 | 3 | public record CreditMakePaymentCriticalErrorOccurred() { 4 | } 5 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/external/credit/protocol/sendpaymentexecution/CreditMakePaymentFailed.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.external.credit.protocol.sendpaymentexecution; 2 | 3 | public record CreditMakePaymentFailed(CreditApply command, String message) { 4 | } 5 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/adaptor/aggregates/user/commands/UserUpgrade.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.adaptor.aggregates.user.commands; 2 | 3 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 4 | 5 | public record UserUpgrade(UserId userId) implements UserCommand { 6 | } 7 | -------------------------------------------------------------------------------- /doc-service/doc-api/src/main/java/com/pubsubdoc/doc/service/api/domain/models/doc/DocCreated.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.api.domain.models.doc; 2 | 3 | import com.pubsubdoc.doc.service.shared.application.doc.models.doc.DocId; 4 | 5 | public record DocCreated( 6 | DocId docId, 7 | String body 8 | ) implements DocEvent { 9 | } 10 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/http/models/users/find/UserFindResponse.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.http.models.users.find; 2 | 3 | import com.pubsubdoc.user.service.web.app.infrastructure.jpa.user.UserDataModel; 4 | 5 | import java.util.List; 6 | 7 | public record UserFindResponse(List users) { 8 | } 9 | -------------------------------------------------------------------------------- /user-service/user-api/src/main/java/com/pubsubdoc/user/service/api/domain/models/user/UserCreated.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.api.domain.models.user; 2 | 3 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 4 | 5 | public record UserCreated( 6 | UserId userId, 7 | String name 8 | ) implements UserEvent { 9 | } 10 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/test/java/com/pubsubdoc/doc/service/web/Demo1ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class Demo1ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/test/java/com/pubsubdoc/doc/service/web/Demo1ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class Demo1ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/adaptor/aggregates/user/commands/UserCreate.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.adaptor.aggregates.user.commands; 2 | 3 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 4 | 5 | public record UserCreate(UserId userId, String name) implements UserCommand { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /user-service/user-web/src/test/java/com/pubsubdoc/doc/service/web/Demo1ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class Demo1ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /doc-service/doc-api/src/main/java/com/pubsubdoc/doc/service/api/domain/models/effective/EffectiveMarked.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.api.domain.models.effective; 2 | 3 | import com.pubsubdoc.doc.service.shared.application.doc.models.doc.DocId; 4 | 5 | import java.util.UUID; 6 | 7 | public record EffectiveMarked(DocId docId, UUID userId) implements EffectiveEvent { 8 | } 9 | -------------------------------------------------------------------------------- /doc-service/doc-api/src/main/java/com/pubsubdoc/doc/service/api/domain/models/effective/EffectiveUnmarked.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.api.domain.models.effective; 2 | 3 | import com.pubsubdoc.doc.service.shared.application.doc.models.doc.DocId; 4 | 5 | import java.util.UUID; 6 | 7 | public record EffectiveUnmarked(DocId docId, UUID userId) implements EffectiveEvent { 8 | } 9 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/test/java/com/pubsubdoc/doc/service/web/Demo1ApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class Demo1ApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/app/application/query/doc/queries/GetDocResult.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.app.application.query.doc.queries; 2 | 3 | import com.pubsubdoc.service.back.app.infrastructure.jpa.doc.DocDataModel; 4 | 5 | import java.util.Optional; 6 | 7 | public record GetDocResult(Optional docDataModel) { 8 | } 9 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/app/application/query/user/queries/FindUserResult.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.app.application.query.user.queries; 2 | 3 | import com.pubsubdoc.service.back.app.infrastructure.jpa.user.UserDataModel; 4 | 5 | import java.util.Optional; 6 | 7 | public record FindUserResult(Optional userDataModel) { 8 | } 9 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/app/adaptor/aggregates/effective/commands/EffectiveCommand.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.app.adaptor.aggregates.effective.commands; 2 | 3 | import org.axonframework.modelling.command.TargetAggregateIdentifier; 4 | 5 | public interface EffectiveCommand { 6 | @TargetAggregateIdentifier 7 | String getIdentifier(); 8 | } 9 | -------------------------------------------------------------------------------- /payment-service/payment-api/src/main/java/com/pubsubdoc/payment/service/api/domain/models/paymentprocess/PaymentProcessEvent.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.api.domain.models.paymentprocess; 2 | 3 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentProcessId; 4 | 5 | public interface PaymentProcessEvent { 6 | PaymentProcessId paymentProcessId(); 7 | } 8 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/query/user/queries/GetUserResult.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.query.user.queries; 2 | 3 | import com.pubsubdoc.user.service.sdk.api.protocol.UsersGetResponse; 4 | 5 | import java.util.Optional; 6 | 7 | public record GetUserResult(Optional userDataModel) { 8 | } 9 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/app/infrastructure/jpa/doc/DocRepository.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.app.infrastructure.jpa.doc; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import org.springframework.stereotype.Repository; 5 | 6 | @Repository 7 | public interface DocRepository extends JpaRepository { 8 | } 9 | -------------------------------------------------------------------------------- /payment-service/payment-api/src/main/java/com/pubsubdoc/payment/service/api/domain/models/transferrequest/TransferRequestEvent.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.api.domain.models.transferrequest; 2 | 3 | import com.pubsubdoc.payment.service.shared.application.doc.models.transferrequest.TransferRequestId; 4 | 5 | public interface TransferRequestEvent { 6 | TransferRequestId transferRequestId(); 7 | } 8 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/app/infrastructure/jpa/user/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.app.infrastructure.jpa.user; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import org.springframework.stereotype.Repository; 5 | 6 | @Repository 7 | public interface UserRepository extends JpaRepository { 8 | } 9 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/application/query/user/queries/FindUserDataModelResult.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.application.query.user.queries; 2 | 3 | import com.pubsubdoc.user.service.web.app.infrastructure.jpa.user.UserDataModel; 4 | 5 | import java.util.List; 6 | 7 | public record FindUserDataModelResult(List userDataModels) { 8 | } 9 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/external/notification/protocol/sendmemberadded/NotificationMemberAddedSent.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.external.notification.protocol.sendmemberadded; 2 | 3 | import com.pubsubdoc.user.service.shared.application.doc.models.team.TeamId; 4 | 5 | public record NotificationMemberAddedSent(TeamId teamId, String message) { 6 | } 7 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/application/query/user/queries/GetUserDataModelResult.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.application.query.user.queries; 2 | 3 | import com.pubsubdoc.user.service.web.app.infrastructure.jpa.user.UserDataModel; 4 | 5 | import java.util.Optional; 6 | 7 | public record GetUserDataModelResult(Optional userDataModel) { 8 | } 9 | -------------------------------------------------------------------------------- /appkit/application-basic/src/main/java/com/example/appkit/backoff/Backoff.java: -------------------------------------------------------------------------------- 1 | package com.example.appkit.backoff; 2 | 3 | import java.time.Duration; 4 | 5 | public class Backoff { 6 | public static Duration exponentialBackoff(int currentCount, int waitBase) { 7 | var waitSecond = waitBase * Math.pow(2.0, currentCount); 8 | 9 | return Duration.ofSeconds((long) waitSecond); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /payment-service/payment-api/src/main/java/com/pubsubdoc/payment/service/api/domain/models/paymentprocess/PaymentProcessFailed.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.api.domain.models.paymentprocess; 2 | 3 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentProcessId; 4 | 5 | public record PaymentProcessFailed(PaymentProcessId paymentProcessId) implements PaymentProcessEvent { 6 | } 7 | -------------------------------------------------------------------------------- /user-service/user-api/src/main/java/com/pubsubdoc/user/service/api/domain/models/team/TeamMemberAdded.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.api.domain.models.team; 2 | 3 | import com.pubsubdoc.user.service.shared.application.doc.models.team.TeamId; 4 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 5 | 6 | public record TeamMemberAdded(TeamId teamId, UserId newMemberId) implements TeamEvent { 7 | } 8 | -------------------------------------------------------------------------------- /payment-service/payment-api/src/main/java/com/pubsubdoc/payment/service/api/domain/models/transferrequest/TransferRequestStarted.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.api.domain.models.transferrequest; 2 | 3 | import com.pubsubdoc.payment.service.shared.application.doc.models.transferrequest.TransferRequestId; 4 | 5 | public record TransferRequestStarted(TransferRequestId transferRequestId) implements TransferRequestEvent { 6 | } 7 | -------------------------------------------------------------------------------- /pubsubdoc-service/back-api/src/main/java/com/pubsubdoc/back/service/api/process/user/requestcreation/UserProcessRequestCreationRequested.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.back.service.api.process.user.requestcreation; 2 | 3 | 4 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 5 | 6 | public record UserProcessRequestCreationRequested(UserId userId, String userName) implements UserProcessRequestCreationEvent { 7 | } 8 | -------------------------------------------------------------------------------- /user-service/user-api/src/main/java/com/pubsubdoc/user/service/api/domain/models/team/TeamCreated.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.api.domain.models.team; 2 | 3 | import com.pubsubdoc.user.service.shared.application.doc.models.team.TeamId; 4 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 5 | 6 | public record TeamCreated(TeamId teamId, String teamName, UserId ownerUserId) implements TeamEvent { 7 | } 8 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/infrastructure/api/credit/makepayment/CreditMakePaymentRequest.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.infrastructure.api.credit.makepayment; 2 | 3 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 4 | 5 | import java.math.BigDecimal; 6 | 7 | public record CreditMakePaymentRequest(UserId userId, BigDecimal amount) { 8 | } 9 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: inmem 4 | group: 5 | inmem: 6 | - common 7 | - app-inmem 8 | - datastore-h2 9 | local: 10 | - common 11 | - app-inmem 12 | - datastore-h2 13 | kafka-single: 14 | - common 15 | - app-kafka-single 16 | - broker-kafka-single 17 | - datastore-mysql 18 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/external/credit/protocol/sendpaymentexecution/CreditAccepted.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.external.credit.protocol.sendpaymentexecution; 2 | 3 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentProcessId; 4 | 5 | public record CreditAccepted(PaymentProcessId paymentProcessId) { 6 | } 7 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/external/credit/protocol/sendpaymentexecution/CreditRejected.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.external.credit.protocol.sendpaymentexecution; 2 | 3 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentProcessId; 4 | 5 | public record CreditRejected(PaymentProcessId paymentProcessId) { 6 | } 7 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: inmem 4 | group: 5 | inmem: 6 | - common 7 | - app-inmem 8 | - datastore-h2 9 | local: 10 | - common 11 | - app-inmem 12 | - datastore-h2 13 | kafka-single: 14 | - common 15 | - app-kafka-single 16 | - broker-kafka-single 17 | - datastore-mysql 18 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/resources/application-app-inmem.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:h2:mem:test 4 | driver-class-name: org.h2.Driver 5 | username: sa 6 | password: 7 | h2: 8 | console: 9 | enabled: true 10 | axon: 11 | axonserver: 12 | enabled: false 13 | kafka: 14 | fetcher: 15 | enabled: false 16 | publisher: 17 | enabled: false 18 | application: 19 | disable-kafka: true -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: inmem 4 | group: 5 | inmem: 6 | - common 7 | - app-inmem 8 | - datastore-h2 9 | local: 10 | - common 11 | - app-inmem 12 | - datastore-h2 13 | kafka-single: 14 | - common 15 | - app-kafka-single 16 | - broker-kafka-single 17 | - datastore-mysql 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PubSubDoc 2 | 3 | ## 起動方法 4 | 5 | 1. docker で kafka などを立ち上げます 6 | 2. .run の run configuration のうち、kafka-single を使うと kafka を利用する設定でサービス群が立ち上がります。 7 | 3. localhost:8080, localhost:8180, localhost:8280, localhost:8380 にアクセスするとそれぞれのサービスの Swagger を開けます。 8 | 9 | ## Run on docker 10 | 11 | ```shell 12 | docker compose up 13 | ``` 14 | 15 | ### Set Environment Variables. 16 | 17 | ``` 18 | SPRING_PROFILES_ACTIVE=kafka-single 19 | ``` 20 | 21 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/app/adaptor/aggregates/doc/commands/DocCommand.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.app.adaptor.aggregates.doc.commands; 2 | 3 | import com.pubsubdoc.doc.service.shared.application.doc.models.doc.DocId; 4 | import org.axonframework.modelling.command.TargetAggregateIdentifier; 5 | 6 | public interface DocCommand { 7 | @TargetAggregateIdentifier 8 | DocId docId(); 9 | } 10 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/app/adaptor/aggregates/doc/commands/create/DocCreate.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.app.adaptor.aggregates.doc.commands.create; 2 | 3 | import com.pubsubdoc.doc.service.shared.application.doc.models.doc.DocId; 4 | import com.pubsubdoc.doc.service.web.app.adaptor.aggregates.doc.commands.DocCommand; 5 | 6 | public record DocCreate(DocId docId, String body) implements DocCommand { 7 | } 8 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/app/adaptor/aggregates/doc/commands/create/DocUpdate.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.app.adaptor.aggregates.doc.commands.create; 2 | 3 | import com.pubsubdoc.doc.service.shared.application.doc.models.doc.DocId; 4 | import com.pubsubdoc.doc.service.web.app.adaptor.aggregates.doc.commands.DocCommand; 5 | 6 | public record DocUpdate(DocId docId, String body) implements DocCommand { 7 | } 8 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/adaptor/aggregates/paymentprocess/commands/PaymentProcessFail.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.adaptor.aggregates.paymentprocess.commands; 2 | 3 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentProcessId; 4 | 5 | public record PaymentProcessFail(PaymentProcessId paymentProcessId) implements PaymentProcessCommand { 6 | } 7 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: inmem 4 | group: 5 | inmem: 6 | - common 7 | - app-inmem 8 | - datastore-h2 9 | local: 10 | - common 11 | - app-inmem 12 | - datastore-h2 13 | kafka-single: 14 | - common 15 | - app-kafka-single 16 | - broker-kafka-single 17 | - datastore-mysql 18 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/resources/application-app-inmem.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:h2:mem:test 4 | driver-class-name: org.h2.Driver 5 | username: sa 6 | password: 7 | h2: 8 | console: 9 | enabled: true 10 | axon: 11 | axonserver: 12 | enabled: false 13 | kafka: 14 | fetcher: 15 | enabled: false 16 | publisher: 17 | enabled: false 18 | application: 19 | disable-kafka: true -------------------------------------------------------------------------------- /user-service/user-web/src/main/resources/application-app-inmem.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:h2:mem:test 4 | driver-class-name: org.h2.Driver 5 | username: sa 6 | password: 7 | h2: 8 | console: 9 | enabled: true 10 | axon: 11 | axonserver: 12 | enabled: false 13 | kafka: 14 | fetcher: 15 | enabled: false 16 | publisher: 17 | enabled: false 18 | application: 19 | disable-kafka: true -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/resources/application-app-inmem.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:h2:mem:test 4 | driver-class-name: org.h2.Driver 5 | username: sa 6 | password: 7 | h2: 8 | console: 9 | enabled: true 10 | axon: 11 | axonserver: 12 | enabled: false 13 | kafka: 14 | fetcher: 15 | enabled: false 16 | publisher: 17 | enabled: false 18 | application: 19 | disable-kafka: true -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/adaptor/aggregates/team/commands/TeamAddMember.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.adaptor.aggregates.team.commands; 2 | 3 | import com.pubsubdoc.user.service.shared.application.doc.models.team.TeamId; 4 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 5 | 6 | public record TeamAddMember(TeamId teamId, UserId newMemberId) implements TeamCommand { 7 | } 8 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/http/controllers/teams/exceptions/TeamsControllerOwnerUserNotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.http.controllers.teams.exceptions; 2 | 3 | import java.util.UUID; 4 | 5 | public class TeamsControllerOwnerUserNotFoundException extends RuntimeException { 6 | public TeamsControllerOwnerUserNotFoundException(UUID ownerUserId) { 7 | super(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/adaptor/aggregates/paymentprocess/commands/PaymentProcessComplete.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.adaptor.aggregates.paymentprocess.commands; 2 | 3 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentProcessId; 4 | 5 | public record PaymentProcessComplete(PaymentProcessId paymentProcessId) implements PaymentProcessCommand { 6 | } 7 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/adaptor/aggregates/team/commands/TeamCommand.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.adaptor.aggregates.team.commands; 2 | 3 | import com.pubsubdoc.user.service.shared.application.doc.models.team.TeamId; 4 | import org.axonframework.modelling.command.TargetAggregateIdentifier; 5 | 6 | public interface TeamCommand { 7 | @TargetAggregateIdentifier 8 | TeamId teamId(); 9 | } 10 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/adaptor/aggregates/user/commands/UserCommand.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.adaptor.aggregates.user.commands; 2 | 3 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 4 | import org.axonframework.modelling.command.TargetAggregateIdentifier; 5 | 6 | public interface UserCommand { 7 | @TargetAggregateIdentifier 8 | UserId userId(); 9 | } 10 | -------------------------------------------------------------------------------- /user-service/user-api/src/main/java/com/pubsubdoc/user/service/api/domain/models/team/TeamOperationFailed.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.api.domain.models.team; 2 | 3 | import com.fasterxml.jackson.annotation.JsonTypeInfo; 4 | import com.pubsubdoc.user.service.shared.application.doc.models.team.TeamId; 5 | 6 | public record TeamOperationFailed(TeamId teamId, @JsonTypeInfo(use = JsonTypeInfo.Id.CLASS) Object command, String message) implements TeamEvent { 7 | } 8 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/resources/application-broker-kafka-single.yaml: -------------------------------------------------------------------------------- 1 | application: 2 | kafka: 3 | topics: doc-service-topic 4 | axon: 5 | kafka: 6 | client-id: doc-service-web 7 | producer: 8 | retries: 0 9 | consumer: 10 | event-processor-mode: tracking 11 | properties: 12 | security.protocol: PLAINTEXT 13 | default-topic: doc-service-topic 14 | bootstrap-servers: localhost:29092,localhost:29192,localhost:29292 15 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/adaptor/aggregates/team/commands/TeamCreate.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.adaptor.aggregates.team.commands; 2 | 3 | import com.pubsubdoc.user.service.shared.application.doc.models.team.TeamId; 4 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 5 | 6 | public record TeamCreate(TeamId teamId, String teamName, UserId ownerUserId) implements TeamCommand { 7 | } 8 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/http/models/payments/post/PaymentsPostRequest.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.http.models.payments.post; 2 | 3 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentMethod; 4 | 5 | import java.math.BigDecimal; 6 | import java.util.UUID; 7 | 8 | public record PaymentsPostRequest(UUID userId, BigDecimal amount, PaymentMethod paymentMethod) { 9 | } 10 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/http/controllers/root/RootController.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.http.controllers.root; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | 6 | @Controller 7 | public class RootController { 8 | @RequestMapping("/") 9 | public String index() { 10 | return "redirect:/swagger-ui/index.html"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /user-service/user-sdk/src/main/java/com/pubsubdoc/user/service/sdk/api/UserServiceApi.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.sdk.api; 2 | 3 | import com.pubsubdoc.user.service.sdk.api.protocol.UsersFindResponse; 4 | import com.pubsubdoc.user.service.sdk.api.protocol.UsersGetResponse; 5 | 6 | import java.util.UUID; 7 | 8 | public interface UserServiceApi { 9 | UsersGetResponse getUser(UUID userId); 10 | 11 | UsersFindResponse findUser(String userName); 12 | } 13 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/adaptor/aggregates/team/TeamAggregateException.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.adaptor.aggregates.team; 2 | 3 | import com.pubsubdoc.user.service.web.app.application.domain.models.team.errors.TeamError; 4 | 5 | public class TeamAggregateException extends RuntimeException { 6 | public TeamAggregateException(TeamError error, String message) { 7 | super(message); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/http/controllers/teamsmemberships/exceptions/TeamsMembersControllerMemberFullException.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.http.controllers.teamsmemberships.exceptions; 2 | 3 | import java.util.UUID; 4 | 5 | public class TeamsMembersControllerMemberFullException extends RuntimeException { 6 | public TeamsMembersControllerMemberFullException(UUID teamId) { 7 | super(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/DocServiceWebApplication.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class DocServiceWebApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(DocServiceWebApplication.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/http/controllers/root/RootController.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.http.controllers.root; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | 6 | @Controller 7 | public class RootController { 8 | @RequestMapping("/") 9 | public String index() { 10 | return "redirect:/swagger-ui/index.html"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/resources/application-broker-kafka-single.yaml: -------------------------------------------------------------------------------- 1 | application: 2 | kafka: 3 | topics: payment-service-topic 4 | axon: 5 | kafka: 6 | client-id: user-service-web 7 | producer: 8 | retries: 0 9 | consumer: 10 | event-processor-mode: tracking 11 | properties: 12 | security.protocol: PLAINTEXT 13 | default-topic: payment-service-topic 14 | bootstrap-servers: localhost:29092,localhost:29192,localhost:29292 15 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/app/application/process/user/requestcreation/UserProcessRequestCreation.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.app.application.process.user.requestcreation; 2 | 3 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 4 | import org.axonframework.modelling.command.TargetAggregateIdentifier; 5 | 6 | public record UserProcessRequestCreation(@TargetAggregateIdentifier UserId userId, String userName) { 7 | } 8 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/UserServiceWebApplication.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class UserServiceWebApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(UserServiceWebApplication.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/external/notification/protocol/sendmemberadded/NotificationSendMemberAdded.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.external.notification.protocol.sendmemberadded; 2 | 3 | import com.pubsubdoc.user.service.shared.application.doc.models.team.TeamId; 4 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 5 | 6 | public record NotificationSendMemberAdded(TeamId teamId, UserId userId) { 7 | } 8 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/http/controllers/root/RootController.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.http.controllers.root; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | 6 | @Controller 7 | public class RootController { 8 | @RequestMapping("/") 9 | public String index() { 10 | return "redirect:/swagger-ui/index.html"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/external/notification/protocol/sendpaymentexecution/NotificationSendPaymentExecution.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.external.notification.protocol.sendpaymentexecution; 2 | 3 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentProcessId; 4 | 5 | public record NotificationSendPaymentExecution(PaymentProcessId paymentProcessId) { 6 | } 7 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/http/controllers/root/RootController.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.http.controllers.root; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | 6 | @Controller 7 | public class RootController { 8 | @RequestMapping("/") 9 | public String index() { 10 | return "redirect:/swagger-ui/index.html"; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/PubSubDocServiceBackApplication.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class PubSubDocServiceBackApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(PubSubDocServiceBackApplication.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/PaymentServiceWebApplication.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class PaymentServiceWebApplication { 8 | public static void main(String[] args) { 9 | SpringApplication.run(PaymentServiceWebApplication.class, args); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /axon/application/src/main/java/com/example/axon/application/external/retry/ExternalRetryRequestedHandler.java: -------------------------------------------------------------------------------- 1 | package com.example.axon.application.external.retry; 2 | 3 | import org.axonframework.commandhandling.gateway.CommandGateway; 4 | import org.axonframework.eventhandling.EventHandler; 5 | 6 | public class ExternalRetryRequestedHandler { 7 | @EventHandler 8 | public void on(ExternalRetryRequested event, CommandGateway commandGateway) { 9 | commandGateway.send(event.command()); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /payment-service/payment-api/src/main/java/com/pubsubdoc/payment/service/api/domain/models/paymentprocess/PaymentProcessCompleted.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.api.domain.models.paymentprocess; 2 | 3 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentProcessId; 4 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 5 | 6 | public record PaymentProcessCompleted(PaymentProcessId paymentProcessId, UserId userId) implements PaymentProcessEvent { 7 | } 8 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/query/transferrequest/TransferRequestRepository.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.query.transferrequest; 2 | 3 | import com.pubsubdoc.payment.service.web.app.application.query.transferrequest.datamodel.TransferRequestDataModel; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | 6 | public interface TransferRequestRepository extends JpaRepository { 7 | } 8 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/resources/application-datastore-h2.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:h2:mem:test 4 | driver-class-name: org.h2.Driver 5 | username: sa 6 | password: 7 | h2: 8 | console: 9 | enabled: true 10 | quartz: 11 | jdbc: 12 | initialize-schema: always 13 | job-store-type: jdbc 14 | properties: 15 | org: 16 | quartz: 17 | jobStore: 18 | driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate -------------------------------------------------------------------------------- /user-service/user-web/src/main/resources/application-broker-kafka-single.yaml: -------------------------------------------------------------------------------- 1 | application: 2 | kafka: 3 | topics: user-service-topic, payment-service-topic, pubsubdoc-service-topic 4 | axon: 5 | kafka: 6 | client-id: user-service-web 7 | producer: 8 | retries: 0 9 | consumer: 10 | event-processor-mode: tracking 11 | properties: 12 | security.protocol: PLAINTEXT 13 | default-topic: user-service-topic 14 | bootstrap-servers: localhost:29092,localhost:29192,localhost:29292 15 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/app/adaptor/aggregates/effective/commands/EffectiveMark.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.app.adaptor.aggregates.effective.commands; 2 | 3 | import com.pubsubdoc.doc.service.shared.application.doc.models.doc.DocId; 4 | 5 | import java.util.UUID; 6 | 7 | public record EffectiveMark(DocId docId, UUID userId) implements EffectiveCommand { 8 | @Override 9 | public String getIdentifier() { 10 | return docId.asString() + ":" + userId; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/infrastructure/jpa/user/UserDataModel.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.infrastructure.jpa.user; 2 | 3 | import jakarta.persistence.Column; 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.Id; 6 | import jakarta.persistence.Table; 7 | import lombok.Data; 8 | 9 | @Data 10 | @Entity 11 | @Table(name = "users") 12 | public class UserDataModel { 13 | @Id 14 | String userId; 15 | 16 | @Column 17 | String name; 18 | } 19 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/infrastructure/jpa/user/UserDataRepository.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.infrastructure.jpa.user; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | import org.springframework.data.jpa.repository.JpaSpecificationExecutor; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface UserDataRepository extends JpaRepository, JpaSpecificationExecutor { 9 | } 10 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/app/adaptor/aggregates/effective/commands/EffectiveUnmark.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.app.adaptor.aggregates.effective.commands; 2 | 3 | import com.pubsubdoc.doc.service.shared.application.doc.models.doc.DocId; 4 | 5 | import java.util.UUID; 6 | 7 | public record EffectiveUnmark(DocId docId, UUID userId) implements EffectiveCommand { 8 | @Override 9 | public String getIdentifier() { 10 | return docId.asString() + ":" + userId; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/infrastructure/api/credit/CreditApi.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.infrastructure.api.credit; 2 | 3 | import com.pubsubdoc.payment.service.web.app.infrastructure.api.credit.makepayment.CreditMakePaymentRequest; 4 | import com.pubsubdoc.payment.service.web.app.infrastructure.api.credit.makepayment.CreditMakePaymentResponse; 5 | 6 | public interface CreditApi { 7 | public CreditMakePaymentResponse makePayment(CreditMakePaymentRequest request); 8 | } 9 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/adaptor/aggregates/paymentprocess/commands/PaymentProcessCommand.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.adaptor.aggregates.paymentprocess.commands; 2 | 3 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentProcessId; 4 | import org.axonframework.modelling.command.TargetAggregateIdentifier; 5 | 6 | public interface PaymentProcessCommand { 7 | @TargetAggregateIdentifier 8 | PaymentProcessId paymentProcessId(); 9 | } 10 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/resources/application-broker-kafka-single.yaml: -------------------------------------------------------------------------------- 1 | application: 2 | kafka: 3 | topics: doc-service-topic, payment-service-topic, pubsubdoc-service-topic, user-service-topic 4 | axon: 5 | kafka: 6 | client-id: pubsubdoc-service-back 7 | producer: 8 | retries: 0 9 | consumer: 10 | event-processor-mode: tracking 11 | properties: 12 | security.protocol: PLAINTEXT 13 | default-topic: pubsubdoc-service-topic 14 | bootstrap-servers: localhost:29092,localhost:29192,localhost:29292 15 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/adaptor/aggregates/paymentprocess/PaymentProcessAggregateException.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.adaptor.aggregates.paymentprocess; 2 | 3 | import com.pubsubdoc.payment.service.web.app.application.domain.models.paymentprocess.errors.PaymentProcessError; 4 | 5 | public class PaymentProcessAggregateException extends RuntimeException { 6 | public PaymentProcessAggregateException(PaymentProcessError error) { 7 | super(error.toString()); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/adaptor/aggregates/paymentprocess/commands/PaymentRequest.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.adaptor.aggregates.paymentprocess.commands; 2 | 3 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentMethod; 4 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 5 | 6 | import java.math.BigDecimal; 7 | 8 | public record PaymentRequest(UserId userId, BigDecimal amount, PaymentMethod paymentMethod) { 9 | } 10 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/adaptor/aggregates/transferrequest/commands/TransferRequestCommand.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.adaptor.aggregates.transferrequest.commands; 2 | 3 | import com.pubsubdoc.payment.service.shared.application.doc.models.transferrequest.TransferRequestId; 4 | import org.axonframework.modelling.command.TargetAggregateIdentifier; 5 | 6 | public interface TransferRequestCommand { 7 | @TargetAggregateIdentifier 8 | TransferRequestId transferRequestId(); 9 | } 10 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/http/models/common/ErrorsResponse.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.http.models.common; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public record ErrorsResponse(List errors) { 7 | public static ErrorsResponse apply(Object code, String message) { 8 | var errors = new ArrayList(); 9 | errors.add(new ErrorModel(code, message)); 10 | 11 | return new ErrorsResponse( 12 | errors 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/http/models/common/ErrorsResponse.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.http.models.common; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public record ErrorsResponse(List errors) { 7 | public static ErrorsResponse apply(Object code, String message) { 8 | var errors = new ArrayList(); 9 | errors.add(new ErrorModel(code, message)); 10 | 11 | return new ErrorsResponse( 12 | errors 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "pubsubdoc" 2 | 3 | include( 4 | "appkit:application-basic", 5 | "axon:application", 6 | "doc-service:doc-api", 7 | "doc-service:doc-shared", 8 | "doc-service:doc-web", 9 | 10 | "pubsubdoc-service:back", 11 | "pubsubdoc-service:back-api", 12 | 13 | "payment-service:payment-api", 14 | "payment-service:payment-shared", 15 | "payment-service:payment-web", 16 | 17 | "user-service:user-api", 18 | "user-service:user-sdk", 19 | "user-service:user-shared", 20 | "user-service:user-web", 21 | ) -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/http/models/common/ErrorsResponse.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.http.models.common; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public record ErrorsResponse(List errors) { 7 | public static ErrorsResponse apply(Object code, String message) { 8 | var errors = new ArrayList(); 9 | errors.add(new ErrorModel(code, message)); 10 | 11 | return new ErrorsResponse( 12 | errors 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/external/notification/protocol/sendpaymentexecution/NotificationPaymentExecutionSent.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.external.notification.protocol.sendpaymentexecution; 2 | 3 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentProcessId; 4 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 5 | 6 | public record NotificationPaymentExecutionSent(PaymentProcessId paymentProcessId, UserId userId) { 7 | } 8 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/adaptor/aggregates/transferrequest/commands/TransferRequestCreate.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.adaptor.aggregates.transferrequest.commands; 2 | 3 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentProcessId; 4 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 5 | 6 | import java.math.BigDecimal; 7 | 8 | public record TransferRequestCreate(PaymentProcessId paymentProcessId, UserId userId, BigDecimal amount) { 9 | } 10 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/query/transferrequest/datamodel/TransferRequestDataModel.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.query.transferrequest.datamodel; 2 | 3 | import jakarta.persistence.*; 4 | import lombok.Data; 5 | 6 | @Data 7 | @Entity 8 | @Table(name = "transfer_requests") 9 | public class TransferRequestDataModel { 10 | @Id 11 | String transferRequestId; 12 | 13 | @Column(nullable = false) 14 | @Enumerated(EnumType.STRING) 15 | TransferRequestStatus status; 16 | } 17 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/http/models/common/ErrorsResponse.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.http.models.common; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | public record ErrorsResponse(List errors) { 7 | public static ErrorsResponse apply(Object code, String message) { 8 | var errors = new ArrayList(); 9 | errors.add(new ErrorModel(code, message)); 10 | 11 | return new ErrorsResponse( 12 | errors 13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.run/inmem.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/app/infrastructure/jpa/doc/DocDataModel.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.app.infrastructure.jpa.doc; 2 | 3 | import jakarta.persistence.Column; 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.Id; 6 | import jakarta.persistence.Table; 7 | import lombok.Data; 8 | 9 | @Data 10 | @Entity 11 | @Table(name = "docs") 12 | public class DocDataModel { 13 | @Id 14 | String docId; 15 | 16 | @Column 17 | String body; 18 | 19 | @Column 20 | int effectiveCount; 21 | } 22 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/app/infrastructure/jpa/user/UserDataModel.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.app.infrastructure.jpa.user; 2 | 3 | import jakarta.persistence.Column; 4 | import jakarta.persistence.Entity; 5 | import jakarta.persistence.Id; 6 | import jakarta.persistence.Table; 7 | import lombok.Data; 8 | 9 | @Data 10 | @Entity 11 | @Table(name = "users") 12 | public class UserDataModel { 13 | @Id 14 | String userId; 15 | 16 | @Column 17 | String name; 18 | 19 | @Column 20 | String teamId; 21 | } 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /doc-service/doc-shared/src/main/java/com/pubsubdoc/doc/service/shared/application/doc/models/doc/DocId.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.shared.application.doc.models.doc; 2 | 3 | import com.example.appkit.application.basic.IdObject; 4 | 5 | import java.util.UUID; 6 | 7 | public record DocId(UUID value) implements IdObject { 8 | public DocId() { 9 | this(UUID.randomUUID()); 10 | } 11 | 12 | @Override 13 | public String asString() { 14 | return value.toString(); 15 | } 16 | 17 | @Override 18 | public String toString() { 19 | return asString(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /appkit/application-basic/src/main/java/com/example/appkit/http/exceptions/NotFoundException.java: -------------------------------------------------------------------------------- 1 | package com.example.appkit.http.exceptions; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public class NotFoundException extends RuntimeException { 7 | private final String errorCode; 8 | 9 | public NotFoundException(String message, String errorCode) { 10 | super(message); 11 | 12 | this.errorCode = errorCode; 13 | } 14 | 15 | public NotFoundException(String message) { 16 | this(message, null); 17 | } 18 | 19 | public NotFoundException() { 20 | this(null); 21 | } 22 | } -------------------------------------------------------------------------------- /user-service/user-shared/src/main/java/com/pubsubdoc/user/service/shared/application/doc/models/team/TeamId.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.shared.application.doc.models.team; 2 | 3 | import com.example.appkit.application.basic.IdObject; 4 | 5 | import java.util.UUID; 6 | 7 | public record TeamId(UUID value) implements IdObject { 8 | public TeamId() { 9 | this(UUID.randomUUID()); 10 | } 11 | 12 | @Override 13 | public String asString() { 14 | return value.toString(); 15 | } 16 | 17 | @Override 18 | public String toString() { 19 | return asString(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /user-service/user-shared/src/main/java/com/pubsubdoc/user/service/shared/application/doc/models/user/UserId.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.shared.application.doc.models.user; 2 | 3 | import com.example.appkit.application.basic.IdObject; 4 | 5 | import java.util.UUID; 6 | 7 | public record UserId(UUID value) implements IdObject { 8 | public UserId() { 9 | this(UUID.randomUUID()); 10 | } 11 | 12 | @Override 13 | public String asString() { 14 | return value.toString(); 15 | } 16 | 17 | @Override 18 | public String toString() { 19 | return asString(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/resources/application-common.yaml: -------------------------------------------------------------------------------- 1 | application: 2 | services: 3 | doc: 4 | host: http://localhost:8080 5 | payment: 6 | host: http://localhost:8180 7 | pubsubdoc: 8 | host: http://localhost:8280 9 | user: 10 | host: http://localhost:8380 11 | axon: 12 | serializer: 13 | general: jackson 14 | events: jackson 15 | messages: jackson 16 | server: 17 | port: 8080 18 | springdoc: 19 | packages-to-scan: com.pubsubdoc.doc.service.web 20 | paths-to-match: "/api/**" 21 | default-consumes-media-type: application/json 22 | default-produces-media-type: application/json -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/resources/application-common.yaml: -------------------------------------------------------------------------------- 1 | application: 2 | services: 3 | doc: 4 | host: http://localhost:8080 5 | payment: 6 | host: http://localhost:8180 7 | pubsubdoc: 8 | host: http://localhost:8280 9 | user: 10 | host: http://localhost:8380 11 | axon: 12 | serializer: 13 | general: jackson 14 | events: jackson 15 | messages: jackson 16 | server: 17 | port: 8280 18 | springdoc: 19 | packages-to-scan: com.pubsubdoc.service.back 20 | paths-to-match: "/api/**" 21 | default-consumes-media-type: application/json 22 | default-produces-media-type: application/json -------------------------------------------------------------------------------- /user-service/user-web/src/main/resources/application-common.yaml: -------------------------------------------------------------------------------- 1 | application: 2 | services: 3 | doc: 4 | host: http://localhost:8080 5 | payment: 6 | host: http://localhost:8180 7 | pubsubdoc: 8 | host: http://localhost:8280 9 | user: 10 | host: http://localhost:8380 11 | axon: 12 | serializer: 13 | general: jackson 14 | events: jackson 15 | messages: jackson 16 | server: 17 | port: 8380 18 | springdoc: 19 | packages-to-scan: com.pubsubdoc.user.service.web 20 | paths-to-match: "/api/**" 21 | default-consumes-media-type: application/json 22 | default-produces-media-type: application/json -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/resources/application-common.yaml: -------------------------------------------------------------------------------- 1 | application: 2 | services: 3 | doc: 4 | host: http://localhost:8080 5 | payment: 6 | host: http://localhost:8180 7 | pubsubdoc: 8 | host: http://localhost:8280 9 | user: 10 | host: http://localhost:8380 11 | axon: 12 | serializer: 13 | general: jackson 14 | events: jackson 15 | messages: jackson 16 | server: 17 | port: 8180 18 | springdoc: 19 | packages-to-scan: com.pubsubdoc.payment.service.web 20 | paths-to-match: "/api/**" 21 | default-consumes-media-type: application/json 22 | default-produces-media-type: application/json -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/infrastructure/api/credit/CreditApiImpl.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.infrastructure.api.credit; 2 | 3 | import com.pubsubdoc.payment.service.web.app.infrastructure.api.credit.makepayment.CreditMakePaymentRequest; 4 | import com.pubsubdoc.payment.service.web.app.infrastructure.api.credit.makepayment.CreditMakePaymentResponse; 5 | 6 | public class CreditApiImpl implements CreditApi { 7 | @Override 8 | public CreditMakePaymentResponse makePayment(CreditMakePaymentRequest request) { 9 | throw new UnsupportedOperationException("Not implemented yet"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.run/dockerKafkaSIngle.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /payment-service/payment-shared/src/main/java/com/pubsubdoc/payment/service/shared/application/doc/models/paymentprocess/PaymentProcessId.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess; 2 | 3 | import com.example.appkit.application.basic.IdObject; 4 | 5 | import java.util.UUID; 6 | 7 | public record PaymentProcessId(UUID value) implements IdObject { 8 | public PaymentProcessId() { 9 | this(UUID.randomUUID()); 10 | } 11 | 12 | @Override 13 | public String asString() { 14 | return value.toString(); 15 | } 16 | 17 | @Override 18 | public String toString() { 19 | return asString(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /payment-service/payment-shared/src/main/java/com/pubsubdoc/payment/service/shared/application/doc/models/transferrequest/TransferRequestId.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.shared.application.doc.models.transferrequest; 2 | 3 | import com.example.appkit.application.basic.IdObject; 4 | 5 | import java.util.UUID; 6 | 7 | public record TransferRequestId(UUID value) implements IdObject { 8 | public TransferRequestId() { 9 | this(UUID.randomUUID()); 10 | } 11 | 12 | @Override 13 | public String asString() { 14 | return value.toString(); 15 | } 16 | 17 | @Override 18 | public String toString() { 19 | return asString(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/config/infrastructure/InMemoryConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.config.infrastructure; 2 | 3 | import com.pubsubdoc.user.service.sdk.api.InMemoryUserServiceApi; 4 | import com.pubsubdoc.user.service.sdk.api.UserServiceApi; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | import org.springframework.context.annotation.Profile; 8 | 9 | @Configuration 10 | @Profile("inmem") 11 | public class InMemoryConfiguration { 12 | @Bean 13 | public UserServiceApi userService() { 14 | return new InMemoryUserServiceApi(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /payment-service/payment-api/src/main/java/com/pubsubdoc/payment/service/api/domain/models/paymentprocess/PaymentProcessRequested.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.api.domain.models.paymentprocess; 2 | 3 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentMethod; 4 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentProcessId; 5 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 6 | 7 | import java.math.BigDecimal; 8 | 9 | public record PaymentProcessRequested(PaymentProcessId paymentProcessId, UserId userId, BigDecimal amount, PaymentMethod paymentMethod) implements PaymentProcessEvent { 10 | } 11 | -------------------------------------------------------------------------------- /user-service/user-sdk/src/main/java/com/pubsubdoc/user/service/sdk/api/InMemoryUserServiceApi.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.sdk.api; 2 | 3 | import com.pubsubdoc.user.service.sdk.api.protocol.UsersFindResponse; 4 | import com.pubsubdoc.user.service.sdk.api.protocol.UsersGetResponse; 5 | 6 | import java.util.List; 7 | import java.util.UUID; 8 | 9 | public class InMemoryUserServiceApi implements UserServiceApi { 10 | @Override 11 | public UsersGetResponse getUser(UUID userId) { 12 | return new UsersGetResponse(userId, "", null); 13 | } 14 | 15 | @Override 16 | public UsersFindResponse findUser(String userName) { 17 | return new UsersFindResponse(List.of()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/config/OpenApiConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.config; 2 | 3 | import io.swagger.v3.oas.models.OpenAPI; 4 | import io.swagger.v3.oas.models.info.Info; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | @Configuration 9 | public class OpenApiConfiguration { 10 | @Bean 11 | public OpenAPI openApi() { 12 | return new OpenAPI() 13 | .info( 14 | new Info() 15 | .title("Doc Service") 16 | .version("1.0.0") 17 | ); 18 | } 19 | } -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/resources/application-datastore-mysql.yaml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:mysql://localhost:3316/db 4 | driver-class-name: com.mysql.cj.jdbc.Driver 5 | username: docker 6 | password: mysql 7 | jpa: 8 | database: mysql 9 | hibernate: 10 | ddl-auto: update 11 | quartz: 12 | jdbc: 13 | schema: classpath:org/quartz/impl/jdbcjobstore/tables_mysql.sql 14 | initialize-schema: always 15 | job-store-type: jdbc 16 | properties: 17 | org: 18 | quartz: 19 | jobStore: 20 | driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate 21 | isClustered: true 22 | clusterCheckinInterval: 20000 -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/config/OpenApiConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.config; 2 | 3 | import io.swagger.v3.oas.models.OpenAPI; 4 | import io.swagger.v3.oas.models.info.Info; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | @Configuration 9 | public class OpenApiConfiguration { 10 | @Bean 11 | public OpenAPI openApi() { 12 | return new OpenAPI() 13 | .info( 14 | new Info() 15 | .title("PubSubDoc Backend") 16 | .version("1.0.0") 17 | ); 18 | } 19 | } -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/config/OpenApiConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.config; 2 | 3 | import io.swagger.v3.oas.models.OpenAPI; 4 | import io.swagger.v3.oas.models.info.Info; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | @Configuration 9 | public class OpenApiConfiguration { 10 | @Bean 11 | public OpenAPI openApi() { 12 | return new OpenAPI() 13 | .info( 14 | new Info() 15 | .title("User Service") 16 | .version("1.0.0") 17 | ); 18 | } 19 | } -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/config/OpenApiConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.config; 2 | 3 | import io.swagger.v3.oas.models.OpenAPI; 4 | import io.swagger.v3.oas.models.info.Info; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.Configuration; 7 | 8 | @Configuration 9 | public class OpenApiConfiguration { 10 | @Bean 11 | public OpenAPI openApi() { 12 | return new OpenAPI() 13 | .info( 14 | new Info() 15 | .title("Payment Service") 16 | .version("1.0.0") 17 | ); 18 | } 19 | } -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/infrastructure/inmem/api/credit/InMemoryCreditApi.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.infrastructure.inmem.api.credit; 2 | 3 | import com.pubsubdoc.payment.service.web.app.infrastructure.api.credit.CreditApi; 4 | import com.pubsubdoc.payment.service.web.app.infrastructure.api.credit.makepayment.CreditMakePaymentRequest; 5 | import com.pubsubdoc.payment.service.web.app.infrastructure.api.credit.makepayment.CreditMakePaymentResponse; 6 | 7 | public class InMemoryCreditApi implements CreditApi { 8 | @Override 9 | public CreditMakePaymentResponse makePayment(CreditMakePaymentRequest request) { 10 | return new CreditMakePaymentResponse(true, 200); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/listener/paymentservice/PaymentServiceListener.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.listener.paymentservice; 2 | 3 | import com.pubsubdoc.payment.service.api.domain.models.paymentprocess.PaymentProcessCompleted; 4 | import com.pubsubdoc.user.service.web.app.adaptor.aggregates.user.commands.UserUpgrade; 5 | import org.axonframework.commandhandling.gateway.CommandGateway; 6 | import org.axonframework.eventhandling.EventHandler; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public record PaymentServiceListener(CommandGateway commandGateway) { 11 | @EventHandler 12 | public void on(PaymentProcessCompleted event) { 13 | commandGateway.send(new UserUpgrade(event.userId())); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/app/application/query/user/UserQueryService.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.app.application.query.user; 2 | 3 | import com.pubsubdoc.service.back.app.application.query.user.queries.FindUser; 4 | import com.pubsubdoc.service.back.app.application.query.user.queries.FindUserResult; 5 | import com.pubsubdoc.service.back.app.infrastructure.jpa.user.UserRepository; 6 | import org.axonframework.queryhandling.QueryHandler; 7 | import org.springframework.stereotype.Service; 8 | 9 | @Service 10 | public record UserQueryService(UserRepository userRepository) { 11 | @QueryHandler 12 | public FindUserResult handle(FindUser criteria) { 13 | var maybeUser = userRepository.findById(criteria.userId().toString()); 14 | 15 | return new FindUserResult(maybeUser); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/config/infrastructure/LocalConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.config.infrastructure; 2 | 3 | 4 | import com.pubsubdoc.user.service.sdk.api.UserServiceApi; 5 | import com.pubsubdoc.user.service.sdk.api.UserServiceApiApiImpl; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.context.annotation.Profile; 10 | 11 | @Configuration 12 | @Profile("local") 13 | public class LocalConfiguration { 14 | @Value("${application.services.user.host}") 15 | private String userServiceHost; 16 | 17 | @Bean 18 | public UserServiceApi userService() { 19 | return new UserServiceApiApiImpl(userServiceHost); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /doc-service/doc-shared/src/main/java/com/pubsubdoc/doc/service/shared/application/doc/models/effective/EffectiveId.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.shared.application.doc.models.effective; 2 | 3 | import com.example.appkit.application.basic.IdObject; 4 | import com.pubsubdoc.doc.service.shared.application.doc.models.doc.DocId; 5 | 6 | import java.util.UUID; 7 | 8 | public record EffectiveId(DocId docId, UUID userId) implements IdObject { 9 | public EffectiveId() { 10 | this(new DocId(), UUID.randomUUID()); 11 | } 12 | 13 | public String getIdentifier() { 14 | return docId.asString() + ":" + userId.toString(); 15 | } 16 | 17 | @Override 18 | public String asString() { 19 | return getIdentifier(); 20 | } 21 | 22 | @Override 23 | public String toString() { 24 | return asString(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/app/application/query/doc/DocQueryService.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.app.application.query.doc; 2 | 3 | import com.pubsubdoc.service.back.app.application.query.doc.queries.GetDoc; 4 | import com.pubsubdoc.service.back.app.application.query.doc.queries.GetDocResult; 5 | import com.pubsubdoc.service.back.app.infrastructure.jpa.doc.DocRepository; 6 | import org.axonframework.queryhandling.QueryGateway; 7 | import org.axonframework.queryhandling.QueryHandler; 8 | import org.springframework.stereotype.Service; 9 | 10 | @Service 11 | public record DocQueryService(QueryGateway queryGateway, DocRepository repository) { 12 | @QueryHandler 13 | public GetDocResult handle(GetDoc query) { 14 | return new GetDocResult(repository.findById(query.docId().toString())); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.run/PaymentServiceWebApplication.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/config/infrastructure/KafkaSingleConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.config.infrastructure; 2 | 3 | 4 | import com.pubsubdoc.user.service.sdk.api.UserServiceApi; 5 | import com.pubsubdoc.user.service.sdk.api.UserServiceApiApiImpl; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.context.annotation.Profile; 10 | 11 | @Configuration 12 | @Profile("kafka-single") 13 | public class KafkaSingleConfiguration { 14 | @Value("${application.services.user.host}") 15 | private String userServiceHost; 16 | 17 | @Bean 18 | public UserServiceApi userService() { 19 | return new UserServiceApiApiImpl(userServiceHost); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/http/controllers/advice/AxonExceptionAdvice.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.http.controllers.advice; 2 | 3 | import com.pubsubdoc.service.back.http.models.common.ErrorsResponse; 4 | import org.axonframework.modelling.command.AggregateNotFoundException; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.web.bind.annotation.ExceptionHandler; 7 | import org.springframework.web.bind.annotation.ResponseStatus; 8 | import org.springframework.web.bind.annotation.RestControllerAdvice; 9 | 10 | @RestControllerAdvice 11 | public class AxonExceptionAdvice { 12 | @ExceptionHandler(AggregateNotFoundException.class) 13 | @ResponseStatus(HttpStatus.NOT_FOUND) 14 | public ErrorsResponse handle(AggregateNotFoundException ex) { 15 | return ErrorsResponse.apply("Not Found", ex.getMessage()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/http/controllers/advice/AxonExceptionAdvice.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.http.controllers.advice; 2 | 3 | import com.pubsubdoc.doc.service.web.http.models.common.ErrorsResponse; 4 | import org.axonframework.modelling.command.AggregateNotFoundException; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.web.bind.annotation.ExceptionHandler; 7 | import org.springframework.web.bind.annotation.ResponseStatus; 8 | import org.springframework.web.bind.annotation.RestControllerAdvice; 9 | 10 | @RestControllerAdvice 11 | public class AxonExceptionAdvice { 12 | @ExceptionHandler(AggregateNotFoundException.class) 13 | @ResponseStatus(HttpStatus.NOT_FOUND) 14 | public ErrorsResponse handle(AggregateNotFoundException ex) { 15 | return ErrorsResponse.apply("Not Found", ex.getMessage()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/http/controllers/advice/AxonExceptionAdvice.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.http.controllers.advice; 2 | 3 | import com.pubsubdoc.user.service.web.http.models.common.ErrorsResponse; 4 | import org.axonframework.modelling.command.AggregateNotFoundException; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.web.bind.annotation.ExceptionHandler; 7 | import org.springframework.web.bind.annotation.ResponseStatus; 8 | import org.springframework.web.bind.annotation.RestControllerAdvice; 9 | 10 | @RestControllerAdvice 11 | public class AxonExceptionAdvice { 12 | @ExceptionHandler(AggregateNotFoundException.class) 13 | @ResponseStatus(HttpStatus.NOT_FOUND) 14 | public ErrorsResponse handle(AggregateNotFoundException ex) { 15 | return ErrorsResponse.apply("Not Found", ex.getMessage()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/application/process/team/addmember/notification/TeamProcessAddMemberNotificationStep.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.application.process.team.addmember.notification; 2 | 3 | import com.pubsubdoc.user.service.api.domain.models.team.TeamMemberAdded; 4 | import com.pubsubdoc.user.service.web.app.external.notification.protocol.sendmemberadded.NotificationSendMemberAdded; 5 | import org.axonframework.commandhandling.gateway.CommandGateway; 6 | import org.axonframework.eventhandling.EventHandler; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public record TeamProcessAddMemberNotificationStep(CommandGateway commandGateway) { 11 | @EventHandler 12 | public void on(TeamMemberAdded event) { 13 | commandGateway.send(new NotificationSendMemberAdded(event.teamId(), event.newMemberId())); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/http/controllers/advice/AxonExceptionAdvice.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.http.controllers.advice; 2 | 3 | import com.pubsubdoc.payment.service.web.http.models.common.ErrorsResponse; 4 | import org.axonframework.modelling.command.AggregateNotFoundException; 5 | import org.springframework.http.HttpStatus; 6 | import org.springframework.web.bind.annotation.ExceptionHandler; 7 | import org.springframework.web.bind.annotation.ResponseStatus; 8 | import org.springframework.web.bind.annotation.RestControllerAdvice; 9 | 10 | @RestControllerAdvice 11 | public class AxonExceptionAdvice { 12 | @ExceptionHandler(AggregateNotFoundException.class) 13 | @ResponseStatus(HttpStatus.NOT_FOUND) 14 | public ErrorsResponse handle(AggregateNotFoundException ex) { 15 | return ErrorsResponse.apply("Not Found", ex.getMessage()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/application/process/user/create/creation/UserProcessCreateCreationStep.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.application.process.user.create.creation; 2 | 3 | import com.pubsubdoc.back.service.api.process.user.requestcreation.UserProcessRequestCreationRequested; 4 | import com.pubsubdoc.user.service.web.app.adaptor.aggregates.user.commands.UserCreate; 5 | import org.axonframework.commandhandling.gateway.CommandGateway; 6 | import org.axonframework.eventhandling.EventHandler; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public record UserProcessCreateCreationStep(CommandGateway commandGateway) { 11 | @EventHandler 12 | public void on(UserProcessRequestCreationRequested event) { 13 | var command = new UserCreate(event.userId(), event.userName()); 14 | commandGateway.send(command); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/config/axon/AxonKafkaTrackingConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.config.axon; 2 | 3 | import org.axonframework.config.EventProcessingConfigurer; 4 | import org.axonframework.extensions.kafka.eventhandling.consumer.streamable.StreamableKafkaMessageSource; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | @Configuration 10 | @ConditionalOnExpression("!${application.disable-kafka:false} and '${axon.kafka.consumer.event-processor-mode}' == 'tracking'") 11 | public class AxonKafkaTrackingConfiguration { 12 | @Autowired 13 | public void registerProcessor(EventProcessingConfigurer configurer, StreamableKafkaMessageSource streamableKafkaMessageSource) { 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/process/paymentprocess/request/request/PaymentProcessRequestCompensation.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.process.paymentprocess.request.request; 2 | 3 | import com.pubsubdoc.payment.service.web.app.adaptor.aggregates.paymentprocess.commands.PaymentProcessFail; 4 | import com.pubsubdoc.payment.service.web.app.application.external.credit.protocol.sendpaymentexecution.CreditRejected; 5 | import org.axonframework.commandhandling.gateway.CommandGateway; 6 | import org.axonframework.eventhandling.EventHandler; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public record PaymentProcessRequestCompensation(CommandGateway commandGateway) { 11 | @EventHandler 12 | public void on(CreditRejected event) { 13 | commandGateway.send(new PaymentProcessFail(event.paymentProcessId())); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/application/query/user/UserDataModelProjection.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.application.query.user; 2 | 3 | import com.pubsubdoc.user.service.api.domain.models.user.UserCreated; 4 | import com.pubsubdoc.user.service.web.app.infrastructure.jpa.user.UserDataModel; 5 | import com.pubsubdoc.user.service.web.app.infrastructure.jpa.user.UserDataRepository; 6 | import org.axonframework.eventhandling.EventHandler; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public record UserDataModelProjection(UserDataRepository userDataRepository) { 11 | @EventHandler 12 | public void on(UserCreated event) { 13 | var userDataModel = new UserDataModel(); 14 | userDataModel.setUserId(event.userId().asString()); 15 | userDataModel.setName(event.name()); 16 | 17 | userDataRepository.save(userDataModel); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/external/notification/NotificationService.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.external.notification; 2 | 3 | import com.pubsubdoc.user.service.web.app.external.notification.protocol.sendmemberadded.NotificationMemberAddedSent; 4 | import com.pubsubdoc.user.service.web.app.external.notification.protocol.sendmemberadded.NotificationSendMemberAdded; 5 | import org.axonframework.commandhandling.CommandHandler; 6 | import org.axonframework.eventhandling.gateway.EventGateway; 7 | import org.springframework.stereotype.Service; 8 | 9 | @Service 10 | public record NotificationService(EventGateway eventGateway) { 11 | @CommandHandler 12 | public void handle(NotificationSendMemberAdded command) { 13 | // Call http client to send notification. 14 | 15 | eventGateway.publish(new NotificationMemberAddedSent(command.teamId(), "encrypted message.")); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/config/axon/AxonKafkaTrackingConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.config.axon; 2 | 3 | import org.axonframework.config.EventProcessingConfigurer; 4 | import org.axonframework.extensions.kafka.eventhandling.consumer.streamable.StreamableKafkaMessageSource; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | @Configuration 10 | @ConditionalOnExpression("!${application.disable-kafka:false} and '${axon.kafka.consumer.event-processor-mode}' == 'tracking'") 11 | public class AxonKafkaTrackingConfiguration { 12 | @Autowired 13 | public void registerProcessor(EventProcessingConfigurer configurer, StreamableKafkaMessageSource streamableKafkaMessageSource) { 14 | 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.run/dockerKafkaSingleUserServiceWebApplication.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/process/paymentprocess/request/complete/PaymentProcessCompleteStep.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.process.paymentprocess.request.complete; 2 | 3 | import com.pubsubdoc.payment.service.web.app.adaptor.aggregates.paymentprocess.commands.PaymentProcessComplete; 4 | import com.pubsubdoc.payment.service.web.app.application.external.notification.protocol.sendpaymentexecution.NotificationPaymentExecutionSent; 5 | import org.axonframework.commandhandling.gateway.CommandGateway; 6 | import org.axonframework.eventhandling.EventHandler; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public record PaymentProcessCompleteStep(CommandGateway commandGateway) { 11 | @EventHandler 12 | public void on(NotificationPaymentExecutionSent event) { 13 | commandGateway.send(new PaymentProcessComplete(event.paymentProcessId())); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.run/dockerKafkaSinglePaymentServiceWebApplication.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/external/credit/protocol/sendpaymentexecution/CreditApply.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.external.credit.protocol.sendpaymentexecution; 2 | 3 | import com.example.axon.application.external.retry.RetryableCommand; 4 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentProcessId; 5 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 6 | 7 | import java.math.BigDecimal; 8 | 9 | public record CreditApply(PaymentProcessId paymentProcessId, UserId userId, BigDecimal amount, int count) implements RetryableCommand { 10 | public CreditApply(PaymentProcessId paymentProcessId, UserId userId, BigDecimal amount) { 11 | this(paymentProcessId, userId, amount, 0); 12 | } 13 | 14 | public CreditApply countUp() { 15 | return new CreditApply(paymentProcessId, userId, amount, count + 1); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/process/paymentprocess/request/notification/PaymentProcessNotificationStep.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.process.paymentprocess.request.notification; 2 | 3 | import com.pubsubdoc.payment.service.web.app.application.external.credit.protocol.sendpaymentexecution.CreditAccepted; 4 | import com.pubsubdoc.payment.service.web.app.application.external.notification.protocol.sendpaymentexecution.NotificationSendPaymentExecution; 5 | import org.axonframework.commandhandling.gateway.CommandGateway; 6 | import org.axonframework.eventhandling.EventHandler; 7 | import org.springframework.stereotype.Component; 8 | 9 | @Component 10 | public record PaymentProcessNotificationStep(CommandGateway commandHandler) { 11 | @EventHandler 12 | public void on(CreditAccepted event) { 13 | commandHandler.send(new NotificationSendPaymentExecution(event.paymentProcessId())); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/config/infrastructure/InMemoryConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.config.infrastructure; 2 | 3 | import com.pubsubdoc.payment.service.web.app.infrastructure.api.credit.CreditApi; 4 | import com.pubsubdoc.payment.service.web.app.infrastructure.inmem.api.credit.InMemoryCreditApi; 5 | import com.pubsubdoc.user.service.sdk.api.InMemoryUserServiceApi; 6 | import com.pubsubdoc.user.service.sdk.api.UserServiceApi; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | import org.springframework.context.annotation.Profile; 10 | 11 | @Configuration 12 | @Profile("inmem") 13 | public class InMemoryConfiguration { 14 | @Bean 15 | public UserServiceApi userService() { 16 | return new InMemoryUserServiceApi(); 17 | } 18 | 19 | @Bean 20 | public CreditApi creditApi() { 21 | return new InMemoryCreditApi(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/config/axon/SecureXStreamSerializer.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.config.axon; 2 | 3 | import com.thoughtworks.xstream.XStream; 4 | import org.axonframework.serialization.xml.XStreamSerializer; 5 | 6 | public class SecureXStreamSerializer { 7 | 8 | private static XStreamSerializer _instance; 9 | 10 | public static XStreamSerializer get() { 11 | if (_instance == null) { 12 | _instance = secureXStreamSerializer(); 13 | } 14 | return _instance; 15 | } 16 | 17 | private static XStreamSerializer secureXStreamSerializer() { 18 | XStream xStream = new XStream(); 19 | xStream.setClassLoader(SecureXStreamSerializer.class.getClassLoader()); 20 | xStream.allowTypesByWildcard(new String[]{ 21 | "org.axonframework.**", 22 | "java.util.**", 23 | "com.pubsubdoc.**" 24 | }); 25 | return XStreamSerializer.builder().xStream(xStream).build(); 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/config/axon/SecureXStreamSerializer.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.config.axon; 2 | 3 | import com.thoughtworks.xstream.XStream; 4 | import org.axonframework.serialization.xml.XStreamSerializer; 5 | 6 | public class SecureXStreamSerializer { 7 | 8 | private static XStreamSerializer _instance; 9 | 10 | public static XStreamSerializer get() { 11 | if (_instance == null) { 12 | _instance = secureXStreamSerializer(); 13 | } 14 | return _instance; 15 | } 16 | 17 | private static XStreamSerializer secureXStreamSerializer() { 18 | XStream xStream = new XStream(); 19 | xStream.setClassLoader(SecureXStreamSerializer.class.getClassLoader()); 20 | xStream.allowTypesByWildcard(new String[]{ 21 | "org.axonframework.**", 22 | "java.util.**", 23 | "com.pubsubdoc.**" 24 | }); 25 | return XStreamSerializer.builder().xStream(xStream).build(); 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/config/axon/SecureXStreamSerializer.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.config.axon; 2 | 3 | import com.thoughtworks.xstream.XStream; 4 | import org.axonframework.serialization.xml.XStreamSerializer; 5 | 6 | public class SecureXStreamSerializer { 7 | 8 | private static XStreamSerializer _instance; 9 | 10 | public static XStreamSerializer get() { 11 | if (_instance == null) { 12 | _instance = secureXStreamSerializer(); 13 | } 14 | return _instance; 15 | } 16 | 17 | private static XStreamSerializer secureXStreamSerializer() { 18 | XStream xStream = new XStream(); 19 | xStream.setClassLoader(SecureXStreamSerializer.class.getClassLoader()); 20 | xStream.allowTypesByWildcard(new String[]{ 21 | "org.axonframework.**", 22 | "java.util.**", 23 | "com.pubsubdoc.**" 24 | }); 25 | return XStreamSerializer.builder().xStream(xStream).build(); 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /user-service/user-sdk/src/main/java/com/pubsubdoc/user/service/sdk/api/UserServiceApiApiImpl.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.sdk.api; 2 | 3 | import com.pubsubdoc.user.service.sdk.api.protocol.UsersFindResponse; 4 | import com.pubsubdoc.user.service.sdk.api.protocol.UsersGetResponse; 5 | import org.springframework.web.client.RestTemplate; 6 | 7 | import java.util.UUID; 8 | 9 | public record UserServiceApiApiImpl(String host) implements UserServiceApi { 10 | @Override 11 | public UsersGetResponse getUser(UUID userId) { 12 | var restTemplate = new RestTemplate(); 13 | var response = restTemplate.getForEntity(host + "/api/users/" + userId, UsersGetResponse.class); 14 | return response.getBody(); 15 | } 16 | 17 | @Override 18 | public UsersFindResponse findUser(String userName) { 19 | var restTemplate = new RestTemplate(); 20 | var response = restTemplate.getForEntity(host + "/api/users?userName=" + userName, UsersFindResponse.class); 21 | 22 | return response.getBody(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /axon/application/src/main/java/com/example/axon/application/config/AxonExtendsAutoConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.example.axon.application.config; 2 | 3 | import com.example.axon.application.external.retry.ExternalRetryRequestedHandler; 4 | import org.axonframework.springboot.autoconfig.AxonAutoConfiguration; 5 | import org.springframework.boot.autoconfigure.AutoConfiguration; 6 | import org.springframework.boot.autoconfigure.AutoConfigureAfter; 7 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 8 | import org.springframework.context.annotation.Bean; 9 | 10 | @AutoConfiguration 11 | //@ConditionalOnClass(ExternalRetryRequestedHandler.class) 12 | //@ConditionalOnMissingBean(ExternalRetryRequestedHandler.class) 13 | @AutoConfigureAfter(AxonAutoConfiguration.class) 14 | @EnableConfigurationProperties(AxonExtendsProperties.class) 15 | public class AxonExtendsAutoConfiguration { 16 | @Bean 17 | public ExternalRetryRequestedHandler externalRetryRequestedHandler() { 18 | return new ExternalRetryRequestedHandler(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/config/axon/SecureXStreamSerializer.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.config.axon; 2 | 3 | import com.thoughtworks.xstream.XStream; 4 | import org.axonframework.serialization.xml.XStreamSerializer; 5 | 6 | public class SecureXStreamSerializer { 7 | 8 | private static XStreamSerializer _instance; 9 | 10 | public static XStreamSerializer get() { 11 | if (_instance == null) { 12 | _instance = secureXStreamSerializer(); 13 | } 14 | return _instance; 15 | } 16 | 17 | private static XStreamSerializer secureXStreamSerializer() { 18 | XStream xStream = new XStream(); 19 | xStream.setClassLoader(SecureXStreamSerializer.class.getClassLoader()); 20 | xStream.allowTypesByWildcard(new String[]{ 21 | "org.axonframework.**", 22 | "java.util.**", 23 | "com.pubsubdoc.**" 24 | }); 25 | return XStreamSerializer.builder().xStream(xStream).build(); 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /.run/UserServiceWebApplication.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/config/axon/AxonConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.config.axon; 2 | 3 | import org.axonframework.commandhandling.CommandMessage; 4 | import org.axonframework.messaging.correlation.CorrelationDataProvider; 5 | import org.axonframework.messaging.correlation.MessageOriginProvider; 6 | import org.axonframework.messaging.correlation.MultiCorrelationDataProvider; 7 | import org.axonframework.messaging.correlation.SimpleCorrelationDataProvider; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | import java.util.List; 12 | 13 | @Configuration 14 | public class AxonConfiguration { 15 | @Bean 16 | public CorrelationDataProvider processIdCorrelationDataProvider() { 17 | return new MultiCorrelationDataProvider>( 18 | List.of( 19 | new SimpleCorrelationDataProvider("processId"), 20 | new MessageOriginProvider() 21 | ) 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/config/axon/AxonConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.config.axon; 2 | 3 | import org.axonframework.commandhandling.CommandMessage; 4 | import org.axonframework.messaging.correlation.CorrelationDataProvider; 5 | import org.axonframework.messaging.correlation.MessageOriginProvider; 6 | import org.axonframework.messaging.correlation.MultiCorrelationDataProvider; 7 | import org.axonframework.messaging.correlation.SimpleCorrelationDataProvider; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | import java.util.List; 12 | 13 | @Configuration 14 | public class AxonConfiguration { 15 | @Bean 16 | public CorrelationDataProvider processIdCorrelationDataProvider() { 17 | return new MultiCorrelationDataProvider>( 18 | List.of( 19 | new SimpleCorrelationDataProvider("processId"), 20 | new MessageOriginProvider() 21 | ) 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/config/axon/AxonConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.config.axon; 2 | 3 | import org.axonframework.commandhandling.CommandMessage; 4 | import org.axonframework.messaging.correlation.CorrelationDataProvider; 5 | import org.axonframework.messaging.correlation.MessageOriginProvider; 6 | import org.axonframework.messaging.correlation.MultiCorrelationDataProvider; 7 | import org.axonframework.messaging.correlation.SimpleCorrelationDataProvider; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | import java.util.List; 12 | 13 | @Configuration 14 | public class AxonConfiguration { 15 | @Bean 16 | public CorrelationDataProvider processIdCorrelationDataProvider() { 17 | return new MultiCorrelationDataProvider>( 18 | List.of( 19 | new SimpleCorrelationDataProvider("processId"), 20 | new MessageOriginProvider() 21 | ) 22 | ); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/application/domain/models/user/User.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.application.domain.models.user; 2 | 3 | import com.example.appkit.application.basic.EventDrivenAggregateRoot; 4 | import com.pubsubdoc.user.service.api.domain.models.user.UserCreated; 5 | import com.pubsubdoc.user.service.api.domain.models.user.UserEvent; 6 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 7 | 8 | public record User(UserId userId) implements EventDrivenAggregateRoot { 9 | public static UserCreated create(UserId docId, String name) { 10 | return new UserCreated(docId, name); 11 | } 12 | 13 | public static User applyEvent(UserCreated event) { 14 | return new User(event.userId()); 15 | } 16 | 17 | @Override 18 | public EventDrivenAggregateRoot applyEvent(UserEvent event) { 19 | return switch (event) { 20 | case UserCreated __ -> new User(userId); 21 | default -> throw new IllegalStateException("Unexpected value: " + event); 22 | }; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/process/paymentprocess/request/creditpayment/PaymentProcessCreditPaymentStep.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.process.paymentprocess.request.creditpayment; 2 | 3 | import com.pubsubdoc.payment.service.api.domain.models.paymentprocess.PaymentProcessRequested; 4 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentMethod; 5 | import com.pubsubdoc.payment.service.web.app.application.external.credit.protocol.sendpaymentexecution.CreditApply; 6 | import org.axonframework.commandhandling.gateway.CommandGateway; 7 | import org.axonframework.eventhandling.EventHandler; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | public record PaymentProcessCreditPaymentStep(CommandGateway commandGateway) { 12 | @EventHandler 13 | public void on(PaymentProcessRequested event) { 14 | if (event.paymentMethod() == PaymentMethod.CREDIT) { 15 | commandGateway.send(new CreditApply(event.paymentProcessId(), event.userId(), event.amount())); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.run/DocServiceWebApplication.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/config/infrastructure/LocalConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.config.infrastructure; 2 | 3 | 4 | import com.pubsubdoc.payment.service.web.app.infrastructure.api.credit.CreditApi; 5 | import com.pubsubdoc.payment.service.web.app.infrastructure.inmem.api.credit.InMemoryCreditApi; 6 | import com.pubsubdoc.user.service.sdk.api.UserServiceApi; 7 | import com.pubsubdoc.user.service.sdk.api.UserServiceApiApiImpl; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.context.annotation.Profile; 12 | 13 | @Configuration 14 | @Profile("local") 15 | public class LocalConfiguration { 16 | @Value("${application.services.user.host}") 17 | private String userServiceHost; 18 | 19 | @Bean 20 | public UserServiceApi userService() { 21 | return new UserServiceApiApiImpl(userServiceHost); 22 | } 23 | 24 | @Bean 25 | public CreditApi creditApi() { 26 | return new InMemoryCreditApi(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/http/controllers/teams/TeamsControllerAdvice.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.http.controllers.teams; 2 | 3 | import com.pubsubdoc.user.service.web.http.controllers.teams.exceptions.TeamsControllerOwnerUserNotFoundException; 4 | import com.pubsubdoc.user.service.web.http.models.common.ErrorsResponse; 5 | import org.springframework.core.Ordered; 6 | import org.springframework.core.annotation.Order; 7 | import org.springframework.http.HttpStatus; 8 | import org.springframework.web.bind.annotation.ExceptionHandler; 9 | import org.springframework.web.bind.annotation.ResponseStatus; 10 | import org.springframework.web.bind.annotation.RestControllerAdvice; 11 | 12 | @Order(Ordered.HIGHEST_PRECEDENCE) 13 | @RestControllerAdvice(basePackageClasses = TeamsController.class) 14 | public class TeamsControllerAdvice { 15 | @ExceptionHandler(TeamsControllerOwnerUserNotFoundException.class) 16 | @ResponseStatus(HttpStatus.BAD_REQUEST) 17 | public ErrorsResponse handle(TeamsControllerOwnerUserNotFoundException exception) { 18 | return ErrorsResponse.apply("400", "Owner user not found."); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.run/PubSubDocServiceBackApplication.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24 | -------------------------------------------------------------------------------- /.run/dockerKafkaSingleDocServiceWebApplication.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/config/infrastructure/KafkaSingleConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.config.infrastructure; 2 | 3 | 4 | import com.pubsubdoc.payment.service.web.app.infrastructure.api.credit.CreditApi; 5 | import com.pubsubdoc.payment.service.web.app.infrastructure.inmem.api.credit.InMemoryCreditApi; 6 | import com.pubsubdoc.user.service.sdk.api.UserServiceApi; 7 | import com.pubsubdoc.user.service.sdk.api.UserServiceApiApiImpl; 8 | import org.springframework.beans.factory.annotation.Value; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.context.annotation.Profile; 12 | 13 | @Configuration 14 | @Profile("kafka-single") 15 | public class KafkaSingleConfiguration { 16 | @Value("${application.services.user.host}") 17 | private String userServiceHost; 18 | 19 | @Bean 20 | public UserServiceApi userService() { 21 | return new UserServiceApiApiImpl(userServiceHost); 22 | } 23 | 24 | @Bean 25 | public CreditApi creditApi() { 26 | return new InMemoryCreditApi(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/process/paymentprocess/request/transferrequest/PaymentProcessTransferRequestStep.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.process.paymentprocess.request.transferrequest; 2 | 3 | import com.pubsubdoc.payment.service.api.domain.models.paymentprocess.PaymentProcessRequested; 4 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentMethod; 5 | import com.pubsubdoc.payment.service.web.app.adaptor.aggregates.transferrequest.commands.TransferRequestCreate; 6 | import org.axonframework.commandhandling.gateway.CommandGateway; 7 | import org.axonframework.eventhandling.EventHandler; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | public record PaymentProcessTransferRequestStep(CommandGateway commandGateway) { 12 | @EventHandler 13 | public void on(PaymentProcessRequested event) { 14 | if (event.paymentMethod() == PaymentMethod.BANK_TRANSFER) { 15 | var command = new TransferRequestCreate(event.paymentProcessId(), event.userId(), event.amount()); 16 | commandGateway.send(command); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.run/dockerKafkaSinglePubSubDocServiceBackApplication.run.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 24 | -------------------------------------------------------------------------------- /axon/application/src/main/java/com/example/axon/application/external/retry/RetryScheduler.java: -------------------------------------------------------------------------------- 1 | package com.example.axon.application.external.retry; 2 | 3 | import com.example.appkit.backoff.Backoff; 4 | import org.axonframework.eventhandling.scheduling.EventScheduler; 5 | 6 | import java.time.Duration; 7 | import java.util.function.Consumer; 8 | import java.util.function.Supplier; 9 | 10 | public class RetryScheduler { 11 | public static void exponentialBackoff(EventScheduler scheduler, int currentCount, int waitBase, long max, Supplier ifThen) { 12 | Duration backoff = Backoff.exponentialBackoff(currentCount, waitBase); 13 | 14 | if (backoff.getSeconds() < max) { 15 | scheduler.schedule(backoff, ifThen.get()); 16 | } 17 | } 18 | 19 | public static void exponentialBackoff(EventScheduler scheduler, int currentCount, int waitBase, long max, Consumer elseThen, Supplier ifThen) { 20 | Duration backoff = Backoff.exponentialBackoff(currentCount, waitBase); 21 | 22 | if (backoff.getSeconds() < max) { 23 | scheduler.schedule(backoff, ifThen.get()); 24 | } else { 25 | elseThen.accept(backoff); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/http/controllers/teamsmemberships/TeamsMembershipsControllerAdvice.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.http.controllers.teamsmemberships; 2 | 3 | 4 | import com.pubsubdoc.user.service.web.http.controllers.teamsmemberships.exceptions.TeamsMembersControllerMemberFullException; 5 | import com.pubsubdoc.user.service.web.http.models.common.ErrorsResponse; 6 | import org.springframework.core.Ordered; 7 | import org.springframework.core.annotation.Order; 8 | import org.springframework.http.HttpStatus; 9 | import org.springframework.web.bind.annotation.ExceptionHandler; 10 | import org.springframework.web.bind.annotation.ResponseStatus; 11 | import org.springframework.web.bind.annotation.RestControllerAdvice; 12 | 13 | @Order(Ordered.HIGHEST_PRECEDENCE) 14 | @RestControllerAdvice(basePackageClasses = TeamsMembershipsController.class) 15 | public class TeamsMembershipsControllerAdvice { 16 | @ExceptionHandler(TeamsMembersControllerMemberFullException.class) 17 | @ResponseStatus(HttpStatus.BAD_REQUEST) 18 | public ErrorsResponse handle(TeamsMembersControllerMemberFullException exception) { 19 | return ErrorsResponse.apply("400", "Member is full."); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/query/transferrequest/TransferRequestProjection.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.query.transferrequest; 2 | 3 | import com.pubsubdoc.payment.service.api.domain.models.transferrequest.TransferRequestStarted; 4 | import com.pubsubdoc.payment.service.web.app.application.query.transferrequest.datamodel.TransferRequestDataModel; 5 | import com.pubsubdoc.payment.service.web.app.application.query.transferrequest.datamodel.TransferRequestStatus; 6 | import org.axonframework.eventhandling.EventHandler; 7 | import org.axonframework.eventhandling.ResetHandler; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | public record TransferRequestProjection(TransferRequestRepository repository) { 12 | @ResetHandler 13 | public void reset() { 14 | repository.deleteAll(); 15 | } 16 | 17 | @EventHandler 18 | public void on(TransferRequestStarted event) { 19 | var data = new TransferRequestDataModel(); 20 | data.setTransferRequestId(event.transferRequestId().asString()); 21 | data.setStatus(TransferRequestStatus.CREATED); 22 | 23 | repository.save(data); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/app/application/process/user/requestcreation/UserProcessRequestCreationStep.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.app.application.process.user.requestcreation; 2 | 3 | import com.pubsubdoc.back.service.api.process.user.requestcreation.UserProcessRequestCreationRequested; 4 | import com.pubsubdoc.user.service.sdk.api.UserServiceApi; 5 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 6 | import org.axonframework.commandhandling.CommandHandler; 7 | import org.axonframework.eventhandling.gateway.EventGateway; 8 | import org.springframework.stereotype.Component; 9 | 10 | @Component 11 | public record UserProcessRequestCreationStep(UserServiceApi userServiceApi, EventGateway eventGateway) { 12 | @CommandHandler 13 | public UserId on(UserProcessRequestCreation command) { 14 | // If you need checking duplicated. 15 | var result = userServiceApi.findUser(command.userName()); 16 | var target = result.users().stream().findFirst(); 17 | 18 | var event = new UserProcessRequestCreationRequested(command.userId(), command.userName()); 19 | eventGateway.publish(event); 20 | 21 | return command.userId(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/config/axon/AxonKafkaTrackingConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.config.axon; 2 | 3 | import com.pubsubdoc.user.service.web.app.application.process.user.create.creation.UserProcessCreateCreationStep; 4 | import org.axonframework.config.EventProcessingConfigurer; 5 | import org.axonframework.extensions.kafka.eventhandling.consumer.streamable.StreamableKafkaMessageSource; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | @Configuration 11 | @ConditionalOnExpression("!${application.disable-kafka:false} and '${axon.kafka.consumer.event-processor-mode}' == 'tracking'") 12 | public class AxonKafkaTrackingConfiguration { 13 | @Autowired 14 | public void registerProcessor(EventProcessingConfigurer configurer, StreamableKafkaMessageSource streamableKafkaMessageSource) { 15 | configurer.registerTrackingEventProcessor( 16 | UserProcessCreateCreationStep.class.getPackageName(), 17 | c -> streamableKafkaMessageSource 18 | ); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/query/user/UserQueryService.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.query.user; 2 | 3 | import com.pubsubdoc.payment.service.web.app.application.query.user.queries.GetUser; 4 | import com.pubsubdoc.payment.service.web.app.application.query.user.queries.GetUserResult; 5 | import com.pubsubdoc.user.service.sdk.api.UserServiceApi; 6 | import org.axonframework.queryhandling.QueryHandler; 7 | import org.springframework.http.HttpStatusCode; 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.web.client.HttpClientErrorException; 10 | 11 | import java.util.Optional; 12 | 13 | @Service 14 | public record UserQueryService(UserServiceApi userServiceApi) { 15 | @QueryHandler 16 | public GetUserResult handle(GetUser criteria) { 17 | try { 18 | var response = userServiceApi.getUser(criteria.userId()); 19 | 20 | return new GetUserResult(Optional.of(response)); 21 | } catch (HttpClientErrorException e) { 22 | if (e.getStatusCode() == HttpStatusCode.valueOf(404)) { 23 | return new GetUserResult(Optional.empty()); 24 | } else { 25 | throw e; 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/http/controllers/advice/ExpectedExceptionAdvice.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.http.controllers.advice; 2 | 3 | import com.example.appkit.http.exceptions.NotFoundException; 4 | import com.pubsubdoc.service.back.http.models.common.ErrorsResponse; 5 | import io.swagger.v3.oas.annotations.Hidden; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | import org.springframework.web.bind.annotation.ResponseStatus; 9 | import org.springframework.web.bind.annotation.RestControllerAdvice; 10 | import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; 11 | 12 | @Hidden 13 | @RestControllerAdvice 14 | public class ExpectedExceptionAdvice extends ResponseEntityExceptionHandler { 15 | @ExceptionHandler 16 | @ResponseStatus(HttpStatus.NOT_FOUND) 17 | public ErrorsResponse handle(NotFoundException notFoundException) { 18 | String code = notFoundException.getErrorCode(); 19 | if (code == null) { 20 | code = "404"; 21 | } 22 | 23 | String message = notFoundException.getMessage(); 24 | if (message == null) { 25 | message = "Not Found"; 26 | } 27 | 28 | return ErrorsResponse.apply(code, message); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/http/controllers/advice/ExpectedExceptionAdvice.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.http.controllers.advice; 2 | 3 | import com.example.appkit.http.exceptions.NotFoundException; 4 | import com.pubsubdoc.user.service.web.http.models.common.ErrorsResponse; 5 | import io.swagger.v3.oas.annotations.Hidden; 6 | import org.springframework.http.HttpStatus; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | import org.springframework.web.bind.annotation.ResponseStatus; 9 | import org.springframework.web.bind.annotation.RestControllerAdvice; 10 | import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; 11 | 12 | @Hidden 13 | @RestControllerAdvice 14 | public class ExpectedExceptionAdvice extends ResponseEntityExceptionHandler { 15 | @ExceptionHandler 16 | @ResponseStatus(HttpStatus.NOT_FOUND) 17 | public ErrorsResponse handle(NotFoundException notFoundException) { 18 | String code = notFoundException.getErrorCode(); 19 | if (code == null) { 20 | code = "404"; 21 | } 22 | 23 | String message = notFoundException.getMessage(); 24 | if (message == null) { 25 | message = "Not Found"; 26 | } 27 | 28 | return ErrorsResponse.apply(code, message); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/domain/models/transferrequest/TransferRequest.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.domain.models.transferrequest; 2 | 3 | import com.example.appkit.application.basic.EventDrivenAggregateRoot; 4 | import com.pubsubdoc.payment.service.api.domain.models.transferrequest.TransferRequestEvent; 5 | import com.pubsubdoc.payment.service.api.domain.models.transferrequest.TransferRequestStarted; 6 | import com.pubsubdoc.payment.service.shared.application.doc.models.transferrequest.TransferRequestId; 7 | 8 | public record TransferRequest(TransferRequestId transferRequestId) implements EventDrivenAggregateRoot { 9 | public static TransferRequestStarted create(TransferRequestId transferRequestId) { 10 | return new TransferRequestStarted(transferRequestId); 11 | } 12 | 13 | public static TransferRequest applyEvent(TransferRequestStarted event) { 14 | return new TransferRequest(event.transferRequestId()); 15 | } 16 | 17 | @Override 18 | public EventDrivenAggregateRoot applyEvent(TransferRequestEvent transferRequestEvent) { 19 | return switch (transferRequestEvent) { 20 | case TransferRequestStarted __ -> this; 21 | default -> throw new IllegalArgumentException("Unknown event: " + transferRequestEvent); 22 | }; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/app/application/domain/models/doc/Doc.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.app.application.domain.models.doc; 2 | 3 | import com.example.appkit.application.basic.EventDrivenAggregateRoot; 4 | import com.pubsubdoc.doc.service.api.domain.models.doc.DocCreated; 5 | import com.pubsubdoc.doc.service.api.domain.models.doc.DocEvent; 6 | import com.pubsubdoc.doc.service.api.domain.models.doc.DocUpdated; 7 | import com.pubsubdoc.doc.service.shared.application.doc.models.doc.DocId; 8 | 9 | public record Doc( 10 | DocId docId, 11 | String body 12 | ) implements EventDrivenAggregateRoot { 13 | public static DocCreated create(DocId docId, String body) { 14 | return new DocCreated(docId, body); 15 | } 16 | 17 | public static Doc applyEvent(DocCreated event) { 18 | return new Doc(event.docId(), event.body()); 19 | } 20 | 21 | public DocUpdated update(String body) { 22 | return new DocUpdated(docId, body); 23 | } 24 | 25 | @Override 26 | public EventDrivenAggregateRoot applyEvent(DocEvent event) { 27 | return switch (event) { 28 | case DocCreated docCreated -> new Doc(docCreated.docId(), docCreated.body()); 29 | case DocUpdated docUpdated -> new Doc(this.docId, docUpdated.body()); 30 | default -> throw new IllegalStateException("Unexpected value: " + event); 31 | }; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/config/axon/AxonKafkaTrackingConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.config.axon; 2 | 3 | import com.pubsubdoc.service.back.app.application.query.doc.DocProjection; 4 | import com.pubsubdoc.service.back.app.application.query.user.UserProjection; 5 | import org.axonframework.config.EventProcessingConfigurer; 6 | import org.axonframework.extensions.kafka.eventhandling.consumer.streamable.StreamableKafkaMessageSource; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | import java.util.List; 12 | 13 | @Configuration 14 | @ConditionalOnExpression("!${application.disable-kafka:false} and '${axon.kafka.consumer.event-processor-mode}' == 'tracking'") 15 | public class AxonKafkaTrackingConfiguration { 16 | @Autowired 17 | public void registerProcessor(EventProcessingConfigurer configurer, StreamableKafkaMessageSource streamableKafkaMessageSource) { 18 | var processorNames = List.of( 19 | DocProjection.class.getPackageName(), 20 | UserProjection.class.getPackageName() 21 | ); 22 | 23 | processorNames.forEach(it -> 24 | configurer.registerTrackingEventProcessor( 25 | it, 26 | c -> streamableKafkaMessageSource 27 | )); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/app/application/query/user/UserProjection.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.app.application.query.user; 2 | 3 | import com.pubsubdoc.service.back.app.infrastructure.jpa.user.UserDataModel; 4 | import com.pubsubdoc.service.back.app.infrastructure.jpa.user.UserRepository; 5 | import com.pubsubdoc.user.service.api.domain.models.team.TeamMemberAdded; 6 | import com.pubsubdoc.user.service.api.domain.models.user.UserCreated; 7 | import org.axonframework.eventhandling.EventHandler; 8 | import org.axonframework.eventhandling.ResetHandler; 9 | import org.springframework.stereotype.Component; 10 | 11 | @Component 12 | public class UserProjection { 13 | private final UserRepository userRepository; 14 | 15 | public UserProjection(UserRepository userRepository) { 16 | this.userRepository = userRepository; 17 | } 18 | 19 | @ResetHandler 20 | public void reset() { 21 | userRepository.deleteAll(); 22 | } 23 | 24 | @EventHandler 25 | public void on(UserCreated event) { 26 | var user = new UserDataModel(); 27 | user.setUserId(event.userId().asString()); 28 | user.setName(event.name()); 29 | 30 | userRepository.save(user); 31 | } 32 | 33 | @EventHandler 34 | public void on(TeamMemberAdded event) { 35 | var user = userRepository.findById(event.newMemberId().asString()).orElseThrow(); 36 | user.setTeamId(event.teamId().asString()); 37 | 38 | userRepository.save(user); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/external/notification/NotificationService.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.external.notification; 2 | 3 | import com.pubsubdoc.payment.service.web.app.adaptor.aggregates.paymentprocess.PaymentProcessAggregate; 4 | import com.pubsubdoc.payment.service.web.app.application.external.notification.protocol.sendpaymentexecution.NotificationPaymentExecutionSent; 5 | import com.pubsubdoc.payment.service.web.app.application.external.notification.protocol.sendpaymentexecution.NotificationSendPaymentExecution; 6 | import org.axonframework.commandhandling.CommandHandler; 7 | import org.axonframework.eventhandling.gateway.EventGateway; 8 | import org.axonframework.eventsourcing.EventSourcingRepository; 9 | import org.springframework.stereotype.Service; 10 | 11 | @Service 12 | public record NotificationService(EventGateway eventGateway, EventSourcingRepository paymentAggregateRepository) { 13 | //public record NotificationService(EventGateway eventGateway) { 14 | @CommandHandler 15 | public void handle(NotificationSendPaymentExecution command) { 16 | paymentAggregateRepository.load(command.paymentProcessId().asString()) 17 | .execute(paymentProcessAggregate -> { 18 | var payment = paymentProcessAggregate.getAggregate(); 19 | 20 | // Call http client to send notification. 21 | 22 | eventGateway.publish(new NotificationPaymentExecutionSent(command.paymentProcessId(), payment.userId())); 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/adaptor/aggregates/user/UserAggregate.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.adaptor.aggregates.user; 2 | 3 | import com.example.axon.application.adaptor.AbstractAggregate; 4 | import com.pubsubdoc.user.service.api.domain.models.user.UserCreated; 5 | import com.pubsubdoc.user.service.api.domain.models.user.UserEvent; 6 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 7 | import com.pubsubdoc.user.service.web.app.adaptor.aggregates.user.commands.UserCreate; 8 | import com.pubsubdoc.user.service.web.app.application.domain.models.user.User; 9 | import org.axonframework.commandhandling.CommandHandler; 10 | import org.axonframework.spring.stereotype.Aggregate; 11 | 12 | @Aggregate 13 | public class UserAggregate extends AbstractAggregate { 14 | 15 | @Override 16 | protected UserId getAggregateRootId(User aggregate) { 17 | if (aggregate != null) { 18 | return aggregate.userId(); 19 | } else { 20 | return null; 21 | } 22 | } 23 | 24 | @Override 25 | protected User newAggregateRootByEvent(UserEvent event) { 26 | return User.applyEvent((UserCreated) event); 27 | } 28 | 29 | @Override 30 | protected boolean isConstructEvent(UserEvent event) { 31 | return event instanceof UserCreated; 32 | } 33 | 34 | protected UserAggregate() { 35 | } 36 | 37 | @CommandHandler 38 | public UserAggregate(UserCreate command) { 39 | var event = User.create(command.userId(), command.name()); 40 | apply(event); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/http/controllers/payments/PaymentsController.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.http.controllers.payments; 2 | 3 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentProcessId; 4 | import com.pubsubdoc.payment.service.web.app.adaptor.aggregates.paymentprocess.commands.PaymentRequest; 5 | import com.pubsubdoc.payment.service.web.http.models.payments.post.PaymentsPostRequest; 6 | import com.pubsubdoc.payment.service.web.http.models.payments.post.PaymentsPostResponse; 7 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 8 | import io.swagger.v3.oas.annotations.Operation; 9 | import io.swagger.v3.oas.annotations.tags.Tag; 10 | import org.axonframework.commandhandling.gateway.CommandGateway; 11 | import org.springframework.http.HttpStatus; 12 | import org.springframework.web.bind.annotation.PostMapping; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | import org.springframework.web.bind.annotation.ResponseStatus; 15 | import org.springframework.web.bind.annotation.RestController; 16 | 17 | @Tag(description = "Payment API", name = "Payment API") 18 | @RestController 19 | @RequestMapping("/api/payments") 20 | public record PaymentsController(CommandGateway commandGateway) { 21 | @Operation(summary = "Request payment.") 22 | @PostMapping 23 | @ResponseStatus(HttpStatus.CREATED) 24 | public PaymentsPostResponse post(PaymentsPostRequest request) { 25 | var userId = new UserId(request.userId()); 26 | PaymentProcessId paymentProcessId = commandGateway.sendAndWait(new PaymentRequest(userId, request.amount(), request.paymentMethod())); 27 | 28 | return new PaymentsPostResponse(paymentProcessId.value()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/app/adaptor/aggregates/doc/DocAggregate.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.app.adaptor.aggregates.doc; 2 | 3 | import com.example.axon.application.adaptor.AbstractAggregate; 4 | import com.pubsubdoc.doc.service.api.domain.models.doc.DocCreated; 5 | import com.pubsubdoc.doc.service.api.domain.models.doc.DocEvent; 6 | import com.pubsubdoc.doc.service.shared.application.doc.models.doc.DocId; 7 | import com.pubsubdoc.doc.service.web.app.adaptor.aggregates.doc.commands.create.DocCreate; 8 | import com.pubsubdoc.doc.service.web.app.adaptor.aggregates.doc.commands.create.DocUpdate; 9 | import com.pubsubdoc.doc.service.web.app.application.domain.models.doc.Doc; 10 | import org.axonframework.commandhandling.CommandHandler; 11 | import org.axonframework.spring.stereotype.Aggregate; 12 | 13 | @Aggregate 14 | public class DocAggregate extends AbstractAggregate { 15 | @Override 16 | protected DocId getAggregateRootId(Doc aggregate) { 17 | if (aggregate != null) { 18 | return aggregate.docId(); 19 | } else { 20 | return null; 21 | } 22 | } 23 | 24 | @Override 25 | protected Doc newAggregateRootByEvent(DocEvent event) { 26 | return Doc.applyEvent((DocCreated) event); 27 | } 28 | 29 | @Override 30 | protected boolean isConstructEvent(DocEvent event) { 31 | return event instanceof DocCreated; 32 | } 33 | 34 | public DocAggregate() { 35 | } 36 | 37 | @CommandHandler 38 | public DocAggregate(DocCreate command) { 39 | var event = Doc.create(command.docId(), command.body()); 40 | apply(event); 41 | } 42 | 43 | @CommandHandler 44 | public void handle(DocUpdate command) { 45 | apply(it -> it.update(command.body())); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/http/controllers/effectives/EffectivesController.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.http.controllers.effectives; 2 | 3 | import com.pubsubdoc.doc.service.shared.application.doc.models.doc.DocId; 4 | import com.pubsubdoc.doc.service.web.app.adaptor.aggregates.effective.commands.EffectiveMark; 5 | import com.pubsubdoc.doc.service.web.app.adaptor.aggregates.effective.commands.EffectiveUnmark; 6 | import com.pubsubdoc.doc.service.web.http.models.effectives.post.EffectivesPostRequest; 7 | import io.swagger.v3.oas.annotations.Operation; 8 | import io.swagger.v3.oas.annotations.tags.Tag; 9 | import org.axonframework.commandhandling.gateway.CommandGateway; 10 | import org.springframework.validation.annotation.Validated; 11 | import org.springframework.web.bind.annotation.PostMapping; 12 | import org.springframework.web.bind.annotation.RequestBody; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | import org.springframework.web.bind.annotation.RestController; 15 | 16 | @Tag(description = "Effective API", name = "Effective API") 17 | @RestController 18 | @RequestMapping("/api/effectives") 19 | public record EffectivesController(CommandGateway commandGateway) { 20 | @Operation(summary = "Effective.") 21 | @PostMapping("/mark") 22 | public void effectivePost(@Validated @RequestBody EffectivesPostRequest request) { 23 | var command = new EffectiveMark(new DocId(request.docId()), request.userId()); 24 | commandGateway.sendAndWait(command); 25 | } 26 | 27 | @Operation(summary = "Effective.") 28 | @PostMapping("/unmark") 29 | public void effectiveDelete(@Validated @RequestBody EffectivesPostRequest request) { 30 | var command = new EffectiveUnmark(new DocId(request.docId()), request.userId()); 31 | commandGateway.sendAndWait(command); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/http/controllers/docs/DocsController.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.http.controllers.docs; 2 | 3 | 4 | import com.example.appkit.http.exceptions.NotFoundException; 5 | import com.pubsubdoc.service.back.app.application.query.doc.DocProjection; 6 | import com.pubsubdoc.service.back.app.application.query.doc.queries.GetDoc; 7 | import com.pubsubdoc.service.back.app.application.query.doc.queries.GetDocResult; 8 | import com.pubsubdoc.service.back.http.models.docs.get.DocsGetResponse; 9 | import org.axonframework.config.EventProcessingConfiguration; 10 | import org.axonframework.eventhandling.TrackingEventProcessor; 11 | import org.axonframework.queryhandling.QueryGateway; 12 | import org.springframework.web.bind.annotation.*; 13 | 14 | import java.util.UUID; 15 | import java.util.concurrent.ExecutionException; 16 | 17 | @RestController 18 | @RequestMapping("/api/docs") 19 | public record DocsController(QueryGateway queryGateway, EventProcessingConfiguration eventProcessingConfiguration) { 20 | @GetMapping("{docsId}") 21 | public DocsGetResponse get(@PathVariable UUID docsId) throws ExecutionException, InterruptedException { 22 | var query = new GetDoc(docsId); 23 | var result = queryGateway.query(query, GetDocResult.class).get(); 24 | 25 | var docDataModel = result.docDataModel().orElseThrow(NotFoundException::new); 26 | return new DocsGetResponse(docsId, docDataModel.getBody(), docDataModel.getEffectiveCount()); 27 | } 28 | 29 | @PostMapping("reset") 30 | public void reset() { 31 | eventProcessingConfiguration.eventProcessor(DocProjection.class.getPackageName(), TrackingEventProcessor.class) 32 | .ifPresent(it -> { 33 | it.shutDown(); 34 | it.resetTokens(); 35 | it.start(); 36 | }); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/http/controllers/docs/DocsController.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.http.controllers.docs; 2 | 3 | import com.pubsubdoc.doc.service.shared.application.doc.models.doc.DocId; 4 | import com.pubsubdoc.doc.service.web.app.adaptor.aggregates.doc.commands.create.DocCreate; 5 | import com.pubsubdoc.doc.service.web.app.adaptor.aggregates.doc.commands.create.DocUpdate; 6 | import com.pubsubdoc.doc.service.web.http.models.docs.post.DocsPostRequest; 7 | import com.pubsubdoc.doc.service.web.http.models.docs.post.DocsPostResponse; 8 | import com.pubsubdoc.doc.service.web.http.models.docs.put.DocsPutRequest; 9 | import io.swagger.v3.oas.annotations.Operation; 10 | import io.swagger.v3.oas.annotations.tags.Tag; 11 | import org.axonframework.commandhandling.gateway.CommandGateway; 12 | import org.springframework.http.HttpStatus; 13 | import org.springframework.validation.annotation.Validated; 14 | import org.springframework.web.bind.annotation.*; 15 | 16 | import java.util.UUID; 17 | 18 | @Tag(description = "Doc API", name = "Doc API") 19 | @RestController 20 | @RequestMapping("/api/docs") 21 | public record DocsController(CommandGateway commandGateway) { 22 | 23 | @Operation(summary = "Creating a new doc.") 24 | @PostMapping 25 | @ResponseStatus(HttpStatus.CREATED) 26 | public DocsPostResponse post(@Validated @RequestBody DocsPostRequest request) { 27 | var command = new DocCreate(new DocId(), request.body()); 28 | DocId docId = commandGateway.sendAndWait(command); 29 | 30 | return new DocsPostResponse(docId.value()); 31 | } 32 | 33 | @Operation(summary = "Modify a doc.") 34 | @PutMapping("/{docId}") 35 | public void put(@PathVariable UUID docId, @Validated @RequestBody DocsPutRequest request) { 36 | var command = new DocUpdate(new DocId(docId), request.body()); 37 | commandGateway.sendAndWait(command); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/http/controllers/teamsmemberships/TeamsMembershipsController.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.http.controllers.teamsmemberships; 2 | 3 | import com.pubsubdoc.user.service.api.domain.models.team.TeamEvent; 4 | import com.pubsubdoc.user.service.shared.application.doc.models.team.TeamId; 5 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 6 | import com.pubsubdoc.user.service.web.app.adaptor.aggregates.team.commands.TeamAddMember; 7 | import com.pubsubdoc.user.service.web.app.application.domain.models.team.errors.TeamError; 8 | import com.pubsubdoc.user.service.web.http.controllers.teamsmemberships.exceptions.TeamsMembersControllerMemberFullException; 9 | import fj.data.Either; 10 | import io.swagger.v3.oas.annotations.Operation; 11 | import io.swagger.v3.oas.annotations.tags.Tag; 12 | import org.axonframework.commandhandling.gateway.CommandGateway; 13 | import org.springframework.web.bind.annotation.PathVariable; 14 | import org.springframework.web.bind.annotation.PutMapping; 15 | import org.springframework.web.bind.annotation.RequestMapping; 16 | import org.springframework.web.bind.annotation.RestController; 17 | 18 | import java.util.UUID; 19 | 20 | @Tag(description = "Team Membership API", name = "Team Membership API") 21 | @RestController 22 | @RequestMapping("/api/teams/{teamId}/memberships") 23 | public record TeamsMembershipsController(CommandGateway commandGateway) { 24 | @Operation(summary = "Update a team membership.") 25 | @PutMapping("/{userId}") 26 | public void put(@PathVariable UUID teamId, @PathVariable UUID userId) { 27 | var command = new TeamAddMember(new TeamId(teamId), new UserId(userId)); 28 | Either result = commandGateway.sendAndWait(command); 29 | 30 | if (result.isLeft()) { 31 | throw new TeamsMembersControllerMemberFullException(userId); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/application/query/user/UserDataModelQueryService.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.application.query.user; 2 | 3 | import com.pubsubdoc.user.service.web.app.application.query.user.queries.FindUserDataModel; 4 | import com.pubsubdoc.user.service.web.app.application.query.user.queries.FindUserDataModelResult; 5 | import com.pubsubdoc.user.service.web.app.application.query.user.queries.GetUserDataModel; 6 | import com.pubsubdoc.user.service.web.app.application.query.user.queries.GetUserDataModelResult; 7 | import com.pubsubdoc.user.service.web.app.infrastructure.jpa.user.UserDataModel; 8 | import com.pubsubdoc.user.service.web.app.infrastructure.jpa.user.UserDataRepository; 9 | import org.axonframework.queryhandling.QueryHandler; 10 | import org.springframework.data.jpa.domain.Specification; 11 | import org.springframework.stereotype.Service; 12 | 13 | import java.util.Optional; 14 | 15 | @Service 16 | public record UserDataModelQueryService(UserDataRepository userDataRepository) { 17 | @QueryHandler 18 | public GetUserDataModelResult handle(GetUserDataModel criteria) { 19 | return userDataRepository.findById(criteria.userId().toString()) 20 | .map(it -> new GetUserDataModelResult(Optional.of(it))) 21 | .orElseGet(() -> new GetUserDataModelResult(Optional.empty())); 22 | } 23 | 24 | @QueryHandler 25 | public FindUserDataModelResult handle(FindUserDataModel criteria) { 26 | var spec = Specification.where( 27 | equalUserName(criteria.userName()) 28 | ); 29 | var users = userDataRepository.findAll(spec); 30 | 31 | return new FindUserDataModelResult(users); 32 | } 33 | 34 | private Specification equalUserName(String userName) { 35 | if (userName == null) { 36 | return null; 37 | } 38 | return (root, query, cb) -> 39 | cb.equal(root.get("name"), userName); 40 | 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/adaptor/aggregates/transferrequest/TransferRequestAggregate.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.adaptor.aggregates.transferrequest; 2 | 3 | import com.example.axon.application.adaptor.AbstractAggregate; 4 | import com.pubsubdoc.payment.service.api.domain.models.transferrequest.TransferRequestEvent; 5 | import com.pubsubdoc.payment.service.api.domain.models.transferrequest.TransferRequestStarted; 6 | import com.pubsubdoc.payment.service.shared.application.doc.models.transferrequest.TransferRequestId; 7 | import com.pubsubdoc.payment.service.web.app.adaptor.aggregates.transferrequest.commands.TransferRequestCreate; 8 | import com.pubsubdoc.payment.service.web.app.application.domain.models.transferrequest.TransferRequest; 9 | import org.axonframework.commandhandling.CommandHandler; 10 | import org.axonframework.spring.stereotype.Aggregate; 11 | 12 | @Aggregate 13 | public class TransferRequestAggregate extends AbstractAggregate { 14 | @Override 15 | protected TransferRequestId getAggregateRootId(TransferRequest aggregate) { 16 | if (aggregate != null) { 17 | return aggregate.transferRequestId(); 18 | } else { 19 | return null; 20 | } 21 | } 22 | @Override 23 | protected TransferRequest newAggregateRootByEvent(TransferRequestEvent transferRequestEvent) { 24 | return TransferRequest.applyEvent((TransferRequestStarted) transferRequestEvent); 25 | } 26 | @Override 27 | protected boolean isConstructEvent(TransferRequestEvent transferRequestEvent) { 28 | return transferRequestEvent instanceof TransferRequestStarted; 29 | } 30 | 31 | protected TransferRequestAggregate() { 32 | } 33 | 34 | @CommandHandler 35 | public TransferRequestAggregate(TransferRequestCreate command) { 36 | var event = TransferRequest.create(new TransferRequestId()); 37 | apply(event); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/app/application/query/doc/DocProjection.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.app.application.query.doc; 2 | 3 | import com.pubsubdoc.doc.service.api.domain.models.doc.DocCreated; 4 | import com.pubsubdoc.doc.service.api.domain.models.doc.DocUpdated; 5 | import com.pubsubdoc.doc.service.api.domain.models.effective.EffectiveMarked; 6 | import com.pubsubdoc.doc.service.api.domain.models.effective.EffectiveUnmarked; 7 | import com.pubsubdoc.service.back.app.infrastructure.jpa.doc.DocDataModel; 8 | import com.pubsubdoc.service.back.app.infrastructure.jpa.doc.DocRepository; 9 | import org.axonframework.eventhandling.EventHandler; 10 | import org.axonframework.eventhandling.ResetHandler; 11 | import org.springframework.stereotype.Component; 12 | 13 | @Component 14 | public class DocProjection { 15 | private final DocRepository repository; 16 | 17 | public DocProjection(DocRepository repository) { 18 | this.repository = repository; 19 | } 20 | 21 | @ResetHandler 22 | public void reset() { 23 | this.repository.deleteAll(); 24 | } 25 | 26 | @EventHandler 27 | public void on(DocCreated event) { 28 | var doc = new DocDataModel(); 29 | doc.setDocId(event.docId().asString()); 30 | doc.setBody(event.body()); 31 | repository.save(doc); 32 | } 33 | 34 | @EventHandler 35 | public void on(DocUpdated event) { 36 | var doc = repository.findById(event.docId().asString()).orElseThrow(); 37 | doc.setBody(event.body()); 38 | repository.save(doc); 39 | } 40 | 41 | @EventHandler 42 | public void on(EffectiveMarked event) { 43 | var doc = repository.findById(event.docId().asString()).orElseThrow(); 44 | doc.setEffectiveCount(doc.getEffectiveCount() + 1); 45 | repository.save(doc); 46 | } 47 | 48 | @EventHandler 49 | public void on(EffectiveUnmarked event) { 50 | var doc = repository.findById(event.docId().asString()).orElseThrow(); 51 | doc.setEffectiveCount(doc.getEffectiveCount() - 1); 52 | repository.save(doc); 53 | } 54 | } 55 | 56 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/external/credit/CreditService.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.external.credit; 2 | 3 | import com.example.axon.application.external.retry.ExternalRetryRequested; 4 | import com.example.axon.application.external.retry.RetryScheduler; 5 | import com.pubsubdoc.payment.service.web.app.application.external.credit.protocol.sendpaymentexecution.*; 6 | import com.pubsubdoc.payment.service.web.app.infrastructure.api.credit.CreditApi; 7 | import com.pubsubdoc.payment.service.web.app.infrastructure.api.credit.makepayment.CreditMakePaymentRequest; 8 | import org.axonframework.commandhandling.CommandHandler; 9 | import org.axonframework.eventhandling.EventHandler; 10 | import org.axonframework.eventhandling.gateway.EventGateway; 11 | import org.axonframework.eventhandling.scheduling.EventScheduler; 12 | import org.axonframework.queryhandling.QueryGateway; 13 | import org.springframework.stereotype.Service; 14 | 15 | @Service 16 | public record CreditService(CreditApi creditApi, QueryGateway queryGateway, EventGateway eventGateway, EventScheduler scheduler) { 17 | @CommandHandler 18 | public void handle(CreditApply command) { 19 | var response = creditApi.makePayment(new CreditMakePaymentRequest(command.userId(), command.amount())); 20 | if (response.statusCode() != 200) { 21 | eventGateway.publish(new CreditMakePaymentFailed(command, null)); 22 | return; 23 | } 24 | 25 | if (response.accepted()) { 26 | eventGateway.publish(new CreditAccepted(command.paymentProcessId())); 27 | } else { 28 | eventGateway.publish(new CreditRejected(command.paymentProcessId())); 29 | } 30 | } 31 | 32 | @EventHandler 33 | public void on(CreditMakePaymentFailed event) { 34 | RetryScheduler.exponentialBackoff(scheduler, event.command().count(), 5, 60, (duration) -> { 35 | eventGateway.publish(new CreditMakePaymentCriticalErrorOccurred()); 36 | }, () -> { 37 | var command = event.command().countUp(); 38 | return new ExternalRetryRequested(command); 39 | }); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/config/axon/AxonConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.config.axon; 2 | 3 | import com.pubsubdoc.payment.service.web.app.adaptor.aggregates.paymentprocess.PaymentProcessAggregate; 4 | import org.axonframework.commandhandling.CommandMessage; 5 | import org.axonframework.eventhandling.scheduling.quartz.QuartzEventScheduler; 6 | import org.axonframework.eventsourcing.EventSourcingRepository; 7 | import org.axonframework.eventsourcing.eventstore.EventStore; 8 | import org.axonframework.messaging.correlation.CorrelationDataProvider; 9 | import org.axonframework.messaging.correlation.MessageOriginProvider; 10 | import org.axonframework.messaging.correlation.MultiCorrelationDataProvider; 11 | import org.axonframework.messaging.correlation.SimpleCorrelationDataProvider; 12 | import org.axonframework.serialization.Serializer; 13 | import org.axonframework.spring.eventhandling.scheduling.quartz.QuartzEventSchedulerFactoryBean; 14 | import org.springframework.context.annotation.Bean; 15 | import org.springframework.context.annotation.Configuration; 16 | 17 | import java.util.List; 18 | 19 | @Configuration 20 | public class AxonConfiguration { 21 | @Bean 22 | public EventSourcingRepository paymentAggregateEventSourcingRepository(EventStore eventStore) { 23 | return EventSourcingRepository.builder(PaymentProcessAggregate.class) 24 | .eventStore(eventStore) 25 | .build(); 26 | } 27 | 28 | @Bean 29 | public CorrelationDataProvider processIdCorrelationDataProvider() { 30 | return new MultiCorrelationDataProvider>( 31 | List.of( 32 | new SimpleCorrelationDataProvider("processId"), 33 | new MessageOriginProvider() 34 | ) 35 | ); 36 | } 37 | 38 | @Bean 39 | public QuartzEventSchedulerFactoryBean quartzEventSchedulerFactoryBean(Serializer serializer) { 40 | var bean = new QuartzEventSchedulerFactoryBean(); 41 | bean.setEventJobDataBinder(new QuartzEventScheduler.DirectEventJobDataBinder(serializer)); 42 | 43 | return bean; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/http/controllers/users/UsersController.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.http.controllers.users; 2 | 3 | import com.pubsubdoc.service.back.app.application.process.user.requestcreation.UserProcessRequestCreation; 4 | import com.pubsubdoc.service.back.app.application.query.user.queries.FindUser; 5 | import com.pubsubdoc.service.back.app.application.query.user.queries.FindUserResult; 6 | import com.pubsubdoc.service.back.http.models.users.get.UsersGetResponse; 7 | import com.pubsubdoc.service.back.http.models.users.get.UsersResponseModel; 8 | import com.pubsubdoc.service.back.http.models.users.post.UsersPostRequest; 9 | import com.pubsubdoc.service.back.http.models.users.post.UsersPostResponse; 10 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 11 | import io.swagger.v3.oas.annotations.tags.Tag; 12 | import org.axonframework.commandhandling.gateway.CommandGateway; 13 | import org.axonframework.messaging.MetaData; 14 | import org.axonframework.queryhandling.QueryGateway; 15 | import org.springframework.web.bind.annotation.*; 16 | 17 | import java.util.Map; 18 | import java.util.UUID; 19 | import java.util.concurrent.ExecutionException; 20 | 21 | @Tag(description = "User API", name = "User API") 22 | @RestController 23 | @RequestMapping("/api/users") 24 | public record UsersController(CommandGateway commandGateway, QueryGateway queryGateway) { 25 | @GetMapping("{userId}") 26 | public UsersGetResponse get(@PathVariable UUID userId) throws ExecutionException, InterruptedException { 27 | var criteria = new FindUser(userId); 28 | var result = queryGateway.query(criteria, FindUserResult.class).get(); 29 | var user = result.userDataModel() 30 | .map(it -> new UsersResponseModel(userId, it.getName(), it.getTeamId())) 31 | .orElse(null); 32 | 33 | return new UsersGetResponse(user); 34 | } 35 | 36 | @PostMapping 37 | public UsersPostResponse post(UsersPostRequest request) { 38 | var command = new UserProcessRequestCreation(new UserId(), request.userName()); 39 | UserId userId = commandGateway.sendAndWait(command, new MetaData(Map.of("processId", UUID.randomUUID()))); 40 | 41 | return new UsersPostResponse(userId.value()); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/app/application/domain/models/effective/Effective.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.app.application.domain.models.effective; 2 | 3 | import com.example.appkit.application.basic.EventDrivenAggregateRoot; 4 | import com.pubsubdoc.doc.service.api.domain.models.effective.EffectiveEvent; 5 | import com.pubsubdoc.doc.service.api.domain.models.effective.EffectiveMarked; 6 | import com.pubsubdoc.doc.service.api.domain.models.effective.EffectiveUnmarked; 7 | import com.pubsubdoc.doc.service.shared.application.doc.models.doc.DocId; 8 | import com.pubsubdoc.doc.service.shared.application.doc.models.effective.EffectiveId; 9 | import com.pubsubdoc.doc.service.web.app.application.domain.models.effective.exceptions.EffectiveMarkedException; 10 | import com.pubsubdoc.doc.service.web.app.application.domain.models.effective.exceptions.EffectiveUnmarkedException; 11 | import fj.data.Either; 12 | 13 | import java.util.UUID; 14 | 15 | public record Effective(EffectiveId effectiveId, boolean marked) implements EventDrivenAggregateRoot { 16 | public static EffectiveMarked create(DocId docId, UUID userId) { 17 | return new EffectiveMarked(docId, userId); 18 | } 19 | 20 | public static Effective applyEvent(EffectiveMarked event) { 21 | return new Effective(new EffectiveId(event.docId(), event.userId()), true); 22 | } 23 | 24 | public Either mark() { 25 | if (marked) { 26 | return Either.left(new EffectiveMarkedException()); 27 | } 28 | 29 | return Either.right(new EffectiveMarked(effectiveId.docId(), effectiveId.userId())); 30 | } 31 | 32 | public Either unmark() { 33 | if (!marked) { 34 | return Either.left(new EffectiveUnmarkedException()); 35 | } 36 | 37 | return Either.right(new EffectiveUnmarked(effectiveId.docId(), effectiveId.userId())); 38 | } 39 | 40 | @Override 41 | public EventDrivenAggregateRoot applyEvent(EffectiveEvent event) { 42 | return switch (event) { 43 | case EffectiveMarked __ -> new Effective(effectiveId, true); 44 | case EffectiveUnmarked __ -> new Effective(effectiveId, false); 45 | default -> throw new IllegalStateException("Unexpected value: " + event); 46 | }; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/application/domain/models/team/Team.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.application.domain.models.team; 2 | 3 | import com.example.appkit.application.basic.EventDrivenAggregateRoot; 4 | import com.pubsubdoc.user.service.api.domain.models.team.TeamCreated; 5 | import com.pubsubdoc.user.service.api.domain.models.team.TeamEvent; 6 | import com.pubsubdoc.user.service.api.domain.models.team.TeamMemberAdded; 7 | import com.pubsubdoc.user.service.api.domain.models.team.TeamOperationFailed; 8 | import com.pubsubdoc.user.service.shared.application.doc.models.team.TeamId; 9 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 10 | import com.pubsubdoc.user.service.web.app.application.domain.models.team.errors.TeamError; 11 | import com.pubsubdoc.user.service.web.app.application.domain.models.team.errors.TeamMemberFullError; 12 | import fj.data.Either; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | public record Team(TeamId teamId, UserId ownerUserId, List memberUserIds) implements EventDrivenAggregateRoot { 18 | public static TeamCreated create(TeamId teamId, String teamName, UserId ownerUserId) { 19 | return new TeamCreated(teamId, teamName, ownerUserId); 20 | } 21 | 22 | public static Team applyEvent(TeamCreated event) { 23 | return new Team(event.teamId(), event.ownerUserId(), List.of()); 24 | } 25 | 26 | public Either join(UserId memberId) { 27 | if (memberUserIds.size() >= 3) { 28 | return Either.left(new TeamMemberFullError()); 29 | } else { 30 | return Either.right(new TeamMemberAdded(teamId, memberId)); 31 | } 32 | } 33 | 34 | @Override 35 | public EventDrivenAggregateRoot applyEvent(TeamEvent event) { 36 | return switch (event) { 37 | case TeamCreated __ -> new Team(teamId, ownerUserId, memberUserIds); 38 | case TeamMemberAdded teamMemberAdded -> { 39 | var updatedList = new ArrayList(memberUserIds); 40 | updatedList.add(teamMemberAdded.newMemberId()); 41 | yield new Team(teamId, ownerUserId, updatedList); 42 | } 43 | case TeamOperationFailed __ -> this; 44 | default -> throw new IllegalStateException("Unexpected value: " + event); 45 | }; 46 | } 47 | } -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/config/axon/AxonKafkaConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.config.axon; 2 | 3 | import org.axonframework.extensions.kafka.KafkaProperties; 4 | import org.axonframework.extensions.kafka.eventhandling.KafkaMessageConverter; 5 | import org.axonframework.extensions.kafka.eventhandling.consumer.ConsumerFactory; 6 | import org.axonframework.extensions.kafka.eventhandling.consumer.Fetcher; 7 | import org.axonframework.extensions.kafka.eventhandling.consumer.streamable.KafkaEventMessage; 8 | import org.axonframework.extensions.kafka.eventhandling.consumer.streamable.SortedKafkaMessageBuffer; 9 | import org.axonframework.extensions.kafka.eventhandling.consumer.streamable.StreamableKafkaMessageSource; 10 | import org.axonframework.serialization.Serializer; 11 | import org.springframework.beans.factory.annotation.Value; 12 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 13 | import org.springframework.context.annotation.Bean; 14 | import org.springframework.context.annotation.Configuration; 15 | 16 | import java.util.List; 17 | 18 | @Configuration 19 | @ConditionalOnExpression("!${application.disable-kafka:false} and '${axon.kafka.consumer.event-processor-mode}' == 'tracking'") 20 | public class AxonKafkaConfiguration { 21 | @Value("${application.kafka.topics}") 22 | private List topics; 23 | 24 | @Bean 25 | public StreamableKafkaMessageSource streamableKafkaMessageSource( 26 | ConsumerFactory kafkaConsumerFactory, 27 | Fetcher kafkaFetcher, 28 | KafkaMessageConverter kafkaMessageConverter, 29 | KafkaProperties properties, 30 | Serializer serializer 31 | ) { 32 | return StreamableKafkaMessageSource.builder() 33 | .topics(topics) 34 | .consumerFactory(kafkaConsumerFactory) 35 | .fetcher(kafkaFetcher) 36 | .messageConverter(kafkaMessageConverter) 37 | .bufferFactory( 38 | () -> new SortedKafkaMessageBuffer<>( 39 | properties.getFetcher().getBufferSize() 40 | ) 41 | ) 42 | .serializer(serializer) 43 | // .serializer(SecureXStreamSerializer.get()) 44 | .build(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /pubsubdoc-service/back/src/main/java/com/pubsubdoc/service/back/config/axon/AxonKafkaConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.service.back.config.axon; 2 | 3 | import org.axonframework.extensions.kafka.KafkaProperties; 4 | import org.axonframework.extensions.kafka.eventhandling.KafkaMessageConverter; 5 | import org.axonframework.extensions.kafka.eventhandling.consumer.ConsumerFactory; 6 | import org.axonframework.extensions.kafka.eventhandling.consumer.Fetcher; 7 | import org.axonframework.extensions.kafka.eventhandling.consumer.streamable.KafkaEventMessage; 8 | import org.axonframework.extensions.kafka.eventhandling.consumer.streamable.SortedKafkaMessageBuffer; 9 | import org.axonframework.extensions.kafka.eventhandling.consumer.streamable.StreamableKafkaMessageSource; 10 | import org.axonframework.serialization.Serializer; 11 | import org.springframework.beans.factory.annotation.Value; 12 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 13 | import org.springframework.context.annotation.Bean; 14 | import org.springframework.context.annotation.Configuration; 15 | 16 | import java.util.List; 17 | 18 | @Configuration 19 | @ConditionalOnExpression("!${application.disable-kafka:false} and '${axon.kafka.consumer.event-processor-mode}' == 'tracking'") 20 | public class AxonKafkaConfiguration { 21 | @Value("${application.kafka.topics}") 22 | private List topics; 23 | 24 | @Bean 25 | public StreamableKafkaMessageSource streamableKafkaMessageSource( 26 | ConsumerFactory kafkaConsumerFactory, 27 | Fetcher kafkaFetcher, 28 | KafkaMessageConverter kafkaMessageConverter, 29 | KafkaProperties properties, 30 | Serializer serializer 31 | ) { 32 | return StreamableKafkaMessageSource.builder() 33 | .topics(topics) 34 | .consumerFactory(kafkaConsumerFactory) 35 | .fetcher(kafkaFetcher) 36 | .messageConverter(kafkaMessageConverter) 37 | .bufferFactory( 38 | () -> new SortedKafkaMessageBuffer<>( 39 | properties.getFetcher().getBufferSize() 40 | ) 41 | ) 42 | .serializer(serializer) 43 | // .serializer(SecureXStreamSerializer.get()) 44 | .build(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/config/axon/AxonKafkaConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.config.axon; 2 | 3 | import org.axonframework.extensions.kafka.KafkaProperties; 4 | import org.axonframework.extensions.kafka.eventhandling.KafkaMessageConverter; 5 | import org.axonframework.extensions.kafka.eventhandling.consumer.ConsumerFactory; 6 | import org.axonframework.extensions.kafka.eventhandling.consumer.Fetcher; 7 | import org.axonframework.extensions.kafka.eventhandling.consumer.streamable.KafkaEventMessage; 8 | import org.axonframework.extensions.kafka.eventhandling.consumer.streamable.SortedKafkaMessageBuffer; 9 | import org.axonframework.extensions.kafka.eventhandling.consumer.streamable.StreamableKafkaMessageSource; 10 | import org.axonframework.serialization.Serializer; 11 | import org.springframework.beans.factory.annotation.Value; 12 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 13 | import org.springframework.context.annotation.Bean; 14 | import org.springframework.context.annotation.Configuration; 15 | 16 | import java.util.List; 17 | 18 | @Configuration 19 | @ConditionalOnExpression("!${application.disable-kafka:false} and '${axon.kafka.consumer.event-processor-mode}' == 'tracking'") 20 | public class AxonKafkaConfiguration { 21 | @Value("${application.kafka.topics}") 22 | private List topics; 23 | 24 | @Bean 25 | public StreamableKafkaMessageSource streamableKafkaMessageSource( 26 | ConsumerFactory kafkaConsumerFactory, 27 | Fetcher kafkaFetcher, 28 | KafkaMessageConverter kafkaMessageConverter, 29 | KafkaProperties properties, 30 | Serializer serializer 31 | ) { 32 | return StreamableKafkaMessageSource.builder() 33 | .topics(topics) 34 | .consumerFactory(kafkaConsumerFactory) 35 | .fetcher(kafkaFetcher) 36 | .messageConverter(kafkaMessageConverter) 37 | .bufferFactory( 38 | () -> new SortedKafkaMessageBuffer<>( 39 | properties.getFetcher().getBufferSize() 40 | ) 41 | ) 42 | .serializer(serializer) 43 | // .serializer(SecureXStreamSerializer.get()) 44 | .build(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/http/controllers/teams/TeamsController.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.http.controllers.teams; 2 | 3 | import com.pubsubdoc.user.service.shared.application.doc.models.team.TeamId; 4 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 5 | import com.pubsubdoc.user.service.web.app.adaptor.aggregates.team.commands.TeamCreate; 6 | import com.pubsubdoc.user.service.web.app.application.query.user.queries.GetUserDataModel; 7 | import com.pubsubdoc.user.service.web.app.application.query.user.queries.GetUserDataModelResult; 8 | import com.pubsubdoc.user.service.web.http.controllers.teams.exceptions.TeamsControllerOwnerUserNotFoundException; 9 | import com.pubsubdoc.user.service.web.http.models.teams.post.TeamsPostRequest; 10 | import com.pubsubdoc.user.service.web.http.models.teams.post.TeamsPostResponse; 11 | import io.swagger.v3.oas.annotations.Operation; 12 | import io.swagger.v3.oas.annotations.tags.Tag; 13 | import org.axonframework.commandhandling.gateway.CommandGateway; 14 | import org.axonframework.queryhandling.QueryGateway; 15 | import org.springframework.http.HttpStatus; 16 | import org.springframework.web.bind.annotation.PostMapping; 17 | import org.springframework.web.bind.annotation.RequestMapping; 18 | import org.springframework.web.bind.annotation.ResponseStatus; 19 | import org.springframework.web.bind.annotation.RestController; 20 | 21 | import java.util.concurrent.ExecutionException; 22 | 23 | @Tag(description = "Team API", name = "Team API") 24 | @RestController 25 | @RequestMapping("/api/teams") 26 | public record TeamsController(CommandGateway commandGateway, QueryGateway queryGateway) { 27 | @Operation(summary = "Create a new team.") 28 | @PostMapping 29 | @ResponseStatus(HttpStatus.CREATED) 30 | public TeamsPostResponse post(TeamsPostRequest request) throws ExecutionException, InterruptedException { 31 | var result = queryGateway.query(new GetUserDataModel(request.ownerUserId()), GetUserDataModelResult.class) 32 | .get(); 33 | if (result.userDataModel().isEmpty()) { 34 | throw new TeamsControllerOwnerUserNotFoundException(request.ownerUserId()); 35 | } 36 | 37 | var command = new TeamCreate(new TeamId(), request.teamName(), new UserId(request.ownerUserId())); 38 | TeamId teamId = commandGateway.sendAndWait(command); 39 | 40 | return new TeamsPostResponse(teamId.value()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/config/axon/AxonKafkaConfiguration.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.config.axon; 2 | 3 | import org.axonframework.extensions.kafka.KafkaProperties; 4 | import org.axonframework.extensions.kafka.eventhandling.KafkaMessageConverter; 5 | import org.axonframework.extensions.kafka.eventhandling.consumer.ConsumerFactory; 6 | import org.axonframework.extensions.kafka.eventhandling.consumer.Fetcher; 7 | import org.axonframework.extensions.kafka.eventhandling.consumer.streamable.KafkaEventMessage; 8 | import org.axonframework.extensions.kafka.eventhandling.consumer.streamable.SortedKafkaMessageBuffer; 9 | import org.axonframework.extensions.kafka.eventhandling.consumer.streamable.StreamableKafkaMessageSource; 10 | import org.axonframework.serialization.Serializer; 11 | import org.springframework.beans.factory.annotation.Value; 12 | import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; 13 | import org.springframework.context.annotation.Bean; 14 | import org.springframework.context.annotation.Configuration; 15 | 16 | import java.util.List; 17 | 18 | @Configuration 19 | @ConditionalOnExpression("!${application.disable-kafka:false} and '${axon.kafka.consumer.event-processor-mode}' == 'tracking'") 20 | public class AxonKafkaConfiguration { 21 | @Value("${application.kafka.topics}") 22 | private List topics; 23 | 24 | @Bean 25 | public StreamableKafkaMessageSource streamableKafkaMessageSource( 26 | ConsumerFactory kafkaConsumerFactory, 27 | Fetcher kafkaFetcher, 28 | KafkaMessageConverter kafkaMessageConverter, 29 | KafkaProperties properties, 30 | Serializer serializer 31 | ) { 32 | return StreamableKafkaMessageSource.builder() 33 | .topics(topics) 34 | .consumerFactory(kafkaConsumerFactory) 35 | .fetcher(kafkaFetcher) 36 | .messageConverter(kafkaMessageConverter) 37 | .bufferFactory( 38 | () -> new SortedKafkaMessageBuffer<>( 39 | properties.getFetcher().getBufferSize() 40 | ) 41 | ) 42 | .serializer(serializer) 43 | // .serializer(SecureXStreamSerializer.get()) 44 | .build(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /user-service/user-web/src/main/java/com/pubsubdoc/user/service/web/app/adaptor/aggregates/team/TeamAggregate.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.user.service.web.app.adaptor.aggregates.team; 2 | 3 | import com.example.axon.application.adaptor.AbstractAggregate; 4 | import com.pubsubdoc.user.service.api.domain.models.team.TeamCreated; 5 | import com.pubsubdoc.user.service.api.domain.models.team.TeamEvent; 6 | import com.pubsubdoc.user.service.api.domain.models.team.TeamOperationFailed; 7 | import com.pubsubdoc.user.service.shared.application.doc.models.team.TeamId; 8 | import com.pubsubdoc.user.service.web.app.adaptor.aggregates.team.commands.TeamAddMember; 9 | import com.pubsubdoc.user.service.web.app.adaptor.aggregates.team.commands.TeamCommand; 10 | import com.pubsubdoc.user.service.web.app.adaptor.aggregates.team.commands.TeamCreate; 11 | import com.pubsubdoc.user.service.web.app.application.domain.models.team.Team; 12 | import com.pubsubdoc.user.service.web.app.application.domain.models.team.errors.TeamError; 13 | import fj.data.Either; 14 | import org.axonframework.commandhandling.CommandHandler; 15 | import org.axonframework.spring.stereotype.Aggregate; 16 | 17 | @Aggregate 18 | public class TeamAggregate extends AbstractAggregate { 19 | @Override 20 | protected TeamId getAggregateRootId(Team aggregate) { 21 | if (aggregate != null) { 22 | return aggregate.teamId(); 23 | } else { 24 | return null; 25 | } 26 | } 27 | 28 | @Override 29 | protected Team newAggregateRootByEvent(TeamEvent event) { 30 | return Team.applyEvent((TeamCreated) event); 31 | } 32 | 33 | @Override 34 | protected boolean isConstructEvent(TeamEvent event) { 35 | return event instanceof TeamCreated; 36 | } 37 | 38 | @CommandHandler 39 | public TeamAggregate(TeamCreate command) { 40 | var event = Team.create(command.teamId(), command.teamName(), command.ownerUserId()); 41 | apply(event); 42 | } 43 | 44 | protected TeamAggregate() { 45 | } 46 | 47 | @CommandHandler 48 | public Either handle(TeamAddMember command) { 49 | var result = apply(it -> it.join(command.newMemberId()), 50 | it -> applyFail(command, it)); 51 | 52 | return result; 53 | } 54 | 55 | private void applyFail(TeamCommand command, TeamError error) { 56 | var failEvent = new TeamOperationFailed(command.teamId(), command, error.toString()); 57 | apply(failEvent); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /doc-service/doc-web/src/main/java/com/pubsubdoc/doc/service/web/app/adaptor/aggregates/effective/EffectiveAggregate.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.doc.service.web.app.adaptor.aggregates.effective; 2 | 3 | import com.example.axon.application.adaptor.AbstractAggregate; 4 | import com.pubsubdoc.doc.service.api.domain.models.effective.EffectiveEvent; 5 | import com.pubsubdoc.doc.service.api.domain.models.effective.EffectiveMarked; 6 | import com.pubsubdoc.doc.service.shared.application.doc.models.effective.EffectiveId; 7 | import com.pubsubdoc.doc.service.web.app.adaptor.aggregates.effective.commands.EffectiveMark; 8 | import com.pubsubdoc.doc.service.web.app.adaptor.aggregates.effective.commands.EffectiveUnmark; 9 | import com.pubsubdoc.doc.service.web.app.application.domain.models.effective.Effective; 10 | import org.axonframework.commandhandling.CommandHandler; 11 | import org.axonframework.modelling.command.AggregateCreationPolicy; 12 | import org.axonframework.modelling.command.CreationPolicy; 13 | import org.axonframework.spring.stereotype.Aggregate; 14 | 15 | @Aggregate 16 | public class EffectiveAggregate extends AbstractAggregate { 17 | @Override 18 | protected EffectiveId getAggregateRootId(Effective aggregate) { 19 | if (aggregate != null) { 20 | return aggregate.effectiveId(); 21 | } else { 22 | return null; 23 | } 24 | } 25 | 26 | @Override 27 | protected Effective newAggregateRootByEvent(EffectiveEvent event) { 28 | if (event instanceof EffectiveMarked) { 29 | return Effective.applyEvent((EffectiveMarked) event); 30 | } 31 | 32 | throw new IllegalArgumentException(); 33 | } 34 | 35 | @Override 36 | protected boolean isConstructEvent(EffectiveEvent event) { 37 | return event instanceof EffectiveMarked; 38 | } 39 | 40 | @CommandHandler 41 | @CreationPolicy(AggregateCreationPolicy.CREATE_IF_MISSING) 42 | public void handle(EffectiveMark command) { 43 | var aggregate = getAggregate(); 44 | if (aggregate == null) { 45 | var event = Effective.create(command.docId(), command.userId()); 46 | apply(event); 47 | } else { 48 | var result = aggregate.mark(); 49 | result.right().forEach(this::apply); 50 | } 51 | } 52 | 53 | @CommandHandler 54 | public void handle(EffectiveUnmark command) { 55 | var result = getAggregate().unmark(); 56 | result.right().forEach(this::apply); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/adaptor/aggregates/paymentprocess/PaymentProcessAggregate.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.adaptor.aggregates.paymentprocess; 2 | 3 | import com.example.axon.application.adaptor.AbstractAggregate; 4 | import com.pubsubdoc.payment.service.api.domain.models.paymentprocess.PaymentProcessEvent; 5 | import com.pubsubdoc.payment.service.api.domain.models.paymentprocess.PaymentProcessRequested; 6 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentProcessId; 7 | import com.pubsubdoc.payment.service.web.app.adaptor.aggregates.paymentprocess.commands.PaymentProcessComplete; 8 | import com.pubsubdoc.payment.service.web.app.adaptor.aggregates.paymentprocess.commands.PaymentProcessFail; 9 | import com.pubsubdoc.payment.service.web.app.adaptor.aggregates.paymentprocess.commands.PaymentRequest; 10 | import com.pubsubdoc.payment.service.web.app.application.domain.models.paymentprocess.PaymentProcess; 11 | import org.axonframework.commandhandling.CommandHandler; 12 | import org.axonframework.messaging.MetaData; 13 | import org.axonframework.spring.stereotype.Aggregate; 14 | 15 | @Aggregate 16 | public class PaymentProcessAggregate extends AbstractAggregate { 17 | 18 | @Override 19 | protected PaymentProcessId getAggregateRootId(PaymentProcess aggregate) { 20 | if (aggregate != null) { 21 | return aggregate.paymentProcessId(); 22 | } else { 23 | return null; 24 | } 25 | } 26 | 27 | @Override 28 | protected PaymentProcess newAggregateRootByEvent(PaymentProcessEvent event) { 29 | return PaymentProcess.applyEvent((PaymentProcessRequested) event); 30 | } 31 | 32 | @Override 33 | protected boolean isConstructEvent(PaymentProcessEvent event) { 34 | return event instanceof PaymentProcessRequested; 35 | } 36 | 37 | protected PaymentProcessAggregate() { 38 | } 39 | 40 | @CommandHandler 41 | public PaymentProcessAggregate(PaymentRequest command) { 42 | var event = PaymentProcess.create(new PaymentProcessId(), command.userId(), command.amount(), command.paymentMethod()); 43 | apply(event, MetaData.with("processId", event.paymentProcessId().value())); 44 | } 45 | 46 | @CommandHandler 47 | public void handle(PaymentProcessComplete command) { 48 | applyOrThrow(PaymentProcess::complete, (error) -> { 49 | throw new PaymentProcessAggregateException(error); 50 | }); 51 | } 52 | 53 | @CommandHandler 54 | public void handle(PaymentProcessFail command) { 55 | apply(PaymentProcess::fail); 56 | } 57 | } -------------------------------------------------------------------------------- /payment-service/payment-web/src/main/java/com/pubsubdoc/payment/service/web/app/application/domain/models/paymentprocess/PaymentProcess.java: -------------------------------------------------------------------------------- 1 | package com.pubsubdoc.payment.service.web.app.application.domain.models.paymentprocess; 2 | 3 | import com.example.appkit.application.basic.EventDrivenAggregateRoot; 4 | import com.pubsubdoc.payment.service.api.domain.models.paymentprocess.PaymentProcessCompleted; 5 | import com.pubsubdoc.payment.service.api.domain.models.paymentprocess.PaymentProcessEvent; 6 | import com.pubsubdoc.payment.service.api.domain.models.paymentprocess.PaymentProcessFailed; 7 | import com.pubsubdoc.payment.service.api.domain.models.paymentprocess.PaymentProcessRequested; 8 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentMethod; 9 | import com.pubsubdoc.payment.service.shared.application.doc.models.paymentprocess.PaymentProcessId; 10 | import com.pubsubdoc.payment.service.web.app.application.domain.models.paymentprocess.errors.PaymentProcessError; 11 | import com.pubsubdoc.payment.service.web.app.application.domain.models.paymentprocess.errors.PaymentProcessInvalidError; 12 | import com.pubsubdoc.user.service.shared.application.doc.models.user.UserId; 13 | import fj.data.Either; 14 | 15 | import java.math.BigDecimal; 16 | 17 | public record PaymentProcess(PaymentProcessId paymentProcessId, UserId userId, boolean error) implements EventDrivenAggregateRoot { 18 | public static PaymentProcessRequested create(PaymentProcessId paymentProcessId, UserId userId, BigDecimal price, PaymentMethod paymentMethod) { 19 | return new PaymentProcessRequested(paymentProcessId, userId, price, paymentMethod); 20 | } 21 | 22 | public static PaymentProcess applyEvent(PaymentProcessRequested event) { 23 | return new PaymentProcess(event.paymentProcessId(), event.userId(), false); 24 | } 25 | 26 | @Override 27 | public EventDrivenAggregateRoot applyEvent(PaymentProcessEvent event) { 28 | return switch (event) { 29 | case PaymentProcessRequested __ -> new PaymentProcess(paymentProcessId, userId, false); 30 | case PaymentProcessCompleted __ -> this; 31 | case PaymentProcessFailed __ -> new PaymentProcess(paymentProcessId, userId, true); 32 | default -> throw new IllegalStateException("Unexpected value: " + event); 33 | }; 34 | } 35 | 36 | public Either complete() { 37 | if (error) { 38 | return Either.left(new PaymentProcessInvalidError()); 39 | } 40 | 41 | return Either.right(new PaymentProcessCompleted(paymentProcessId, userId)); 42 | } 43 | 44 | public PaymentProcessFailed fail() { 45 | return new PaymentProcessFailed(paymentProcessId); 46 | } 47 | } --------------------------------------------------------------------------------