├── 02-from_where_publish_domain_events ├── 1-from_use_case │ ├── .editorconfig │ ├── .eslintrc.json │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── databases │ │ └── ecommerce.sql │ ├── docker-compose.yml │ ├── etc │ │ └── http │ │ │ ├── seller_backoffice │ │ │ ├── product-GET.http │ │ │ ├── product-PUT.http │ │ │ └── products-GET.http │ │ │ └── shop │ │ │ ├── product-GET.http │ │ │ ├── product_review-PUT.http │ │ │ ├── product_reviews-GET.http │ │ │ ├── products-GET.http │ │ │ ├── user-GET.http │ │ │ └── user-PUT.http │ ├── jest.config.js │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── public │ │ └── codely.svg │ ├── src │ │ ├── app │ │ │ └── api │ │ │ │ ├── seller_backoffice │ │ │ │ └── products │ │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ └── shop │ │ │ │ ├── product_reviews │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ │ ├── products │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ │ └── users │ │ │ │ └── [id] │ │ │ │ └── route.ts │ │ └── contexts │ │ │ ├── seller_backoffice │ │ │ └── products │ │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── ProductCreator.ts │ │ │ │ ├── search │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ └── search_all │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ │ ├── domain │ │ │ │ ├── Product.ts │ │ │ │ ├── ProductId.ts │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ ├── ProductName.ts │ │ │ │ ├── ProductRepository.ts │ │ │ │ └── ProductViews.ts │ │ │ │ └── infrastructure │ │ │ │ └── MySqlProductRepository.ts │ │ │ ├── shared │ │ │ ├── domain │ │ │ │ ├── Collection.ts │ │ │ │ ├── DomainEvent.ts │ │ │ │ ├── EventBus.ts │ │ │ │ ├── Identifier.ts │ │ │ │ ├── Money.ts │ │ │ │ └── StringValueObject.ts │ │ │ └── infrastructure │ │ │ │ └── MariaDBConnection.ts │ │ │ └── shop │ │ │ ├── product_reviews │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── ProductReviewCreator.ts │ │ │ │ └── search_by_product_id │ │ │ │ │ └── ProductReviewsByProductSearcher.ts │ │ │ ├── domain │ │ │ │ ├── ProductReview.ts │ │ │ │ ├── ProductReviewComment.ts │ │ │ │ ├── ProductReviewId.ts │ │ │ │ ├── ProductReviewRating.ts │ │ │ │ └── ProductReviewRepository.ts │ │ │ └── infrastructure │ │ │ │ └── MySqlProductReviewRepository.ts │ │ │ ├── products │ │ │ ├── application │ │ │ │ ├── search │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ └── search_all │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ ├── domain │ │ │ │ ├── Product.ts │ │ │ │ ├── ProductFeaturedReview.ts │ │ │ │ ├── ProductId.ts │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ ├── ProductName.ts │ │ │ │ ├── ProductRating.ts │ │ │ │ └── ProductRepository.ts │ │ │ └── infrastructure │ │ │ │ └── MySqlProductRepository.ts │ │ │ └── users │ │ │ ├── application │ │ │ ├── find │ │ │ │ └── UserFinder.ts │ │ │ ├── registrar │ │ │ │ └── UserRegistrar.ts │ │ │ └── search │ │ │ │ └── UserSearcher.ts │ │ │ ├── domain │ │ │ ├── User.ts │ │ │ ├── UserEmail.ts │ │ │ ├── UserId.ts │ │ │ ├── UserName.ts │ │ │ ├── UserProfilePicture.ts │ │ │ ├── UserRegisteredDomainEvent.ts │ │ │ └── UserRepository.ts │ │ │ └── infrastructure │ │ │ └── MySqlUserRepository.ts │ ├── tailwind.config.ts │ ├── tests │ │ └── contexts │ │ │ ├── shared │ │ │ └── infrastructure │ │ │ │ └── MockEventBus.ts │ │ │ └── shop │ │ │ └── users │ │ │ ├── application │ │ │ └── registrar │ │ │ │ └── UserRegistrar.test.ts │ │ │ ├── domain │ │ │ ├── UserEmailMother.ts │ │ │ ├── UserIdMother.ts │ │ │ ├── UserMother.ts │ │ │ ├── UserNameMother.ts │ │ │ ├── UserProfilePictureMother.ts │ │ │ └── UserRegisteredDomainEventMother.ts │ │ │ └── infrastructure │ │ │ └── MockUserRepository.ts │ └── tsconfig.json ├── 2-from_constructor │ ├── .editorconfig │ ├── .eslintrc.json │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── databases │ │ └── ecommerce.sql │ ├── docker-compose.yml │ ├── etc │ │ └── http │ │ │ ├── seller_backoffice │ │ │ ├── product-GET.http │ │ │ ├── product-PUT.http │ │ │ └── products-GET.http │ │ │ └── shop │ │ │ ├── product-GET.http │ │ │ ├── product_review-PUT.http │ │ │ ├── product_reviews-GET.http │ │ │ ├── products-GET.http │ │ │ ├── user-GET.http │ │ │ └── user-PUT.http │ ├── jest.config.js │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── public │ │ └── codely.svg │ ├── src │ │ ├── app │ │ │ └── api │ │ │ │ ├── seller_backoffice │ │ │ │ └── products │ │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ └── shop │ │ │ │ ├── product_reviews │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ │ ├── products │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ │ └── users │ │ │ │ └── [id] │ │ │ │ └── route.ts │ │ └── contexts │ │ │ ├── seller_backoffice │ │ │ └── products │ │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── ProductCreator.ts │ │ │ │ ├── search │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ └── search_all │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ │ ├── domain │ │ │ │ ├── Product.ts │ │ │ │ ├── ProductId.ts │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ ├── ProductName.ts │ │ │ │ ├── ProductRepository.ts │ │ │ │ └── ProductViews.ts │ │ │ │ └── infrastructure │ │ │ │ └── MySqlProductRepository.ts │ │ │ ├── shared │ │ │ ├── domain │ │ │ │ ├── Collection.ts │ │ │ │ ├── DomainEvent.ts │ │ │ │ ├── EventBus.ts │ │ │ │ ├── Identifier.ts │ │ │ │ ├── Money.ts │ │ │ │ └── StringValueObject.ts │ │ │ └── infrastructure │ │ │ │ └── MariaDBConnection.ts │ │ │ └── shop │ │ │ ├── product_reviews │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── ProductReviewCreator.ts │ │ │ │ └── search_by_product_id │ │ │ │ │ └── ProductReviewsByProductSearcher.ts │ │ │ ├── domain │ │ │ │ ├── ProductReview.ts │ │ │ │ ├── ProductReviewComment.ts │ │ │ │ ├── ProductReviewId.ts │ │ │ │ ├── ProductReviewRating.ts │ │ │ │ └── ProductReviewRepository.ts │ │ │ └── infrastructure │ │ │ │ └── MySqlProductReviewRepository.ts │ │ │ ├── products │ │ │ ├── application │ │ │ │ ├── search │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ └── search_all │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ ├── domain │ │ │ │ ├── Product.ts │ │ │ │ ├── ProductFeaturedReview.ts │ │ │ │ ├── ProductId.ts │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ ├── ProductName.ts │ │ │ │ ├── ProductRating.ts │ │ │ │ └── ProductRepository.ts │ │ │ └── infrastructure │ │ │ │ └── MySqlProductRepository.ts │ │ │ └── users │ │ │ ├── application │ │ │ ├── find │ │ │ │ └── UserFinder.ts │ │ │ ├── registrar │ │ │ │ └── UserRegistrar.ts │ │ │ └── search │ │ │ │ └── UserSearcher.ts │ │ │ ├── domain │ │ │ ├── User.ts │ │ │ ├── UserEmail.ts │ │ │ ├── UserId.ts │ │ │ ├── UserName.ts │ │ │ ├── UserProfilePicture.ts │ │ │ ├── UserRegisteredDomainEvent.ts │ │ │ └── UserRepository.ts │ │ │ └── infrastructure │ │ │ └── MySqlUserRepository.ts │ ├── tailwind.config.ts │ ├── tests │ │ └── contexts │ │ │ └── shop │ │ │ └── users │ │ │ ├── application │ │ │ └── registrar │ │ │ │ └── UserRegistrar.test.ts │ │ │ ├── domain │ │ │ ├── UserEmailMother.ts │ │ │ ├── UserIdMother.ts │ │ │ ├── UserMother.ts │ │ │ ├── UserNameMother.ts │ │ │ ├── UserProfilePictureMother.ts │ │ │ └── UserRegisteredDomainEventMother.ts │ │ │ └── infrastructure │ │ │ └── MockUserRepository.ts │ └── tsconfig.json ├── 3-registering_in_named_constructor │ ├── .editorconfig │ ├── .eslintrc.json │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── databases │ │ └── ecommerce.sql │ ├── docker-compose.yml │ ├── etc │ │ └── http │ │ │ ├── seller_backoffice │ │ │ ├── product-GET.http │ │ │ ├── product-PUT.http │ │ │ └── products-GET.http │ │ │ └── shop │ │ │ ├── product-GET.http │ │ │ ├── product_review-PUT.http │ │ │ ├── product_reviews-GET.http │ │ │ ├── products-GET.http │ │ │ ├── user-GET.http │ │ │ └── user-PUT.http │ ├── jest.config.js │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── public │ │ └── codely.svg │ ├── src │ │ ├── app │ │ │ └── api │ │ │ │ ├── seller_backoffice │ │ │ │ └── products │ │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ └── shop │ │ │ │ ├── product_reviews │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ │ ├── products │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ │ └── users │ │ │ │ └── [id] │ │ │ │ └── route.ts │ │ └── contexts │ │ │ ├── seller_backoffice │ │ │ └── products │ │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── ProductCreator.ts │ │ │ │ ├── search │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ └── search_all │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ │ ├── domain │ │ │ │ ├── Product.ts │ │ │ │ ├── ProductId.ts │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ ├── ProductName.ts │ │ │ │ ├── ProductRepository.ts │ │ │ │ └── ProductViews.ts │ │ │ │ └── infrastructure │ │ │ │ └── MySqlProductRepository.ts │ │ │ ├── shared │ │ │ ├── domain │ │ │ │ ├── AggregateRoot.ts │ │ │ │ ├── Collection.ts │ │ │ │ ├── DomainEvent.ts │ │ │ │ ├── EventBus.ts │ │ │ │ ├── Identifier.ts │ │ │ │ ├── Money.ts │ │ │ │ └── StringValueObject.ts │ │ │ └── infrastructure │ │ │ │ └── MariaDBConnection.ts │ │ │ └── shop │ │ │ ├── product_reviews │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── ProductReviewCreator.ts │ │ │ │ └── search_by_product_id │ │ │ │ │ └── ProductReviewsByProductSearcher.ts │ │ │ ├── domain │ │ │ │ ├── ProductReview.ts │ │ │ │ ├── ProductReviewComment.ts │ │ │ │ ├── ProductReviewId.ts │ │ │ │ ├── ProductReviewRating.ts │ │ │ │ └── ProductReviewRepository.ts │ │ │ └── infrastructure │ │ │ │ └── MySqlProductReviewRepository.ts │ │ │ ├── products │ │ │ ├── application │ │ │ │ ├── search │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ └── search_all │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ ├── domain │ │ │ │ ├── Product.ts │ │ │ │ ├── ProductFeaturedReview.ts │ │ │ │ ├── ProductId.ts │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ ├── ProductName.ts │ │ │ │ ├── ProductRating.ts │ │ │ │ └── ProductRepository.ts │ │ │ └── infrastructure │ │ │ │ └── MySqlProductRepository.ts │ │ │ └── users │ │ │ ├── application │ │ │ ├── find │ │ │ │ └── UserFinder.ts │ │ │ ├── registrar │ │ │ │ └── UserRegistrar.ts │ │ │ └── search │ │ │ │ └── UserSearcher.ts │ │ │ ├── domain │ │ │ ├── User.ts │ │ │ ├── UserEmail.ts │ │ │ ├── UserId.ts │ │ │ ├── UserName.ts │ │ │ ├── UserProfilePicture.ts │ │ │ ├── UserRegisteredDomainEvent.ts │ │ │ └── UserRepository.ts │ │ │ └── infrastructure │ │ │ └── MySqlUserRepository.ts │ ├── tailwind.config.ts │ ├── tests │ │ └── contexts │ │ │ ├── shared │ │ │ └── infrastructure │ │ │ │ └── MockEventBus.ts │ │ │ └── shop │ │ │ └── users │ │ │ ├── application │ │ │ └── registrar │ │ │ │ └── UserRegistrar.test.ts │ │ │ ├── domain │ │ │ ├── UserEmailMother.ts │ │ │ ├── UserIdMother.ts │ │ │ ├── UserMother.ts │ │ │ ├── UserNameMother.ts │ │ │ ├── UserProfilePictureMother.ts │ │ │ └── UserRegisteredDomainEventMother.ts │ │ │ └── infrastructure │ │ │ └── MockUserRepository.ts │ └── tsconfig.json └── 4-event_bus_as_an_argument │ ├── .editorconfig │ ├── .eslintrc.json │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── databases │ └── ecommerce.sql │ ├── docker-compose.yml │ ├── etc │ └── http │ │ ├── seller_backoffice │ │ ├── product-GET.http │ │ ├── product-PUT.http │ │ └── products-GET.http │ │ └── shop │ │ ├── product-GET.http │ │ ├── product_review-PUT.http │ │ ├── product_reviews-GET.http │ │ ├── products-GET.http │ │ ├── user-GET.http │ │ └── user-PUT.http │ ├── jest.config.js │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── public │ └── codely.svg │ ├── src │ ├── app │ │ └── api │ │ │ ├── seller_backoffice │ │ │ └── products │ │ │ │ ├── [id] │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ └── shop │ │ │ ├── product_reviews │ │ │ ├── [id] │ │ │ │ └── route.ts │ │ │ └── route.ts │ │ │ ├── products │ │ │ ├── [id] │ │ │ │ └── route.ts │ │ │ └── route.ts │ │ │ └── users │ │ │ └── [id] │ │ │ └── route.ts │ └── contexts │ │ ├── seller_backoffice │ │ └── products │ │ │ ├── application │ │ │ ├── create │ │ │ │ └── ProductCreator.ts │ │ │ ├── search │ │ │ │ └── ProductSearcher.ts │ │ │ └── search_all │ │ │ │ └── AllProductsSearcher.ts │ │ │ ├── domain │ │ │ ├── Product.ts │ │ │ ├── ProductId.ts │ │ │ ├── ProductImageUrl.ts │ │ │ ├── ProductImageUrls.ts │ │ │ ├── ProductName.ts │ │ │ ├── ProductRepository.ts │ │ │ └── ProductViews.ts │ │ │ └── infrastructure │ │ │ └── MySqlProductRepository.ts │ │ ├── shared │ │ ├── domain │ │ │ ├── AggregateRoot.ts │ │ │ ├── Collection.ts │ │ │ ├── DomainEvent.ts │ │ │ ├── EventBus.ts │ │ │ ├── Identifier.ts │ │ │ ├── Money.ts │ │ │ └── StringValueObject.ts │ │ └── infrastructure │ │ │ └── MariaDBConnection.ts │ │ └── shop │ │ ├── product_reviews │ │ ├── application │ │ │ ├── create │ │ │ │ └── ProductReviewCreator.ts │ │ │ └── search_by_product_id │ │ │ │ └── ProductReviewsByProductSearcher.ts │ │ ├── domain │ │ │ ├── ProductReview.ts │ │ │ ├── ProductReviewComment.ts │ │ │ ├── ProductReviewId.ts │ │ │ ├── ProductReviewRating.ts │ │ │ └── ProductReviewRepository.ts │ │ └── infrastructure │ │ │ └── MySqlProductReviewRepository.ts │ │ ├── products │ │ ├── application │ │ │ ├── search │ │ │ │ └── ProductSearcher.ts │ │ │ └── search_all │ │ │ │ └── AllProductsSearcher.ts │ │ ├── domain │ │ │ ├── Product.ts │ │ │ ├── ProductFeaturedReview.ts │ │ │ ├── ProductId.ts │ │ │ ├── ProductImageUrl.ts │ │ │ ├── ProductImageUrls.ts │ │ │ ├── ProductName.ts │ │ │ ├── ProductRating.ts │ │ │ └── ProductRepository.ts │ │ └── infrastructure │ │ │ └── MySqlProductRepository.ts │ │ └── users │ │ ├── application │ │ ├── find │ │ │ └── UserFinder.ts │ │ ├── registrar │ │ │ └── UserRegistrar.ts │ │ └── search │ │ │ └── UserSearcher.ts │ │ ├── domain │ │ ├── User.ts │ │ ├── UserEmail.ts │ │ ├── UserId.ts │ │ ├── UserName.ts │ │ ├── UserProfilePicture.ts │ │ ├── UserRegisteredDomainEvent.ts │ │ └── UserRepository.ts │ │ └── infrastructure │ │ └── MySqlUserRepository.ts │ ├── tailwind.config.ts │ ├── tests │ └── contexts │ │ ├── shared │ │ └── infrastructure │ │ │ └── MockEventBus.ts │ │ └── shop │ │ └── users │ │ ├── application │ │ └── registrar │ │ │ └── UserRegistrar.test.ts │ │ ├── domain │ │ ├── UserEmailMother.ts │ │ ├── UserIdMother.ts │ │ ├── UserMother.ts │ │ ├── UserNameMother.ts │ │ ├── UserProfilePictureMother.ts │ │ └── UserRegisteredDomainEventMother.ts │ │ └── infrastructure │ │ └── MockUserRepository.ts │ └── tsconfig.json ├── 03-domain_events_design ├── 1-granularity_in_domain_events │ ├── 1-user_updated_domain_event │ │ ├── .editorconfig │ │ ├── .eslintrc.json │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── README.md │ │ ├── databases │ │ │ └── ecommerce.sql │ │ ├── docker-compose.yml │ │ ├── etc │ │ │ └── http │ │ │ │ ├── seller_backoffice │ │ │ │ ├── product-GET.http │ │ │ │ ├── product-PUT.http │ │ │ │ └── products-GET.http │ │ │ │ └── shop │ │ │ │ ├── product-GET.http │ │ │ │ ├── product_review-PUT.http │ │ │ │ ├── product_reviews-GET.http │ │ │ │ ├── products-GET.http │ │ │ │ ├── user-GET.http │ │ │ │ └── user-PUT.http │ │ ├── jest.config.js │ │ ├── next.config.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── postcss.config.js │ │ ├── public │ │ │ └── codely.svg │ │ ├── src │ │ │ ├── app │ │ │ │ └── api │ │ │ │ │ ├── seller_backoffice │ │ │ │ │ └── products │ │ │ │ │ │ ├── [id] │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── shop │ │ │ │ │ ├── product_reviews │ │ │ │ │ ├── [id] │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ │ ├── products │ │ │ │ │ ├── [id] │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ │ └── users │ │ │ │ │ └── [id] │ │ │ │ │ └── route.ts │ │ │ └── contexts │ │ │ │ ├── seller_backoffice │ │ │ │ └── products │ │ │ │ │ ├── application │ │ │ │ │ ├── create │ │ │ │ │ │ └── ProductCreator.ts │ │ │ │ │ ├── search │ │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ │ └── search_all │ │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ │ │ ├── domain │ │ │ │ │ ├── Product.ts │ │ │ │ │ ├── ProductId.ts │ │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ │ ├── ProductName.ts │ │ │ │ │ ├── ProductRepository.ts │ │ │ │ │ └── ProductViews.ts │ │ │ │ │ └── infrastructure │ │ │ │ │ └── MySqlProductRepository.ts │ │ │ │ ├── shared │ │ │ │ ├── domain │ │ │ │ │ ├── AggregateRoot.ts │ │ │ │ │ ├── Collection.ts │ │ │ │ │ ├── DomainEvent.ts │ │ │ │ │ ├── EventBus.ts │ │ │ │ │ ├── Identifier.ts │ │ │ │ │ ├── Money.ts │ │ │ │ │ └── StringValueObject.ts │ │ │ │ └── infrastructure │ │ │ │ │ └── MariaDBConnection.ts │ │ │ │ └── shop │ │ │ │ ├── product_reviews │ │ │ │ ├── application │ │ │ │ │ ├── create │ │ │ │ │ │ └── ProductReviewCreator.ts │ │ │ │ │ └── search_by_product_id │ │ │ │ │ │ └── ProductReviewsByProductSearcher.ts │ │ │ │ ├── domain │ │ │ │ │ ├── ProductReview.ts │ │ │ │ │ ├── ProductReviewComment.ts │ │ │ │ │ ├── ProductReviewId.ts │ │ │ │ │ ├── ProductReviewRating.ts │ │ │ │ │ └── ProductReviewRepository.ts │ │ │ │ └── infrastructure │ │ │ │ │ └── MySqlProductReviewRepository.ts │ │ │ │ ├── products │ │ │ │ ├── application │ │ │ │ │ ├── search │ │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ │ └── search_all │ │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ │ ├── domain │ │ │ │ │ ├── Product.ts │ │ │ │ │ ├── ProductFeaturedReview.ts │ │ │ │ │ ├── ProductId.ts │ │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ │ ├── ProductName.ts │ │ │ │ │ ├── ProductRating.ts │ │ │ │ │ └── ProductRepository.ts │ │ │ │ └── infrastructure │ │ │ │ │ └── MySqlProductRepository.ts │ │ │ │ └── users │ │ │ │ ├── application │ │ │ │ ├── find │ │ │ │ │ └── UserFinder.ts │ │ │ │ ├── registrar │ │ │ │ │ └── UserRegistrar.ts │ │ │ │ ├── search │ │ │ │ │ └── UserSearcher.ts │ │ │ │ └── update_email │ │ │ │ │ └── UserEmailUpdater.ts │ │ │ │ ├── domain │ │ │ │ ├── User.ts │ │ │ │ ├── UserDoesNotExist.ts │ │ │ │ ├── UserEmail.ts │ │ │ │ ├── UserId.ts │ │ │ │ ├── UserName.ts │ │ │ │ ├── UserProfilePicture.ts │ │ │ │ ├── UserRegisteredDomainEvent.ts │ │ │ │ ├── UserRepository.ts │ │ │ │ └── UserUpdatedDomainEvent.ts │ │ │ │ └── infrastructure │ │ │ │ └── MySqlUserRepository.ts │ │ ├── tailwind.config.ts │ │ ├── tests │ │ │ └── contexts │ │ │ │ ├── shared │ │ │ │ └── infrastructure │ │ │ │ │ └── MockEventBus.ts │ │ │ │ └── shop │ │ │ │ └── users │ │ │ │ ├── application │ │ │ │ ├── registrar │ │ │ │ │ └── UserRegistrar.test.ts │ │ │ │ └── update_email │ │ │ │ │ └── UserEmailUpdater.test.ts │ │ │ │ ├── domain │ │ │ │ ├── UserEmailMother.ts │ │ │ │ ├── UserIdMother.ts │ │ │ │ ├── UserMother.ts │ │ │ │ ├── UserNameMother.ts │ │ │ │ ├── UserProfilePictureMother.ts │ │ │ │ ├── UserRegisteredDomainEventMother.ts │ │ │ │ └── UserUpdatedDomainEventMother.ts │ │ │ │ └── infrastructure │ │ │ │ └── MockUserRepository.ts │ │ └── tsconfig.json │ └── 2-user_email_updated_domain_event │ │ ├── .editorconfig │ │ ├── .eslintrc.json │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── README.md │ │ ├── databases │ │ └── ecommerce.sql │ │ ├── docker-compose.yml │ │ ├── etc │ │ └── http │ │ │ ├── seller_backoffice │ │ │ ├── product-GET.http │ │ │ ├── product-PUT.http │ │ │ └── products-GET.http │ │ │ └── shop │ │ │ ├── product-GET.http │ │ │ ├── product_review-PUT.http │ │ │ ├── product_reviews-GET.http │ │ │ ├── products-GET.http │ │ │ ├── user-GET.http │ │ │ └── user-PUT.http │ │ ├── jest.config.js │ │ ├── next.config.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── postcss.config.js │ │ ├── public │ │ └── codely.svg │ │ ├── src │ │ ├── app │ │ │ └── api │ │ │ │ ├── seller_backoffice │ │ │ │ └── products │ │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ └── shop │ │ │ │ ├── product_reviews │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ │ ├── products │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ │ └── users │ │ │ │ └── [id] │ │ │ │ └── route.ts │ │ └── contexts │ │ │ ├── seller_backoffice │ │ │ └── products │ │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── ProductCreator.ts │ │ │ │ ├── search │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ └── search_all │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ │ ├── domain │ │ │ │ ├── Product.ts │ │ │ │ ├── ProductId.ts │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ ├── ProductName.ts │ │ │ │ ├── ProductRepository.ts │ │ │ │ └── ProductViews.ts │ │ │ │ └── infrastructure │ │ │ │ └── MySqlProductRepository.ts │ │ │ ├── shared │ │ │ ├── domain │ │ │ │ ├── AggregateRoot.ts │ │ │ │ ├── Collection.ts │ │ │ │ ├── DomainEvent.ts │ │ │ │ ├── EventBus.ts │ │ │ │ ├── Identifier.ts │ │ │ │ ├── Money.ts │ │ │ │ └── StringValueObject.ts │ │ │ └── infrastructure │ │ │ │ └── MariaDBConnection.ts │ │ │ └── shop │ │ │ ├── product_reviews │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── ProductReviewCreator.ts │ │ │ │ └── search_by_product_id │ │ │ │ │ └── ProductReviewsByProductSearcher.ts │ │ │ ├── domain │ │ │ │ ├── ProductReview.ts │ │ │ │ ├── ProductReviewComment.ts │ │ │ │ ├── ProductReviewId.ts │ │ │ │ ├── ProductReviewRating.ts │ │ │ │ └── ProductReviewRepository.ts │ │ │ └── infrastructure │ │ │ │ └── MySqlProductReviewRepository.ts │ │ │ ├── products │ │ │ ├── application │ │ │ │ ├── search │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ └── search_all │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ ├── domain │ │ │ │ ├── Product.ts │ │ │ │ ├── ProductFeaturedReview.ts │ │ │ │ ├── ProductId.ts │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ ├── ProductName.ts │ │ │ │ ├── ProductRating.ts │ │ │ │ └── ProductRepository.ts │ │ │ └── infrastructure │ │ │ │ └── MySqlProductRepository.ts │ │ │ └── users │ │ │ ├── application │ │ │ ├── find │ │ │ │ └── UserFinder.ts │ │ │ ├── registrar │ │ │ │ └── UserRegistrar.ts │ │ │ ├── search │ │ │ │ └── UserSearcher.ts │ │ │ └── update_email │ │ │ │ └── UserEmailUpdater.ts │ │ │ ├── domain │ │ │ ├── User.ts │ │ │ ├── UserDoesNotExist.ts │ │ │ ├── UserEmail.ts │ │ │ ├── UserEmailUpdatedDomainEvent.ts │ │ │ ├── UserId.ts │ │ │ ├── UserName.ts │ │ │ ├── UserProfilePicture.ts │ │ │ ├── UserRegisteredDomainEvent.ts │ │ │ └── UserRepository.ts │ │ │ └── infrastructure │ │ │ └── MySqlUserRepository.ts │ │ ├── tailwind.config.ts │ │ ├── tests │ │ └── contexts │ │ │ ├── shared │ │ │ └── infrastructure │ │ │ │ └── MockEventBus.ts │ │ │ └── shop │ │ │ └── users │ │ │ ├── application │ │ │ ├── registrar │ │ │ │ └── UserRegistrar.test.ts │ │ │ └── update_email │ │ │ │ └── UserEmailUpdater.test.ts │ │ │ ├── domain │ │ │ ├── UserEmailMother.ts │ │ │ ├── UserEmailUpdatedDomainEventMother.ts │ │ │ ├── UserIdMother.ts │ │ │ ├── UserMother.ts │ │ │ ├── UserNameMother.ts │ │ │ ├── UserProfilePictureMother.ts │ │ │ └── UserRegisteredDomainEventMother.ts │ │ │ └── infrastructure │ │ │ └── MockUserRepository.ts │ │ └── tsconfig.json └── 2-semantics_in_domain_events │ ├── 1-user_status_updated_domain_event │ ├── .editorconfig │ ├── .eslintrc.json │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── databases │ │ └── ecommerce.sql │ ├── docker-compose.yml │ ├── etc │ │ └── http │ │ │ ├── seller_backoffice │ │ │ ├── product-GET.http │ │ │ ├── product-PUT.http │ │ │ └── products-GET.http │ │ │ └── shop │ │ │ ├── product-GET.http │ │ │ ├── product_review-PUT.http │ │ │ ├── product_reviews-GET.http │ │ │ ├── products-GET.http │ │ │ ├── user-GET.http │ │ │ └── user-PUT.http │ ├── jest.config.js │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── public │ │ └── codely.svg │ ├── src │ │ ├── app │ │ │ └── api │ │ │ │ ├── seller_backoffice │ │ │ │ └── products │ │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ └── shop │ │ │ │ ├── product_reviews │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ │ ├── products │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ │ └── users │ │ │ │ └── [id] │ │ │ │ └── route.ts │ │ └── contexts │ │ │ ├── seller_backoffice │ │ │ └── products │ │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── ProductCreator.ts │ │ │ │ ├── search │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ └── search_all │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ │ ├── domain │ │ │ │ ├── Product.ts │ │ │ │ ├── ProductId.ts │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ ├── ProductName.ts │ │ │ │ ├── ProductRepository.ts │ │ │ │ └── ProductViews.ts │ │ │ │ └── infrastructure │ │ │ │ └── MySqlProductRepository.ts │ │ │ ├── shared │ │ │ ├── domain │ │ │ │ ├── AggregateRoot.ts │ │ │ │ ├── Collection.ts │ │ │ │ ├── DomainEvent.ts │ │ │ │ ├── EventBus.ts │ │ │ │ ├── Identifier.ts │ │ │ │ ├── Money.ts │ │ │ │ └── StringValueObject.ts │ │ │ └── infrastructure │ │ │ │ └── MariaDBConnection.ts │ │ │ └── shop │ │ │ ├── product_reviews │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── ProductReviewCreator.ts │ │ │ │ └── search_by_product_id │ │ │ │ │ └── ProductReviewsByProductSearcher.ts │ │ │ ├── domain │ │ │ │ ├── ProductReview.ts │ │ │ │ ├── ProductReviewComment.ts │ │ │ │ ├── ProductReviewId.ts │ │ │ │ ├── ProductReviewRating.ts │ │ │ │ └── ProductReviewRepository.ts │ │ │ └── infrastructure │ │ │ │ └── MySqlProductReviewRepository.ts │ │ │ ├── products │ │ │ ├── application │ │ │ │ ├── search │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ └── search_all │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ ├── domain │ │ │ │ ├── Product.ts │ │ │ │ ├── ProductFeaturedReview.ts │ │ │ │ ├── ProductId.ts │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ ├── ProductName.ts │ │ │ │ ├── ProductRating.ts │ │ │ │ └── ProductRepository.ts │ │ │ └── infrastructure │ │ │ │ └── MySqlProductRepository.ts │ │ │ └── users │ │ │ ├── application │ │ │ ├── archive │ │ │ │ └── UserArchiver.ts │ │ │ ├── find │ │ │ │ └── UserFinder.ts │ │ │ ├── registrar │ │ │ │ └── UserRegistrar.ts │ │ │ ├── search │ │ │ │ └── UserSearcher.ts │ │ │ └── update_email │ │ │ │ └── UserEmailUpdater.ts │ │ │ ├── domain │ │ │ ├── User.ts │ │ │ ├── UserDoesNotExist.ts │ │ │ ├── UserEmail.ts │ │ │ ├── UserEmailUpdatedDomainEvent.ts │ │ │ ├── UserFinder.ts │ │ │ ├── UserId.ts │ │ │ ├── UserName.ts │ │ │ ├── UserProfilePicture.ts │ │ │ ├── UserRegisteredDomainEvent.ts │ │ │ ├── UserRepository.ts │ │ │ ├── UserStatus.ts │ │ │ └── UserStatusUpdatedDomainEvent.ts │ │ │ └── infrastructure │ │ │ └── MySqlUserRepository.ts │ ├── tailwind.config.ts │ ├── tests │ │ └── contexts │ │ │ ├── shared │ │ │ ├── domain │ │ │ │ └── EnumMother.ts │ │ │ └── infrastructure │ │ │ │ └── MockEventBus.ts │ │ │ └── shop │ │ │ └── users │ │ │ ├── application │ │ │ ├── archive │ │ │ │ └── UserArchiver.test.ts │ │ │ ├── registrar │ │ │ │ └── UserRegistrar.test.ts │ │ │ └── update_email │ │ │ │ └── UserEmailUpdater.test.ts │ │ │ ├── domain │ │ │ ├── UserEmailMother.ts │ │ │ ├── UserEmailUpdatedDomainEventMother.ts │ │ │ ├── UserIdMother.ts │ │ │ ├── UserMother.ts │ │ │ ├── UserNameMother.ts │ │ │ ├── UserProfilePictureMother.ts │ │ │ ├── UserRegisteredDomainEventMother.ts │ │ │ └── UserStatusUpdatedDomainEventMother.ts │ │ │ └── infrastructure │ │ │ └── MockUserRepository.ts │ └── tsconfig.json │ └── 2-user_archived_domain_event │ ├── .editorconfig │ ├── .eslintrc.json │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── databases │ └── ecommerce.sql │ ├── docker-compose.yml │ ├── etc │ └── http │ │ ├── seller_backoffice │ │ ├── product-GET.http │ │ ├── product-PUT.http │ │ └── products-GET.http │ │ └── shop │ │ ├── product-GET.http │ │ ├── product_review-PUT.http │ │ ├── product_reviews-GET.http │ │ ├── products-GET.http │ │ ├── user-GET.http │ │ └── user-PUT.http │ ├── jest.config.js │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── public │ └── codely.svg │ ├── src │ ├── app │ │ └── api │ │ │ ├── seller_backoffice │ │ │ └── products │ │ │ │ ├── [id] │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ └── shop │ │ │ ├── product_reviews │ │ │ ├── [id] │ │ │ │ └── route.ts │ │ │ └── route.ts │ │ │ ├── products │ │ │ ├── [id] │ │ │ │ └── route.ts │ │ │ └── route.ts │ │ │ └── users │ │ │ └── [id] │ │ │ └── route.ts │ └── contexts │ │ ├── seller_backoffice │ │ └── products │ │ │ ├── application │ │ │ ├── create │ │ │ │ └── ProductCreator.ts │ │ │ ├── search │ │ │ │ └── ProductSearcher.ts │ │ │ └── search_all │ │ │ │ └── AllProductsSearcher.ts │ │ │ ├── domain │ │ │ ├── Product.ts │ │ │ ├── ProductId.ts │ │ │ ├── ProductImageUrl.ts │ │ │ ├── ProductImageUrls.ts │ │ │ ├── ProductName.ts │ │ │ ├── ProductRepository.ts │ │ │ └── ProductViews.ts │ │ │ └── infrastructure │ │ │ └── MySqlProductRepository.ts │ │ ├── shared │ │ ├── domain │ │ │ ├── AggregateRoot.ts │ │ │ ├── Collection.ts │ │ │ ├── DomainEvent.ts │ │ │ ├── EventBus.ts │ │ │ ├── Identifier.ts │ │ │ ├── Money.ts │ │ │ └── StringValueObject.ts │ │ └── infrastructure │ │ │ └── MariaDBConnection.ts │ │ └── shop │ │ ├── product_reviews │ │ ├── application │ │ │ ├── create │ │ │ │ └── ProductReviewCreator.ts │ │ │ └── search_by_product_id │ │ │ │ └── ProductReviewsByProductSearcher.ts │ │ ├── domain │ │ │ ├── ProductReview.ts │ │ │ ├── ProductReviewComment.ts │ │ │ ├── ProductReviewId.ts │ │ │ ├── ProductReviewRating.ts │ │ │ └── ProductReviewRepository.ts │ │ └── infrastructure │ │ │ └── MySqlProductReviewRepository.ts │ │ ├── products │ │ ├── application │ │ │ ├── search │ │ │ │ └── ProductSearcher.ts │ │ │ └── search_all │ │ │ │ └── AllProductsSearcher.ts │ │ ├── domain │ │ │ ├── Product.ts │ │ │ ├── ProductFeaturedReview.ts │ │ │ ├── ProductId.ts │ │ │ ├── ProductImageUrl.ts │ │ │ ├── ProductImageUrls.ts │ │ │ ├── ProductName.ts │ │ │ ├── ProductRating.ts │ │ │ └── ProductRepository.ts │ │ └── infrastructure │ │ │ └── MySqlProductRepository.ts │ │ └── users │ │ ├── application │ │ ├── archive │ │ │ └── UserArchiver.ts │ │ ├── find │ │ │ └── UserFinder.ts │ │ ├── registrar │ │ │ └── UserRegistrar.ts │ │ ├── search │ │ │ └── UserSearcher.ts │ │ └── update_email │ │ │ └── UserEmailUpdater.ts │ │ ├── domain │ │ ├── User.ts │ │ ├── UserArchivedDomainEvent.ts │ │ ├── UserDoesNotExist.ts │ │ ├── UserEmail.ts │ │ ├── UserEmailUpdatedDomainEvent.ts │ │ ├── UserFinder.ts │ │ ├── UserId.ts │ │ ├── UserName.ts │ │ ├── UserProfilePicture.ts │ │ ├── UserRegisteredDomainEvent.ts │ │ ├── UserRepository.ts │ │ └── UserStatus.ts │ │ └── infrastructure │ │ └── MySqlUserRepository.ts │ ├── tailwind.config.ts │ ├── tests │ └── contexts │ │ ├── shared │ │ ├── domain │ │ │ └── EnumMother.ts │ │ └── infrastructure │ │ │ └── MockEventBus.ts │ │ └── shop │ │ └── users │ │ ├── application │ │ ├── archive │ │ │ └── UserArchiver.test.ts │ │ ├── registrar │ │ │ └── UserRegistrar.test.ts │ │ └── update_email │ │ │ └── UserEmailUpdater.test.ts │ │ ├── domain │ │ ├── UserArchivedDomainEventMother.ts │ │ ├── UserEmailMother.ts │ │ ├── UserEmailUpdatedDomainEventMother.ts │ │ ├── UserIdMother.ts │ │ ├── UserMother.ts │ │ ├── UserNameMother.ts │ │ ├── UserProfilePictureMother.ts │ │ └── UserRegisteredDomainEventMother.ts │ │ └── infrastructure │ │ └── MockUserRepository.ts │ └── tsconfig.json ├── 04-react_to_domain_events ├── 1-subscriber_listen_one_event │ ├── .editorconfig │ ├── .eslintrc.json │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── databases │ │ └── ecommerce.sql │ ├── docker-compose.yml │ ├── etc │ │ └── http │ │ │ ├── seller_backoffice │ │ │ ├── product-GET.http │ │ │ ├── product-PUT.http │ │ │ └── products-GET.http │ │ │ └── shop │ │ │ ├── product-GET.http │ │ │ ├── product_review-PUT.http │ │ │ ├── product_reviews-GET.http │ │ │ ├── products-GET.http │ │ │ ├── user-GET.http │ │ │ └── user-PUT.http │ ├── jest.config.js │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── public │ │ └── codely.svg │ ├── src │ │ ├── app │ │ │ └── api │ │ │ │ ├── seller_backoffice │ │ │ │ └── products │ │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ └── shop │ │ │ │ ├── product_reviews │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ │ ├── products │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ │ └── users │ │ │ │ └── [id] │ │ │ │ └── route.ts │ │ └── contexts │ │ │ ├── retention │ │ │ └── email │ │ │ │ ├── application │ │ │ │ └── send_welcome_email │ │ │ │ │ ├── SendWelcomeEmailOnUserRegistered.ts │ │ │ │ │ └── WelcomeEmailSender.ts │ │ │ │ └── domain │ │ │ │ ├── Email.ts │ │ │ │ ├── EmailBody.ts │ │ │ │ ├── EmailId.ts │ │ │ │ ├── EmailSender.ts │ │ │ │ ├── WelcomeEmail.ts │ │ │ │ └── WelcomeEmailSentDomainEvent.ts │ │ │ ├── seller_backoffice │ │ │ └── products │ │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── ProductCreator.ts │ │ │ │ ├── search │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ └── search_all │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ │ ├── domain │ │ │ │ ├── Product.ts │ │ │ │ ├── ProductId.ts │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ ├── ProductName.ts │ │ │ │ ├── ProductRepository.ts │ │ │ │ └── ProductViews.ts │ │ │ │ └── infrastructure │ │ │ │ └── MySqlProductRepository.ts │ │ │ ├── shared │ │ │ ├── domain │ │ │ │ ├── AggregateRoot.ts │ │ │ │ ├── Collection.ts │ │ │ │ ├── DomainEvent.ts │ │ │ │ ├── DomainEventName.ts │ │ │ │ ├── DomainEventSubscriber.ts │ │ │ │ ├── EmailAddress.ts │ │ │ │ ├── EventBus.ts │ │ │ │ ├── Identifier.ts │ │ │ │ ├── Money.ts │ │ │ │ ├── StringValueObject.ts │ │ │ │ └── UuidGenerator.ts │ │ │ └── infrastructure │ │ │ │ └── MariaDBConnection.ts │ │ │ └── shop │ │ │ ├── product_reviews │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── ProductReviewCreator.ts │ │ │ │ └── search_by_product_id │ │ │ │ │ └── ProductReviewsByProductSearcher.ts │ │ │ ├── domain │ │ │ │ ├── ProductReview.ts │ │ │ │ ├── ProductReviewComment.ts │ │ │ │ ├── ProductReviewId.ts │ │ │ │ ├── ProductReviewRating.ts │ │ │ │ └── ProductReviewRepository.ts │ │ │ └── infrastructure │ │ │ │ └── MySqlProductReviewRepository.ts │ │ │ ├── products │ │ │ ├── application │ │ │ │ ├── search │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ └── search_all │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ ├── domain │ │ │ │ ├── Product.ts │ │ │ │ ├── ProductFeaturedReview.ts │ │ │ │ ├── ProductId.ts │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ ├── ProductName.ts │ │ │ │ ├── ProductRating.ts │ │ │ │ └── ProductRepository.ts │ │ │ └── infrastructure │ │ │ │ └── MySqlProductRepository.ts │ │ │ └── users │ │ │ ├── application │ │ │ ├── archive │ │ │ │ └── UserArchiver.ts │ │ │ ├── find │ │ │ │ └── UserFinder.ts │ │ │ ├── registrar │ │ │ │ └── UserRegistrar.ts │ │ │ ├── search │ │ │ │ └── UserSearcher.ts │ │ │ └── update_email │ │ │ │ └── UserEmailUpdater.ts │ │ │ ├── domain │ │ │ ├── User.ts │ │ │ ├── UserArchivedDomainEvent.ts │ │ │ ├── UserDoesNotExist.ts │ │ │ ├── UserEmail.ts │ │ │ ├── UserEmailUpdatedDomainEvent.ts │ │ │ ├── UserFinder.ts │ │ │ ├── UserId.ts │ │ │ ├── UserName.ts │ │ │ ├── UserProfilePicture.ts │ │ │ ├── UserRegisteredDomainEvent.ts │ │ │ ├── UserRepository.ts │ │ │ └── UserStatus.ts │ │ │ └── infrastructure │ │ │ └── MySqlUserRepository.ts │ ├── tailwind.config.ts │ ├── tests │ │ └── contexts │ │ │ ├── retention │ │ │ └── email │ │ │ │ ├── application │ │ │ │ └── SendWelcomeEmailOnUserRegistered.test.ts │ │ │ │ ├── domain │ │ │ │ ├── EmailBodyMother.ts │ │ │ │ ├── EmailIdMother.ts │ │ │ │ ├── WelcomeEmailMother.ts │ │ │ │ └── WelcomeEmailSentDomainEventMother.ts │ │ │ │ └── infrastructure │ │ │ │ └── MockEmailSender.ts │ │ │ ├── shared │ │ │ ├── domain │ │ │ │ ├── EmailAddressMother.ts │ │ │ │ └── EnumMother.ts │ │ │ └── infrastructure │ │ │ │ ├── MockEventBus.ts │ │ │ │ └── MockUuidGenerator.ts │ │ │ └── shop │ │ │ └── users │ │ │ ├── application │ │ │ ├── archive │ │ │ │ └── UserArchiver.test.ts │ │ │ ├── registrar │ │ │ │ └── UserRegistrar.test.ts │ │ │ └── update_email │ │ │ │ └── UserEmailUpdater.test.ts │ │ │ ├── domain │ │ │ ├── UserArchivedDomainEventMother.ts │ │ │ ├── UserEmailMother.ts │ │ │ ├── UserEmailUpdatedDomainEventMother.ts │ │ │ ├── UserIdMother.ts │ │ │ ├── UserMother.ts │ │ │ ├── UserNameMother.ts │ │ │ ├── UserProfilePictureMother.ts │ │ │ └── UserRegisteredDomainEventMother.ts │ │ │ └── infrastructure │ │ │ └── MockUserRepository.ts │ └── tsconfig.json ├── 2-test_subscriber │ ├── .editorconfig │ ├── .eslintrc.json │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── databases │ │ └── ecommerce.sql │ ├── docker-compose.yml │ ├── etc │ │ └── http │ │ │ ├── seller_backoffice │ │ │ ├── product-GET.http │ │ │ ├── product-PUT.http │ │ │ └── products-GET.http │ │ │ └── shop │ │ │ ├── product-GET.http │ │ │ ├── product_review-PUT.http │ │ │ ├── product_reviews-GET.http │ │ │ ├── products-GET.http │ │ │ ├── user-GET.http │ │ │ └── user-PUT.http │ ├── jest.config.js │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── public │ │ └── codely.svg │ ├── src │ │ ├── app │ │ │ └── api │ │ │ │ ├── seller_backoffice │ │ │ │ └── products │ │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ └── shop │ │ │ │ ├── product_reviews │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ │ ├── products │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ │ └── users │ │ │ │ └── [id] │ │ │ │ └── route.ts │ │ └── contexts │ │ │ ├── retention │ │ │ └── email │ │ │ │ ├── application │ │ │ │ └── send_welcome_email │ │ │ │ │ ├── SendWelcomeEmailOnUserRegistered.ts │ │ │ │ │ └── WelcomeEmailSender.ts │ │ │ │ └── domain │ │ │ │ ├── Email.ts │ │ │ │ ├── EmailBody.ts │ │ │ │ ├── EmailId.ts │ │ │ │ ├── EmailSender.ts │ │ │ │ ├── WelcomeEmail.ts │ │ │ │ └── WelcomeEmailSentDomainEvent.ts │ │ │ ├── seller_backoffice │ │ │ └── products │ │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── ProductCreator.ts │ │ │ │ ├── search │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ └── search_all │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ │ ├── domain │ │ │ │ ├── Product.ts │ │ │ │ ├── ProductId.ts │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ ├── ProductName.ts │ │ │ │ ├── ProductRepository.ts │ │ │ │ └── ProductViews.ts │ │ │ │ └── infrastructure │ │ │ │ └── MySqlProductRepository.ts │ │ │ ├── shared │ │ │ ├── domain │ │ │ │ ├── AggregateRoot.ts │ │ │ │ ├── Collection.ts │ │ │ │ ├── DomainEvent.ts │ │ │ │ ├── DomainEventName.ts │ │ │ │ ├── DomainEventSubscriber.ts │ │ │ │ ├── EmailAddress.ts │ │ │ │ ├── EventBus.ts │ │ │ │ ├── Identifier.ts │ │ │ │ ├── Money.ts │ │ │ │ ├── StringValueObject.ts │ │ │ │ └── UuidGenerator.ts │ │ │ └── infrastructure │ │ │ │ └── MariaDBConnection.ts │ │ │ └── shop │ │ │ ├── product_reviews │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── ProductReviewCreator.ts │ │ │ │ └── search_by_product_id │ │ │ │ │ └── ProductReviewsByProductSearcher.ts │ │ │ ├── domain │ │ │ │ ├── ProductReview.ts │ │ │ │ ├── ProductReviewComment.ts │ │ │ │ ├── ProductReviewId.ts │ │ │ │ ├── ProductReviewRating.ts │ │ │ │ └── ProductReviewRepository.ts │ │ │ └── infrastructure │ │ │ │ └── MySqlProductReviewRepository.ts │ │ │ ├── products │ │ │ ├── application │ │ │ │ ├── search │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ └── search_all │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ ├── domain │ │ │ │ ├── Product.ts │ │ │ │ ├── ProductFeaturedReview.ts │ │ │ │ ├── ProductId.ts │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ ├── ProductName.ts │ │ │ │ ├── ProductRating.ts │ │ │ │ └── ProductRepository.ts │ │ │ └── infrastructure │ │ │ │ └── MySqlProductRepository.ts │ │ │ └── users │ │ │ ├── application │ │ │ ├── archive │ │ │ │ └── UserArchiver.ts │ │ │ ├── find │ │ │ │ └── UserFinder.ts │ │ │ ├── registrar │ │ │ │ └── UserRegistrar.ts │ │ │ ├── search │ │ │ │ └── UserSearcher.ts │ │ │ └── update_email │ │ │ │ └── UserEmailUpdater.ts │ │ │ ├── domain │ │ │ ├── User.ts │ │ │ ├── UserArchivedDomainEvent.ts │ │ │ ├── UserDoesNotExist.ts │ │ │ ├── UserEmail.ts │ │ │ ├── UserEmailUpdatedDomainEvent.ts │ │ │ ├── UserFinder.ts │ │ │ ├── UserId.ts │ │ │ ├── UserName.ts │ │ │ ├── UserProfilePicture.ts │ │ │ ├── UserRegisteredDomainEvent.ts │ │ │ ├── UserRepository.ts │ │ │ └── UserStatus.ts │ │ │ └── infrastructure │ │ │ └── MySqlUserRepository.ts │ ├── tailwind.config.ts │ ├── tests │ │ └── contexts │ │ │ ├── retention │ │ │ └── email │ │ │ │ ├── application │ │ │ │ └── SendWelcomeEmailOnUserRegistered.test.ts │ │ │ │ ├── domain │ │ │ │ ├── EmailBodyMother.ts │ │ │ │ ├── EmailIdMother.ts │ │ │ │ ├── WelcomeEmailMother.ts │ │ │ │ └── WelcomeEmailSentDomainEventMother.ts │ │ │ │ └── infrastructure │ │ │ │ └── MockEmailSender.ts │ │ │ ├── shared │ │ │ ├── domain │ │ │ │ ├── EmailAddressMother.ts │ │ │ │ └── EnumMother.ts │ │ │ └── infrastructure │ │ │ │ ├── MockEventBus.ts │ │ │ │ └── MockUuidGenerator.ts │ │ │ └── shop │ │ │ └── users │ │ │ ├── application │ │ │ ├── archive │ │ │ │ └── UserArchiver.test.ts │ │ │ ├── registrar │ │ │ │ └── UserRegistrar.test.ts │ │ │ └── update_email │ │ │ │ └── UserEmailUpdater.test.ts │ │ │ ├── domain │ │ │ ├── UserArchivedDomainEventMother.ts │ │ │ ├── UserEmailMother.ts │ │ │ ├── UserEmailUpdatedDomainEventMother.ts │ │ │ ├── UserIdMother.ts │ │ │ ├── UserMother.ts │ │ │ ├── UserNameMother.ts │ │ │ ├── UserProfilePictureMother.ts │ │ │ └── UserRegisteredDomainEventMother.ts │ │ │ └── infrastructure │ │ │ └── MockUserRepository.ts │ └── tsconfig.json ├── 3-subscriber_listen_multiple_events │ ├── .editorconfig │ ├── .eslintrc.json │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── databases │ │ └── ecommerce.sql │ ├── docker-compose.yml │ ├── etc │ │ └── http │ │ │ ├── seller_backoffice │ │ │ ├── product-GET.http │ │ │ ├── product-PUT.http │ │ │ └── products-GET.http │ │ │ └── shop │ │ │ ├── product-GET.http │ │ │ ├── product_review-PUT.http │ │ │ ├── product_reviews-GET.http │ │ │ ├── products-GET.http │ │ │ ├── user-GET.http │ │ │ └── user-PUT.http │ ├── jest.config.js │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── public │ │ └── codely.svg │ ├── src │ │ ├── app │ │ │ └── api │ │ │ │ ├── seller_backoffice │ │ │ │ └── products │ │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ └── shop │ │ │ │ ├── product_reviews │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ │ ├── products │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ │ └── users │ │ │ │ └── [id] │ │ │ │ └── route.ts │ │ └── contexts │ │ │ ├── retention │ │ │ ├── email │ │ │ │ ├── application │ │ │ │ │ └── send_welcome_email │ │ │ │ │ │ ├── SendWelcomeEmailOnUserRegistered.ts │ │ │ │ │ │ └── WelcomeEmailSender.ts │ │ │ │ └── domain │ │ │ │ │ ├── Email.ts │ │ │ │ │ ├── EmailBody.ts │ │ │ │ │ ├── EmailId.ts │ │ │ │ │ ├── EmailSender.ts │ │ │ │ │ ├── WelcomeEmail.ts │ │ │ │ │ └── WelcomeEmailSentDomainEvent.ts │ │ │ └── user │ │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── .gitkeep │ │ │ │ └── update_last_activity_date │ │ │ │ │ ├── UpdateLastActivityDateOnUserUpdated.ts │ │ │ │ │ └── UserLastActivityUpdater.ts │ │ │ │ └── domain │ │ │ │ ├── RetentionUser.ts │ │ │ │ └── RetentionUserRepository.ts │ │ │ ├── seller_backoffice │ │ │ └── products │ │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── ProductCreator.ts │ │ │ │ ├── search │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ └── search_all │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ │ ├── domain │ │ │ │ ├── Product.ts │ │ │ │ ├── ProductId.ts │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ ├── ProductName.ts │ │ │ │ ├── ProductRepository.ts │ │ │ │ └── ProductViews.ts │ │ │ │ └── infrastructure │ │ │ │ └── MySqlProductRepository.ts │ │ │ ├── shared │ │ │ ├── domain │ │ │ │ ├── AggregateRoot.ts │ │ │ │ ├── Collection.ts │ │ │ │ ├── DomainEvent.ts │ │ │ │ ├── DomainEventName.ts │ │ │ │ ├── DomainEventSubscriber.ts │ │ │ │ ├── EmailAddress.ts │ │ │ │ ├── EventBus.ts │ │ │ │ ├── Identifier.ts │ │ │ │ ├── Money.ts │ │ │ │ ├── StringValueObject.ts │ │ │ │ └── UuidGenerator.ts │ │ │ └── infrastructure │ │ │ │ └── MariaDBConnection.ts │ │ │ └── shop │ │ │ ├── product_reviews │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── ProductReviewCreator.ts │ │ │ │ └── search_by_product_id │ │ │ │ │ └── ProductReviewsByProductSearcher.ts │ │ │ ├── domain │ │ │ │ ├── ProductReview.ts │ │ │ │ ├── ProductReviewComment.ts │ │ │ │ ├── ProductReviewId.ts │ │ │ │ ├── ProductReviewRating.ts │ │ │ │ └── ProductReviewRepository.ts │ │ │ └── infrastructure │ │ │ │ └── MySqlProductReviewRepository.ts │ │ │ ├── products │ │ │ ├── application │ │ │ │ ├── search │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ └── search_all │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ ├── domain │ │ │ │ ├── Product.ts │ │ │ │ ├── ProductFeaturedReview.ts │ │ │ │ ├── ProductId.ts │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ ├── ProductName.ts │ │ │ │ ├── ProductRating.ts │ │ │ │ └── ProductRepository.ts │ │ │ └── infrastructure │ │ │ │ └── MySqlProductRepository.ts │ │ │ └── users │ │ │ ├── application │ │ │ ├── archive │ │ │ │ └── UserArchiver.ts │ │ │ ├── find │ │ │ │ └── UserFinder.ts │ │ │ ├── registrar │ │ │ │ └── UserRegistrar.ts │ │ │ ├── search │ │ │ │ └── UserSearcher.ts │ │ │ └── update_email │ │ │ │ └── UserEmailUpdater.ts │ │ │ ├── domain │ │ │ ├── User.ts │ │ │ ├── UserArchivedDomainEvent.ts │ │ │ ├── UserDoesNotExist.ts │ │ │ ├── UserEmail.ts │ │ │ ├── UserEmailUpdatedDomainEvent.ts │ │ │ ├── UserFinder.ts │ │ │ ├── UserId.ts │ │ │ ├── UserName.ts │ │ │ ├── UserProfilePicture.ts │ │ │ ├── UserRegisteredDomainEvent.ts │ │ │ ├── UserRepository.ts │ │ │ └── UserStatus.ts │ │ │ └── infrastructure │ │ │ └── MySqlUserRepository.ts │ ├── tailwind.config.ts │ ├── tests │ │ └── contexts │ │ │ ├── retention │ │ │ ├── email │ │ │ │ ├── application │ │ │ │ │ └── SendWelcomeEmailOnUserRegistered.test.ts │ │ │ │ ├── domain │ │ │ │ │ ├── EmailBodyMother.ts │ │ │ │ │ ├── EmailIdMother.ts │ │ │ │ │ ├── WelcomeEmailMother.ts │ │ │ │ │ └── WelcomeEmailSentDomainEventMother.ts │ │ │ │ └── infrastructure │ │ │ │ │ └── MockEmailSender.ts │ │ │ └── user │ │ │ │ ├── application │ │ │ │ └── update_last_activity_date │ │ │ │ │ └── UpdateLastActivityDateOnUserUpdated.test.ts │ │ │ │ ├── domain │ │ │ │ └── RetentionUserMother.ts │ │ │ │ └── infrastructure │ │ │ │ └── MockRetentionUserRepository.ts │ │ │ ├── shared │ │ │ ├── domain │ │ │ │ ├── EmailAddressMother.ts │ │ │ │ └── EnumMother.ts │ │ │ └── infrastructure │ │ │ │ ├── MockEventBus.ts │ │ │ │ └── MockUuidGenerator.ts │ │ │ └── shop │ │ │ └── users │ │ │ ├── application │ │ │ ├── archive │ │ │ │ └── UserArchiver.test.ts │ │ │ ├── registrar │ │ │ │ └── UserRegistrar.test.ts │ │ │ └── update_email │ │ │ │ └── UserEmailUpdater.test.ts │ │ │ ├── domain │ │ │ ├── DateMother.ts │ │ │ ├── UserArchivedDomainEventMother.ts │ │ │ ├── UserEmailMother.ts │ │ │ ├── UserEmailUpdatedDomainEventMother.ts │ │ │ ├── UserIdMother.ts │ │ │ ├── UserMother.ts │ │ │ ├── UserNameMother.ts │ │ │ ├── UserProfilePictureMother.ts │ │ │ └── UserRegisteredDomainEventMother.ts │ │ │ └── infrastructure │ │ │ └── MockUserRepository.ts │ └── tsconfig.json └── 4-save_as_derivated_action │ ├── .editorconfig │ ├── .eslintrc.json │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── databases │ └── ecommerce.sql │ ├── docker-compose.yml │ ├── etc │ └── http │ │ ├── seller_backoffice │ │ ├── product-GET.http │ │ ├── product-PUT.http │ │ └── products-GET.http │ │ └── shop │ │ ├── product-GET.http │ │ ├── product_review-PUT.http │ │ ├── product_reviews-GET.http │ │ ├── products-GET.http │ │ ├── user-GET.http │ │ └── user-PUT.http │ ├── jest.config.js │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── public │ └── codely.svg │ ├── src │ ├── app │ │ └── api │ │ │ ├── seller_backoffice │ │ │ └── products │ │ │ │ ├── [id] │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ └── shop │ │ │ ├── product_reviews │ │ │ ├── [id] │ │ │ │ └── route.ts │ │ │ └── route.ts │ │ │ ├── products │ │ │ ├── [id] │ │ │ │ └── route.ts │ │ │ └── route.ts │ │ │ └── users │ │ │ └── [id] │ │ │ └── route.ts │ └── contexts │ │ ├── retention │ │ ├── email │ │ │ ├── application │ │ │ │ └── send_welcome_email │ │ │ │ │ ├── SendWelcomeEmailOnUserRegistered.ts │ │ │ │ │ └── WelcomeEmailSender.ts │ │ │ └── domain │ │ │ │ ├── Email.ts │ │ │ │ ├── EmailBody.ts │ │ │ │ ├── EmailId.ts │ │ │ │ ├── EmailSender.ts │ │ │ │ ├── WelcomeEmail.ts │ │ │ │ └── WelcomeEmailSentDomainEvent.ts │ │ └── user │ │ │ ├── application │ │ │ ├── create │ │ │ │ └── .gitkeep │ │ │ └── update_last_activity_date │ │ │ │ ├── UpdateLastActivityDateOnUserUpdated.ts │ │ │ │ └── UserLastActivityUpdater.ts │ │ │ └── domain │ │ │ ├── RetentionUser.ts │ │ │ └── RetentionUserRepository.ts │ │ ├── seller_backoffice │ │ └── products │ │ │ ├── application │ │ │ ├── create │ │ │ │ └── ProductCreator.ts │ │ │ ├── search │ │ │ │ └── ProductSearcher.ts │ │ │ └── search_all │ │ │ │ └── AllProductsSearcher.ts │ │ │ ├── domain │ │ │ ├── Product.ts │ │ │ ├── ProductId.ts │ │ │ ├── ProductImageUrl.ts │ │ │ ├── ProductImageUrls.ts │ │ │ ├── ProductName.ts │ │ │ ├── ProductRepository.ts │ │ │ └── ProductViews.ts │ │ │ └── infrastructure │ │ │ └── MySqlProductRepository.ts │ │ ├── shared │ │ ├── domain │ │ │ ├── AggregateRoot.ts │ │ │ ├── Collection.ts │ │ │ ├── EmailAddress.ts │ │ │ ├── Identifier.ts │ │ │ ├── Money.ts │ │ │ ├── StringValueObject.ts │ │ │ ├── UuidGenerator.ts │ │ │ └── event │ │ │ │ ├── DomainEvent.ts │ │ │ │ ├── DomainEventName.ts │ │ │ │ ├── DomainEventSubscriber.ts │ │ │ │ └── EventBus.ts │ │ └── infrastructure │ │ │ ├── MariaDBConnection.ts │ │ │ └── event │ │ │ └── InMemoryEventBus.ts │ │ └── shop │ │ ├── product_reviews │ │ ├── application │ │ │ ├── create │ │ │ │ └── ProductReviewCreator.ts │ │ │ └── search_by_product_id │ │ │ │ └── ProductReviewsByProductSearcher.ts │ │ ├── domain │ │ │ ├── ProductReview.ts │ │ │ ├── ProductReviewComment.ts │ │ │ ├── ProductReviewId.ts │ │ │ ├── ProductReviewRating.ts │ │ │ └── ProductReviewRepository.ts │ │ └── infrastructure │ │ │ └── MySqlProductReviewRepository.ts │ │ ├── products │ │ ├── application │ │ │ ├── search │ │ │ │ └── ProductSearcher.ts │ │ │ └── search_all │ │ │ │ └── AllProductsSearcher.ts │ │ ├── domain │ │ │ ├── Product.ts │ │ │ ├── ProductFeaturedReview.ts │ │ │ ├── ProductId.ts │ │ │ ├── ProductImageUrl.ts │ │ │ ├── ProductImageUrls.ts │ │ │ ├── ProductName.ts │ │ │ ├── ProductRating.ts │ │ │ └── ProductRepository.ts │ │ └── infrastructure │ │ │ └── MySqlProductRepository.ts │ │ └── users │ │ ├── application │ │ ├── archive │ │ │ └── UserArchiver.ts │ │ ├── find │ │ │ └── UserFinder.ts │ │ ├── registrar │ │ │ └── UserRegistrar.ts │ │ ├── save │ │ │ ├── SaveUserOnUserRegistered.ts │ │ │ └── UserSaver.ts │ │ ├── search │ │ │ └── UserSearcher.ts │ │ └── update_email │ │ │ └── UserEmailUpdater.ts │ │ ├── domain │ │ ├── User.ts │ │ ├── UserArchivedDomainEvent.ts │ │ ├── UserDoesNotExist.ts │ │ ├── UserEmail.ts │ │ ├── UserEmailUpdatedDomainEvent.ts │ │ ├── UserFinder.ts │ │ ├── UserId.ts │ │ ├── UserName.ts │ │ ├── UserProfilePicture.ts │ │ ├── UserRegisteredDomainEvent.ts │ │ ├── UserRepository.ts │ │ └── UserStatus.ts │ │ └── infrastructure │ │ └── MySqlUserRepository.ts │ ├── tailwind.config.ts │ ├── tests │ └── contexts │ │ ├── retention │ │ ├── email │ │ │ ├── application │ │ │ │ └── SendWelcomeEmailOnUserRegistered.test.ts │ │ │ ├── domain │ │ │ │ ├── EmailBodyMother.ts │ │ │ │ ├── EmailIdMother.ts │ │ │ │ ├── WelcomeEmailMother.ts │ │ │ │ └── WelcomeEmailSentDomainEventMother.ts │ │ │ └── infrastructure │ │ │ │ └── MockEmailSender.ts │ │ └── user │ │ │ ├── application │ │ │ └── update_last_activity_date │ │ │ │ └── UpdateLastActivityDateOnUserUpdated.test.ts │ │ │ ├── domain │ │ │ └── RetentionUserMother.ts │ │ │ └── infrastructure │ │ │ └── MockRetentionUserRepository.ts │ │ ├── shared │ │ ├── domain │ │ │ ├── EmailAddressMother.ts │ │ │ └── EnumMother.ts │ │ └── infrastructure │ │ │ ├── MockEventBus.ts │ │ │ └── MockUuidGenerator.ts │ │ └── shop │ │ └── users │ │ ├── application │ │ ├── archive │ │ │ └── UserArchiver.test.ts │ │ ├── registrar │ │ │ └── UserRegistrar.test.ts │ │ └── update_email │ │ │ └── UserEmailUpdater.test.ts │ │ ├── domain │ │ ├── DateMother.ts │ │ ├── UserArchivedDomainEventMother.ts │ │ ├── UserEmailMother.ts │ │ ├── UserEmailUpdatedDomainEventMother.ts │ │ ├── UserIdMother.ts │ │ ├── UserMother.ts │ │ ├── UserNameMother.ts │ │ ├── UserProfilePictureMother.ts │ │ └── UserRegisteredDomainEventMother.ts │ │ └── infrastructure │ │ └── MockUserRepository.ts │ └── tsconfig.json ├── 06-external_vs_internal_domain_events ├── 1-info_in_domain_events │ ├── 1-publish_all │ │ ├── .editorconfig │ │ ├── .eslintrc.json │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── README.md │ │ ├── databases │ │ │ └── ecommerce.sql │ │ ├── docker-compose.yml │ │ ├── etc │ │ │ └── http │ │ │ │ ├── seller_backoffice │ │ │ │ ├── product-GET.http │ │ │ │ ├── product-PUT.http │ │ │ │ └── products-GET.http │ │ │ │ └── shop │ │ │ │ ├── product-GET.http │ │ │ │ ├── product_review-PUT.http │ │ │ │ ├── product_reviews-GET.http │ │ │ │ ├── products-GET.http │ │ │ │ ├── user-GET.http │ │ │ │ └── user-PUT.http │ │ ├── jest.config.js │ │ ├── next.config.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── postcss.config.js │ │ ├── public │ │ │ └── codely.svg │ │ ├── src │ │ │ ├── app │ │ │ │ └── api │ │ │ │ │ ├── seller_backoffice │ │ │ │ │ └── products │ │ │ │ │ │ ├── [id] │ │ │ │ │ │ └── route.ts │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── shop │ │ │ │ │ ├── product_reviews │ │ │ │ │ ├── [id] │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ │ ├── products │ │ │ │ │ ├── [id] │ │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ │ └── users │ │ │ │ │ └── [id] │ │ │ │ │ └── route.ts │ │ │ └── contexts │ │ │ │ ├── retention │ │ │ │ ├── email │ │ │ │ │ ├── application │ │ │ │ │ │ └── send_welcome_email │ │ │ │ │ │ │ ├── SendWelcomeEmailOnUserRegistered.ts │ │ │ │ │ │ │ └── WelcomeEmailSender.ts │ │ │ │ │ └── domain │ │ │ │ │ │ ├── Email.ts │ │ │ │ │ │ ├── EmailBody.ts │ │ │ │ │ │ ├── EmailId.ts │ │ │ │ │ │ ├── EmailSender.ts │ │ │ │ │ │ ├── WelcomeEmail.ts │ │ │ │ │ │ └── WelcomeEmailSentDomainEvent.ts │ │ │ │ └── user │ │ │ │ │ ├── application │ │ │ │ │ ├── create │ │ │ │ │ │ └── .gitkeep │ │ │ │ │ └── update_last_activity_date │ │ │ │ │ │ ├── UpdateLastActivityDateOnUserUpdated.ts │ │ │ │ │ │ └── UserLastActivityUpdater.ts │ │ │ │ │ └── domain │ │ │ │ │ ├── RetentionUser.ts │ │ │ │ │ └── RetentionUserRepository.ts │ │ │ │ ├── seller_backoffice │ │ │ │ └── products │ │ │ │ │ ├── application │ │ │ │ │ ├── create │ │ │ │ │ │ └── ProductCreator.ts │ │ │ │ │ ├── search │ │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ │ └── search_all │ │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ │ │ ├── domain │ │ │ │ │ ├── Product.ts │ │ │ │ │ ├── ProductId.ts │ │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ │ ├── ProductName.ts │ │ │ │ │ ├── ProductRepository.ts │ │ │ │ │ └── ProductViews.ts │ │ │ │ │ └── infrastructure │ │ │ │ │ └── MySqlProductRepository.ts │ │ │ │ ├── shared │ │ │ │ ├── domain │ │ │ │ │ ├── AggregateRoot.ts │ │ │ │ │ ├── Collection.ts │ │ │ │ │ ├── DomainEvent.ts │ │ │ │ │ ├── DomainEventName.ts │ │ │ │ │ ├── DomainEventSubscriber.ts │ │ │ │ │ ├── EmailAddress.ts │ │ │ │ │ ├── EventBus.ts │ │ │ │ │ ├── Identifier.ts │ │ │ │ │ ├── Money.ts │ │ │ │ │ ├── StringValueObject.ts │ │ │ │ │ └── UuidGenerator.ts │ │ │ │ └── infrastructure │ │ │ │ │ └── MariaDBConnection.ts │ │ │ │ └── shop │ │ │ │ ├── product_reviews │ │ │ │ ├── application │ │ │ │ │ ├── create │ │ │ │ │ │ └── ProductReviewCreator.ts │ │ │ │ │ └── search_by_product_id │ │ │ │ │ │ └── ProductReviewsByProductSearcher.ts │ │ │ │ ├── domain │ │ │ │ │ ├── ProductReview.ts │ │ │ │ │ ├── ProductReviewComment.ts │ │ │ │ │ ├── ProductReviewId.ts │ │ │ │ │ ├── ProductReviewRating.ts │ │ │ │ │ └── ProductReviewRepository.ts │ │ │ │ └── infrastructure │ │ │ │ │ └── MySqlProductReviewRepository.ts │ │ │ │ ├── products │ │ │ │ ├── application │ │ │ │ │ ├── search │ │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ │ └── search_all │ │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ │ ├── domain │ │ │ │ │ ├── Product.ts │ │ │ │ │ ├── ProductFeaturedReview.ts │ │ │ │ │ ├── ProductId.ts │ │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ │ ├── ProductName.ts │ │ │ │ │ ├── ProductRating.ts │ │ │ │ │ └── ProductRepository.ts │ │ │ │ └── infrastructure │ │ │ │ │ └── MySqlProductRepository.ts │ │ │ │ └── users │ │ │ │ ├── application │ │ │ │ ├── archive │ │ │ │ │ └── UserArchiver.ts │ │ │ │ ├── find │ │ │ │ │ └── UserFinder.ts │ │ │ │ ├── registrar │ │ │ │ │ └── UserRegistrar.ts │ │ │ │ ├── search │ │ │ │ │ └── UserSearcher.ts │ │ │ │ └── update_email │ │ │ │ │ └── UserEmailUpdater.ts │ │ │ │ ├── domain │ │ │ │ ├── User.ts │ │ │ │ ├── UserArchivedDomainEvent.ts │ │ │ │ ├── UserDoesNotExist.ts │ │ │ │ ├── UserEmail.ts │ │ │ │ ├── UserEmailUpdatedDomainEvent.ts │ │ │ │ ├── UserFinder.ts │ │ │ │ ├── UserId.ts │ │ │ │ ├── UserName.ts │ │ │ │ ├── UserProfilePicture.ts │ │ │ │ ├── UserRegisteredDomainEvent.ts │ │ │ │ ├── UserRepository.ts │ │ │ │ └── UserStatus.ts │ │ │ │ └── infrastructure │ │ │ │ └── MySqlUserRepository.ts │ │ ├── tailwind.config.ts │ │ ├── tests │ │ │ └── contexts │ │ │ │ ├── retention │ │ │ │ ├── email │ │ │ │ │ ├── application │ │ │ │ │ │ └── SendWelcomeEmailOnUserRegistered.test.ts │ │ │ │ │ ├── domain │ │ │ │ │ │ ├── EmailBodyMother.ts │ │ │ │ │ │ ├── EmailIdMother.ts │ │ │ │ │ │ ├── WelcomeEmailMother.ts │ │ │ │ │ │ └── WelcomeEmailSentDomainEventMother.ts │ │ │ │ │ └── infrastructure │ │ │ │ │ │ └── MockEmailSender.ts │ │ │ │ └── user │ │ │ │ │ ├── application │ │ │ │ │ └── update_last_activity_date │ │ │ │ │ │ └── UpdateLastActivityDateOnUserUpdated.test.ts │ │ │ │ │ ├── domain │ │ │ │ │ └── RetentionUserMother.ts │ │ │ │ │ └── infrastructure │ │ │ │ │ └── MockRetentionUserRepository.ts │ │ │ │ ├── shared │ │ │ │ ├── domain │ │ │ │ │ ├── EmailAddressMother.ts │ │ │ │ │ └── EnumMother.ts │ │ │ │ └── infrastructure │ │ │ │ │ ├── MockEventBus.ts │ │ │ │ │ └── MockUuidGenerator.ts │ │ │ │ └── shop │ │ │ │ └── users │ │ │ │ ├── application │ │ │ │ ├── archive │ │ │ │ │ └── UserArchiver.test.ts │ │ │ │ ├── registrar │ │ │ │ │ └── UserRegistrar.test.ts │ │ │ │ └── update_email │ │ │ │ │ └── UserEmailUpdater.test.ts │ │ │ │ ├── domain │ │ │ │ ├── DateMother.ts │ │ │ │ ├── UserArchivedDomainEventMother.ts │ │ │ │ ├── UserEmailMother.ts │ │ │ │ ├── UserEmailUpdatedDomainEventMother.ts │ │ │ │ ├── UserIdMother.ts │ │ │ │ ├── UserMother.ts │ │ │ │ ├── UserNameMother.ts │ │ │ │ ├── UserProfilePictureMother.ts │ │ │ │ └── UserRegisteredDomainEventMother.ts │ │ │ │ └── infrastructure │ │ │ │ └── MockUserRepository.ts │ │ └── tsconfig.json │ └── 2-publish_only_external │ │ ├── .editorconfig │ │ ├── .eslintrc.json │ │ ├── .gitignore │ │ ├── Makefile │ │ ├── README.md │ │ ├── databases │ │ └── ecommerce.sql │ │ ├── docker-compose.yml │ │ ├── etc │ │ └── http │ │ │ ├── seller_backoffice │ │ │ ├── product-GET.http │ │ │ ├── product-PUT.http │ │ │ └── products-GET.http │ │ │ └── shop │ │ │ ├── product-GET.http │ │ │ ├── product_review-PUT.http │ │ │ ├── product_reviews-GET.http │ │ │ ├── products-GET.http │ │ │ ├── user-GET.http │ │ │ └── user-PUT.http │ │ ├── jest.config.js │ │ ├── next.config.js │ │ ├── package-lock.json │ │ ├── package.json │ │ ├── postcss.config.js │ │ ├── public │ │ └── codely.svg │ │ ├── src │ │ ├── app │ │ │ └── api │ │ │ │ ├── seller_backoffice │ │ │ │ └── products │ │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ │ └── route.ts │ │ │ │ └── shop │ │ │ │ ├── product_reviews │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ │ ├── products │ │ │ │ ├── [id] │ │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ │ └── users │ │ │ │ └── [id] │ │ │ │ └── route.ts │ │ └── contexts │ │ │ ├── retention │ │ │ ├── email │ │ │ │ ├── application │ │ │ │ │ └── send_welcome_email │ │ │ │ │ │ ├── SendWelcomeEmailOnUserRegistered.ts │ │ │ │ │ │ └── WelcomeEmailSender.ts │ │ │ │ └── domain │ │ │ │ │ ├── Email.ts │ │ │ │ │ ├── EmailBody.ts │ │ │ │ │ ├── EmailId.ts │ │ │ │ │ ├── EmailSender.ts │ │ │ │ │ ├── WelcomeEmail.ts │ │ │ │ │ └── WelcomeEmailSentDomainEvent.ts │ │ │ └── user │ │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── .gitkeep │ │ │ │ └── update_last_activity_date │ │ │ │ │ ├── UpdateLastActivityDateOnUserUpdated.ts │ │ │ │ │ └── UserLastActivityUpdater.ts │ │ │ │ └── domain │ │ │ │ ├── RetentionUser.ts │ │ │ │ └── RetentionUserRepository.ts │ │ │ ├── seller_backoffice │ │ │ └── products │ │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── ProductCreator.ts │ │ │ │ ├── search │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ └── search_all │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ │ ├── domain │ │ │ │ ├── Product.ts │ │ │ │ ├── ProductId.ts │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ ├── ProductName.ts │ │ │ │ ├── ProductRepository.ts │ │ │ │ └── ProductViews.ts │ │ │ │ └── infrastructure │ │ │ │ └── MySqlProductRepository.ts │ │ │ ├── shared │ │ │ ├── application │ │ │ │ └── publish_external_domain_event │ │ │ │ │ ├── ExternalDomainEventPublisher.ts │ │ │ │ │ └── PublishExternalDomainEventOnDomainEventPublished.ts │ │ │ ├── domain │ │ │ │ ├── AggregateRoot.ts │ │ │ │ ├── Collection.ts │ │ │ │ ├── DomainEvent.ts │ │ │ │ ├── DomainEventName.ts │ │ │ │ ├── DomainEventSubscriber.ts │ │ │ │ ├── EmailAddress.ts │ │ │ │ ├── ExternalEventBus.ts │ │ │ │ ├── Identifier.ts │ │ │ │ ├── InternalEventBus.ts │ │ │ │ ├── Money.ts │ │ │ │ ├── StringValueObject.ts │ │ │ │ └── UuidGenerator.ts │ │ │ └── infrastructure │ │ │ │ └── MariaDBConnection.ts │ │ │ └── shop │ │ │ ├── product_reviews │ │ │ ├── application │ │ │ │ ├── create │ │ │ │ │ └── ProductReviewCreator.ts │ │ │ │ └── search_by_product_id │ │ │ │ │ └── ProductReviewsByProductSearcher.ts │ │ │ ├── domain │ │ │ │ ├── ProductReview.ts │ │ │ │ ├── ProductReviewComment.ts │ │ │ │ ├── ProductReviewId.ts │ │ │ │ ├── ProductReviewRating.ts │ │ │ │ └── ProductReviewRepository.ts │ │ │ └── infrastructure │ │ │ │ └── MySqlProductReviewRepository.ts │ │ │ ├── products │ │ │ ├── application │ │ │ │ ├── search │ │ │ │ │ └── ProductSearcher.ts │ │ │ │ └── search_all │ │ │ │ │ └── AllProductsSearcher.ts │ │ │ ├── domain │ │ │ │ ├── Product.ts │ │ │ │ ├── ProductFeaturedReview.ts │ │ │ │ ├── ProductId.ts │ │ │ │ ├── ProductImageUrl.ts │ │ │ │ ├── ProductImageUrls.ts │ │ │ │ ├── ProductName.ts │ │ │ │ ├── ProductRating.ts │ │ │ │ └── ProductRepository.ts │ │ │ └── infrastructure │ │ │ │ └── MySqlProductRepository.ts │ │ │ └── users │ │ │ ├── application │ │ │ ├── archive │ │ │ │ └── UserArchiver.ts │ │ │ ├── find │ │ │ │ └── UserFinder.ts │ │ │ ├── registrar │ │ │ │ └── UserRegistrar.ts │ │ │ ├── search │ │ │ │ └── UserSearcher.ts │ │ │ └── update_email │ │ │ │ └── UserEmailUpdater.ts │ │ │ ├── domain │ │ │ ├── User.ts │ │ │ ├── UserArchivedDomainEvent.ts │ │ │ ├── UserDoesNotExist.ts │ │ │ ├── UserEmail.ts │ │ │ ├── UserEmailUpdatedDomainEvent.ts │ │ │ ├── UserFinder.ts │ │ │ ├── UserId.ts │ │ │ ├── UserName.ts │ │ │ ├── UserProfilePicture.ts │ │ │ ├── UserRegisteredDomainEvent.ts │ │ │ ├── UserRepository.ts │ │ │ └── UserStatus.ts │ │ │ └── infrastructure │ │ │ └── MySqlUserRepository.ts │ │ ├── tailwind.config.ts │ │ ├── tests │ │ └── contexts │ │ │ ├── retention │ │ │ ├── email │ │ │ │ ├── application │ │ │ │ │ └── SendWelcomeEmailOnUserRegistered.test.ts │ │ │ │ ├── domain │ │ │ │ │ ├── EmailBodyMother.ts │ │ │ │ │ ├── EmailIdMother.ts │ │ │ │ │ ├── WelcomeEmailMother.ts │ │ │ │ │ └── WelcomeEmailSentDomainEventMother.ts │ │ │ │ └── infrastructure │ │ │ │ │ └── MockEmailSender.ts │ │ │ └── user │ │ │ │ ├── application │ │ │ │ └── update_last_activity_date │ │ │ │ │ └── UpdateLastActivityDateOnUserUpdated.test.ts │ │ │ │ ├── domain │ │ │ │ └── RetentionUserMother.ts │ │ │ │ └── infrastructure │ │ │ │ └── MockRetentionUserRepository.ts │ │ │ ├── shared │ │ │ ├── domain │ │ │ │ ├── EmailAddressMother.ts │ │ │ │ └── EnumMother.ts │ │ │ └── infrastructure │ │ │ │ ├── MockEventBus.ts │ │ │ │ └── MockUuidGenerator.ts │ │ │ └── shop │ │ │ └── users │ │ │ ├── application │ │ │ ├── archive │ │ │ │ └── UserArchiver.test.ts │ │ │ ├── registrar │ │ │ │ └── UserRegistrar.test.ts │ │ │ └── update_email │ │ │ │ └── UserEmailUpdater.test.ts │ │ │ ├── domain │ │ │ ├── DateMother.ts │ │ │ ├── UserArchivedDomainEventMother.ts │ │ │ ├── UserEmailMother.ts │ │ │ ├── UserEmailUpdatedDomainEventMother.ts │ │ │ ├── UserIdMother.ts │ │ │ ├── UserMother.ts │ │ │ ├── UserNameMother.ts │ │ │ ├── UserProfilePictureMother.ts │ │ │ └── UserRegisteredDomainEventMother.ts │ │ │ └── infrastructure │ │ │ └── MockUserRepository.ts │ │ └── tsconfig.json └── 2-enrich_domain_events │ ├── .editorconfig │ ├── .eslintrc.json │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── databases │ └── ecommerce.sql │ ├── docker-compose.yml │ ├── etc │ └── http │ │ ├── seller_backoffice │ │ ├── product-GET.http │ │ ├── product-PUT.http │ │ └── products-GET.http │ │ └── shop │ │ ├── product-GET.http │ │ ├── product_review-PUT.http │ │ ├── product_reviews-GET.http │ │ ├── products-GET.http │ │ ├── user-GET.http │ │ └── user-PUT.http │ ├── jest.config.js │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── public │ └── codely.svg │ ├── src │ ├── app │ │ └── api │ │ │ ├── seller_backoffice │ │ │ └── products │ │ │ │ ├── [id] │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ └── shop │ │ │ ├── product_reviews │ │ │ ├── [id] │ │ │ │ └── route.ts │ │ │ └── route.ts │ │ │ ├── products │ │ │ ├── [id] │ │ │ │ └── route.ts │ │ │ └── route.ts │ │ │ └── users │ │ │ └── [id] │ │ │ └── route.ts │ └── contexts │ │ ├── retention │ │ ├── email │ │ │ ├── application │ │ │ │ └── send_welcome_email │ │ │ │ │ ├── SendWelcomeEmailOnUserRegistered.ts │ │ │ │ │ └── WelcomeEmailSender.ts │ │ │ └── domain │ │ │ │ ├── Email.ts │ │ │ │ ├── EmailBody.ts │ │ │ │ ├── EmailId.ts │ │ │ │ ├── EmailSender.ts │ │ │ │ ├── WelcomeEmail.ts │ │ │ │ └── WelcomeEmailSentDomainEvent.ts │ │ └── user │ │ │ ├── application │ │ │ ├── create │ │ │ │ └── .gitkeep │ │ │ └── update_last_activity_date │ │ │ │ ├── UpdateLastActivityDateOnUserUpdated.ts │ │ │ │ └── UserLastActivityUpdater.ts │ │ │ └── domain │ │ │ ├── RetentionUser.ts │ │ │ └── RetentionUserRepository.ts │ │ ├── seller_backoffice │ │ └── products │ │ │ ├── application │ │ │ ├── create │ │ │ │ └── ProductCreator.ts │ │ │ ├── search │ │ │ │ └── ProductSearcher.ts │ │ │ └── search_all │ │ │ │ └── AllProductsSearcher.ts │ │ │ ├── domain │ │ │ ├── Product.ts │ │ │ ├── ProductId.ts │ │ │ ├── ProductImageUrl.ts │ │ │ ├── ProductImageUrls.ts │ │ │ ├── ProductName.ts │ │ │ ├── ProductRepository.ts │ │ │ └── ProductViews.ts │ │ │ └── infrastructure │ │ │ └── MySqlProductRepository.ts │ │ ├── shared │ │ ├── domain │ │ │ ├── AggregateRoot.ts │ │ │ ├── Collection.ts │ │ │ ├── DomainEvent.ts │ │ │ ├── DomainEventName.ts │ │ │ ├── DomainEventSubscriber.ts │ │ │ ├── EmailAddress.ts │ │ │ ├── EventBus.ts │ │ │ ├── Identifier.ts │ │ │ ├── Money.ts │ │ │ ├── StringValueObject.ts │ │ │ ├── UuidGenerator.ts │ │ │ └── shop │ │ │ │ └── users │ │ │ │ └── UserEmailUpdatedDomainEvent.ts │ │ └── infrastructure │ │ │ └── MariaDBConnection.ts │ │ └── shop │ │ ├── product_reviews │ │ ├── application │ │ │ ├── create │ │ │ │ └── ProductReviewCreator.ts │ │ │ └── search_by_product_id │ │ │ │ └── ProductReviewsByProductSearcher.ts │ │ ├── domain │ │ │ ├── ProductReview.ts │ │ │ ├── ProductReviewComment.ts │ │ │ ├── ProductReviewId.ts │ │ │ ├── ProductReviewRating.ts │ │ │ └── ProductReviewRepository.ts │ │ └── infrastructure │ │ │ └── MySqlProductReviewRepository.ts │ │ ├── products │ │ ├── application │ │ │ ├── search │ │ │ │ └── ProductSearcher.ts │ │ │ └── search_all │ │ │ │ └── AllProductsSearcher.ts │ │ ├── domain │ │ │ ├── Product.ts │ │ │ ├── ProductFeaturedReview.ts │ │ │ ├── ProductId.ts │ │ │ ├── ProductImageUrl.ts │ │ │ ├── ProductImageUrls.ts │ │ │ ├── ProductName.ts │ │ │ ├── ProductRating.ts │ │ │ └── ProductRepository.ts │ │ └── infrastructure │ │ │ └── MySqlProductRepository.ts │ │ └── users │ │ ├── application │ │ ├── archive │ │ │ └── UserArchiver.ts │ │ ├── find │ │ │ └── UserFinder.ts │ │ ├── registrar │ │ │ └── UserRegistrar.ts │ │ ├── search │ │ │ └── UserSearcher.ts │ │ └── update_email │ │ │ └── UserEmailUpdater.ts │ │ ├── domain │ │ ├── User.ts │ │ ├── UserArchivedDomainEvent.ts │ │ ├── UserDoesNotExist.ts │ │ ├── UserEmail.ts │ │ ├── UserFinder.ts │ │ ├── UserId.ts │ │ ├── UserName.ts │ │ ├── UserProfilePicture.ts │ │ ├── UserRegisteredDomainEvent.ts │ │ ├── UserRepository.ts │ │ └── UserStatus.ts │ │ └── infrastructure │ │ └── MySqlUserRepository.ts │ ├── tailwind.config.ts │ ├── tests │ └── contexts │ │ ├── retention │ │ ├── email │ │ │ ├── application │ │ │ │ └── SendWelcomeEmailOnUserRegistered.test.ts │ │ │ ├── domain │ │ │ │ ├── EmailBodyMother.ts │ │ │ │ ├── EmailIdMother.ts │ │ │ │ ├── WelcomeEmailMother.ts │ │ │ │ └── WelcomeEmailSentDomainEventMother.ts │ │ │ └── infrastructure │ │ │ │ └── MockEmailSender.ts │ │ └── user │ │ │ ├── application │ │ │ └── update_last_activity_date │ │ │ │ └── UpdateLastActivityDateOnUserUpdated.test.ts │ │ │ ├── domain │ │ │ └── RetentionUserMother.ts │ │ │ └── infrastructure │ │ │ └── MockRetentionUserRepository.ts │ │ ├── shared │ │ ├── domain │ │ │ ├── EmailAddressMother.ts │ │ │ └── EnumMother.ts │ │ └── infrastructure │ │ │ ├── MockEventBus.ts │ │ │ └── MockUuidGenerator.ts │ │ └── shop │ │ └── users │ │ ├── application │ │ ├── archive │ │ │ └── UserArchiver.test.ts │ │ ├── registrar │ │ │ └── UserRegistrar.test.ts │ │ └── update_email │ │ │ └── UserEmailUpdater.test.ts │ │ ├── domain │ │ ├── DateMother.ts │ │ ├── UserArchivedDomainEventMother.ts │ │ ├── UserEmailMother.ts │ │ ├── UserEmailUpdatedDomainEventMother.ts │ │ ├── UserIdMother.ts │ │ ├── UserMother.ts │ │ ├── UserNameMother.ts │ │ ├── UserProfilePictureMother.ts │ │ └── UserRegisteredDomainEventMother.ts │ │ └── infrastructure │ │ └── MockUserRepository.ts │ └── tsconfig.json ├── 07-implement_event_bus └── 1-sync_event_bus │ ├── .editorconfig │ ├── .eslintrc.json │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── databases │ └── ecommerce.sql │ ├── docker-compose.yml │ ├── etc │ └── http │ │ ├── seller_backoffice │ │ ├── product-GET.http │ │ ├── product-PUT.http │ │ └── products-GET.http │ │ └── shop │ │ ├── product-GET.http │ │ ├── product_review-PUT.http │ │ ├── product_reviews-GET.http │ │ ├── products-GET.http │ │ ├── user-GET.http │ │ └── user-PUT.http │ ├── jest.config.js │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── public │ └── codely.svg │ ├── src │ ├── app │ │ └── api │ │ │ ├── seller_backoffice │ │ │ └── products │ │ │ │ ├── [id] │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ └── shop │ │ │ ├── product_reviews │ │ │ ├── [id] │ │ │ │ └── route.ts │ │ │ └── route.ts │ │ │ ├── products │ │ │ ├── [id] │ │ │ │ └── route.ts │ │ │ └── route.ts │ │ │ └── users │ │ │ └── [id] │ │ │ └── route.ts │ └── contexts │ │ ├── retention │ │ ├── email │ │ │ ├── application │ │ │ │ └── send_welcome_email │ │ │ │ │ ├── SendWelcomeEmailOnUserRegistered.ts │ │ │ │ │ └── WelcomeEmailSender.ts │ │ │ └── domain │ │ │ │ ├── Email.ts │ │ │ │ ├── EmailBody.ts │ │ │ │ ├── EmailId.ts │ │ │ │ ├── EmailSender.ts │ │ │ │ ├── WelcomeEmail.ts │ │ │ │ └── WelcomeEmailSentDomainEvent.ts │ │ └── user │ │ │ ├── application │ │ │ ├── create │ │ │ │ └── .gitkeep │ │ │ └── update_last_activity_date │ │ │ │ ├── UpdateLastActivityDateOnUserUpdated.ts │ │ │ │ └── UserLastActivityUpdater.ts │ │ │ └── domain │ │ │ ├── RetentionUser.ts │ │ │ └── RetentionUserRepository.ts │ │ ├── seller_backoffice │ │ └── products │ │ │ ├── application │ │ │ ├── create │ │ │ │ └── ProductCreator.ts │ │ │ ├── search │ │ │ │ └── ProductSearcher.ts │ │ │ └── search_all │ │ │ │ └── AllProductsSearcher.ts │ │ │ ├── domain │ │ │ ├── Product.ts │ │ │ ├── ProductId.ts │ │ │ ├── ProductImageUrl.ts │ │ │ ├── ProductImageUrls.ts │ │ │ ├── ProductName.ts │ │ │ ├── ProductRepository.ts │ │ │ └── ProductViews.ts │ │ │ └── infrastructure │ │ │ └── MySqlProductRepository.ts │ │ ├── shared │ │ ├── domain │ │ │ ├── AggregateRoot.ts │ │ │ ├── Collection.ts │ │ │ ├── EmailAddress.ts │ │ │ ├── Identifier.ts │ │ │ ├── Money.ts │ │ │ ├── StringValueObject.ts │ │ │ ├── UuidGenerator.ts │ │ │ └── event │ │ │ │ ├── DomainEvent.ts │ │ │ │ ├── DomainEventName.ts │ │ │ │ ├── DomainEventSubscriber.ts │ │ │ │ └── EventBus.ts │ │ └── infrastructure │ │ │ ├── MariaDBConnection.ts │ │ │ └── event │ │ │ └── InMemoryEventBus.ts │ │ └── shop │ │ ├── product_reviews │ │ ├── application │ │ │ ├── create │ │ │ │ └── ProductReviewCreator.ts │ │ │ └── search_by_product_id │ │ │ │ └── ProductReviewsByProductSearcher.ts │ │ ├── domain │ │ │ ├── ProductReview.ts │ │ │ ├── ProductReviewComment.ts │ │ │ ├── ProductReviewId.ts │ │ │ ├── ProductReviewRating.ts │ │ │ └── ProductReviewRepository.ts │ │ └── infrastructure │ │ │ └── MySqlProductReviewRepository.ts │ │ ├── products │ │ ├── application │ │ │ ├── search │ │ │ │ └── ProductSearcher.ts │ │ │ └── search_all │ │ │ │ └── AllProductsSearcher.ts │ │ ├── domain │ │ │ ├── Product.ts │ │ │ ├── ProductFeaturedReview.ts │ │ │ ├── ProductId.ts │ │ │ ├── ProductImageUrl.ts │ │ │ ├── ProductImageUrls.ts │ │ │ ├── ProductName.ts │ │ │ ├── ProductRating.ts │ │ │ └── ProductRepository.ts │ │ └── infrastructure │ │ │ └── MySqlProductRepository.ts │ │ └── users │ │ ├── application │ │ ├── archive │ │ │ └── UserArchiver.ts │ │ ├── find │ │ │ └── UserFinder.ts │ │ ├── registrar │ │ │ └── UserRegistrar.ts │ │ ├── search │ │ │ └── UserSearcher.ts │ │ └── update_email │ │ │ └── UserEmailUpdater.ts │ │ ├── domain │ │ ├── User.ts │ │ ├── UserArchivedDomainEvent.ts │ │ ├── UserDoesNotExist.ts │ │ ├── UserEmail.ts │ │ ├── UserEmailUpdatedDomainEvent.ts │ │ ├── UserFinder.ts │ │ ├── UserId.ts │ │ ├── UserName.ts │ │ ├── UserProfilePicture.ts │ │ ├── UserRegisteredDomainEvent.ts │ │ ├── UserRepository.ts │ │ └── UserStatus.ts │ │ └── infrastructure │ │ └── MySqlUserRepository.ts │ ├── tailwind.config.ts │ ├── tests │ └── contexts │ │ ├── retention │ │ ├── email │ │ │ ├── application │ │ │ │ └── SendWelcomeEmailOnUserRegistered.test.ts │ │ │ ├── domain │ │ │ │ ├── EmailBodyMother.ts │ │ │ │ ├── EmailIdMother.ts │ │ │ │ ├── WelcomeEmailMother.ts │ │ │ │ └── WelcomeEmailSentDomainEventMother.ts │ │ │ └── infrastructure │ │ │ │ └── MockEmailSender.ts │ │ └── user │ │ │ ├── application │ │ │ └── update_last_activity_date │ │ │ │ └── UpdateLastActivityDateOnUserUpdated.test.ts │ │ │ ├── domain │ │ │ └── RetentionUserMother.ts │ │ │ └── infrastructure │ │ │ └── MockRetentionUserRepository.ts │ │ ├── shared │ │ ├── domain │ │ │ ├── EmailAddressMother.ts │ │ │ └── EnumMother.ts │ │ └── infrastructure │ │ │ ├── MockEventBus.ts │ │ │ └── MockUuidGenerator.ts │ │ └── shop │ │ └── users │ │ ├── application │ │ ├── archive │ │ │ └── UserArchiver.test.ts │ │ ├── registrar │ │ │ └── UserRegistrar.test.ts │ │ └── update_email │ │ │ └── UserEmailUpdater.test.ts │ │ ├── domain │ │ ├── DateMother.ts │ │ ├── UserArchivedDomainEventMother.ts │ │ ├── UserEmailMother.ts │ │ ├── UserEmailUpdatedDomainEventMother.ts │ │ ├── UserIdMother.ts │ │ ├── UserMother.ts │ │ ├── UserNameMother.ts │ │ ├── UserProfilePictureMother.ts │ │ └── UserRegisteredDomainEventMother.ts │ │ └── infrastructure │ │ └── MockUserRepository.ts │ └── tsconfig.json ├── 08-add_domain_events_to_legacy └── 2-add_event_bus │ └── 1-without_events │ ├── .editorconfig │ ├── .eslintrc.json │ ├── .gitignore │ ├── Makefile │ ├── README.md │ ├── databases │ └── ecommerce.sql │ ├── docker-compose.yml │ ├── etc │ └── http │ │ ├── seller_backoffice │ │ ├── product-GET.http │ │ ├── product-PUT.http │ │ └── products-GET.http │ │ └── shop │ │ ├── product-GET.http │ │ ├── product_review-PUT.http │ │ ├── product_reviews-GET.http │ │ ├── products-GET.http │ │ ├── user-GET.http │ │ └── user-PUT.http │ ├── jest.config.js │ ├── next.config.js │ ├── package-lock.json │ ├── package.json │ ├── postcss.config.js │ ├── public │ └── codely.svg │ ├── src │ ├── app │ │ └── api │ │ │ ├── seller_backoffice │ │ │ └── products │ │ │ │ ├── [id] │ │ │ │ └── route.ts │ │ │ │ └── route.ts │ │ │ └── shop │ │ │ ├── product_reviews │ │ │ ├── [id] │ │ │ │ └── route.ts │ │ │ └── route.ts │ │ │ ├── products │ │ │ ├── [id] │ │ │ │ └── route.ts │ │ │ └── route.ts │ │ │ └── users │ │ │ └── [id] │ │ │ └── route.ts │ └── contexts │ │ ├── retention │ │ ├── email │ │ │ ├── application │ │ │ │ └── send_welcome_email │ │ │ │ │ └── WelcomeEmailSender.ts │ │ │ └── domain │ │ │ │ ├── Email.ts │ │ │ │ ├── EmailBody.ts │ │ │ │ ├── EmailId.ts │ │ │ │ ├── EmailSender.ts │ │ │ │ ├── WelcomeEmail.ts │ │ │ │ └── WelcomeEmailSentDomainEvent.ts │ │ └── user │ │ │ ├── application │ │ │ ├── create │ │ │ │ └── .gitkeep │ │ │ └── update_last_activity_date │ │ │ │ ├── UpdateLastActivityDateOnUserUpdated.ts │ │ │ │ └── UserLastActivityUpdater.ts │ │ │ └── domain │ │ │ ├── RetentionUser.ts │ │ │ └── RetentionUserRepository.ts │ │ ├── seller_backoffice │ │ └── products │ │ │ ├── application │ │ │ ├── create │ │ │ │ └── ProductCreator.ts │ │ │ ├── search │ │ │ │ └── ProductSearcher.ts │ │ │ └── search_all │ │ │ │ └── AllProductsSearcher.ts │ │ │ ├── domain │ │ │ ├── Product.ts │ │ │ ├── ProductId.ts │ │ │ ├── ProductImageUrl.ts │ │ │ ├── ProductImageUrls.ts │ │ │ ├── ProductName.ts │ │ │ ├── ProductRepository.ts │ │ │ └── ProductViews.ts │ │ │ └── infrastructure │ │ │ └── MySqlProductRepository.ts │ │ ├── shared │ │ ├── domain │ │ │ ├── AggregateRoot.ts │ │ │ ├── Collection.ts │ │ │ ├── EmailAddress.ts │ │ │ ├── Identifier.ts │ │ │ ├── Money.ts │ │ │ ├── StringValueObject.ts │ │ │ ├── UuidGenerator.ts │ │ │ └── event │ │ │ │ ├── DomainEvent.ts │ │ │ │ ├── DomainEventName.ts │ │ │ │ ├── DomainEventSubscriber.ts │ │ │ │ └── EventBus.ts │ │ └── infrastructure │ │ │ ├── MariaDBConnection.ts │ │ │ └── event │ │ │ └── InMemoryEventBus.ts │ │ └── shop │ │ ├── product_reviews │ │ ├── application │ │ │ ├── create │ │ │ │ └── ProductReviewCreator.ts │ │ │ └── search_by_product_id │ │ │ │ └── ProductReviewsByProductSearcher.ts │ │ ├── domain │ │ │ ├── ProductReview.ts │ │ │ ├── ProductReviewComment.ts │ │ │ ├── ProductReviewId.ts │ │ │ ├── ProductReviewRating.ts │ │ │ └── ProductReviewRepository.ts │ │ └── infrastructure │ │ │ └── MySqlProductReviewRepository.ts │ │ ├── products │ │ ├── application │ │ │ ├── search │ │ │ │ └── ProductSearcher.ts │ │ │ └── search_all │ │ │ │ └── AllProductsSearcher.ts │ │ ├── domain │ │ │ ├── Product.ts │ │ │ ├── ProductFeaturedReview.ts │ │ │ ├── ProductId.ts │ │ │ ├── ProductImageUrl.ts │ │ │ ├── ProductImageUrls.ts │ │ │ ├── ProductName.ts │ │ │ ├── ProductRating.ts │ │ │ └── ProductRepository.ts │ │ └── infrastructure │ │ │ └── MySqlProductRepository.ts │ │ └── users │ │ ├── application │ │ ├── archive │ │ │ └── UserArchiver.ts │ │ ├── find │ │ │ └── UserFinder.ts │ │ ├── registrar │ │ │ └── UserRegistrar.ts │ │ ├── search │ │ │ └── UserSearcher.ts │ │ └── update_email │ │ │ └── UserEmailUpdater.ts │ │ ├── domain │ │ ├── User.ts │ │ ├── UserArchivedDomainEvent.ts │ │ ├── UserDoesNotExist.ts │ │ ├── UserEmail.ts │ │ ├── UserEmailUpdatedDomainEvent.ts │ │ ├── UserFinder.ts │ │ ├── UserId.ts │ │ ├── UserName.ts │ │ ├── UserProfilePicture.ts │ │ ├── UserRegisteredDomainEvent.ts │ │ ├── UserRepository.ts │ │ └── UserStatus.ts │ │ └── infrastructure │ │ └── MySqlUserRepository.ts │ ├── tailwind.config.ts │ ├── tests │ └── contexts │ │ ├── retention │ │ ├── email │ │ │ ├── domain │ │ │ │ ├── EmailBodyMother.ts │ │ │ │ ├── EmailIdMother.ts │ │ │ │ ├── WelcomeEmailMother.ts │ │ │ │ └── WelcomeEmailSentDomainEventMother.ts │ │ │ └── infrastructure │ │ │ │ └── MockEmailSender.ts │ │ └── user │ │ │ ├── application │ │ │ └── update_last_activity_date │ │ │ │ └── UpdateLastActivityDateOnUserUpdated.test.ts │ │ │ ├── domain │ │ │ └── RetentionUserMother.ts │ │ │ └── infrastructure │ │ │ └── MockRetentionUserRepository.ts │ │ ├── shared │ │ ├── domain │ │ │ ├── EmailAddressMother.ts │ │ │ └── EnumMother.ts │ │ └── infrastructure │ │ │ ├── MockEventBus.ts │ │ │ └── MockUuidGenerator.ts │ │ └── shop │ │ └── users │ │ ├── application │ │ ├── archive │ │ │ └── UserArchiver.test.ts │ │ ├── registrar │ │ │ └── UserRegistrar.test.ts │ │ └── update_email │ │ │ └── UserEmailUpdater.test.ts │ │ ├── domain │ │ ├── DateMother.ts │ │ ├── UserArchivedDomainEventMother.ts │ │ ├── UserEmailMother.ts │ │ ├── UserEmailUpdatedDomainEventMother.ts │ │ ├── UserIdMother.ts │ │ ├── UserMother.ts │ │ ├── UserNameMother.ts │ │ ├── UserProfilePictureMother.ts │ │ └── UserRegisteredDomainEventMother.ts │ │ └── infrastructure │ │ └── MockUserRepository.ts │ └── tsconfig.json ├── 09-change_data_capture └── 2-add_change_data_capture │ ├── .env │ ├── .github │ ├── FUNDING.yml │ └── workflows │ │ ├── ci.yml │ │ └── labeler.yml │ ├── .gitignore │ ├── Dockerfile │ ├── Makefile │ ├── README.md │ ├── apps │ ├── backoffice │ │ ├── backend │ │ │ ├── bin │ │ │ │ └── console │ │ │ ├── config │ │ │ │ ├── bundles.php │ │ │ │ ├── routes │ │ │ │ │ ├── courses.yaml │ │ │ │ │ ├── health-check.yaml │ │ │ │ │ └── metrics.yaml │ │ │ │ ├── services.yaml │ │ │ │ ├── services │ │ │ │ │ └── framework.yaml │ │ │ │ └── services_test.yaml │ │ │ ├── public │ │ │ │ └── index.php │ │ │ └── src │ │ │ │ ├── BackofficeBackendKernel.php │ │ │ │ └── Controller │ │ │ │ ├── Courses │ │ │ │ └── CoursesGetController.php │ │ │ │ ├── HealthCheck │ │ │ │ └── HealthCheckGetController.php │ │ │ │ └── Metrics │ │ │ │ └── MetricsController.php │ │ └── frontend │ │ │ ├── bin │ │ │ └── console │ │ │ ├── config │ │ │ ├── bundles.php │ │ │ ├── routes │ │ │ │ ├── api_courses.yaml │ │ │ │ ├── courses.yaml │ │ │ │ ├── health-check.yaml │ │ │ │ ├── home.yaml │ │ │ │ └── metrics.yaml │ │ │ ├── services.yaml │ │ │ ├── services │ │ │ │ └── framework.yaml │ │ │ └── services_test.yaml │ │ │ ├── public │ │ │ ├── images │ │ │ │ └── logo.png │ │ │ └── index.php │ │ │ ├── src │ │ │ ├── BackofficeFrontendKernel.php │ │ │ ├── Command │ │ │ │ └── ImportCoursesToElasticsearchCommand.php │ │ │ └── Controller │ │ │ │ ├── Courses │ │ │ │ ├── CoursesGetWebController.php │ │ │ │ └── CoursesPostWebController.php │ │ │ │ ├── HealthCheck │ │ │ │ └── HealthCheckGetController.php │ │ │ │ ├── Home │ │ │ │ └── HomeGetWebController.php │ │ │ │ └── Metrics │ │ │ │ └── MetricsController.php │ │ │ └── templates │ │ │ ├── master.html.twig │ │ │ ├── pages │ │ │ ├── courses │ │ │ │ ├── courses.html.twig │ │ │ │ └── partials │ │ │ │ │ ├── list_courses.html.twig │ │ │ │ │ └── new_course_form.html.twig │ │ │ └── home.html.twig │ │ │ └── partials │ │ │ ├── footer.html.twig │ │ │ └── header.html.twig │ ├── bootstrap.php │ └── mooc │ │ ├── backend │ │ ├── bin │ │ │ └── console │ │ ├── config │ │ │ ├── bundles.php │ │ │ ├── routes │ │ │ │ ├── courses.yaml │ │ │ │ ├── courses_counter.yaml │ │ │ │ ├── health-check.yaml │ │ │ │ └── metrics.yaml │ │ │ ├── services.yaml │ │ │ ├── services │ │ │ │ └── framework.yaml │ │ │ └── services_test.yaml │ │ ├── public │ │ │ └── index.php │ │ ├── src │ │ │ ├── Command │ │ │ │ └── DomainEvents │ │ │ │ │ ├── MySql │ │ │ │ │ └── ConsumeMySqlDomainEventsCommand.php │ │ │ │ │ ├── PublishDomainEventsFromMutationsCommand.php │ │ │ │ │ └── RabbitMq │ │ │ │ │ ├── ConfigureRabbitMqCommand.php │ │ │ │ │ ├── ConsumeRabbitMqDomainEventsCommand.php │ │ │ │ │ └── GenerateSupervisorRabbitMqConsumerFilesCommand.php │ │ │ ├── Controller │ │ │ │ ├── Courses │ │ │ │ │ └── CoursesPutController.php │ │ │ │ ├── CoursesCounter │ │ │ │ │ └── CoursesCounterGetController.php │ │ │ │ ├── HealthCheck │ │ │ │ │ └── HealthCheckGetController.php │ │ │ │ └── Metrics │ │ │ │ │ └── MetricsController.php │ │ │ └── MoocBackendKernel.php │ │ └── tests │ │ │ ├── features │ │ │ ├── courses │ │ │ │ └── course_put.feature │ │ │ ├── courses_counter │ │ │ │ └── courses_counter_get.feature │ │ │ └── health_check │ │ │ │ └── health_check_get.feature │ │ │ └── mooc_backend.yml │ │ └── frontend │ │ └── src │ │ └── .gitkeep │ ├── behat.yml │ ├── composer.json │ ├── composer.lock │ ├── docker-compose.yml │ ├── ecs.php │ ├── etc │ ├── databases │ │ ├── backoffice │ │ │ └── courses.json │ │ └── mooc.sql │ ├── endpoints │ │ ├── backoffice_frontend.http │ │ └── mooc_backend.http │ ├── infrastructure │ │ └── php │ │ │ ├── conf.d │ │ │ ├── apcu.ini │ │ │ ├── opcache.ini │ │ │ └── xdebug.ini │ │ │ └── php.ini │ └── prometheus │ │ └── prometheus.yml │ ├── phpmd.xml │ ├── phpstan.neon │ ├── phpunit.xml │ ├── psalm.xml │ ├── rector.php │ ├── src │ ├── Analytics │ │ └── DomainEvents │ │ │ ├── Application │ │ │ └── Store │ │ │ │ ├── DomainEventStorer.php │ │ │ │ └── StoreDomainEventOnOccurred.php │ │ │ └── Domain │ │ │ ├── AnalyticsDomainEvent.php │ │ │ ├── AnalyticsDomainEventAggregateId.php │ │ │ ├── AnalyticsDomainEventBody.php │ │ │ ├── AnalyticsDomainEventId.php │ │ │ ├── AnalyticsDomainEventName.php │ │ │ └── DomainEventsRepository.php │ ├── Backoffice │ │ ├── Auth │ │ │ ├── Application │ │ │ │ └── Authenticate │ │ │ │ │ ├── AuthenticateUserCommand.php │ │ │ │ │ ├── AuthenticateUserCommandHandler.php │ │ │ │ │ └── UserAuthenticator.php │ │ │ ├── Domain │ │ │ │ ├── AuthPassword.php │ │ │ │ ├── AuthRepository.php │ │ │ │ ├── AuthUser.php │ │ │ │ ├── AuthUsername.php │ │ │ │ ├── InvalidAuthCredentials.php │ │ │ │ └── InvalidAuthUsername.php │ │ │ └── Infrastructure │ │ │ │ └── Persistence │ │ │ │ └── InMemoryAuthRepository.php │ │ ├── Courses │ │ │ ├── Application │ │ │ │ ├── BackofficeCourseResponse.php │ │ │ │ ├── BackofficeCoursesResponse.php │ │ │ │ ├── Create │ │ │ │ │ ├── BackofficeCourseCreator.php │ │ │ │ │ └── CreateBackofficeCourseOnCourseCreated.php │ │ │ │ ├── SearchAll │ │ │ │ │ ├── AllBackofficeCoursesSearcher.php │ │ │ │ │ ├── SearchAllBackofficeCoursesQuery.php │ │ │ │ │ └── SearchAllBackofficeCoursesQueryHandler.php │ │ │ │ └── SearchByCriteria │ │ │ │ │ ├── BackofficeCoursesByCriteriaSearcher.php │ │ │ │ │ ├── SearchBackofficeCoursesByCriteriaQuery.php │ │ │ │ │ └── SearchBackofficeCoursesByCriteriaQueryHandler.php │ │ │ ├── Domain │ │ │ │ ├── BackofficeCourse.php │ │ │ │ └── BackofficeCourseRepository.php │ │ │ └── Infrastructure │ │ │ │ └── Persistence │ │ │ │ ├── Doctrine │ │ │ │ └── BackofficeCourse.orm.xml │ │ │ │ ├── ElasticsearchBackofficeCourseRepository.php │ │ │ │ ├── InMemoryCacheBackofficeCourseRepository.php │ │ │ │ └── MySqlBackofficeCourseRepository.php │ │ └── Shared │ │ │ └── Infrastructure │ │ │ └── Symfony │ │ │ └── DependencyInjection │ │ │ └── backoffice_services.yaml │ ├── Mooc │ │ ├── Courses │ │ │ ├── Application │ │ │ │ ├── Create │ │ │ │ │ ├── CourseCreator.php │ │ │ │ │ ├── CreateCourseCommand.php │ │ │ │ │ └── CreateCourseCommandHandler.php │ │ │ │ ├── Find │ │ │ │ │ └── CourseFinder.php │ │ │ │ └── Update │ │ │ │ │ └── CourseRenamer.php │ │ │ ├── Domain │ │ │ │ ├── Course.php │ │ │ │ ├── CourseCreatedDomainEvent.php │ │ │ │ ├── CourseDuration.php │ │ │ │ ├── CourseName.php │ │ │ │ ├── CourseNotExist.php │ │ │ │ └── CourseRepository.php │ │ │ └── Infrastructure │ │ │ │ ├── Cdc │ │ │ │ └── DatabaseMutationToCourseCreatedDomainEvent.php │ │ │ │ └── Persistence │ │ │ │ ├── Doctrine │ │ │ │ ├── Course.orm.xml │ │ │ │ ├── CourseDuration.orm.xml │ │ │ │ ├── CourseIdType.php │ │ │ │ └── CourseName.orm.xml │ │ │ │ ├── DoctrineCourseRepository.php │ │ │ │ └── FileCourseRepository.php │ │ ├── CoursesCounter │ │ │ ├── Application │ │ │ │ ├── Find │ │ │ │ │ ├── CoursesCounterFinder.php │ │ │ │ │ ├── CoursesCounterResponse.php │ │ │ │ │ ├── FindCoursesCounterQuery.php │ │ │ │ │ └── FindCoursesCounterQueryHandler.php │ │ │ │ └── Increment │ │ │ │ │ ├── CoursesCounterIncrementer.php │ │ │ │ │ └── IncrementCoursesCounterOnCourseCreated.php │ │ │ ├── Domain │ │ │ │ ├── CoursesCounter.php │ │ │ │ ├── CoursesCounterId.php │ │ │ │ ├── CoursesCounterIncrementedDomainEvent.php │ │ │ │ ├── CoursesCounterNotExist.php │ │ │ │ ├── CoursesCounterRepository.php │ │ │ │ └── CoursesCounterTotal.php │ │ │ └── Infrastructure │ │ │ │ └── Persistence │ │ │ │ ├── Doctrine │ │ │ │ ├── CourseCounterIdType.php │ │ │ │ ├── CourseIdsType.php │ │ │ │ ├── CoursesCounter.orm.xml │ │ │ │ └── CoursesCounterTotal.orm.xml │ │ │ │ └── DoctrineCoursesCounterRepository.php │ │ ├── Notifications │ │ │ └── Application │ │ │ │ ├── SendNewCommentReplyEmail │ │ │ │ └── .gitkeep │ │ │ │ ├── SendNewCommentReplyPush │ │ │ │ └── .gitkeep │ │ │ │ └── SendResetPasswordEmail │ │ │ │ └── .gitkeep │ │ ├── Shared │ │ │ ├── Domain │ │ │ │ ├── Courses │ │ │ │ │ └── CourseId.php │ │ │ │ └── Videos │ │ │ │ │ └── VideoUrl.php │ │ │ └── Infrastructure │ │ │ │ ├── Doctrine │ │ │ │ ├── DbalTypesSearcher.php │ │ │ │ ├── DoctrinePrefixesSearcher.php │ │ │ │ └── MoocEntityManagerFactory.php │ │ │ │ └── Symfony │ │ │ │ └── DependencyInjection │ │ │ │ └── mooc_services.yaml │ │ └── Videos │ │ │ ├── Application │ │ │ ├── Create │ │ │ │ ├── CreateVideoCommand.php │ │ │ │ ├── CreateVideoCommandHandler.php │ │ │ │ └── VideoCreator.php │ │ │ ├── Find │ │ │ │ ├── FindVideoQuery.php │ │ │ │ ├── FindVideoQueryHandler.php │ │ │ │ ├── VideoFinder.php │ │ │ │ ├── VideoResponse.php │ │ │ │ └── VideoResponseConverter.php │ │ │ ├── Trim │ │ │ │ ├── TrimVideoCommand.php │ │ │ │ ├── TrimVideoCommandHandler.php │ │ │ │ └── VideoTrimmer.php │ │ │ └── Update │ │ │ │ └── VideoTitleUpdater.php │ │ │ ├── Domain │ │ │ ├── Video.php │ │ │ ├── VideoCreatedDomainEvent.php │ │ │ ├── VideoFinder.php │ │ │ ├── VideoId.php │ │ │ ├── VideoNotFound.php │ │ │ ├── VideoRepository.php │ │ │ ├── VideoTitle.php │ │ │ ├── VideoType.php │ │ │ └── Videos.php │ │ │ └── Infrastructure │ │ │ └── Persistence │ │ │ ├── Doctrine │ │ │ ├── Video.orm.xml │ │ │ ├── VideoIdType.php │ │ │ ├── VideoTitle.orm.xml │ │ │ └── VideoType.orm.xml │ │ │ └── VideoRepositoryMySql.php │ ├── Retention │ │ ├── Campaign │ │ │ ├── Application │ │ │ │ ├── NewCourseAvailable │ │ │ │ │ ├── Schedule │ │ │ │ │ │ └── .gitkeep │ │ │ │ │ └── Trigger │ │ │ │ │ │ └── .gitkeep │ │ │ │ └── WelcomeUser │ │ │ │ │ └── Trigger │ │ │ │ │ └── .gitkeep │ │ │ ├── Domain │ │ │ │ └── .gitkeep │ │ │ └── Infrastructure │ │ │ │ └── .gitkeep │ │ ├── Email │ │ │ ├── Application │ │ │ │ ├── SendNewCourseAvailable │ │ │ │ │ └── .gitkeep │ │ │ │ └── SendWelcomeUser │ │ │ │ │ └── .gitkeep │ │ │ ├── Domain │ │ │ │ └── .gitkeep │ │ │ └── Infrastructure │ │ │ │ └── .gitkeep │ │ ├── Push │ │ │ ├── Application │ │ │ │ └── SendNewCourseAvailable │ │ │ │ │ └── .gitkeep │ │ │ ├── Domain │ │ │ │ └── .gitkeep │ │ │ └── Infrastructure │ │ │ │ └── .gitkeep │ │ └── Sms │ │ │ ├── Application │ │ │ └── .gitkeep │ │ │ ├── Domain │ │ │ └── .gitkeep │ │ │ └── Infrastructure │ │ │ └── .gitkeep │ └── Shared │ │ ├── Domain │ │ ├── Aggregate │ │ │ └── AggregateRoot.php │ │ ├── Assert.php │ │ ├── Bus │ │ │ ├── Command │ │ │ │ ├── Command.php │ │ │ │ ├── CommandBus.php │ │ │ │ └── CommandHandler.php │ │ │ ├── Event │ │ │ │ ├── DomainEvent.php │ │ │ │ ├── DomainEventSubscriber.php │ │ │ │ └── EventBus.php │ │ │ └── Query │ │ │ │ ├── Query.php │ │ │ │ ├── QueryBus.php │ │ │ │ ├── QueryHandler.php │ │ │ │ └── Response.php │ │ ├── Collection.php │ │ ├── Criteria │ │ │ ├── Criteria.php │ │ │ ├── Filter.php │ │ │ ├── FilterField.php │ │ │ ├── FilterOperator.php │ │ │ ├── FilterValue.php │ │ │ ├── Filters.php │ │ │ ├── Order.php │ │ │ ├── OrderBy.php │ │ │ └── OrderType.php │ │ ├── DomainError.php │ │ ├── Logger.php │ │ ├── Monitoring.php │ │ ├── RandomNumberGenerator.php │ │ ├── Second.php │ │ ├── SecondsInterval.php │ │ ├── Utils.php │ │ ├── UuidGenerator.php │ │ └── ValueObject │ │ │ ├── IntValueObject.php │ │ │ ├── SimpleUuid.php │ │ │ ├── StringValueObject.php │ │ │ └── Uuid.php │ │ └── Infrastructure │ │ ├── Bus │ │ ├── CallableFirstParameterExtractor.php │ │ ├── Command │ │ │ ├── CommandNotRegisteredError.php │ │ │ └── InMemorySymfonyCommandBus.php │ │ ├── Event │ │ │ ├── DomainEventJsonDeserializer.php │ │ │ ├── DomainEventJsonSerializer.php │ │ │ ├── DomainEventMapping.php │ │ │ ├── DomainEventSubscriberLocator.php │ │ │ ├── InMemory │ │ │ │ └── InMemorySymfonyEventBus.php │ │ │ ├── MySql │ │ │ │ ├── MySqlDoctrineDomainEventsConsumer.php │ │ │ │ └── MySqlDoctrineEventBus.php │ │ │ ├── RabbitMq │ │ │ │ ├── RabbitMqConfigurer.php │ │ │ │ ├── RabbitMqConnection.php │ │ │ │ ├── RabbitMqDomainEventsConsumer.php │ │ │ │ ├── RabbitMqEventBus.php │ │ │ │ ├── RabbitMqExchangeNameFormatter.php │ │ │ │ └── RabbitMqQueueNameFormatter.php │ │ │ └── WithMonitoring │ │ │ │ └── WithPrometheusMonitoringEventBus.php │ │ └── Query │ │ │ ├── InMemorySymfonyQueryBus.php │ │ │ └── QueryNotRegisteredError.php │ │ ├── Cdc │ │ ├── DatabaseMutationAction.php │ │ └── DatabaseMutationToDomainEvent.php │ │ ├── Doctrine │ │ ├── DatabaseConnections.php │ │ ├── Dbal │ │ │ ├── DbalCustomTypesRegistrar.php │ │ │ └── DoctrineCustomType.php │ │ └── DoctrineEntityManagerFactory.php │ │ ├── Elasticsearch │ │ ├── ElasticsearchClient.php │ │ └── ElasticsearchClientFactory.php │ │ ├── Logger │ │ └── MonologLogger.php │ │ ├── Monitoring │ │ └── PrometheusMonitor.php │ │ ├── Persistence │ │ ├── Doctrine │ │ │ ├── DoctrineCriteriaConverter.php │ │ │ ├── DoctrineRepository.php │ │ │ └── UuidType.php │ │ └── Elasticsearch │ │ │ ├── ElasticQueryGenerator.php │ │ │ ├── ElasticsearchCriteriaConverter.php │ │ │ └── ElasticsearchRepository.php │ │ ├── PhpRandomNumberGenerator.php │ │ ├── RamseyUuidGenerator.php │ │ └── Symfony │ │ ├── AddJsonBodyToRequestListener.php │ │ ├── ApiController.php │ │ ├── ApiExceptionListener.php │ │ ├── ApiExceptionsHttpStatusCodeMapping.php │ │ ├── BasicHttpAuthMiddleware.php │ │ ├── FlashSession.php │ │ └── WebController.php │ └── tests │ ├── Backoffice │ ├── Auth │ │ ├── Application │ │ │ └── Authenticate │ │ │ │ ├── AuthenticateUserCommandHandlerTest.php │ │ │ │ └── AuthenticateUserCommandMother.php │ │ ├── AuthModuleUnitTestCase.php │ │ └── Domain │ │ │ ├── AuthPasswordMother.php │ │ │ ├── AuthUserMother.php │ │ │ └── AuthUsernameMother.php │ ├── Courses │ │ ├── BackofficeCoursesModuleInfrastructureTestCase.php │ │ ├── Domain │ │ │ ├── BackofficeCourseCriteriaMother.php │ │ │ └── BackofficeCourseMother.php │ │ └── Infrastructure │ │ │ └── Persistence │ │ │ ├── ElasticsearchBackofficeCourseRepositoryTest.php │ │ │ └── MySqlBackofficeCourseRepositoryTest.php │ └── Shared │ │ └── Infraestructure │ │ └── PhpUnit │ │ ├── BackofficeContextInfrastructureTestCase.php │ │ └── BackofficeEnvironmentArranger.php │ ├── Mooc │ ├── Courses │ │ ├── Application │ │ │ ├── Create │ │ │ │ ├── CreateCourseCommandHandlerTest.php │ │ │ │ └── CreateCourseCommandMother.php │ │ │ └── Update │ │ │ │ └── CourseRenamerTest.php │ │ ├── CoursesModuleInfrastructureTestCase.php │ │ ├── CoursesModuleUnitTestCase.php │ │ ├── Domain │ │ │ ├── CourseCreatedDomainEventMother.php │ │ │ ├── CourseDurationMother.php │ │ │ ├── CourseIdMother.php │ │ │ ├── CourseMother.php │ │ │ └── CourseNameMother.php │ │ └── Infrastructure │ │ │ └── Persistence │ │ │ └── CourseRepositoryTest.php │ ├── CoursesCounter │ │ ├── Application │ │ │ ├── Find │ │ │ │ ├── CoursesCounterResponseMother.php │ │ │ │ └── FindCoursesCounterQueryHandlerTest.php │ │ │ └── Increment │ │ │ │ └── IncrementCoursesCounterOnCourseCreatedTest.php │ │ ├── CoursesCounterModuleUnitTestCase.php │ │ └── Domain │ │ │ ├── CoursesCounterIdMother.php │ │ │ ├── CoursesCounterIncrementedDomainEventMother.php │ │ │ ├── CoursesCounterMother.php │ │ │ └── CoursesCounterTotalMother.php │ ├── MoocArchitectureTest.php │ ├── Shared │ │ ├── Domain │ │ │ └── .gitkeep │ │ └── Infrastructure │ │ │ └── PhpUnit │ │ │ ├── MoocContextInfrastructureTestCase.php │ │ │ └── MoocEnvironmentArranger.php │ └── Videos │ │ ├── Application │ │ └── .gitkeep │ │ ├── Domain │ │ └── .gitkeep │ │ └── Infrastructure │ │ └── .gitkeep │ └── Shared │ ├── Domain │ ├── Criteria │ │ ├── CriteriaMother.php │ │ ├── FilterFieldMother.php │ │ ├── FilterMother.php │ │ ├── FilterValueMother.php │ │ ├── FiltersMother.php │ │ ├── OrderByMother.php │ │ └── OrderMother.php │ ├── DuplicatorMother.php │ ├── IntegerMother.php │ ├── MotherCreator.php │ ├── RandomElementPicker.php │ ├── Repeater.php │ ├── TestUtils.php │ ├── UuidMother.php │ └── WordMother.php │ ├── Infrastructure │ ├── ArchitectureTest.php │ ├── Arranger │ │ └── EnvironmentArranger.php │ ├── Behat │ │ ├── ApiContext.php │ │ └── ApplicationFeatureContext.php │ ├── Bus │ │ ├── Command │ │ │ ├── FakeCommand.php │ │ │ └── InMemorySymfonyCommandBusTest.php │ │ ├── Event │ │ │ ├── MySql │ │ │ │ └── MySqlDoctrineEventBusTest.php │ │ │ └── RabbitMq │ │ │ │ ├── RabbitMqEventBusTest.php │ │ │ │ └── TestAllWorksOnRabbitMqEventsPublished.php │ │ └── Query │ │ │ ├── FakeQuery.php │ │ │ ├── FakeResponse.php │ │ │ └── InMemorySymfonyQueryBusTest.php │ ├── ConstantRandomNumberGenerator.php │ ├── Doctrine │ │ └── MySqlDatabaseCleaner.php │ ├── Elastic │ │ └── ElasticDatabaseCleaner.php │ ├── Mink │ │ ├── MinkHelper.php │ │ └── MinkSessionRequestHelper.php │ ├── Mockery │ │ └── CodelyTvMatcherIsSimilar.php │ └── PhpUnit │ │ ├── Comparator │ │ ├── AggregateRootArraySimilarComparator.php │ │ ├── AggregateRootSimilarComparator.php │ │ ├── DateTimeSimilarComparator.php │ │ ├── DateTimeStringSimilarComparator.php │ │ ├── DomainEventArraySimilarComparator.php │ │ └── DomainEventSimilarComparator.php │ │ ├── Constraint │ │ └── CodelyTvConstraintIsSimilar.php │ │ ├── InfrastructureTestCase.php │ │ └── UnitTestCase.php │ └── SharedArchitectureTest.php ├── LICENSE └── README.md /02-from_where_publish_domain_events/1-from_use_case/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.tsx] 2 | indent_style = tab 3 | tab_width = 2 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/Makefile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/domain_modeling-domain_events-course/4b7bc354df242362d2e8080ef7be083d3ae33df5/02-from_where_publish_domain_events/1-from_use_case/Makefile -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/etc/http/seller_backoffice/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products/8910e9e9-3567-4e1a-8ffa-9491bdbda12e 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/etc/http/seller_backoffice/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/etc/http/shop/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products/34878c68-dd03-438d-9f4a-da6e53cf8ca4 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/etc/http/shop/product_reviews-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/product_reviews?product_id=1f2a73e3-e0e9-4418-8a53-d080871b24b3 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/etc/http/shop/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/etc/http/shop/user-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/users/1ec0b8ee-dbdc-48f6-ae5a-bfb99bee5e27 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/etc/http/shop/user-PUT.http: -------------------------------------------------------------------------------- 1 | PUT http://localhost:3000/api/shop/users/{{$random.uuid}} 2 | Content-Type: application/json 3 | 4 | { 5 | "name": "Javier Ferrer", 6 | "profilePicture": "https://" 7 | } 8 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/seller_backoffice/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/seller_backoffice/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/seller_backoffice/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/seller_backoffice/products/domain/ProductViews.ts: -------------------------------------------------------------------------------- 1 | export class ProductViews { 2 | constructor(public readonly value: number) {} 3 | 4 | static initialice(): ProductViews { 5 | return new ProductViews(0); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/shared/domain/Collection.ts: -------------------------------------------------------------------------------- 1 | export abstract class Collection { 2 | constructor(public readonly value: T[]) {} 3 | } 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/shared/domain/DomainEvent.ts: -------------------------------------------------------------------------------- 1 | export class DomainEvent {} 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/shared/domain/EventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export interface EventBus { 4 | publish(events: DomainEvent[]): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/shared/domain/Identifier.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export abstract class Identifier extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/shared/domain/Money.ts: -------------------------------------------------------------------------------- 1 | export type Currency = "EUR" | "USD"; 2 | 3 | export type Money = { 4 | amount: number; 5 | currency: Currency; 6 | }; 7 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/shared/domain/StringValueObject.ts: -------------------------------------------------------------------------------- 1 | export abstract class StringValueObject { 2 | constructor(public readonly value: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/shop/product_reviews/domain/ProductReviewComment.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductReviewComment extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/shop/product_reviews/domain/ProductReviewId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductReviewId extends Identifier {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/shop/product_reviews/domain/ProductReviewRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductReviewRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/shop/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/shop/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/shop/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/shop/products/domain/ProductRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/shop/users/domain/UserEmail.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserEmail extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/shop/users/domain/UserId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class UserId extends Identifier {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/shop/users/domain/UserName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/1-from_use_case/src/contexts/shop/users/domain/UserProfilePicture.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserProfilePicture extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.tsx] 2 | indent_style = tab 3 | tab_width = 2 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/Makefile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/domain_modeling-domain_events-course/4b7bc354df242362d2e8080ef7be083d3ae33df5/02-from_where_publish_domain_events/2-from_constructor/Makefile -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/etc/http/seller_backoffice/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products/8910e9e9-3567-4e1a-8ffa-9491bdbda12e 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/etc/http/seller_backoffice/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/etc/http/shop/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products/34878c68-dd03-438d-9f4a-da6e53cf8ca4 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/etc/http/shop/product_reviews-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/product_reviews?product_id=1f2a73e3-e0e9-4418-8a53-d080871b24b3 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/etc/http/shop/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/etc/http/shop/user-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/users/1ec0b8ee-dbdc-48f6-ae5a-bfb99bee5e27 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/etc/http/shop/user-PUT.http: -------------------------------------------------------------------------------- 1 | PUT http://localhost:3000/api/shop/users/{{$random.uuid}} 2 | Content-Type: application/json 3 | 4 | { 5 | "name": "Javier Ferrer", 6 | "profilePicture": "https://" 7 | } 8 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/seller_backoffice/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/seller_backoffice/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/seller_backoffice/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/seller_backoffice/products/domain/ProductViews.ts: -------------------------------------------------------------------------------- 1 | export class ProductViews { 2 | constructor(public readonly value: number) {} 3 | 4 | static initialice(): ProductViews { 5 | return new ProductViews(0); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/shared/domain/Collection.ts: -------------------------------------------------------------------------------- 1 | export abstract class Collection { 2 | constructor(public readonly value: T[]) {} 3 | } 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/shared/domain/DomainEvent.ts: -------------------------------------------------------------------------------- 1 | export class DomainEvent {} 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/shared/domain/EventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export class EventBus { 4 | static async publish(events: DomainEvent[]): void {} 5 | } 6 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/shared/domain/Identifier.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export abstract class Identifier extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/shared/domain/Money.ts: -------------------------------------------------------------------------------- 1 | export type Currency = "EUR" | "USD"; 2 | 3 | export type Money = { 4 | amount: number; 5 | currency: Currency; 6 | }; 7 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/shared/domain/StringValueObject.ts: -------------------------------------------------------------------------------- 1 | export abstract class StringValueObject { 2 | constructor(public readonly value: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/shop/product_reviews/domain/ProductReviewComment.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductReviewComment extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/shop/product_reviews/domain/ProductReviewId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductReviewId extends Identifier {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/shop/product_reviews/domain/ProductReviewRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductReviewRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/shop/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/shop/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/shop/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/shop/products/domain/ProductRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/shop/users/domain/UserEmail.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserEmail extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/shop/users/domain/UserId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class UserId extends Identifier {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/shop/users/domain/UserName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/2-from_constructor/src/contexts/shop/users/domain/UserProfilePicture.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserProfilePicture extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.tsx] 2 | indent_style = tab 3 | tab_width = 2 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/Makefile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/domain_modeling-domain_events-course/4b7bc354df242362d2e8080ef7be083d3ae33df5/02-from_where_publish_domain_events/3-registering_in_named_constructor/Makefile -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/etc/http/seller_backoffice/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products/8910e9e9-3567-4e1a-8ffa-9491bdbda12e 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/etc/http/seller_backoffice/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/etc/http/shop/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products/34878c68-dd03-438d-9f4a-da6e53cf8ca4 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/etc/http/shop/product_reviews-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/product_reviews?product_id=1f2a73e3-e0e9-4418-8a53-d080871b24b3 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/etc/http/shop/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/etc/http/shop/user-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/users/1ec0b8ee-dbdc-48f6-ae5a-bfb99bee5e27 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/etc/http/shop/user-PUT.http: -------------------------------------------------------------------------------- 1 | PUT http://localhost:3000/api/shop/users/{{$random.uuid}} 2 | Content-Type: application/json 3 | 4 | { 5 | "name": "Javier Ferrer", 6 | "profilePicture": "https://" 7 | } 8 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/seller_backoffice/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/seller_backoffice/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/seller_backoffice/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/shared/domain/Collection.ts: -------------------------------------------------------------------------------- 1 | export abstract class Collection { 2 | constructor(public readonly value: T[]) {} 3 | } 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/shared/domain/DomainEvent.ts: -------------------------------------------------------------------------------- 1 | export class DomainEvent {} 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/shared/domain/EventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export interface EventBus { 4 | publish(events: DomainEvent[]): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/shared/domain/Identifier.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export abstract class Identifier extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/shared/domain/Money.ts: -------------------------------------------------------------------------------- 1 | export type Currency = "EUR" | "USD"; 2 | 3 | export type Money = { 4 | amount: number; 5 | currency: Currency; 6 | }; 7 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/shared/domain/StringValueObject.ts: -------------------------------------------------------------------------------- 1 | export abstract class StringValueObject { 2 | constructor(public readonly value: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/shop/product_reviews/domain/ProductReviewComment.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductReviewComment extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/shop/product_reviews/domain/ProductReviewId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductReviewId extends Identifier {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/shop/product_reviews/domain/ProductReviewRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductReviewRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/shop/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/shop/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/shop/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/shop/products/domain/ProductRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/shop/users/domain/UserEmail.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserEmail extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/shop/users/domain/UserId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class UserId extends Identifier {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/shop/users/domain/UserName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/3-registering_in_named_constructor/src/contexts/shop/users/domain/UserProfilePicture.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserProfilePicture extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.tsx] 2 | indent_style = tab 3 | tab_width = 2 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/Makefile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/domain_modeling-domain_events-course/4b7bc354df242362d2e8080ef7be083d3ae33df5/02-from_where_publish_domain_events/4-event_bus_as_an_argument/Makefile -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/etc/http/seller_backoffice/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products/8910e9e9-3567-4e1a-8ffa-9491bdbda12e 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/etc/http/seller_backoffice/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/etc/http/shop/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products/34878c68-dd03-438d-9f4a-da6e53cf8ca4 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/etc/http/shop/product_reviews-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/product_reviews?product_id=1f2a73e3-e0e9-4418-8a53-d080871b24b3 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/etc/http/shop/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/etc/http/shop/user-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/users/1ec0b8ee-dbdc-48f6-ae5a-bfb99bee5e27 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/etc/http/shop/user-PUT.http: -------------------------------------------------------------------------------- 1 | PUT http://localhost:3000/api/shop/users/{{$random.uuid}} 2 | Content-Type: application/json 3 | 4 | { 5 | "name": "Javier Ferrer", 6 | "profilePicture": "https://" 7 | } 8 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/seller_backoffice/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/seller_backoffice/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/seller_backoffice/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/shared/domain/Collection.ts: -------------------------------------------------------------------------------- 1 | export abstract class Collection { 2 | constructor(public readonly value: T[]) {} 3 | } 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/shared/domain/DomainEvent.ts: -------------------------------------------------------------------------------- 1 | export class DomainEvent {} 2 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/shared/domain/EventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export interface EventBus { 4 | publish(events: DomainEvent[]): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/shared/domain/Identifier.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export abstract class Identifier extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/shared/domain/Money.ts: -------------------------------------------------------------------------------- 1 | export type Currency = "EUR" | "USD"; 2 | 3 | export type Money = { 4 | amount: number; 5 | currency: Currency; 6 | }; 7 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/shared/domain/StringValueObject.ts: -------------------------------------------------------------------------------- 1 | export abstract class StringValueObject { 2 | constructor(public readonly value: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/shop/product_reviews/domain/ProductReviewComment.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductReviewComment extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/shop/product_reviews/domain/ProductReviewId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductReviewId extends Identifier {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/shop/product_reviews/domain/ProductReviewRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductReviewRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/shop/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/shop/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/shop/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/shop/products/domain/ProductRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/shop/users/domain/UserEmail.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserEmail extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/shop/users/domain/UserId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class UserId extends Identifier {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/shop/users/domain/UserName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /02-from_where_publish_domain_events/4-event_bus_as_an_argument/src/contexts/shop/users/domain/UserProfilePicture.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserProfilePicture extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.tsx] 2 | indent_style = tab 3 | tab_width = 2 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/etc/http/seller_backoffice/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products/8910e9e9-3567-4e1a-8ffa-9491bdbda12e 2 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/etc/http/seller_backoffice/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products 2 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/etc/http/shop/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products/34878c68-dd03-438d-9f4a-da6e53cf8ca4 2 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/etc/http/shop/product_reviews-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/product_reviews?product_id=1f2a73e3-e0e9-4418-8a53-d080871b24b3 2 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/etc/http/shop/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products 2 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/etc/http/shop/user-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/users/1ec0b8ee-dbdc-48f6-ae5a-bfb99bee5e27 2 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/etc/http/shop/user-PUT.http: -------------------------------------------------------------------------------- 1 | PUT http://localhost:3000/api/shop/users/{{$random.uuid}} 2 | Content-Type: application/json 3 | 4 | { 5 | "name": "Javier Ferrer", 6 | "profilePicture": "https://" 7 | } 8 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/seller_backoffice/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/seller_backoffice/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/seller_backoffice/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/shared/domain/Collection.ts: -------------------------------------------------------------------------------- 1 | export abstract class Collection { 2 | constructor(public readonly value: T[]) {} 3 | } 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/shared/domain/DomainEvent.ts: -------------------------------------------------------------------------------- 1 | export class DomainEvent {} 2 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/shared/domain/EventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export interface EventBus { 4 | publish(events: DomainEvent[]): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/shared/domain/Identifier.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export abstract class Identifier extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/shared/domain/Money.ts: -------------------------------------------------------------------------------- 1 | export type Currency = "EUR" | "USD"; 2 | 3 | export type Money = { 4 | amount: number; 5 | currency: Currency; 6 | }; 7 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/shared/domain/StringValueObject.ts: -------------------------------------------------------------------------------- 1 | export abstract class StringValueObject { 2 | constructor(public readonly value: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/shop/product_reviews/domain/ProductReviewId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductReviewId extends Identifier {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/shop/product_reviews/domain/ProductReviewRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductReviewRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/shop/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/shop/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/shop/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/shop/products/domain/ProductRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/shop/users/domain/UserDoesNotExist.ts: -------------------------------------------------------------------------------- 1 | export class UserDoesNotExist extends Error { 2 | constructor(id: string) { 3 | super(`The user ${id} does not exist`); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/shop/users/domain/UserEmail.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserEmail extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/shop/users/domain/UserId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class UserId extends Identifier {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/shop/users/domain/UserName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/1-user_updated_domain_event/src/contexts/shop/users/domain/UserProfilePicture.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserProfilePicture extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.tsx] 2 | indent_style = tab 3 | tab_width = 2 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/etc/http/seller_backoffice/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products/8910e9e9-3567-4e1a-8ffa-9491bdbda12e 2 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/etc/http/seller_backoffice/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products 2 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/etc/http/shop/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products/34878c68-dd03-438d-9f4a-da6e53cf8ca4 2 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/etc/http/shop/product_reviews-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/product_reviews?product_id=1f2a73e3-e0e9-4418-8a53-d080871b24b3 2 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/etc/http/shop/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products 2 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/etc/http/shop/user-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/users/1ec0b8ee-dbdc-48f6-ae5a-bfb99bee5e27 2 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/etc/http/shop/user-PUT.http: -------------------------------------------------------------------------------- 1 | PUT http://localhost:3000/api/shop/users/{{$random.uuid}} 2 | Content-Type: application/json 3 | 4 | { 5 | "name": "Javier Ferrer", 6 | "profilePicture": "https://" 7 | } 8 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/src/contexts/seller_backoffice/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/src/contexts/shared/domain/Collection.ts: -------------------------------------------------------------------------------- 1 | export abstract class Collection { 2 | constructor(public readonly value: T[]) {} 3 | } 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/src/contexts/shared/domain/DomainEvent.ts: -------------------------------------------------------------------------------- 1 | export class DomainEvent {} 2 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/src/contexts/shared/domain/EventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export interface EventBus { 4 | publish(events: DomainEvent[]): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/src/contexts/shared/domain/Identifier.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export abstract class Identifier extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/src/contexts/shared/domain/Money.ts: -------------------------------------------------------------------------------- 1 | export type Currency = "EUR" | "USD"; 2 | 3 | export type Money = { 4 | amount: number; 5 | currency: Currency; 6 | }; 7 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/src/contexts/shared/domain/StringValueObject.ts: -------------------------------------------------------------------------------- 1 | export abstract class StringValueObject { 2 | constructor(public readonly value: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/src/contexts/shop/product_reviews/domain/ProductReviewId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductReviewId extends Identifier {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/src/contexts/shop/product_reviews/domain/ProductReviewRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductReviewRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/src/contexts/shop/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/src/contexts/shop/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/src/contexts/shop/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/src/contexts/shop/products/domain/ProductRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/src/contexts/shop/users/domain/UserDoesNotExist.ts: -------------------------------------------------------------------------------- 1 | export class UserDoesNotExist extends Error { 2 | constructor(id: string) { 3 | super(`The user ${id} does not exist`); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/src/contexts/shop/users/domain/UserEmail.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserEmail extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/src/contexts/shop/users/domain/UserId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class UserId extends Identifier {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/src/contexts/shop/users/domain/UserName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/1-granularity_in_domain_events/2-user_email_updated_domain_event/src/contexts/shop/users/domain/UserProfilePicture.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserProfilePicture extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.tsx] 2 | indent_style = tab 3 | tab_width = 2 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/etc/http/seller_backoffice/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products/8910e9e9-3567-4e1a-8ffa-9491bdbda12e 2 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/etc/http/seller_backoffice/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products 2 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/etc/http/shop/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products/34878c68-dd03-438d-9f4a-da6e53cf8ca4 2 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/etc/http/shop/product_reviews-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/product_reviews?product_id=1f2a73e3-e0e9-4418-8a53-d080871b24b3 2 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/etc/http/shop/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products 2 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/etc/http/shop/user-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/users/1ec0b8ee-dbdc-48f6-ae5a-bfb99bee5e27 2 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/src/contexts/seller_backoffice/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/src/contexts/shared/domain/Collection.ts: -------------------------------------------------------------------------------- 1 | export abstract class Collection { 2 | constructor(public readonly value: T[]) {} 3 | } 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/src/contexts/shared/domain/DomainEvent.ts: -------------------------------------------------------------------------------- 1 | export class DomainEvent {} 2 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/src/contexts/shared/domain/EventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export interface EventBus { 4 | publish(events: DomainEvent[]): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/src/contexts/shared/domain/Identifier.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export abstract class Identifier extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/src/contexts/shared/domain/Money.ts: -------------------------------------------------------------------------------- 1 | export type Currency = "EUR" | "USD"; 2 | 3 | export type Money = { 4 | amount: number; 5 | currency: Currency; 6 | }; 7 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/src/contexts/shared/domain/StringValueObject.ts: -------------------------------------------------------------------------------- 1 | export abstract class StringValueObject { 2 | constructor(public readonly value: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/src/contexts/shop/product_reviews/domain/ProductReviewId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductReviewId extends Identifier {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/src/contexts/shop/product_reviews/domain/ProductReviewRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductReviewRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/src/contexts/shop/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/src/contexts/shop/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/src/contexts/shop/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/src/contexts/shop/products/domain/ProductRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/src/contexts/shop/users/domain/UserDoesNotExist.ts: -------------------------------------------------------------------------------- 1 | export class UserDoesNotExist extends Error { 2 | constructor(id: string) { 3 | super(`The user ${id} does not exist`); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/src/contexts/shop/users/domain/UserEmail.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserEmail extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/src/contexts/shop/users/domain/UserId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class UserId extends Identifier {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/src/contexts/shop/users/domain/UserName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/src/contexts/shop/users/domain/UserProfilePicture.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserProfilePicture extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/1-user_status_updated_domain_event/src/contexts/shop/users/domain/UserStatus.ts: -------------------------------------------------------------------------------- 1 | export enum UserStatus { 2 | Active = "active", 3 | Archived = "archived", 4 | } 5 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.tsx] 2 | indent_style = tab 3 | tab_width = 2 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/etc/http/seller_backoffice/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products/8910e9e9-3567-4e1a-8ffa-9491bdbda12e 2 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/etc/http/seller_backoffice/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products 2 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/etc/http/shop/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products/34878c68-dd03-438d-9f4a-da6e53cf8ca4 2 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/etc/http/shop/product_reviews-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/product_reviews?product_id=1f2a73e3-e0e9-4418-8a53-d080871b24b3 2 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/etc/http/shop/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products 2 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/etc/http/shop/user-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/users/1ec0b8ee-dbdc-48f6-ae5a-bfb99bee5e27 2 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/etc/http/shop/user-PUT.http: -------------------------------------------------------------------------------- 1 | PUT http://localhost:3000/api/shop/users/{{$random.uuid}} 2 | Content-Type: application/json 3 | 4 | { 5 | "name": "Javier Ferrer", 6 | "profilePicture": "https://" 7 | } 8 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/seller_backoffice/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/seller_backoffice/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/shared/domain/Collection.ts: -------------------------------------------------------------------------------- 1 | export abstract class Collection { 2 | constructor(public readonly value: T[]) {} 3 | } 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/shared/domain/DomainEvent.ts: -------------------------------------------------------------------------------- 1 | export class DomainEvent {} 2 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/shared/domain/EventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export interface EventBus { 4 | publish(events: DomainEvent[]): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/shared/domain/Identifier.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export abstract class Identifier extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/shared/domain/Money.ts: -------------------------------------------------------------------------------- 1 | export type Currency = "EUR" | "USD"; 2 | 3 | export type Money = { 4 | amount: number; 5 | currency: Currency; 6 | }; 7 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/shared/domain/StringValueObject.ts: -------------------------------------------------------------------------------- 1 | export abstract class StringValueObject { 2 | constructor(public readonly value: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/shop/product_reviews/domain/ProductReviewId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductReviewId extends Identifier {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/shop/product_reviews/domain/ProductReviewRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductReviewRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/shop/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/shop/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/shop/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/shop/products/domain/ProductRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/shop/users/domain/UserDoesNotExist.ts: -------------------------------------------------------------------------------- 1 | export class UserDoesNotExist extends Error { 2 | constructor(id: string) { 3 | super(`The user ${id} does not exist`); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/shop/users/domain/UserEmail.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserEmail extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/shop/users/domain/UserId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class UserId extends Identifier {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/shop/users/domain/UserName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/shop/users/domain/UserProfilePicture.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserProfilePicture extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /03-domain_events_design/2-semantics_in_domain_events/2-user_archived_domain_event/src/contexts/shop/users/domain/UserStatus.ts: -------------------------------------------------------------------------------- 1 | export enum UserStatus { 2 | Active = "active", 3 | Archived = "archived", 4 | } 5 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.tsx] 2 | indent_style = tab 3 | tab_width = 2 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/Makefile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/domain_modeling-domain_events-course/4b7bc354df242362d2e8080ef7be083d3ae33df5/04-react_to_domain_events/1-subscriber_listen_one_event/Makefile -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/etc/http/seller_backoffice/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products/8910e9e9-3567-4e1a-8ffa-9491bdbda12e 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/etc/http/seller_backoffice/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/etc/http/shop/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products/34878c68-dd03-438d-9f4a-da6e53cf8ca4 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/etc/http/shop/product_reviews-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/product_reviews?product_id=1f2a73e3-e0e9-4418-8a53-d080871b24b3 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/etc/http/shop/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/etc/http/shop/user-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/users/1ec0b8ee-dbdc-48f6-ae5a-bfb99bee5e27 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/etc/http/shop/user-PUT.http: -------------------------------------------------------------------------------- 1 | PUT http://localhost:3000/api/shop/users/{{$random.uuid}} 2 | Content-Type: application/json 3 | 4 | { 5 | "name": "Javier Ferrer", 6 | "profilePicture": "https://" 7 | } 8 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/retention/email/domain/EmailBody.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class EmailBody extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/retention/email/domain/EmailId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class EmailId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/retention/email/domain/EmailSender.ts: -------------------------------------------------------------------------------- 1 | import { Email } from "./Email"; 2 | 3 | export interface EmailSender { 4 | send(email: T): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/seller_backoffice/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/seller_backoffice/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/seller_backoffice/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shared/domain/Collection.ts: -------------------------------------------------------------------------------- 1 | export abstract class Collection { 2 | constructor(public readonly value: T[]) {} 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shared/domain/DomainEvent.ts: -------------------------------------------------------------------------------- 1 | export class DomainEvent { 2 | protected constructor(public readonly eventName: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shared/domain/DomainEventName.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export type DomainEventName = Pick; 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shared/domain/EmailAddress.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export class EmailAddress extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shared/domain/EventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export interface EventBus { 4 | publish(events: DomainEvent[]): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shared/domain/Identifier.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export abstract class Identifier extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shared/domain/Money.ts: -------------------------------------------------------------------------------- 1 | export type Currency = "EUR" | "USD"; 2 | 3 | export type Money = { 4 | amount: number; 5 | currency: Currency; 6 | }; 7 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shared/domain/StringValueObject.ts: -------------------------------------------------------------------------------- 1 | export abstract class StringValueObject { 2 | constructor(public readonly value: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shared/domain/UuidGenerator.ts: -------------------------------------------------------------------------------- 1 | export interface UuidGenerator { 2 | generate(): Promise; 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shop/product_reviews/domain/ProductReviewComment.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductReviewComment extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shop/product_reviews/domain/ProductReviewId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductReviewId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shop/product_reviews/domain/ProductReviewRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductReviewRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shop/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shop/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shop/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shop/products/domain/ProductRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shop/users/domain/UserDoesNotExist.ts: -------------------------------------------------------------------------------- 1 | export class UserDoesNotExist extends Error { 2 | constructor(id: string) { 3 | super(`The user ${id} does not exist`); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shop/users/domain/UserEmail.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserEmail extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shop/users/domain/UserId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class UserId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shop/users/domain/UserName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shop/users/domain/UserProfilePicture.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserProfilePicture extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/1-subscriber_listen_one_event/src/contexts/shop/users/domain/UserStatus.ts: -------------------------------------------------------------------------------- 1 | export enum UserStatus { 2 | Active = "active", 3 | Archived = "archived", 4 | } 5 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.tsx] 2 | indent_style = tab 3 | tab_width = 2 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/Makefile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/domain_modeling-domain_events-course/4b7bc354df242362d2e8080ef7be083d3ae33df5/04-react_to_domain_events/2-test_subscriber/Makefile -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/etc/http/seller_backoffice/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products/8910e9e9-3567-4e1a-8ffa-9491bdbda12e 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/etc/http/seller_backoffice/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/etc/http/shop/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products/34878c68-dd03-438d-9f4a-da6e53cf8ca4 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/etc/http/shop/product_reviews-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/product_reviews?product_id=1f2a73e3-e0e9-4418-8a53-d080871b24b3 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/etc/http/shop/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/etc/http/shop/user-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/users/1ec0b8ee-dbdc-48f6-ae5a-bfb99bee5e27 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/etc/http/shop/user-PUT.http: -------------------------------------------------------------------------------- 1 | PUT http://localhost:3000/api/shop/users/{{$random.uuid}} 2 | Content-Type: application/json 3 | 4 | { 5 | "name": "Javier Ferrer", 6 | "profilePicture": "https://" 7 | } 8 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/retention/email/domain/EmailBody.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class EmailBody extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/retention/email/domain/EmailId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class EmailId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/retention/email/domain/EmailSender.ts: -------------------------------------------------------------------------------- 1 | import { Email } from "./Email"; 2 | 3 | export interface EmailSender { 4 | send(email: T): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/seller_backoffice/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/seller_backoffice/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/seller_backoffice/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/seller_backoffice/products/domain/ProductViews.ts: -------------------------------------------------------------------------------- 1 | export class ProductViews { 2 | constructor(public readonly value: number) {} 3 | 4 | static initialice(): ProductViews { 5 | return new ProductViews(0); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shared/domain/Collection.ts: -------------------------------------------------------------------------------- 1 | export abstract class Collection { 2 | constructor(public readonly value: T[]) {} 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shared/domain/DomainEvent.ts: -------------------------------------------------------------------------------- 1 | export class DomainEvent { 2 | protected constructor(public readonly eventName: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shared/domain/DomainEventName.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export type DomainEventName = Pick; 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shared/domain/EmailAddress.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export class EmailAddress extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shared/domain/EventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export interface EventBus { 4 | publish(events: DomainEvent[]): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shared/domain/Identifier.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export abstract class Identifier extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shared/domain/Money.ts: -------------------------------------------------------------------------------- 1 | export type Currency = "EUR" | "USD"; 2 | 3 | export type Money = { 4 | amount: number; 5 | currency: Currency; 6 | }; 7 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shared/domain/StringValueObject.ts: -------------------------------------------------------------------------------- 1 | export abstract class StringValueObject { 2 | constructor(public readonly value: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shared/domain/UuidGenerator.ts: -------------------------------------------------------------------------------- 1 | export interface UuidGenerator { 2 | generate(): Promise; 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shop/product_reviews/domain/ProductReviewComment.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductReviewComment extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shop/product_reviews/domain/ProductReviewId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductReviewId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shop/product_reviews/domain/ProductReviewRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductReviewRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shop/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shop/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shop/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shop/products/domain/ProductRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shop/users/domain/UserDoesNotExist.ts: -------------------------------------------------------------------------------- 1 | export class UserDoesNotExist extends Error { 2 | constructor(id: string) { 3 | super(`The user ${id} does not exist`); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shop/users/domain/UserEmail.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserEmail extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shop/users/domain/UserId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class UserId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shop/users/domain/UserName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shop/users/domain/UserProfilePicture.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserProfilePicture extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/2-test_subscriber/src/contexts/shop/users/domain/UserStatus.ts: -------------------------------------------------------------------------------- 1 | export enum UserStatus { 2 | Active = "active", 3 | Archived = "archived", 4 | } 5 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.tsx] 2 | indent_style = tab 3 | tab_width = 2 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/Makefile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/domain_modeling-domain_events-course/4b7bc354df242362d2e8080ef7be083d3ae33df5/04-react_to_domain_events/3-subscriber_listen_multiple_events/Makefile -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/etc/http/seller_backoffice/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products/8910e9e9-3567-4e1a-8ffa-9491bdbda12e 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/etc/http/seller_backoffice/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/etc/http/shop/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products/34878c68-dd03-438d-9f4a-da6e53cf8ca4 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/etc/http/shop/product_reviews-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/product_reviews?product_id=1f2a73e3-e0e9-4418-8a53-d080871b24b3 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/etc/http/shop/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/etc/http/shop/user-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/users/1ec0b8ee-dbdc-48f6-ae5a-bfb99bee5e27 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/etc/http/shop/user-PUT.http: -------------------------------------------------------------------------------- 1 | PUT http://localhost:3000/api/shop/users/{{$random.uuid}} 2 | Content-Type: application/json 3 | 4 | { 5 | "name": "Javier Ferrer", 6 | "profilePicture": "https://" 7 | } 8 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/retention/email/domain/EmailBody.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class EmailBody extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/retention/email/domain/EmailId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class EmailId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/retention/email/domain/EmailSender.ts: -------------------------------------------------------------------------------- 1 | import { Email } from "./Email"; 2 | 3 | export interface EmailSender { 4 | send(email: T): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/seller_backoffice/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/seller_backoffice/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/seller_backoffice/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shared/domain/Collection.ts: -------------------------------------------------------------------------------- 1 | export abstract class Collection { 2 | constructor(public readonly value: T[]) {} 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shared/domain/DomainEventName.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export type DomainEventName = Pick; 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shared/domain/EmailAddress.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export class EmailAddress extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shared/domain/EventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export interface EventBus { 4 | publish(events: DomainEvent[]): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shared/domain/Identifier.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export abstract class Identifier extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shared/domain/Money.ts: -------------------------------------------------------------------------------- 1 | export type Currency = "EUR" | "USD"; 2 | 3 | export type Money = { 4 | amount: number; 5 | currency: Currency; 6 | }; 7 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shared/domain/StringValueObject.ts: -------------------------------------------------------------------------------- 1 | export abstract class StringValueObject { 2 | constructor(public readonly value: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shared/domain/UuidGenerator.ts: -------------------------------------------------------------------------------- 1 | export interface UuidGenerator { 2 | generate(): Promise; 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shop/product_reviews/domain/ProductReviewComment.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductReviewComment extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shop/product_reviews/domain/ProductReviewId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductReviewId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shop/product_reviews/domain/ProductReviewRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductReviewRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shop/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shop/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shop/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shop/products/domain/ProductRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shop/users/domain/UserDoesNotExist.ts: -------------------------------------------------------------------------------- 1 | export class UserDoesNotExist extends Error { 2 | constructor(id: string) { 3 | super(`The user ${id} does not exist`); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shop/users/domain/UserEmail.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserEmail extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shop/users/domain/UserId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class UserId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shop/users/domain/UserName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shop/users/domain/UserProfilePicture.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserProfilePicture extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/3-subscriber_listen_multiple_events/src/contexts/shop/users/domain/UserStatus.ts: -------------------------------------------------------------------------------- 1 | export enum UserStatus { 2 | Active = "active", 3 | Archived = "archived", 4 | } 5 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.tsx] 2 | indent_style = tab 3 | tab_width = 2 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/Makefile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/domain_modeling-domain_events-course/4b7bc354df242362d2e8080ef7be083d3ae33df5/04-react_to_domain_events/4-save_as_derivated_action/Makefile -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/etc/http/seller_backoffice/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products/8910e9e9-3567-4e1a-8ffa-9491bdbda12e 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/etc/http/seller_backoffice/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/etc/http/shop/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products/34878c68-dd03-438d-9f4a-da6e53cf8ca4 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/etc/http/shop/product_reviews-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/product_reviews?product_id=1f2a73e3-e0e9-4418-8a53-d080871b24b3 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/etc/http/shop/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/etc/http/shop/user-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/users/1ec0b8ee-dbdc-48f6-ae5a-bfb99bee5e27 2 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/etc/http/shop/user-PUT.http: -------------------------------------------------------------------------------- 1 | PUT http://localhost:3000/api/shop/users/{{$random.uuid}} 2 | Content-Type: application/json 3 | 4 | { 5 | "name": "Javier Ferrer", 6 | "profilePicture": "https://" 7 | } 8 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/retention/email/domain/EmailBody.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class EmailBody extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/retention/email/domain/EmailId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class EmailId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/retention/email/domain/EmailSender.ts: -------------------------------------------------------------------------------- 1 | import { Email } from "./Email"; 2 | 3 | export interface EmailSender { 4 | send(email: T): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/seller_backoffice/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/seller_backoffice/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/seller_backoffice/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/seller_backoffice/products/domain/ProductViews.ts: -------------------------------------------------------------------------------- 1 | export class ProductViews { 2 | constructor(public readonly value: number) {} 3 | 4 | static initialice(): ProductViews { 5 | return new ProductViews(0); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shared/domain/Collection.ts: -------------------------------------------------------------------------------- 1 | export abstract class Collection { 2 | constructor(public readonly value: T[]) {} 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shared/domain/EmailAddress.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export class EmailAddress extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shared/domain/Identifier.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export abstract class Identifier extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shared/domain/Money.ts: -------------------------------------------------------------------------------- 1 | export type Currency = "EUR" | "USD"; 2 | 3 | export type Money = { 4 | amount: number; 5 | currency: Currency; 6 | }; 7 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shared/domain/StringValueObject.ts: -------------------------------------------------------------------------------- 1 | export abstract class StringValueObject { 2 | constructor(public readonly value: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shared/domain/UuidGenerator.ts: -------------------------------------------------------------------------------- 1 | export interface UuidGenerator { 2 | generate(): Promise; 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shared/domain/event/DomainEventName.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export type DomainEventName = Pick; 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shared/domain/event/EventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export interface EventBus { 4 | publish(events: DomainEvent[]): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shop/product_reviews/domain/ProductReviewComment.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductReviewComment extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shop/product_reviews/domain/ProductReviewId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductReviewId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shop/product_reviews/domain/ProductReviewRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductReviewRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shop/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shop/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shop/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shop/products/domain/ProductRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shop/users/domain/UserDoesNotExist.ts: -------------------------------------------------------------------------------- 1 | export class UserDoesNotExist extends Error { 2 | constructor(id: string) { 3 | super(`The user ${id} does not exist`); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shop/users/domain/UserEmail.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserEmail extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shop/users/domain/UserId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class UserId extends Identifier {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shop/users/domain/UserName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shop/users/domain/UserProfilePicture.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserProfilePicture extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /04-react_to_domain_events/4-save_as_derivated_action/src/contexts/shop/users/domain/UserStatus.ts: -------------------------------------------------------------------------------- 1 | export enum UserStatus { 2 | Active = "active", 3 | Archived = "archived", 4 | } 5 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.tsx] 2 | indent_style = tab 3 | tab_width = 2 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/Makefile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/domain_modeling-domain_events-course/4b7bc354df242362d2e8080ef7be083d3ae33df5/06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/Makefile -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/etc/http/seller_backoffice/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products/8910e9e9-3567-4e1a-8ffa-9491bdbda12e 2 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/etc/http/seller_backoffice/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products 2 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/etc/http/shop/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products/34878c68-dd03-438d-9f4a-da6e53cf8ca4 2 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/etc/http/shop/product_reviews-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/product_reviews?product_id=1f2a73e3-e0e9-4418-8a53-d080871b24b3 2 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/etc/http/shop/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products 2 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/etc/http/shop/user-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/users/1ec0b8ee-dbdc-48f6-ae5a-bfb99bee5e27 2 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/etc/http/shop/user-PUT.http: -------------------------------------------------------------------------------- 1 | PUT http://localhost:3000/api/shop/users/{{$random.uuid}} 2 | Content-Type: application/json 3 | 4 | { 5 | "name": "Javier Ferrer", 6 | "profilePicture": "https://" 7 | } 8 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/retention/email/domain/EmailBody.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class EmailBody extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/retention/email/domain/EmailId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class EmailId extends Identifier {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/retention/email/domain/EmailSender.ts: -------------------------------------------------------------------------------- 1 | import { Email } from "./Email"; 2 | 3 | export interface EmailSender { 4 | send(email: T): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/seller_backoffice/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/seller_backoffice/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/seller_backoffice/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shared/domain/Collection.ts: -------------------------------------------------------------------------------- 1 | export abstract class Collection { 2 | constructor(public readonly value: T[]) {} 3 | } 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shared/domain/DomainEventName.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export type DomainEventName = Pick; 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shared/domain/EmailAddress.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export class EmailAddress extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shared/domain/EventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export interface EventBus { 4 | publish(events: DomainEvent[]): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shared/domain/Identifier.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export abstract class Identifier extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shared/domain/Money.ts: -------------------------------------------------------------------------------- 1 | export type Currency = "EUR" | "USD"; 2 | 3 | export type Money = { 4 | amount: number; 5 | currency: Currency; 6 | }; 7 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shared/domain/StringValueObject.ts: -------------------------------------------------------------------------------- 1 | export abstract class StringValueObject { 2 | constructor(public readonly value: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shared/domain/UuidGenerator.ts: -------------------------------------------------------------------------------- 1 | export interface UuidGenerator { 2 | generate(): Promise; 3 | } 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shop/product_reviews/domain/ProductReviewId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductReviewId extends Identifier {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shop/product_reviews/domain/ProductReviewRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductReviewRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shop/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shop/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shop/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shop/products/domain/ProductRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shop/users/domain/UserDoesNotExist.ts: -------------------------------------------------------------------------------- 1 | export class UserDoesNotExist extends Error { 2 | constructor(id: string) { 3 | super(`The user ${id} does not exist`); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shop/users/domain/UserEmail.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserEmail extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shop/users/domain/UserId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class UserId extends Identifier {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shop/users/domain/UserName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shop/users/domain/UserProfilePicture.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserProfilePicture extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/1-publish_all/src/contexts/shop/users/domain/UserStatus.ts: -------------------------------------------------------------------------------- 1 | export enum UserStatus { 2 | Active = "active", 3 | Archived = "archived", 4 | } 5 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.tsx] 2 | indent_style = tab 3 | tab_width = 2 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/etc/http/seller_backoffice/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products/8910e9e9-3567-4e1a-8ffa-9491bdbda12e 2 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/etc/http/seller_backoffice/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products 2 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/etc/http/shop/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products/34878c68-dd03-438d-9f4a-da6e53cf8ca4 2 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/etc/http/shop/product_reviews-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/product_reviews?product_id=1f2a73e3-e0e9-4418-8a53-d080871b24b3 2 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/etc/http/shop/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products 2 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/etc/http/shop/user-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/users/1ec0b8ee-dbdc-48f6-ae5a-bfb99bee5e27 2 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/etc/http/shop/user-PUT.http: -------------------------------------------------------------------------------- 1 | PUT http://localhost:3000/api/shop/users/{{$random.uuid}} 2 | Content-Type: application/json 3 | 4 | { 5 | "name": "Javier Ferrer", 6 | "profilePicture": "https://" 7 | } 8 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/retention/email/domain/EmailBody.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class EmailBody extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/retention/email/domain/EmailId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class EmailId extends Identifier {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/retention/email/domain/EmailSender.ts: -------------------------------------------------------------------------------- 1 | import { Email } from "./Email"; 2 | 3 | export interface EmailSender { 4 | send(email: T): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/seller_backoffice/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/seller_backoffice/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shared/domain/Collection.ts: -------------------------------------------------------------------------------- 1 | export abstract class Collection { 2 | constructor(public readonly value: T[]) {} 3 | } 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shared/domain/DomainEventName.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export type DomainEventName = Pick; 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shared/domain/EmailAddress.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export class EmailAddress extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shared/domain/ExternalEventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export interface ExternalEventBus { 4 | publish(event: DomainEvent): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shared/domain/Identifier.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export abstract class Identifier extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shared/domain/InternalEventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export interface InternalEventBus { 4 | publish(events: DomainEvent[]): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shared/domain/Money.ts: -------------------------------------------------------------------------------- 1 | export type Currency = "EUR" | "USD"; 2 | 3 | export type Money = { 4 | amount: number; 5 | currency: Currency; 6 | }; 7 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shared/domain/StringValueObject.ts: -------------------------------------------------------------------------------- 1 | export abstract class StringValueObject { 2 | constructor(public readonly value: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shared/domain/UuidGenerator.ts: -------------------------------------------------------------------------------- 1 | export interface UuidGenerator { 2 | generate(): Promise; 3 | } 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shop/product_reviews/domain/ProductReviewId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductReviewId extends Identifier {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shop/product_reviews/domain/ProductReviewRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductReviewRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shop/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shop/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shop/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shop/products/domain/ProductRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shop/users/domain/UserDoesNotExist.ts: -------------------------------------------------------------------------------- 1 | export class UserDoesNotExist extends Error { 2 | constructor(id: string) { 3 | super(`The user ${id} does not exist`); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shop/users/domain/UserEmail.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserEmail extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shop/users/domain/UserId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class UserId extends Identifier {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shop/users/domain/UserName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shop/users/domain/UserProfilePicture.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserProfilePicture extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/1-info_in_domain_events/2-publish_only_external/src/contexts/shop/users/domain/UserStatus.ts: -------------------------------------------------------------------------------- 1 | export enum UserStatus { 2 | Active = "active", 3 | Archived = "archived", 4 | } 5 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.tsx] 2 | indent_style = tab 3 | tab_width = 2 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/Makefile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/domain_modeling-domain_events-course/4b7bc354df242362d2e8080ef7be083d3ae33df5/06-external_vs_internal_domain_events/2-enrich_domain_events/Makefile -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/etc/http/seller_backoffice/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products/8910e9e9-3567-4e1a-8ffa-9491bdbda12e 2 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/etc/http/seller_backoffice/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products 2 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/etc/http/shop/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products/34878c68-dd03-438d-9f4a-da6e53cf8ca4 2 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/etc/http/shop/product_reviews-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/product_reviews?product_id=1f2a73e3-e0e9-4418-8a53-d080871b24b3 2 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/etc/http/shop/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products 2 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/etc/http/shop/user-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/users/1ec0b8ee-dbdc-48f6-ae5a-bfb99bee5e27 2 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/etc/http/shop/user-PUT.http: -------------------------------------------------------------------------------- 1 | PUT http://localhost:3000/api/shop/users/{{$random.uuid}} 2 | Content-Type: application/json 3 | 4 | { 5 | "name": "Javier Ferrer", 6 | "profilePicture": "https://" 7 | } 8 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/retention/email/domain/EmailBody.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class EmailBody extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/retention/email/domain/EmailId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class EmailId extends Identifier {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/retention/email/domain/EmailSender.ts: -------------------------------------------------------------------------------- 1 | import { Email } from "./Email"; 2 | 3 | export interface EmailSender { 4 | send(email: T): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/seller_backoffice/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/seller_backoffice/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/seller_backoffice/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shared/domain/Collection.ts: -------------------------------------------------------------------------------- 1 | export abstract class Collection { 2 | constructor(public readonly value: T[]) {} 3 | } 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shared/domain/DomainEventName.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export type DomainEventName = Pick; 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shared/domain/EmailAddress.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export class EmailAddress extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shared/domain/EventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export interface EventBus { 4 | publish(events: DomainEvent[]): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shared/domain/Identifier.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export abstract class Identifier extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shared/domain/Money.ts: -------------------------------------------------------------------------------- 1 | export type Currency = "EUR" | "USD"; 2 | 3 | export type Money = { 4 | amount: number; 5 | currency: Currency; 6 | }; 7 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shared/domain/StringValueObject.ts: -------------------------------------------------------------------------------- 1 | export abstract class StringValueObject { 2 | constructor(public readonly value: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shared/domain/UuidGenerator.ts: -------------------------------------------------------------------------------- 1 | export interface UuidGenerator { 2 | generate(): Promise; 3 | } 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shop/product_reviews/domain/ProductReviewComment.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductReviewComment extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shop/product_reviews/domain/ProductReviewId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductReviewId extends Identifier {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shop/product_reviews/domain/ProductReviewRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductReviewRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shop/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shop/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shop/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shop/products/domain/ProductRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shop/users/domain/UserDoesNotExist.ts: -------------------------------------------------------------------------------- 1 | export class UserDoesNotExist extends Error { 2 | constructor(id: string) { 3 | super(`The user ${id} does not exist`); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shop/users/domain/UserEmail.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserEmail extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shop/users/domain/UserId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class UserId extends Identifier {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shop/users/domain/UserName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shop/users/domain/UserProfilePicture.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserProfilePicture extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /06-external_vs_internal_domain_events/2-enrich_domain_events/src/contexts/shop/users/domain/UserStatus.ts: -------------------------------------------------------------------------------- 1 | export enum UserStatus { 2 | Active = "active", 3 | Archived = "archived", 4 | } 5 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.tsx] 2 | indent_style = tab 3 | tab_width = 2 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/Makefile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/domain_modeling-domain_events-course/4b7bc354df242362d2e8080ef7be083d3ae33df5/07-implement_event_bus/1-sync_event_bus/Makefile -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/etc/http/seller_backoffice/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products/8910e9e9-3567-4e1a-8ffa-9491bdbda12e 2 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/etc/http/seller_backoffice/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products 2 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/etc/http/shop/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products/34878c68-dd03-438d-9f4a-da6e53cf8ca4 2 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/etc/http/shop/product_reviews-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/product_reviews?product_id=1f2a73e3-e0e9-4418-8a53-d080871b24b3 2 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/etc/http/shop/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products 2 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/etc/http/shop/user-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/users/1ec0b8ee-dbdc-48f6-ae5a-bfb99bee5e27 2 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/etc/http/shop/user-PUT.http: -------------------------------------------------------------------------------- 1 | PUT http://localhost:3000/api/shop/users/{{$random.uuid}} 2 | Content-Type: application/json 3 | 4 | { 5 | "name": "Javier Ferrer", 6 | "profilePicture": "https://" 7 | } 8 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/retention/email/domain/EmailBody.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class EmailBody extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/retention/email/domain/EmailId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class EmailId extends Identifier {} 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/retention/email/domain/EmailSender.ts: -------------------------------------------------------------------------------- 1 | import { Email } from "./Email"; 2 | 3 | export interface EmailSender { 4 | send(email: T): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/seller_backoffice/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/seller_backoffice/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/seller_backoffice/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/seller_backoffice/products/domain/ProductViews.ts: -------------------------------------------------------------------------------- 1 | export class ProductViews { 2 | constructor(public readonly value: number) {} 3 | 4 | static initialice(): ProductViews { 5 | return new ProductViews(0); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shared/domain/Collection.ts: -------------------------------------------------------------------------------- 1 | export abstract class Collection { 2 | constructor(public readonly value: T[]) {} 3 | } 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shared/domain/EmailAddress.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export class EmailAddress extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shared/domain/Identifier.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export abstract class Identifier extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shared/domain/Money.ts: -------------------------------------------------------------------------------- 1 | export type Currency = "EUR" | "USD"; 2 | 3 | export type Money = { 4 | amount: number; 5 | currency: Currency; 6 | }; 7 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shared/domain/StringValueObject.ts: -------------------------------------------------------------------------------- 1 | export abstract class StringValueObject { 2 | constructor(public readonly value: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shared/domain/UuidGenerator.ts: -------------------------------------------------------------------------------- 1 | export interface UuidGenerator { 2 | generate(): Promise; 3 | } 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shared/domain/event/DomainEventName.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export type DomainEventName = Pick; 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shared/domain/event/EventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export interface EventBus { 4 | publish(events: DomainEvent[]): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shop/product_reviews/domain/ProductReviewComment.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductReviewComment extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shop/product_reviews/domain/ProductReviewId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductReviewId extends Identifier {} 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shop/product_reviews/domain/ProductReviewRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductReviewRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shop/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shop/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shop/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shop/products/domain/ProductRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shop/users/domain/UserDoesNotExist.ts: -------------------------------------------------------------------------------- 1 | export class UserDoesNotExist extends Error { 2 | constructor(id: string) { 3 | super(`The user ${id} does not exist`); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shop/users/domain/UserEmail.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserEmail extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shop/users/domain/UserId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class UserId extends Identifier {} 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shop/users/domain/UserName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shop/users/domain/UserProfilePicture.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserProfilePicture extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /07-implement_event_bus/1-sync_event_bus/src/contexts/shop/users/domain/UserStatus.ts: -------------------------------------------------------------------------------- 1 | export enum UserStatus { 2 | Active = "active", 3 | Archived = "archived", 4 | } 5 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.tsx] 2 | indent_style = tab 3 | tab_width = 2 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/Makefile: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/domain_modeling-domain_events-course/4b7bc354df242362d2e8080ef7be083d3ae33df5/08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/Makefile -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/etc/http/seller_backoffice/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products/8910e9e9-3567-4e1a-8ffa-9491bdbda12e 2 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/etc/http/seller_backoffice/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/seller_backoffice/products 2 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/etc/http/shop/product-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products/34878c68-dd03-438d-9f4a-da6e53cf8ca4 2 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/etc/http/shop/product_reviews-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/product_reviews?product_id=1f2a73e3-e0e9-4418-8a53-d080871b24b3 2 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/etc/http/shop/products-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/products 2 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/etc/http/shop/user-GET.http: -------------------------------------------------------------------------------- 1 | GET http://localhost:3000/api/shop/users/1ec0b8ee-dbdc-48f6-ae5a-bfb99bee5e27 2 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/etc/http/shop/user-PUT.http: -------------------------------------------------------------------------------- 1 | PUT http://localhost:3000/api/shop/users/{{$random.uuid}} 2 | Content-Type: application/json 3 | 4 | { 5 | "name": "Javier Ferrer", 6 | "profilePicture": "https://" 7 | } 8 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('ts-jest').JestConfigWithTsJest} */ 2 | module.exports = { 3 | preset: "ts-jest", 4 | testEnvironment: "node", 5 | }; 6 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/retention/email/domain/EmailBody.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class EmailBody extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/retention/email/domain/EmailId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class EmailId extends Identifier {} 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/retention/email/domain/EmailSender.ts: -------------------------------------------------------------------------------- 1 | import { Email } from "./Email"; 2 | 3 | export interface EmailSender { 4 | send(email: T): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/seller_backoffice/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/seller_backoffice/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/seller_backoffice/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shared/domain/Collection.ts: -------------------------------------------------------------------------------- 1 | export abstract class Collection { 2 | constructor(public readonly value: T[]) {} 3 | } 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shared/domain/EmailAddress.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export class EmailAddress extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shared/domain/Identifier.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "./StringValueObject"; 2 | 3 | export abstract class Identifier extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shared/domain/Money.ts: -------------------------------------------------------------------------------- 1 | export type Currency = "EUR" | "USD"; 2 | 3 | export type Money = { 4 | amount: number; 5 | currency: Currency; 6 | }; 7 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shared/domain/StringValueObject.ts: -------------------------------------------------------------------------------- 1 | export abstract class StringValueObject { 2 | constructor(public readonly value: string) {} 3 | } 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shared/domain/UuidGenerator.ts: -------------------------------------------------------------------------------- 1 | export interface UuidGenerator { 2 | generate(): Promise; 3 | } 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shared/domain/event/DomainEventName.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export type DomainEventName = Pick; 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shared/domain/event/EventBus.ts: -------------------------------------------------------------------------------- 1 | import { DomainEvent } from "./DomainEvent"; 2 | 3 | export interface EventBus { 4 | publish(events: DomainEvent[]): Promise; 5 | } 6 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shop/product_reviews/domain/ProductReviewComment.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductReviewComment extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shop/product_reviews/domain/ProductReviewId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductReviewId extends Identifier {} 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shop/product_reviews/domain/ProductReviewRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductReviewRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shop/products/domain/ProductId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class ProductId extends Identifier {} 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shop/products/domain/ProductImageUrl.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductImageUrl extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shop/products/domain/ProductName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class ProductName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shop/products/domain/ProductRating.ts: -------------------------------------------------------------------------------- 1 | export class ProductRating { 2 | constructor(public readonly value: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shop/users/domain/UserDoesNotExist.ts: -------------------------------------------------------------------------------- 1 | export class UserDoesNotExist extends Error { 2 | constructor(id: string) { 3 | super(`The user ${id} does not exist`); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shop/users/domain/UserEmail.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserEmail extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shop/users/domain/UserId.ts: -------------------------------------------------------------------------------- 1 | import { Identifier } from "../../../shared/domain/Identifier"; 2 | 3 | export class UserId extends Identifier {} 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shop/users/domain/UserName.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserName extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shop/users/domain/UserProfilePicture.ts: -------------------------------------------------------------------------------- 1 | import { StringValueObject } from "../../../shared/domain/StringValueObject"; 2 | 3 | export class UserProfilePicture extends StringValueObject {} 4 | -------------------------------------------------------------------------------- /08-add_domain_events_to_legacy/2-add_event_bus/1-without_events/src/contexts/shop/users/domain/UserStatus.ts: -------------------------------------------------------------------------------- 1 | export enum UserStatus { 2 | Active = "active", 3 | Archived = "archived", 4 | } 5 | -------------------------------------------------------------------------------- /09-change_data_capture/2-add_change_data_capture/.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: https://bit.ly/CodelyTvPro 2 | -------------------------------------------------------------------------------- /09-change_data_capture/2-add_change_data_capture/apps/backoffice/backend/config/routes/courses.yaml: -------------------------------------------------------------------------------- 1 | courses_get: 2 | path: /courses 3 | controller: CodelyTv\Apps\Backoffice\Backend\Controller\Courses\CoursesGetController 4 | defaults: { auth: false } 5 | methods: [GET] 6 | -------------------------------------------------------------------------------- /09-change_data_capture/2-add_change_data_capture/apps/backoffice/backend/config/routes/health-check.yaml: -------------------------------------------------------------------------------- 1 | health-check_get: 2 | path: /health-check 3 | controller: CodelyTv\Apps\Backoffice\Backend\Controller\HealthCheck\HealthCheckGetController 4 | methods: [GET] 5 | -------------------------------------------------------------------------------- /09-change_data_capture/2-add_change_data_capture/apps/backoffice/backend/config/routes/metrics.yaml: -------------------------------------------------------------------------------- 1 | metrics_get: 2 | path: /metrics 3 | controller: CodelyTv\Apps\Backoffice\Backend\Controller\Metrics\MetricsController 4 | methods: [GET] 5 | -------------------------------------------------------------------------------- /09-change_data_capture/2-add_change_data_capture/apps/backoffice/frontend/config/routes/api_courses.yaml: -------------------------------------------------------------------------------- 1 | api_courses_get: 2 | path: /api/courses 3 | controller: CodelyTv\Apps\Backoffice\Frontend\Controller\Courses\ApiCoursesGetController 4 | methods: [GET] 5 | -------------------------------------------------------------------------------- /09-change_data_capture/2-add_change_data_capture/apps/backoffice/frontend/config/routes/health-check.yaml: -------------------------------------------------------------------------------- 1 | health-check_get: 2 | path: /health-check 3 | controller: CodelyTv\Apps\Backoffice\Frontend\Controller\HealthCheck\HealthCheckGetController 4 | methods: [GET] 5 | -------------------------------------------------------------------------------- /09-change_data_capture/2-add_change_data_capture/apps/backoffice/frontend/config/routes/home.yaml: -------------------------------------------------------------------------------- 1 | home_get: 2 | path: / 3 | controller: CodelyTv\Apps\Backoffice\Frontend\Controller\Home\HomeGetWebController 4 | methods: [GET] 5 | -------------------------------------------------------------------------------- /09-change_data_capture/2-add_change_data_capture/apps/backoffice/frontend/config/routes/metrics.yaml: -------------------------------------------------------------------------------- 1 | metrics_get: 2 | path: /metrics 3 | controller: CodelyTv\Apps\Backoffice\Frontend\Controller\Metrics\MetricsController 4 | methods: [GET] 5 | -------------------------------------------------------------------------------- /09-change_data_capture/2-add_change_data_capture/apps/backoffice/frontend/templates/pages/home.html.twig: -------------------------------------------------------------------------------- 1 | {% extends 'master.html.twig' %} 2 | 3 | {% block page_title %}HOME{% endblock %} 4 | 5 | {% block main %} 6 | HOLIII HOME 7 | {% endblock %} 8 | -------------------------------------------------------------------------------- /09-change_data_capture/2-add_change_data_capture/apps/mooc/backend/config/routes/courses.yaml: -------------------------------------------------------------------------------- 1 | courses_put: 2 | path: /courses/{id} 3 | controller: CodelyTv\Apps\Mooc\Backend\Controller\Courses\CoursesPutController 4 | methods: [PUT] 5 | -------------------------------------------------------------------------------- /09-change_data_capture/2-add_change_data_capture/apps/mooc/backend/config/routes/courses_counter.yaml: -------------------------------------------------------------------------------- 1 | courses_counter_get: 2 | path: /courses-counter 3 | controller: CodelyTv\Apps\Mooc\Backend\Controller\CoursesCounter\CoursesCounterGetController 4 | methods: [GET] 5 | -------------------------------------------------------------------------------- /09-change_data_capture/2-add_change_data_capture/apps/mooc/backend/config/routes/health-check.yaml: -------------------------------------------------------------------------------- 1 | health-check_get: 2 | path: /health-check 3 | controller: CodelyTv\Apps\Mooc\Backend\Controller\HealthCheck\HealthCheckGetController 4 | methods: [GET] 5 | -------------------------------------------------------------------------------- /09-change_data_capture/2-add_change_data_capture/apps/mooc/backend/config/routes/metrics.yaml: -------------------------------------------------------------------------------- 1 | metrics_get: 2 | path: /metrics 3 | controller: CodelyTv\Apps\Mooc\Backend\Controller\Metrics\MetricsController 4 | methods: [GET] 5 | -------------------------------------------------------------------------------- /09-change_data_capture/2-add_change_data_capture/apps/mooc/frontend/src/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodelyTV/domain_modeling-domain_events-course/4b7bc354df242362d2e8080ef7be083d3ae33df5/09-change_data_capture/2-add_change_data_capture/apps/mooc/frontend/src/.gitkeep -------------------------------------------------------------------------------- /09-change_data_capture/2-add_change_data_capture/behat.yml: -------------------------------------------------------------------------------- 1 | imports: 2 | - apps/mooc/backend/tests/mooc_backend.yml 3 | -------------------------------------------------------------------------------- /09-change_data_capture/2-add_change_data_capture/etc/endpoints/mooc_backend.http: -------------------------------------------------------------------------------- 1 | # Create a course 2 | PUT localhost:8030/courses/{{$uuid}} 3 | Content-Type: application/json 4 | 5 | { 6 | "name": "The best course", 7 | "duration": "5 hours" 8 | } 9 | 10 | ### 11 | -------------------------------------------------------------------------------- /09-change_data_capture/2-add_change_data_capture/etc/infrastructure/php/conf.d/opcache.ini: -------------------------------------------------------------------------------- 1 | opcache.memory_consumption=128 2 | opcache.interned_strings_buffer=8 3 | opcache.max_accelerated_files=4000 4 | opcache.revalidate_freq=60 5 | opcache.fast_shutdown=1 6 | opcache.enable_cli=1 7 | -------------------------------------------------------------------------------- /09-change_data_capture/2-add_change_data_capture/etc/infrastructure/php/php.ini: -------------------------------------------------------------------------------- 1 | date.timezone = "UTC" 2 | html_errors = "On" 3 | display_errors = "On" 4 | error_reporting = E_ALL 5 | -------------------------------------------------------------------------------- /09-change_data_capture/2-add_change_data_capture/src/Mooc/Videos/Domain/VideoId.php: -------------------------------------------------------------------------------- 1 |