├── .github ├── ISSUE_TEMPLATE │ └── issue-template.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── CI.yml ├── .gitignore ├── Dockerfile ├── README.md ├── build.gradle ├── common └── domain │ ├── .gitignore │ ├── build.gradle │ ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties │ └── src │ ├── main │ └── java │ │ └── com │ │ └── sparta │ │ └── common │ │ └── domain │ │ ├── DomainApplication.java │ │ ├── entity │ │ ├── BaseEntity.java │ │ └── KafkaTopicConstant.java │ │ ├── exception │ │ └── BusinessException.java │ │ ├── jwt │ │ └── JwtGlobalConstant.java │ │ └── response │ │ └── ApiResponse.java │ └── test │ └── java │ └── com │ └── sparta │ └── common │ └── domain │ └── DomainApplicationTests.java ├── compose-monitoring.yml ├── docker-compose-dep.yml ├── docker-compose.yml ├── dockerTagAndPush.sh ├── filebeat.yml ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── logstash.conf ├── metricbeat.yml ├── prometheus.yml ├── service ├── auth │ ├── auth_dto │ │ ├── .gitignore │ │ ├── build.gradle │ │ └── src │ │ │ └── main │ │ │ └── java │ │ │ └── com │ │ │ └── sparta │ │ │ └── auth │ │ │ └── auth_dto │ │ │ ├── AuthDtoApplication.java │ │ │ └── jwt │ │ │ └── JwtClaim.java │ └── server │ │ ├── .gitignore │ │ ├── build.gradle │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── sparta │ │ │ │ └── auth │ │ │ │ └── server │ │ │ │ ├── AuthApplication.java │ │ │ │ ├── application │ │ │ │ ├── dto │ │ │ │ │ └── AuthResponse.java │ │ │ │ └── service │ │ │ │ │ ├── AuthService.java │ │ │ │ │ └── UserService.java │ │ │ │ ├── domain │ │ │ │ └── JwtConstant.java │ │ │ │ ├── exception │ │ │ │ ├── AuthControllerAdvice.java │ │ │ │ ├── AuthErrorCode.java │ │ │ │ └── AuthException.java │ │ │ │ ├── infrastructure │ │ │ │ ├── configuration │ │ │ │ │ ├── JwtConfig.java │ │ │ │ │ ├── SecurityConfig.java │ │ │ │ │ └── UserFeignConfig.java │ │ │ │ ├── feign │ │ │ │ │ ├── UserClient.java │ │ │ │ │ └── UserErrorDecoder.java │ │ │ │ └── properties │ │ │ │ │ └── JwtProperties.java │ │ │ │ └── presentation │ │ │ │ ├── controller │ │ │ │ ├── AuthController.java │ │ │ │ └── AuthInternalController.java │ │ │ │ └── request │ │ │ │ └── AuthRequest.java │ │ └── resources │ │ │ ├── application-local.yml │ │ │ ├── application-prod.yml │ │ │ ├── application.yml │ │ │ └── logback-spring.xml │ │ └── test │ │ ├── java │ │ └── com │ │ │ └── sparta │ │ │ └── auth │ │ │ └── server │ │ │ ├── AuthApplicationTests.java │ │ │ └── http │ │ │ └── AuthApiTest.http │ │ └── resources │ │ └── application-test.yml ├── eureka │ └── server │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── sparta │ │ │ │ └── eureka │ │ │ │ └── EurekaApplication.java │ │ └── resources │ │ │ ├── application-local.yml │ │ │ ├── application-prod.yml │ │ │ └── application.yml │ │ └── test │ │ └── java │ │ └── com │ │ └── sparta │ │ └── eureka │ │ └── EurekaApplicationTests.java ├── gateway │ └── server │ │ ├── .gitignore │ │ ├── build.gradle │ │ └── src │ │ └── main │ │ ├── java │ │ └── com │ │ │ └── sparta │ │ │ └── gateway │ │ │ └── server │ │ │ ├── GatewayApplication.java │ │ │ ├── application │ │ │ ├── AuthService.java │ │ │ ├── DistributedLockComponent.java │ │ │ ├── UserQueueService.java │ │ │ └── dto │ │ │ │ └── RegisterUserResponse.java │ │ │ └── infrastructure │ │ │ ├── configuration │ │ │ ├── AuthFeignConfig.java │ │ │ └── RedissonConfig.java │ │ │ ├── exception │ │ │ ├── GatewayErrorCode.java │ │ │ ├── GatewayException.java │ │ │ └── GatewayExceptionHandler.java │ │ │ ├── feign │ │ │ └── AuthClient.java │ │ │ └── filter │ │ │ ├── GlobalQueueFilter.java │ │ │ └── JwtAuthenticationFilter.java │ │ └── resources │ │ ├── application-local.yml │ │ ├── application-prod.yml │ │ ├── application.yml │ │ └── logback-spring.xml ├── notification │ ├── notification_dto │ │ ├── .gitignore │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ ├── com │ │ │ │ │ └── sparta │ │ │ │ │ │ └── notification │ │ │ │ │ │ └── notification_dto │ │ │ │ │ │ └── NotificationDtoApplication.java │ │ │ │ └── dto │ │ │ │ │ └── NotificationCreateRequest.java │ │ │ └── resources │ │ │ │ └── application.properties │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── sparta │ │ │ └── notification │ │ │ └── notification_dto │ │ │ └── NotificationDtoApplicationTests.java │ └── server │ │ ├── .gitignore │ │ ├── build.gradle │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── sparta │ │ │ │ └── notification │ │ │ │ └── server │ │ │ │ ├── NotificationApplication.java │ │ │ │ ├── application │ │ │ │ └── service │ │ │ │ │ ├── NotificationService.java │ │ │ │ │ └── strategy │ │ │ │ │ ├── CreateEventNotificationStrategy.java │ │ │ │ │ ├── CreateNotificationService.java │ │ │ │ │ ├── CreateOrderNotificationStrategy.java │ │ │ │ │ └── CreateRestockNotificationStrategy.java │ │ │ │ ├── domain │ │ │ │ ├── model │ │ │ │ │ ├── Notification.java │ │ │ │ │ └── vo │ │ │ │ │ │ └── NotificationType.java │ │ │ │ └── repository │ │ │ │ │ └── NotificationRepository.java │ │ │ │ ├── exception │ │ │ │ ├── BusinessExceptionHandler.java │ │ │ │ ├── NotificationErrorCode.java │ │ │ │ └── NotificationException.java │ │ │ │ ├── infrastructure │ │ │ │ └── client │ │ │ │ │ ├── OrderClient.java │ │ │ │ │ └── UserClient.java │ │ │ │ └── presentation │ │ │ │ └── controller │ │ │ │ └── NotificationController.java │ │ └── resources │ │ │ ├── application-local.yml │ │ │ └── application.yml │ │ └── test │ │ └── java │ │ └── com │ │ └── sparta │ │ └── notification │ │ └── server │ │ └── NotificationApplicationTests.java ├── order │ ├── docker-compose.yml │ ├── dto │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ └── src │ │ │ ├── main │ │ │ └── java │ │ │ │ ├── com │ │ │ │ └── sparta │ │ │ │ │ └── order │ │ │ │ │ └── dto │ │ │ │ │ └── OrderDtoApplication.java │ │ │ │ └── dto │ │ │ │ ├── NotificationOrderDto.java │ │ │ │ ├── OrderCreateRequest.java │ │ │ │ ├── OrderProductDto.java │ │ │ │ └── OrderProductInfo.java │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── sparta │ │ │ └── order │ │ │ └── dto │ │ │ └── NotificationOrderDtoApplicationTests.java │ └── server │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── docs │ │ ├── CartApiTest.http │ │ ├── OrderApiTest.http │ │ └── UserApiTest.http │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── sparta │ │ │ │ └── order │ │ │ │ └── server │ │ │ │ ├── OrderApplication.java │ │ │ │ ├── application │ │ │ │ └── service │ │ │ │ │ ├── CartService.java │ │ │ │ │ ├── OrderCreateService.java │ │ │ │ │ ├── OrderEventHandler.java │ │ │ │ │ ├── OrderRollbackService.java │ │ │ │ │ ├── OrderService.java │ │ │ │ │ └── mapper │ │ │ │ │ └── OrderMapper.java │ │ │ │ ├── domain │ │ │ │ ├── model │ │ │ │ │ ├── Order.java │ │ │ │ │ ├── OrderProduct.java │ │ │ │ │ └── vo │ │ │ │ │ │ ├── OrderState.java │ │ │ │ │ │ └── OrderType.java │ │ │ │ └── repository │ │ │ │ │ ├── OrderProductRepository.java │ │ │ │ │ ├── OrderRepository.java │ │ │ │ │ ├── OrderRepositoryCustom.java │ │ │ │ │ └── OrderRepositoryImpl.java │ │ │ │ ├── exception │ │ │ │ ├── BusinessExceptionHandler.java │ │ │ │ ├── CartErrorCode.java │ │ │ │ ├── CartException.java │ │ │ │ ├── OrderErrorCode.java │ │ │ │ └── OrderException.java │ │ │ │ ├── infrastructure │ │ │ │ ├── client │ │ │ │ │ ├── PaymentClient.java │ │ │ │ │ ├── ProductClient.java │ │ │ │ │ └── UserClient.java │ │ │ │ ├── configuration │ │ │ │ │ ├── QueryDslConfig.java │ │ │ │ │ ├── RedisConfig.java │ │ │ │ │ └── SecurityConfig.java │ │ │ │ ├── event │ │ │ │ │ └── PaymentCompletedEvent.java │ │ │ │ ├── filter │ │ │ │ │ ├── JwtAuthentication.java │ │ │ │ │ └── SecurityContextFilter.java │ │ │ │ └── messaging │ │ │ │ │ └── PreOrderConsumer.java │ │ │ │ └── presentation │ │ │ │ ├── controller │ │ │ │ ├── CartController.java │ │ │ │ ├── OrderController.java │ │ │ │ └── OrderInternalController.java │ │ │ │ └── dto │ │ │ │ ├── CartDto.java │ │ │ │ └── OrderDto.java │ │ └── resources │ │ │ ├── application-local.yml │ │ │ ├── application-prod.yml │ │ │ ├── application.yml │ │ │ └── logback-spring.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── sparta │ │ └── order │ │ └── server │ │ └── OrderApplicationTests.java ├── payment │ ├── payment_dto │ │ ├── .gitignore │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── sparta │ │ │ │ └── payment_dto │ │ │ │ ├── PaymentDtoApplication.java │ │ │ │ └── infrastructure │ │ │ │ └── PaymentInternalDto.java │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── sparta │ │ │ └── payment_dto │ │ │ └── PaymentDtoApplicationTests.java │ └── server │ │ ├── .gitignore │ │ ├── build.gradle │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── sparta │ │ │ │ └── payment │ │ │ │ ├── PaymentApplication.java │ │ │ │ ├── application │ │ │ │ └── service │ │ │ │ │ └── PaymentService.java │ │ │ │ ├── domain │ │ │ │ ├── entity │ │ │ │ │ ├── Payment.java │ │ │ │ │ ├── PaymentHistory.java │ │ │ │ │ └── PaymentState.java │ │ │ │ └── repository │ │ │ │ │ ├── PaymentHistoryRepository.java │ │ │ │ │ ├── PaymentRepository.java │ │ │ │ │ ├── PaymentRepositoryCustom.java │ │ │ │ │ └── PaymentRepositoryCustomImpl.java │ │ │ │ ├── exception │ │ │ │ ├── PaymentErrorCode.java │ │ │ │ ├── PaymentException.java │ │ │ │ └── PaymentExceptionHandler.java │ │ │ │ ├── infrastructure │ │ │ │ ├── client │ │ │ │ │ └── MessageClient.java │ │ │ │ ├── config │ │ │ │ │ ├── QuerydslConfing.java │ │ │ │ │ └── SecurityConfig.java │ │ │ │ ├── event │ │ │ │ │ └── PaymentCompletedEvent.java │ │ │ │ └── filter │ │ │ │ │ ├── JwtAuthentication.java │ │ │ │ │ └── SecurityContextFilter.java │ │ │ │ └── presentation │ │ │ │ ├── PaymentController.java │ │ │ │ ├── PaymentInternalController.java │ │ │ │ └── dto │ │ │ │ ├── PaymentHistoryResponse.java │ │ │ │ ├── PaymentRequest.java │ │ │ │ └── PaymentResponse.java │ │ └── resources │ │ │ ├── application-local.yml │ │ │ ├── application-prod.yml │ │ │ ├── application.yml │ │ │ ├── logback-spring.xml │ │ │ └── templates │ │ │ └── success.html │ │ └── test │ │ └── java │ │ └── com │ │ └── sparta │ │ └── payment │ │ └── server │ │ └── PaymentApplicationTests.java ├── product │ ├── product_dto │ │ ├── .gitignore │ │ ├── build.gradle │ │ └── src │ │ │ ├── main │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── sparta │ │ │ │ └── product_dto │ │ │ │ ├── ProductDto.java │ │ │ │ ├── ProductDtoApplication.java │ │ │ │ └── ProductReadRequest.java │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── sparta │ │ │ └── product_dto │ │ │ └── ProductDtoApplicationTests.java │ └── server │ │ ├── .gitignore │ │ ├── build.gradle │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── sparta │ │ │ │ └── product │ │ │ │ ├── ProductServerApplication.java │ │ │ │ ├── application │ │ │ │ ├── category │ │ │ │ │ ├── CategoryCache.java │ │ │ │ │ └── CategoryService.java │ │ │ │ ├── dto │ │ │ │ │ └── ImgDto.java │ │ │ │ ├── preorder │ │ │ │ │ ├── DistributedLockComponent.java │ │ │ │ │ ├── PreOrderCacheService.java │ │ │ │ │ ├── PreOrderFacadeService.java │ │ │ │ │ ├── PreOrderLockService.java │ │ │ │ │ ├── PreOrderMapper.java │ │ │ │ │ ├── PreOrderRedisService.java │ │ │ │ │ └── PreOrderService.java │ │ │ │ └── product │ │ │ │ │ ├── ElasticsearchService.java │ │ │ │ │ ├── ImageService.java │ │ │ │ │ ├── ProductFacadeService.java │ │ │ │ │ ├── ProductLockService.java │ │ │ │ │ ├── ProductMapper.java │ │ │ │ │ ├── ProductService.java │ │ │ │ │ └── S3ImageService.java │ │ │ │ ├── domain │ │ │ │ ├── model │ │ │ │ │ ├── Category.java │ │ │ │ │ ├── PreOrder.java │ │ │ │ │ ├── PreOrderState.java │ │ │ │ │ ├── Product.java │ │ │ │ │ └── SortOption.java │ │ │ │ └── repository │ │ │ │ │ ├── ElasticSearchRepository.java │ │ │ │ │ ├── ElasticsearchCustomRepository.java │ │ │ │ │ ├── cassandra │ │ │ │ │ └── ProductRepository.java │ │ │ │ │ ├── jpa │ │ │ │ │ ├── CategoryRepository.java │ │ │ │ │ └── PreOrderRepository.java │ │ │ │ │ └── redis │ │ │ │ │ └── RedisRepository.java │ │ │ │ ├── infrastructure │ │ │ │ ├── configuration │ │ │ │ │ ├── AuditAwareImpl.java │ │ │ │ │ ├── ElasticsearchClientConfig.java │ │ │ │ │ ├── KafkaConfig.java │ │ │ │ │ ├── RedisConfig.java │ │ │ │ │ ├── RedissonConfig.java │ │ │ │ │ ├── RepositoryConfig.java │ │ │ │ │ ├── S3Config.java │ │ │ │ │ └── SecurityConfig.java │ │ │ │ ├── filter │ │ │ │ │ ├── JwtAuthentication.java │ │ │ │ │ └── SecurityContextFilter.java │ │ │ │ ├── messaging │ │ │ │ │ └── PreOrderProducer.java │ │ │ │ └── utils │ │ │ │ │ ├── PreOrderRedisDto.java │ │ │ │ │ ├── ProductSearchDto.java │ │ │ │ │ └── RedisUtils.java │ │ │ │ └── presentation │ │ │ │ ├── controller │ │ │ │ ├── CategoryController.java │ │ │ │ ├── PreOrderController.java │ │ │ │ ├── ProductController.java │ │ │ │ ├── ProductInternalController.java │ │ │ │ └── ProductSearchController.java │ │ │ │ ├── exception │ │ │ │ ├── ProductControllerAdvice.java │ │ │ │ ├── ProductErrorCode.java │ │ │ │ └── ProductServerException.java │ │ │ │ ├── request │ │ │ │ ├── CategoryCreateRequest.java │ │ │ │ ├── CategoryUpdateRequest.java │ │ │ │ ├── PreOrderCreateRequest.java │ │ │ │ ├── PreOrderUpdateRequest.java │ │ │ │ ├── ProductCreateRequest.java │ │ │ │ └── ProductUpdateRequest.java │ │ │ │ └── response │ │ │ │ ├── CategoryResponse.java │ │ │ │ ├── PreOrderResponse.java │ │ │ │ └── ProductResponse.java │ │ └── resources │ │ │ ├── application-local.yml │ │ │ ├── application-prod.yml │ │ │ ├── application.yml │ │ │ └── logback-spring.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── sparta │ │ └── product │ │ └── ProductServerApplicationTests.java ├── promotion │ └── server │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── sparta │ │ │ │ └── promotion │ │ │ │ └── server │ │ │ │ ├── PromotionApplication.java │ │ │ │ ├── application │ │ │ │ └── service │ │ │ │ │ ├── CouponService.java │ │ │ │ │ ├── DistributedLockComponent.java │ │ │ │ │ ├── EventService.java │ │ │ │ │ └── UserService.java │ │ │ │ ├── domain │ │ │ │ ├── model │ │ │ │ │ ├── Coupon.java │ │ │ │ │ ├── Event.java │ │ │ │ │ ├── UserCoupon.java │ │ │ │ │ └── vo │ │ │ │ │ │ ├── CouponType.java │ │ │ │ │ │ └── DiscountType.java │ │ │ │ └── repository │ │ │ │ │ ├── CouponRepository.java │ │ │ │ │ ├── EventRepository.java │ │ │ │ │ └── UserCouponRepository.java │ │ │ │ ├── exception │ │ │ │ ├── PromotionControllerAdvice.java │ │ │ │ ├── PromotionErrorCode.java │ │ │ │ └── PromotionException.java │ │ │ │ ├── infrastructure │ │ │ │ ├── configuration │ │ │ │ │ ├── RedissonConfig.java │ │ │ │ │ ├── SecurityConfig.java │ │ │ │ │ └── UserFeignConfig.java │ │ │ │ ├── feign │ │ │ │ │ ├── UserClient.java │ │ │ │ │ └── UserErrorDecoder.java │ │ │ │ ├── filter │ │ │ │ │ ├── JwtAuthentication.java │ │ │ │ │ └── SecurityContextFilter.java │ │ │ │ ├── messaging │ │ │ │ │ └── CouponEventConsumer.java │ │ │ │ └── repository │ │ │ │ │ ├── CouponRepositoryImpl.java │ │ │ │ │ ├── JpaCouponRepository.java │ │ │ │ │ ├── JpaUserCouponRepository.java │ │ │ │ │ └── UserCouponRepositoryImpl.java │ │ │ │ └── presentation │ │ │ │ ├── controller │ │ │ │ ├── CouponController.java │ │ │ │ ├── CouponInternalController.java │ │ │ │ └── EventController.java │ │ │ │ ├── request │ │ │ │ ├── CouponRequest.java │ │ │ │ └── EventRequest.java │ │ │ │ └── response │ │ │ │ ├── CouponResponse.java │ │ │ │ └── EventResponse.java │ │ └── resources │ │ │ ├── application-local.yml │ │ │ ├── application-prod.yml │ │ │ ├── application.yml │ │ │ └── logback-spring.xml │ │ └── test │ │ ├── java │ │ └── com │ │ │ └── sparta │ │ │ └── promotion │ │ │ └── server │ │ │ ├── http │ │ │ └── CouponApiTest.http │ │ │ └── service │ │ │ └── CouponServiceTests.java │ │ └── resources │ │ └── application-test.yml ├── search │ └── server │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── sparta │ │ │ │ └── server │ │ │ │ ├── SearchApplication.java │ │ │ │ ├── application │ │ │ │ └── SearchService.java │ │ │ │ ├── domain │ │ │ │ ├── ProductSearchDto.java │ │ │ │ └── SortOption.java │ │ │ │ ├── exception │ │ │ │ ├── SearchErrorCode.java │ │ │ │ ├── SearchException.java │ │ │ │ └── SearchExceptionHandler.java │ │ │ │ ├── infrastructure │ │ │ │ └── ElasticsearchClientConfig.java │ │ │ │ └── presentaion │ │ │ │ └── SearchController.java │ │ └── resources │ │ │ ├── application-local.yml │ │ │ ├── application-prod.yml │ │ │ ├── application.yml │ │ │ └── logback-spring.xml │ │ └── test │ │ └── java │ │ └── com │ │ └── sparta │ │ └── server │ │ └── SearchApplicationTests.java ├── slack │ ├── server │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── sparta │ │ │ │ │ └── slack │ │ │ │ │ ├── SlackApplication.java │ │ │ │ │ ├── application │ │ │ │ │ ├── dto │ │ │ │ │ │ ├── MessageRequest.java │ │ │ │ │ │ └── MessageResponse.java │ │ │ │ │ └── service │ │ │ │ │ │ └── MessageService.java │ │ │ │ │ ├── domain │ │ │ │ │ ├── entity │ │ │ │ │ │ └── Message.java │ │ │ │ │ └── repository │ │ │ │ │ │ └── MessageRepository.java │ │ │ │ │ ├── exception │ │ │ │ │ ├── MessageErrorCode.java │ │ │ │ │ ├── MessageException.java │ │ │ │ │ └── MessageExceptionHandler.java │ │ │ │ │ └── presentation │ │ │ │ │ └── controller │ │ │ │ │ └── MessageController.java │ │ │ └── resources │ │ │ │ ├── application-local.yml │ │ │ │ ├── application-prod.yml │ │ │ │ ├── application.yml │ │ │ │ └── logback-spring.xml │ │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── sparta │ │ │ └── slack │ │ │ └── SlackApplicationTests.java │ └── slack_dto │ │ ├── .gitignore │ │ ├── build.gradle │ │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── sparta │ │ │ │ └── slack_dto │ │ │ │ ├── SlackDtoApplication.java │ │ │ │ └── infrastructure │ │ │ │ └── MessageInternalDto.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── sparta │ │ └── slack_dto │ │ └── SlackDtoApplicationTests.java └── user │ ├── server │ ├── .gitignore │ ├── build.gradle │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── sparta │ │ │ │ └── user │ │ │ │ ├── UserApplication.java │ │ │ │ ├── application │ │ │ │ ├── dto │ │ │ │ │ ├── AddressResponse.java │ │ │ │ │ ├── PointResponse.java │ │ │ │ │ ├── TierResponse.java │ │ │ │ │ ├── UserResponse.java │ │ │ │ │ └── UserTierResponse.java │ │ │ │ └── service │ │ │ │ │ ├── AddressService.java │ │ │ │ │ ├── PointHistoryService.java │ │ │ │ │ ├── TierService.java │ │ │ │ │ └── UserService.java │ │ │ │ ├── domain │ │ │ │ ├── model │ │ │ │ │ ├── Address.java │ │ │ │ │ ├── PointHistory.java │ │ │ │ │ ├── Tier.java │ │ │ │ │ ├── User.java │ │ │ │ │ ├── UserTier.java │ │ │ │ │ └── vo │ │ │ │ │ │ ├── PointHistoryType.java │ │ │ │ │ │ └── UserRole.java │ │ │ │ └── repository │ │ │ │ │ ├── AddressRepository.java │ │ │ │ │ ├── PointHistoryRepository.java │ │ │ │ │ ├── TierRepository.java │ │ │ │ │ ├── UserRepository.java │ │ │ │ │ └── UserTierRepository.java │ │ │ │ ├── exception │ │ │ │ ├── UserControllerAdvice.java │ │ │ │ ├── UserErrorCode.java │ │ │ │ └── UserException.java │ │ │ │ ├── infrastructure │ │ │ │ ├── configuration │ │ │ │ │ └── SecurityConfig.java │ │ │ │ ├── filter │ │ │ │ │ ├── JwtAuthentication.java │ │ │ │ │ └── SecurityContextFilter.java │ │ │ │ └── repository │ │ │ │ │ ├── AddressRepositoryImpl.java │ │ │ │ │ ├── JpaAddressRepository.java │ │ │ │ │ ├── JpaPointHistoryRepository.java │ │ │ │ │ ├── JpaTierRepository.java │ │ │ │ │ ├── JpaUserRepository.java │ │ │ │ │ ├── JpaUserTierRepository.java │ │ │ │ │ ├── PointHistoryRepositoryImpl.java │ │ │ │ │ ├── TierRepositoryImpl.java │ │ │ │ │ ├── UserRepositoryImpl.java │ │ │ │ │ └── UserTierRepositoryImpl.java │ │ │ │ └── presentation │ │ │ │ ├── controller │ │ │ │ ├── AddressController.java │ │ │ │ ├── AddressInternalController.java │ │ │ │ ├── PointHistoryController.java │ │ │ │ ├── TierController.java │ │ │ │ ├── UserController.java │ │ │ │ ├── UserInternalController.java │ │ │ │ └── UserTierController.java │ │ │ │ └── request │ │ │ │ ├── AddressRequest.java │ │ │ │ ├── TierRequest.java │ │ │ │ └── UserRequest.java │ │ └── resources │ │ │ ├── application-local.yml │ │ │ ├── application-prod.yml │ │ │ ├── application.yml │ │ │ └── logback-spring.xml │ │ └── test │ │ ├── java │ │ └── com │ │ │ └── sparta │ │ │ └── user │ │ │ ├── http │ │ │ ├── AddressApiTest.http │ │ │ ├── PointHistoryApiTest.http │ │ │ ├── TierApiTest.http │ │ │ └── UserApiTest.http │ │ │ └── service │ │ │ ├── AddressServiceTest.java │ │ │ ├── PointHistoryServiceTests.java │ │ │ ├── TierServiceTests.java │ │ │ └── UserServiceTests.java │ │ └── resources │ │ └── application.yml │ └── user_dto │ ├── .gitignore │ ├── build.gradle │ └── src │ └── main │ └── java │ └── com │ └── sparta │ └── user │ └── user_dto │ ├── UserDtoApplication.java │ └── infrastructure │ ├── AddressDto.java │ ├── PointHistoryDto.java │ └── UserDto.java ├── settings.gradle └── stop-used-port.sh /.github/ISSUE_TEMPLATE/issue-template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: issue-template 3 | about: Suggest an idea for this project 4 | title: "[Feat]" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## 어떤 기능인가요? 11 | 12 | > 추가하려는 기능에 대해 간결하게 설명해주세요 13 | 14 | ## 작업 상세 내용(선택) 15 | 16 | - [ ] TODO 17 | - [ ] TODO 18 | - [ ] TODO -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## 🎯 What is this PR 2 | 3 | - 코드 변경 사유 및 목적 설명 (개요) 4 | 5 | ## 📄 Changes Made 6 | 7 | - 구현 내용 설명 8 | 9 | ## 🙋🏻‍ Review Point 10 | 11 | - 리뷰어가 확인해야 할 사항 코멘트 12 | 13 | ## ✅ Test 14 | 15 | - [ ] 완료한 테스트 항목 16 | > 스크린 샷 첨부 17 | 18 | ## 🔗 Reference 19 | 20 | Issue #{이슈번호} -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | pull_request: 5 | branches: [ dev ] 6 | 7 | jobs: 8 | build: 9 | name: Build 10 | runs-on: ubuntu-latest 11 | permissions: 12 | contents: read 13 | 14 | steps: 15 | - name: Checkout repository 16 | uses: actions/checkout@v4 17 | 18 | - name: Set up JDK 17 19 | uses: actions/setup-java@v4 20 | with: 21 | java-version: '17' 22 | distribution: 'temurin' 23 | 24 | - name: Grant execute permission for gradlew 25 | run: chmod +x gradlew 26 | 27 | - name: Setup Gradle 28 | uses: gradle/actions/setup-gradle@v4 29 | 30 | - name: Build with Gradle 31 | run: ./gradlew clean build -x test 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Dockerfile 2 | FROM openjdk:17-jdk-slim 3 | 4 | # 시간대 설정 5 | ENV TZ=Asia/Seoul 6 | RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone 7 | 8 | WORKDIR /app 9 | 10 | ENV SPRING_PROFILES_ACTIVE=prod 11 | 12 | ARG FILE_DIRECTORY 13 | 14 | COPY $FILE_DIRECTORY/build/libs/*.jar /app/app.jar 15 | 16 | ENTRYPOINT ["java", "-jar", "/app/app.jar"] 17 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.3.4' apply(false) 4 | id 'io.spring.dependency-management' version '1.1.6' apply(false) 5 | } 6 | 7 | group = 'com.sparta' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | toolchain { 12 | languageVersion = JavaLanguageVersion.of(17) 13 | } 14 | } 15 | 16 | repositories { 17 | mavenCentral() 18 | } 19 | 20 | dependencies { 21 | implementation 'org.springframework.boot:spring-boot-starter' 22 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 23 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 24 | } 25 | 26 | tasks.named('test') { 27 | useJUnitPlatform() 28 | } 29 | -------------------------------------------------------------------------------- /common/domain/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /common/domain/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sasaping/sasaping-system/ec6f8346458a507fd2af222f61c33ba8b1c580b1/common/domain/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /common/domain/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /common/domain/src/main/java/com/sparta/common/domain/DomainApplication.java: -------------------------------------------------------------------------------- 1 | package com.sparta.common.domain; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class DomainApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(DomainApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /common/domain/src/main/java/com/sparta/common/domain/entity/BaseEntity.java: -------------------------------------------------------------------------------- 1 | package com.sparta.common.domain.entity; 2 | 3 | import jakarta.persistence.EntityListeners; 4 | import jakarta.persistence.MappedSuperclass; 5 | import java.time.LocalDateTime; 6 | import lombok.Getter; 7 | import org.springframework.data.annotation.CreatedBy; 8 | import org.springframework.data.annotation.CreatedDate; 9 | import org.springframework.data.annotation.LastModifiedBy; 10 | import org.springframework.data.annotation.LastModifiedDate; 11 | import org.springframework.data.jpa.domain.support.AuditingEntityListener; 12 | 13 | @MappedSuperclass 14 | @EntityListeners(AuditingEntityListener.class) 15 | @Getter 16 | public abstract class BaseEntity { 17 | @CreatedDate private LocalDateTime createdAt; 18 | 19 | @CreatedBy private String createdBy; 20 | 21 | @LastModifiedDate private LocalDateTime updatedAt; 22 | 23 | @LastModifiedBy private String updatedBy; 24 | } 25 | -------------------------------------------------------------------------------- /common/domain/src/main/java/com/sparta/common/domain/entity/KafkaTopicConstant.java: -------------------------------------------------------------------------------- 1 | package com.sparta.common.domain.entity; 2 | 3 | public class KafkaTopicConstant { 4 | 5 | public static final String PROCESS_PREORDER = "process_preorder"; 6 | public static final String ERROR_IN_PROCESS_PREORDER = "error_in_create_delivery"; 7 | public static final String PAYMENT_COMPLETED = "payment-completed-topic"; 8 | public static final String PROVIDE_EVENT_COUPON = "provide-event-coupon"; 9 | 10 | } 11 | -------------------------------------------------------------------------------- /common/domain/src/main/java/com/sparta/common/domain/exception/BusinessException.java: -------------------------------------------------------------------------------- 1 | package com.sparta.common.domain.exception; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public abstract class BusinessException extends RuntimeException { 7 | 8 | protected String statusName; 9 | private final String message; 10 | 11 | public BusinessException(String statusName, String message) { 12 | super(message); 13 | this.statusName = statusName; 14 | this.message = message; 15 | } 16 | 17 | public BusinessException(String statusName, String message, Object... args) { 18 | super(formattingErrorMessage(message, args)); 19 | this.statusName = statusName; 20 | this.message = formattingErrorMessage(message, args); 21 | } 22 | 23 | private static String formattingErrorMessage(String message, Object... objects) { 24 | return message.formatted(objects); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /common/domain/src/main/java/com/sparta/common/domain/jwt/JwtGlobalConstant.java: -------------------------------------------------------------------------------- 1 | package com.sparta.common.domain.jwt; 2 | 3 | public interface JwtGlobalConstant { 4 | 5 | String BEARER_PREFIX = "Bearer "; 6 | 7 | String AUTHORIZATION = "Authorization"; 8 | 9 | String X_USER_CLAIMS = "x-user-claims"; 10 | } 11 | -------------------------------------------------------------------------------- /common/domain/src/main/java/com/sparta/common/domain/response/ApiResponse.java: -------------------------------------------------------------------------------- 1 | package com.sparta.common.domain.response; 2 | 3 | import lombok.Getter; 4 | import lombok.NoArgsConstructor; 5 | 6 | @Getter 7 | @NoArgsConstructor 8 | public class ApiResponse { 9 | private String statusName; 10 | private String message; 11 | private T data; 12 | 13 | private ApiResponse(String statusName, String message, T data) { 14 | this.statusName = statusName; 15 | this.message = message; 16 | this.data = data; 17 | } 18 | 19 | public static ApiResponse error(String statusName, String message) { 20 | return new ApiResponse<>(statusName, message, null); 21 | } 22 | 23 | public static ApiResponse error(String statusName, String message, T data) { 24 | return new ApiResponse<>(statusName, message, data); 25 | } 26 | 27 | public static ApiResponse created(T data) { 28 | return new ApiResponse<>("CREATED", null, data); 29 | } 30 | 31 | public static ApiResponse ok(T data) { 32 | return new ApiResponse<>("OK", null, data); 33 | } 34 | 35 | public static ApiResponse ok() { 36 | return new ApiResponse<>("OK", null, null); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /common/domain/src/test/java/com/sparta/common/domain/DomainApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sparta.common.domain; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class DomainApplicationTests { 8 | 9 | @Test 10 | void contextLoads() {} 11 | } 12 | -------------------------------------------------------------------------------- /compose-monitoring.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | prometheus: 5 | image: prom/prometheus:latest 6 | container_name: prometheus 7 | ports: 8 | - "9090:9090" 9 | volumes: 10 | - ./prometheus.yml:/etc/prometheus/prometheus.yml 11 | 12 | grafana: 13 | image: grafana/grafana:latest 14 | container_name: grafana 15 | ports: 16 | - "3000:3000" 17 | volumes: 18 | - ./grafana:/var/lib/grafana 19 | -------------------------------------------------------------------------------- /dockerTagAndPush.sh: -------------------------------------------------------------------------------- 1 | # 모든 서비스 도커 이미지를 빌드합니다. 2 | services=("eureka" "gateway" "user" "auth" "order" "payment" "slack" "product" "promotion" "search") 3 | 4 | # 도커 이미지에 commit hash를 기반으로한 이미지 태그를 설정합니다. 5 | commit_hash=$(git rev-parse --short HEAD) 6 | 7 | for service in "${services[@]}" 8 | do 9 | imageName="$ECR_REGISTRY/$ECR_NAMESPACE/$service" 10 | # 이미지를 구분하기 위해서 latest 이외의 태그를 추가합니다. 11 | docker tag "$imageName:latest" "$imageName:$commit_hash" 12 | 13 | # AWS ECR에 Push 14 | docker push "$imageName:latest" 15 | docker push "$imageName:$commit_hash" 16 | 17 | echo "$service image is built and pushed to AWS ECR" 18 | done 19 | 20 | echo "Build and Push processing is done" 21 | -------------------------------------------------------------------------------- /filebeat.yml: -------------------------------------------------------------------------------- 1 | filebeat.inputs: 2 | - type: filestream 3 | id: default-filestream 4 | paths: 5 | - ingest_data/*.log 6 | 7 | filebeat.autodiscover: 8 | providers: 9 | - type: docker 10 | hints.enabled: true 11 | 12 | processors: 13 | - add_docker_metadata: ~ 14 | 15 | setup.kibana: 16 | host: ${KIBANA_HOSTS} 17 | username: ${ELASTIC_USER} 18 | password: ${ELASTIC_PASSWORD} 19 | 20 | output.elasticsearch: 21 | hosts: ${ELASTIC_HOSTS} 22 | username: ${ELASTIC_USER} 23 | password: ${ELASTIC_PASSWORD} 24 | ssl.enabled: true 25 | ssl.certificate_authorities: "certs/ca/ca.crt" 26 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sasaping/sasaping-system/ec6f8346458a507fd2af222f61c33ba8b1c580b1/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /logstash.conf: -------------------------------------------------------------------------------- 1 | input { 2 | beats{ 3 | port => 5044 4 | } 5 | tcp{ 6 | port => 50000 7 | codec => json_lines 8 | } 9 | file { 10 | mode => "tail" 11 | path => "/usr/share/logstash/ingest_data/*" 12 | } 13 | } 14 | 15 | filter { 16 | } 17 | 18 | output { 19 | elasticsearch { 20 | index => "springboot-elk-%{+YYYY.MM.dd}" 21 | hosts=> "${ELASTIC_HOSTS}" 22 | user=> "${ELASTIC_USER}" 23 | password=> "${ELASTIC_PASSWORD}" 24 | cacert=> "certs/ca/ca.crt" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 15s 3 | scrape_configs: 4 | - job_name: 'eureka-services' 5 | eureka_sd_configs: 6 | - server: 'http://host.docker.internal:19090/eureka' # Eureka 서버 주소 7 | metrics_path: '/actuator/prometheus' 8 | relabel_configs: 9 | - source_labels: [ '__meta_eureka_app_name' ] 10 | target_label: 'job' 11 | - source_labels: [ '__meta_eureka_instance_ip_addr' ] 12 | target_label: 'instance' 13 | - source_labels: [ '__meta_eureka_app_instance_status' ] 14 | action: keep 15 | regex: 'UP' # 서비스 상태가 "UP"인 인스턴스만 스크랩 -------------------------------------------------------------------------------- /service/auth/auth_dto/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | bin/ 16 | !**/src/main/**/bin/ 17 | !**/src/test/**/bin/ 18 | 19 | ### IntelliJ IDEA ### 20 | .idea 21 | *.iws 22 | *.iml 23 | *.ipr 24 | out/ 25 | !**/src/main/**/out/ 26 | !**/src/test/**/out/ 27 | 28 | ### NetBeans ### 29 | /nbproject/private/ 30 | /nbbuild/ 31 | /dist/ 32 | /nbdist/ 33 | /.nb-gradle/ 34 | 35 | ### VS Code ### 36 | .vscode/ 37 | -------------------------------------------------------------------------------- /service/auth/auth_dto/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.3.4' 4 | id 'io.spring.dependency-management' version '1.1.6' 5 | } 6 | 7 | group = 'com.sparta.auth' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | bootJar.enabled = false; 11 | 12 | java { 13 | toolchain { 14 | languageVersion = JavaLanguageVersion.of(17) 15 | } 16 | } 17 | 18 | configurations { 19 | compileOnly { 20 | extendsFrom annotationProcessor 21 | } 22 | } 23 | 24 | repositories { 25 | mavenCentral() 26 | } 27 | 28 | dependencies { 29 | implementation 'org.springframework.boot:spring-boot-starter' 30 | compileOnly 'org.projectlombok:lombok' 31 | annotationProcessor 'org.projectlombok:lombok' 32 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 33 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 34 | } 35 | 36 | tasks.named('test') { 37 | useJUnitPlatform() 38 | } 39 | -------------------------------------------------------------------------------- /service/auth/auth_dto/src/main/java/com/sparta/auth/auth_dto/AuthDtoApplication.java: -------------------------------------------------------------------------------- 1 | package com.sparta.auth.auth_dto; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class AuthDtoApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(AuthDtoApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /service/auth/auth_dto/src/main/java/com/sparta/auth/auth_dto/jwt/JwtClaim.java: -------------------------------------------------------------------------------- 1 | package com.sparta.auth.auth_dto.jwt; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | @AllArgsConstructor 8 | @NoArgsConstructor 9 | @Getter 10 | public class JwtClaim { 11 | 12 | private Long userId; 13 | private String username; 14 | private String role; 15 | 16 | public static JwtClaim create(Long userId, String username, String role) { 17 | return new JwtClaim(userId, username, role); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /service/auth/server/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | bin/ 16 | !**/src/main/**/bin/ 17 | !**/src/test/**/bin/ 18 | 19 | ### IntelliJ IDEA ### 20 | .idea 21 | *.iws 22 | *.iml 23 | *.ipr 24 | out/ 25 | !**/src/main/**/out/ 26 | !**/src/test/**/out/ 27 | 28 | ### NetBeans ### 29 | /nbproject/private/ 30 | /nbbuild/ 31 | /dist/ 32 | /nbdist/ 33 | /.nb-gradle/ 34 | 35 | ### VS Code ### 36 | .vscode/ 37 | -------------------------------------------------------------------------------- /service/auth/server/src/main/java/com/sparta/auth/server/AuthApplication.java: -------------------------------------------------------------------------------- 1 | package com.sparta.auth.server; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 6 | import org.springframework.cloud.openfeign.EnableFeignClients; 7 | 8 | @EnableFeignClients 9 | @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) 10 | public class AuthApplication { 11 | 12 | public static void main(String[] args) { 13 | SpringApplication.run(AuthApplication.class, args); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /service/auth/server/src/main/java/com/sparta/auth/server/application/dto/AuthResponse.java: -------------------------------------------------------------------------------- 1 | package com.sparta.auth.server.application.dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | 8 | public class AuthResponse { 9 | 10 | @Getter 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | @Builder 14 | public static class SignIn { 15 | 16 | private String token; 17 | 18 | public static SignIn of(String token) { 19 | return SignIn.builder().token(token).build(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /service/auth/server/src/main/java/com/sparta/auth/server/application/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.sparta.auth.server.application.service; 2 | 3 | import com.sparta.user.user_dto.infrastructure.UserDto; 4 | 5 | public interface UserService { 6 | 7 | UserDto getUserByUsername(String username); 8 | } 9 | -------------------------------------------------------------------------------- /service/auth/server/src/main/java/com/sparta/auth/server/domain/JwtConstant.java: -------------------------------------------------------------------------------- 1 | package com.sparta.auth.server.domain; 2 | 3 | public interface JwtConstant { 4 | 5 | String USER_ID = "USER_ID"; 6 | 7 | String USER_NAME = "USER_NAME"; 8 | 9 | String USER_ROLE = "USER_ROLE"; 10 | 11 | Long MILLI_SECOND = 1000L; 12 | } 13 | -------------------------------------------------------------------------------- /service/auth/server/src/main/java/com/sparta/auth/server/exception/AuthControllerAdvice.java: -------------------------------------------------------------------------------- 1 | package com.sparta.auth.server.exception; 2 | 3 | import com.sparta.common.domain.response.ApiResponse; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.http.ResponseEntity; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | 9 | @Slf4j 10 | @ControllerAdvice 11 | public class AuthControllerAdvice { 12 | 13 | @ExceptionHandler(AuthException.class) 14 | public ResponseEntity businessExceptionHandler(AuthException e) { 15 | AuthErrorCode errorCode = e.getErrorCode(); 16 | log.error("Error occurs in AuthServer : {}", e.getErrorCode()); 17 | return ResponseEntity.status(errorCode.getStatus()) 18 | .body(ApiResponse.error(errorCode.getStatus().name(), errorCode.getMessage())); 19 | } 20 | 21 | @ExceptionHandler(RuntimeException.class) 22 | public ResponseEntity runtimeExceptionHandler(RuntimeException e) { 23 | log.error("Error occurs in AuthServer : {}", e.getMessage()); 24 | return ResponseEntity.status(AuthErrorCode.INTERNAL_SERVER_ERROR.getStatus()) 25 | .body( 26 | ApiResponse.error( 27 | AuthErrorCode.INTERNAL_SERVER_ERROR.getStatus().name(), e.getMessage())); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /service/auth/server/src/main/java/com/sparta/auth/server/exception/AuthErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.sparta.auth.server.exception; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import org.springframework.http.HttpStatus; 6 | 7 | @Getter 8 | @RequiredArgsConstructor 9 | public enum AuthErrorCode { 10 | SIGN_IN_FAIL(HttpStatus.UNAUTHORIZED, "로그인 실패"), 11 | TOEKN_EXPIRED(HttpStatus.UNAUTHORIZED, "만료된 토큰입니다."), 12 | INVALID_TOKEN(HttpStatus.UNAUTHORIZED, "잘못된 토큰입니다."), 13 | INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "내부 서버 오류"); 14 | 15 | private final HttpStatus status; 16 | private final String message; 17 | } 18 | -------------------------------------------------------------------------------- /service/auth/server/src/main/java/com/sparta/auth/server/exception/AuthException.java: -------------------------------------------------------------------------------- 1 | package com.sparta.auth.server.exception; 2 | 3 | import com.sparta.common.domain.exception.BusinessException; 4 | import lombok.Getter; 5 | 6 | @Getter 7 | public class AuthException extends BusinessException { 8 | 9 | AuthErrorCode errorCode; 10 | 11 | public AuthException(AuthErrorCode errorCode) { 12 | super(errorCode.getStatus().name(), errorCode.getMessage()); 13 | this.errorCode = errorCode; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /service/auth/server/src/main/java/com/sparta/auth/server/infrastructure/configuration/JwtConfig.java: -------------------------------------------------------------------------------- 1 | package com.sparta.auth.server.infrastructure.configuration; 2 | 3 | import com.sparta.auth.server.infrastructure.properties.JwtProperties; 4 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 5 | import org.springframework.context.annotation.Configuration; 6 | 7 | @Configuration 8 | @EnableConfigurationProperties(JwtProperties.class) 9 | public class JwtConfig {} 10 | -------------------------------------------------------------------------------- /service/auth/server/src/main/java/com/sparta/auth/server/infrastructure/configuration/UserFeignConfig.java: -------------------------------------------------------------------------------- 1 | package com.sparta.auth.server.infrastructure.configuration; 2 | 3 | import com.sparta.auth.server.infrastructure.feign.UserErrorDecoder; 4 | import feign.Logger; 5 | import feign.codec.ErrorDecoder; 6 | import org.springframework.context.annotation.Bean; 7 | 8 | public class UserFeignConfig { 9 | 10 | @Bean 11 | public ErrorDecoder errorDecoder() { 12 | return new UserErrorDecoder(); 13 | } 14 | 15 | @Bean 16 | public Logger.Level feignLoggerLevel() { 17 | return Logger.Level.FULL; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /service/auth/server/src/main/java/com/sparta/auth/server/infrastructure/feign/UserClient.java: -------------------------------------------------------------------------------- 1 | package com.sparta.auth.server.infrastructure.feign; 2 | 3 | import com.sparta.auth.server.application.service.UserService; 4 | import com.sparta.auth.server.infrastructure.configuration.UserFeignConfig; 5 | import com.sparta.user.user_dto.infrastructure.UserDto; 6 | import org.springframework.cloud.openfeign.FeignClient; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RequestParam; 9 | 10 | @FeignClient(name = "user", configuration = UserFeignConfig.class) 11 | public interface UserClient extends UserService { 12 | 13 | @GetMapping("/internal/users") 14 | UserDto getUserByUsername(@RequestParam(value = "username") String username); 15 | } 16 | -------------------------------------------------------------------------------- /service/auth/server/src/main/java/com/sparta/auth/server/infrastructure/feign/UserErrorDecoder.java: -------------------------------------------------------------------------------- 1 | package com.sparta.auth.server.infrastructure.feign; 2 | 3 | import com.sparta.auth.server.exception.AuthErrorCode; 4 | import com.sparta.auth.server.exception.AuthException; 5 | import feign.Response; 6 | import feign.codec.ErrorDecoder; 7 | 8 | public class UserErrorDecoder implements ErrorDecoder { 9 | 10 | @Override 11 | public Exception decode(String methodKey, Response response) { 12 | return new AuthException(AuthErrorCode.INTERNAL_SERVER_ERROR); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /service/auth/server/src/main/java/com/sparta/auth/server/infrastructure/properties/JwtProperties.java: -------------------------------------------------------------------------------- 1 | package com.sparta.auth.server.infrastructure.properties; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | import org.springframework.boot.context.properties.ConfigurationProperties; 6 | 7 | @Getter 8 | @Setter 9 | @ConfigurationProperties(prefix = "jwt") 10 | public class JwtProperties { 11 | 12 | private String secretKey; 13 | private int accessTokenExpireIn; 14 | } 15 | -------------------------------------------------------------------------------- /service/auth/server/src/main/java/com/sparta/auth/server/presentation/controller/AuthController.java: -------------------------------------------------------------------------------- 1 | package com.sparta.auth.server.presentation.controller; 2 | 3 | import com.sparta.auth.server.application.dto.AuthResponse; 4 | import com.sparta.auth.server.application.service.AuthService; 5 | import com.sparta.auth.server.presentation.request.AuthRequest; 6 | import com.sparta.common.domain.response.ApiResponse; 7 | import lombok.RequiredArgsConstructor; 8 | import org.springframework.web.bind.annotation.PostMapping; 9 | import org.springframework.web.bind.annotation.RequestBody; 10 | import org.springframework.web.bind.annotation.RequestMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | @RequiredArgsConstructor 14 | @RequestMapping("/api/auth") 15 | @RestController 16 | public class AuthController { 17 | 18 | private final AuthService authService; 19 | 20 | @PostMapping("/sign-in") 21 | public ApiResponse signIn(@RequestBody AuthRequest.SignIn request) { 22 | return ApiResponse.ok(authService.signIn(request)); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /service/auth/server/src/main/java/com/sparta/auth/server/presentation/controller/AuthInternalController.java: -------------------------------------------------------------------------------- 1 | package com.sparta.auth.server.presentation.controller; 2 | 3 | import com.sparta.auth.auth_dto.jwt.JwtClaim; 4 | import com.sparta.auth.server.application.service.AuthService; 5 | import lombok.RequiredArgsConstructor; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.RequestHeader; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | @RequiredArgsConstructor 12 | @RequestMapping("/internal/auth") 13 | @RestController 14 | public class AuthInternalController { 15 | 16 | private final AuthService authService; 17 | 18 | @GetMapping("/verify") 19 | public JwtClaim verifyToken(@RequestHeader("Authorization") String token) { 20 | return authService.verifyToken(token); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /service/auth/server/src/main/java/com/sparta/auth/server/presentation/request/AuthRequest.java: -------------------------------------------------------------------------------- 1 | package com.sparta.auth.server.presentation.request; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | public class AuthRequest { 8 | 9 | @Getter 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public static class SignIn { 13 | 14 | private String username; 15 | private String password; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /service/auth/server/src/main/resources/application-local.yml: -------------------------------------------------------------------------------- 1 | eureka: 2 | client: 3 | service-url: 4 | defaultZone: http://localhost:19090/eureka/ 5 | 6 | jwt: 7 | secret-key: Zr2PMyKH4UheWy6zscq6Wc/nSLl6L/AJ6b5QvLzWXJg5wzQiGdJncTTOBCxvW8Rkl1T0N+1bqF52Mw2eZvwA0i5zyq+VVbIjPyz+b7DW0Xd2wTnXifwxM12LU2oyXpyLz 8 | access-token-expire-in: 3600000 9 | 10 | spring: 11 | data: 12 | redis: 13 | host: localhost 14 | port: 6381 15 | username: default 16 | password: systempass 17 | -------------------------------------------------------------------------------- /service/auth/server/src/main/resources/application-prod.yml: -------------------------------------------------------------------------------- 1 | eureka: 2 | client: 3 | service-url: 4 | defaultZone: http://eureka-service:19090/eureka/ 5 | 6 | jwt: 7 | secret-key: ${JWT_SECRET_KEY} 8 | access-token-expire-in: 3600000 9 | -------------------------------------------------------------------------------- /service/auth/server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 19093 3 | 4 | spring: 5 | application: 6 | name: auth 7 | profiles: 8 | default: local 9 | 10 | management: 11 | endpoints: 12 | web: 13 | exposure: 14 | include: health, info 15 | -------------------------------------------------------------------------------- /service/auth/server/src/test/java/com/sparta/auth/server/http/AuthApiTest.http: -------------------------------------------------------------------------------- 1 | @Port=19091 2 | 3 | POST http://localhost:{{Port}}/api/auth/sign-in 4 | Content-Type: application/json 5 | 6 | { 7 | "username": "newUser", 8 | "password": "password123" 9 | } 10 | -------------------------------------------------------------------------------- /service/auth/server/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | eureka: 2 | client: 3 | enabled: false # 단위 테스트 시에는 유레카 클라이언트를 사용하지 않음 4 | -------------------------------------------------------------------------------- /service/eureka/server/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /service/eureka/server/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.3.4' 4 | id 'io.spring.dependency-management' version '1.1.6' 5 | } 6 | 7 | group = 'com.sparta' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | jar.enabled = false 11 | 12 | java { 13 | toolchain { 14 | languageVersion = JavaLanguageVersion.of(17) 15 | } 16 | } 17 | 18 | repositories { 19 | mavenCentral() 20 | } 21 | 22 | ext { 23 | set('springCloudVersion', "2023.0.3") 24 | } 25 | 26 | dependencies { 27 | implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-server' 28 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 29 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 30 | implementation 'org.springframework.boot:spring-boot-starter-actuator' 31 | implementation 'io.micrometer:micrometer-registry-prometheus' 32 | } 33 | 34 | dependencyManagement { 35 | imports { 36 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 37 | } 38 | } 39 | 40 | tasks.named('test') { 41 | useJUnitPlatform() 42 | } 43 | -------------------------------------------------------------------------------- /service/eureka/server/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sasaping/sasaping-system/ec6f8346458a507fd2af222f61c33ba8b1c580b1/service/eureka/server/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /service/eureka/server/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /service/eureka/server/src/main/java/com/sparta/eureka/EurekaApplication.java: -------------------------------------------------------------------------------- 1 | package com.sparta.eureka; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; 6 | 7 | @SpringBootApplication 8 | @EnableEurekaServer 9 | public class EurekaApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(EurekaApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /service/eureka/server/src/main/resources/application-local.yml: -------------------------------------------------------------------------------- 1 | eureka: 2 | client: 3 | register-with-eureka: false 4 | fetch-registry: false 5 | service-url: 6 | defaultZone: http://localhost:19090/eureka/ 7 | instance: 8 | hostname: localhost 9 | -------------------------------------------------------------------------------- /service/eureka/server/src/main/resources/application-prod.yml: -------------------------------------------------------------------------------- 1 | eureka: 2 | client: 3 | register-with-eureka: false 4 | fetch-registry: false 5 | service-url: 6 | defaultZone: http://eureka-service:19090/eureka/ 7 | -------------------------------------------------------------------------------- /service/eureka/server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: eureka 4 | profiles: 5 | active: local 6 | 7 | server: 8 | port: 19090 9 | 10 | management: 11 | endpoints: 12 | web: 13 | exposure: 14 | include: prometheus 15 | endpoint: 16 | health: 17 | show-details: always 18 | prometheus: 19 | enabled: true 20 | metrics: 21 | tags: 22 | application: ${spring.application.name} 23 | -------------------------------------------------------------------------------- /service/eureka/server/src/test/java/com/sparta/eureka/EurekaApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sparta.eureka; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class EurekaApplicationTests { 8 | 9 | @Test 10 | void contextLoads() {} 11 | } 12 | -------------------------------------------------------------------------------- /service/gateway/server/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | bin/ 16 | !**/src/main/**/bin/ 17 | !**/src/test/**/bin/ 18 | 19 | ### IntelliJ IDEA ### 20 | .idea 21 | *.iws 22 | *.iml 23 | *.ipr 24 | out/ 25 | !**/src/main/**/out/ 26 | !**/src/test/**/out/ 27 | 28 | ### NetBeans ### 29 | /nbproject/private/ 30 | /nbbuild/ 31 | /dist/ 32 | /nbdist/ 33 | /.nb-gradle/ 34 | 35 | ### VS Code ### 36 | .vscode/ 37 | -------------------------------------------------------------------------------- /service/gateway/server/src/main/java/com/sparta/gateway/server/GatewayApplication.java: -------------------------------------------------------------------------------- 1 | package com.sparta.gateway.server; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 6 | import org.springframework.cloud.openfeign.EnableFeignClients; 7 | import org.springframework.scheduling.annotation.EnableScheduling; 8 | 9 | @EnableFeignClients 10 | @EnableScheduling 11 | @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) 12 | public class GatewayApplication { 13 | 14 | public static void main(String[] args) { 15 | SpringApplication.run(GatewayApplication.class, args); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /service/gateway/server/src/main/java/com/sparta/gateway/server/application/AuthService.java: -------------------------------------------------------------------------------- 1 | package com.sparta.gateway.server.application; 2 | 3 | import com.sparta.auth.auth_dto.jwt.JwtClaim; 4 | 5 | public interface AuthService { 6 | 7 | JwtClaim verifyToken(String token); 8 | } 9 | -------------------------------------------------------------------------------- /service/gateway/server/src/main/java/com/sparta/gateway/server/application/dto/RegisterUserResponse.java: -------------------------------------------------------------------------------- 1 | package com.sparta.gateway.server.application.dto; 2 | 3 | public record RegisterUserResponse(Long rank) { 4 | 5 | public int getRank() { 6 | return rank.intValue(); 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /service/gateway/server/src/main/java/com/sparta/gateway/server/infrastructure/configuration/AuthFeignConfig.java: -------------------------------------------------------------------------------- 1 | package com.sparta.gateway.server.infrastructure.configuration; 2 | 3 | import feign.Logger; 4 | import feign.codec.Decoder; 5 | import org.springframework.beans.factory.ObjectFactory; 6 | import org.springframework.boot.autoconfigure.http.HttpMessageConverters; 7 | import org.springframework.cloud.openfeign.support.SpringDecoder; 8 | import org.springframework.context.annotation.Bean; 9 | 10 | public class AuthFeignConfig { 11 | 12 | @Bean 13 | public Decoder feignDecoder() { 14 | ObjectFactory messageConverters = HttpMessageConverters::new; 15 | return new SpringDecoder(messageConverters); 16 | } 17 | 18 | @Bean 19 | public Logger.Level feignLoggerLevel() { 20 | return Logger.Level.FULL; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /service/gateway/server/src/main/java/com/sparta/gateway/server/infrastructure/configuration/RedissonConfig.java: -------------------------------------------------------------------------------- 1 | package com.sparta.gateway.server.infrastructure.configuration; 2 | 3 | import lombok.extern.slf4j.Slf4j; 4 | import org.redisson.Redisson; 5 | import org.redisson.api.RedissonClient; 6 | import org.redisson.config.Config; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | 11 | @Configuration 12 | @Slf4j 13 | public class RedissonConfig { 14 | 15 | private static final String REDIS_URL_PREFIX = "redis://"; 16 | 17 | @Value("${spring.data.redis.host}") 18 | private String host; 19 | 20 | @Value("${spring.data.redis.port}") 21 | private int port; 22 | 23 | @Bean 24 | RedissonClient redissonClient() { 25 | Config config = new Config(); 26 | config.useSingleServer().setAddress(REDIS_URL_PREFIX + host + ":" + port); 27 | return Redisson.create(config); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /service/gateway/server/src/main/java/com/sparta/gateway/server/infrastructure/exception/GatewayException.java: -------------------------------------------------------------------------------- 1 | package com.sparta.gateway.server.infrastructure.exception; 2 | 3 | import com.sparta.common.domain.exception.BusinessException; 4 | 5 | public class GatewayException extends BusinessException { 6 | 7 | public GatewayException(GatewayErrorCode errorCode) { 8 | super(errorCode.getStatus().name(), errorCode.getMessage()); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /service/gateway/server/src/main/java/com/sparta/gateway/server/infrastructure/exception/GatewayExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.sparta.gateway.server.infrastructure.exception; 2 | 3 | import com.sparta.common.domain.response.ApiResponse; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.web.bind.annotation.ExceptionHandler; 6 | import org.springframework.web.bind.annotation.RestControllerAdvice; 7 | 8 | @RestControllerAdvice 9 | @Slf4j 10 | public class GatewayExceptionHandler { 11 | 12 | @ExceptionHandler(GatewayException.class) 13 | public ApiResponse handleException(GatewayException e) { 14 | log.error(e.getMessage()); 15 | return ApiResponse.error(e.getStatusName(), e.getMessage()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /service/gateway/server/src/main/java/com/sparta/gateway/server/infrastructure/feign/AuthClient.java: -------------------------------------------------------------------------------- 1 | package com.sparta.gateway.server.infrastructure.feign; 2 | 3 | import com.sparta.auth.auth_dto.jwt.JwtClaim; 4 | import com.sparta.gateway.server.application.AuthService; 5 | import com.sparta.gateway.server.infrastructure.configuration.AuthFeignConfig; 6 | import org.springframework.cloud.openfeign.FeignClient; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RequestHeader; 9 | 10 | @FeignClient(name = "auth", configuration = AuthFeignConfig.class) 11 | public interface AuthClient extends AuthService { 12 | 13 | @GetMapping("/internal/auth/verify") 14 | JwtClaim verifyToken(@RequestHeader("Authorization") String token); 15 | } 16 | -------------------------------------------------------------------------------- /service/gateway/server/src/main/resources/application-local.yml: -------------------------------------------------------------------------------- 1 | eureka: 2 | client: 3 | service-url: 4 | defaultZone: http://localhost:19090/eureka/ 5 | 6 | spring: 7 | data: 8 | redis: 9 | host: localhost 10 | port: 6381 11 | username: default 12 | password: systempass 13 | -------------------------------------------------------------------------------- /service/gateway/server/src/main/resources/application-prod.yml: -------------------------------------------------------------------------------- 1 | eureka: 2 | client: 3 | service-url: 4 | defaultZone: http://eureka-service:19090/eureka/ 5 | 6 | spring: 7 | data: 8 | redis: 9 | host: gateway-cache 10 | port: 6382 11 | -------------------------------------------------------------------------------- /service/notification/notification_dto/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /service/notification/notification_dto/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.3.4' 4 | id 'io.spring.dependency-management' version '1.1.6' 5 | } 6 | 7 | group = 'com.sparta.notification' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | java { 11 | toolchain { 12 | languageVersion = JavaLanguageVersion.of(17) 13 | } 14 | } 15 | 16 | configurations { 17 | compileOnly { 18 | extendsFrom annotationProcessor 19 | } 20 | } 21 | 22 | repositories { 23 | mavenCentral() 24 | } 25 | 26 | dependencies { 27 | implementation 'org.springframework.boot:spring-boot-starter-validation' 28 | implementation 'org.springframework.boot:spring-boot-starter' 29 | compileOnly 'org.projectlombok:lombok' 30 | annotationProcessor 'org.projectlombok:lombok' 31 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 32 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 33 | } 34 | 35 | tasks.named('test') { 36 | useJUnitPlatform() 37 | } 38 | -------------------------------------------------------------------------------- /service/notification/notification_dto/src/main/java/com/sparta/notification/notification_dto/NotificationDtoApplication.java: -------------------------------------------------------------------------------- 1 | package com.sparta.notification.notification_dto; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class NotificationDtoApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(NotificationDtoApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /service/notification/notification_dto/src/main/java/dto/NotificationCreateRequest.java: -------------------------------------------------------------------------------- 1 | package dto; 2 | 3 | import jakarta.validation.constraints.NotNull; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Getter 9 | @NoArgsConstructor 10 | @AllArgsConstructor 11 | public class NotificationCreateRequest { 12 | 13 | @NotNull(message = "사용자 ID는 필수 값입니다.") 14 | private Long userId; 15 | 16 | private Long targetId; 17 | 18 | @NotNull(message = "알림 타입은 필수 값입니다.") 19 | private String notificationType; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /service/notification/notification_dto/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=notification_dto 2 | -------------------------------------------------------------------------------- /service/notification/notification_dto/src/test/java/com/sparta/notification/notification_dto/NotificationDtoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sparta.notification.notification_dto; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class NotificationDtoApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /service/notification/server/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /service/notification/server/src/main/java/com/sparta/notification/server/NotificationApplication.java: -------------------------------------------------------------------------------- 1 | package com.sparta.notification.server; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.openfeign.EnableFeignClients; 6 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing; 7 | 8 | @SpringBootApplication 9 | @EnableFeignClients 10 | @EnableJpaAuditing 11 | public class NotificationApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(NotificationApplication.class, args); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /service/notification/server/src/main/java/com/sparta/notification/server/application/service/strategy/CreateEventNotificationStrategy.java: -------------------------------------------------------------------------------- 1 | package com.sparta.notification.server.application.service.strategy; 2 | 3 | import com.sparta.notification.server.domain.model.vo.NotificationType; 4 | import dto.NotificationCreateRequest; 5 | import org.springframework.stereotype.Service; 6 | 7 | @Service 8 | public class CreateEventNotificationStrategy implements CreateNotificationService { 9 | 10 | @Override 11 | public Long createNotification(NotificationCreateRequest request) { 12 | 13 | return null; 14 | } 15 | 16 | @Override 17 | public boolean isMatched(NotificationType notificationType) { 18 | return notificationType.isEvent(); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /service/notification/server/src/main/java/com/sparta/notification/server/application/service/strategy/CreateNotificationService.java: -------------------------------------------------------------------------------- 1 | package com.sparta.notification.server.application.service.strategy; 2 | 3 | import com.sparta.notification.server.domain.model.vo.NotificationType; 4 | import dto.NotificationCreateRequest; 5 | 6 | 7 | public interface CreateNotificationService { 8 | 9 | Long createNotification(NotificationCreateRequest request); 10 | 11 | boolean isMatched(NotificationType notificationType); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /service/notification/server/src/main/java/com/sparta/notification/server/application/service/strategy/CreateRestockNotificationStrategy.java: -------------------------------------------------------------------------------- 1 | package com.sparta.notification.server.application.service.strategy; 2 | 3 | import com.sparta.notification.server.domain.model.vo.NotificationType; 4 | import dto.NotificationCreateRequest; 5 | import org.springframework.stereotype.Service; 6 | 7 | @Service 8 | public class CreateRestockNotificationStrategy implements CreateNotificationService { 9 | 10 | @Override 11 | public Long createNotification(NotificationCreateRequest request) { 12 | 13 | return null; 14 | } 15 | 16 | @Override 17 | public boolean isMatched(NotificationType notificationType) { 18 | return notificationType.isRestock(); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /service/notification/server/src/main/java/com/sparta/notification/server/domain/model/vo/NotificationType.java: -------------------------------------------------------------------------------- 1 | package com.sparta.notification.server.domain.model.vo; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum NotificationType { 7 | ORDER("주문 알림"), 8 | RESTOCK("재입고 알림"), 9 | EVENT("이벤트 알림"); 10 | 11 | private String description; 12 | 13 | private NotificationType(String description) { 14 | this.description = description; 15 | } 16 | 17 | public boolean isOrder() { 18 | return this == ORDER; 19 | } 20 | 21 | public boolean isRestock() { 22 | return this == RESTOCK; 23 | } 24 | 25 | public boolean isEvent() { 26 | return this == EVENT; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /service/notification/server/src/main/java/com/sparta/notification/server/domain/repository/NotificationRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.notification.server.domain.repository; 2 | 3 | import com.sparta.notification.server.domain.model.Notification; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface NotificationRepository extends JpaRepository { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /service/notification/server/src/main/java/com/sparta/notification/server/exception/NotificationErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.sparta.notification.server.exception; 2 | 3 | import lombok.Getter; 4 | import org.springframework.http.HttpStatus; 5 | 6 | @Getter 7 | public enum NotificationErrorCode { 8 | USER_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 사용자입니다. : [%s]"), 9 | ORDER_NOT_FOUND(HttpStatus.NOT_FOUND, "존재하지 않는 주문입니다. : [%s]"), 10 | INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "Notification 서비스에서 오류가 발생했습니다."), 11 | ORDER_SERVICE_UNAVAILABLE(HttpStatus.SERVICE_UNAVAILABLE, "Order 서비스와 통신 중 오류가 발생했습니다."), 12 | USER_SERVICE_UNAVAILABLE(HttpStatus.SERVICE_UNAVAILABLE, "User 서비스와 통신 중 오류가 발생했습니다."); 13 | 14 | private final HttpStatus status; 15 | private final String message; 16 | 17 | NotificationErrorCode(HttpStatus status, String message) { 18 | this.status = status; 19 | this.message = message; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /service/notification/server/src/main/java/com/sparta/notification/server/exception/NotificationException.java: -------------------------------------------------------------------------------- 1 | package com.sparta.notification.server.exception; 2 | 3 | import com.sparta.common.domain.exception.BusinessException; 4 | 5 | public class NotificationException extends BusinessException { 6 | 7 | private final NotificationErrorCode errorCode; 8 | 9 | public NotificationException(NotificationErrorCode errorCode, Object... args) { 10 | super(errorCode.getStatus().name(), errorCode.getMessage(), args); 11 | this.errorCode = errorCode; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /service/notification/server/src/main/java/com/sparta/notification/server/infrastructure/client/OrderClient.java: -------------------------------------------------------------------------------- 1 | package com.sparta.notification.server.infrastructure.client; 2 | 3 | import dto.NotificationOrderDto; 4 | import org.springframework.cloud.openfeign.FeignClient; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RequestParam; 7 | 8 | @FeignClient(name = "order") 9 | public interface OrderClient { 10 | 11 | @GetMapping("/internal/orders") 12 | NotificationOrderDto getOrder(@RequestParam(value = "orderId") Long orderId); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /service/notification/server/src/main/java/com/sparta/notification/server/infrastructure/client/UserClient.java: -------------------------------------------------------------------------------- 1 | package com.sparta.notification.server.infrastructure.client; 2 | 3 | import com.sparta.user.user_dto.infrastructure.UserDto; 4 | import org.springframework.cloud.openfeign.FeignClient; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.RequestParam; 7 | 8 | @FeignClient(name = "user") 9 | public interface UserClient { 10 | 11 | @GetMapping("/internal/users/user-id") 12 | UserDto getUser(@RequestParam(value = "userId") Long userId); 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /service/notification/server/src/main/java/com/sparta/notification/server/presentation/controller/NotificationController.java: -------------------------------------------------------------------------------- 1 | package com.sparta.notification.server.presentation.controller; 2 | 3 | import com.sparta.common.domain.response.ApiResponse; 4 | import com.sparta.notification.server.application.service.NotificationService; 5 | import dto.NotificationCreateRequest; 6 | import lombok.RequiredArgsConstructor; 7 | import org.springframework.web.bind.annotation.PostMapping; 8 | import org.springframework.web.bind.annotation.RequestBody; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | @RequestMapping("/api/notifications") 13 | @RequiredArgsConstructor 14 | @RestController 15 | public class NotificationController { 16 | 17 | private final NotificationService notificationService; 18 | 19 | @PostMapping("/create") 20 | public ApiResponse createOrder(@RequestBody NotificationCreateRequest request) { 21 | return ApiResponse.created(notificationService.createNotification(request)); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /service/notification/server/src/main/resources/application-local.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 19041 3 | 4 | spring: 5 | application: 6 | name: notification 7 | 8 | datasource: 9 | url: jdbc:mysql://localhost:3306/notificationDB 10 | username: user 11 | password: password 12 | driver-class-name: com.mysql.cj.jdbc.Driver 13 | 14 | jpa: 15 | hibernate: 16 | ddl-auto: update 17 | properties: 18 | hibernate: 19 | show_sql: true 20 | format_sql: true 21 | highlight_sql: true 22 | dialect: org.hibernate.dialect.MySQLDialect 23 | 24 | management: 25 | endpoints: 26 | web: 27 | exposure: 28 | include: health, info 29 | 30 | eureka: 31 | client: 32 | service-url: 33 | defaultZone: http://localhost:19090/eureka/ 34 | -------------------------------------------------------------------------------- /service/notification/server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | profiles: 3 | active: local 4 | -------------------------------------------------------------------------------- /service/notification/server/src/test/java/com/sparta/notification/server/NotificationApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sparta.notification.server; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class NotificationApplicationTests { 8 | 9 | @Test 10 | void contextLoads() {} 11 | } 12 | -------------------------------------------------------------------------------- /service/order/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | services: 3 | db: 4 | image: mysql:8.0 5 | container_name: mysql-container 6 | environment: 7 | MYSQL_ROOT_PASSWORD: root_password 8 | MYSQL_DATABASE: orderDB 9 | MYSQL_USER: user 10 | MYSQL_PASSWORD: password 11 | ports: 12 | - "3306:3306" 13 | -------------------------------------------------------------------------------- /service/order/dto/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /service/order/dto/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.3.4' 4 | id 'io.spring.dependency-management' version '1.1.6' 5 | } 6 | 7 | group = 'com.sparta.order' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | bootJar.enabled = false 11 | 12 | java { 13 | toolchain { 14 | languageVersion = JavaLanguageVersion.of(17) 15 | } 16 | } 17 | 18 | configurations { 19 | compileOnly { 20 | extendsFrom annotationProcessor 21 | } 22 | } 23 | 24 | repositories { 25 | mavenCentral() 26 | } 27 | 28 | dependencies { 29 | implementation project(':common:domain') 30 | 31 | implementation 'org.springframework.boot:spring-boot-starter' 32 | compileOnly 'org.projectlombok:lombok' 33 | annotationProcessor 'org.projectlombok:lombok' 34 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 35 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 36 | } 37 | 38 | tasks.named('test') { 39 | useJUnitPlatform() 40 | } 41 | 42 | tasks.register("prepareKotlinBuildScriptModel") {} 43 | -------------------------------------------------------------------------------- /service/order/dto/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sasaping/sasaping-system/ec6f8346458a507fd2af222f61c33ba8b1c580b1/service/order/dto/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /service/order/dto/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /service/order/dto/src/main/java/com/sparta/order/dto/OrderDtoApplication.java: -------------------------------------------------------------------------------- 1 | package com.sparta.order.dto; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class OrderDtoApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(OrderDtoApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /service/order/dto/src/main/java/dto/NotificationOrderDto.java: -------------------------------------------------------------------------------- 1 | package dto; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Getter 9 | @NoArgsConstructor(access = AccessLevel.PROTECTED) 10 | @AllArgsConstructor 11 | public class NotificationOrderDto { 12 | 13 | private Long orderId; 14 | private Long userId; 15 | private String orderState; 16 | private String displayProductName; 17 | private Integer totalQuantity; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /service/order/dto/src/main/java/dto/OrderCreateRequest.java: -------------------------------------------------------------------------------- 1 | package dto; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.ArrayList; 5 | import java.util.List; 6 | import lombok.AllArgsConstructor; 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | 10 | @Getter 11 | @AllArgsConstructor 12 | @NoArgsConstructor 13 | public class OrderCreateRequest { 14 | 15 | private String orderType; 16 | private List orderProductInfos = new ArrayList<>(); 17 | private BigDecimal pointPrice; 18 | private Long addressId; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /service/order/dto/src/main/java/dto/OrderProductDto.java: -------------------------------------------------------------------------------- 1 | package dto; 2 | 3 | import java.util.UUID; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | import lombok.Setter; 9 | 10 | @Getter 11 | @Setter 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | @Builder 15 | public class OrderProductDto { 16 | 17 | private Long orderProductId; 18 | private Long orderId; 19 | private UUID productId; 20 | private Integer quantity; 21 | private int purchasePrice; 22 | } 23 | -------------------------------------------------------------------------------- /service/order/dto/src/main/java/dto/OrderProductInfo.java: -------------------------------------------------------------------------------- 1 | package dto; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | @Getter 8 | @AllArgsConstructor 9 | @NoArgsConstructor 10 | public class OrderProductInfo { 11 | private String productId; 12 | private int quantity; 13 | private Long userCouponId; 14 | } 15 | -------------------------------------------------------------------------------- /service/order/dto/src/test/java/com/sparta/order/dto/NotificationOrderDtoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sparta.order.dto; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class NotificationOrderDtoApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /service/order/server/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /service/order/server/docs/UserApiTest.http: -------------------------------------------------------------------------------- 1 | @Port=19091 2 | 3 | ### 회원가입 4 | POST http://localhost:{{Port}}/api/users/sign-up 5 | Content-Type: application/json 6 | 7 | { 8 | "username": "newUser", 9 | "password": "password123", 10 | "nickname": "nickname", 11 | "point": 10000, 12 | "role": "관리자" 13 | } 14 | 15 | ### 로그인 16 | POST http://localhost:{{Port}}/api/auth/sign-in 17 | Content-Type: application/json 18 | 19 | { 20 | "username": "newUser", 21 | "password": "password123" 22 | } 23 | > {% 24 | client.global.set("access_token", response.body.data.token); 25 | %} 26 | 27 | 28 | ### 배송지 조회 29 | GET http://localhost:19092/internal/address/1 30 | Authorization: Bearer {{access_token}} 31 | 32 | ### 배송지 생성 33 | POST http://localhost:{{Port}}/api/address 34 | Authorization: Bearer {{access_token}} 35 | Content-Type: application/json 36 | 37 | { 38 | "alias": "Home", 39 | "recipient": "John Doe", 40 | "phoneNumber": "010-1234-5678", 41 | "zipcode": "12345", 42 | "address": "123 Main St, Anytown, AT 12345", 43 | "isDefault": true 44 | } 45 | -------------------------------------------------------------------------------- /service/order/server/src/main/java/com/sparta/order/server/OrderApplication.java: -------------------------------------------------------------------------------- 1 | package com.sparta.order.server; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.openfeign.EnableFeignClients; 6 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing; 7 | 8 | @SpringBootApplication 9 | @EnableFeignClients 10 | @EnableJpaAuditing 11 | public class OrderApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(OrderApplication.class, args); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /service/order/server/src/main/java/com/sparta/order/server/application/service/mapper/OrderMapper.java: -------------------------------------------------------------------------------- 1 | package com.sparta.order.server.application.service.mapper; 2 | 3 | import com.sparta.order.server.domain.model.Order; 4 | import dto.NotificationOrderDto; 5 | 6 | public class OrderMapper { 7 | 8 | public static NotificationOrderDto toNotificationOrderDto(Order order, 9 | String displayProductName) { 10 | return new NotificationOrderDto(order.getOrderId(), order.getUserId(), 11 | order.getState().getDescription(), displayProductName, order.getTotalQuantity()); 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /service/order/server/src/main/java/com/sparta/order/server/domain/model/vo/OrderState.java: -------------------------------------------------------------------------------- 1 | package com.sparta.order.server.domain.model.vo; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum OrderState { 7 | 8 | PENDING_PAYMENT("결제 대기중"), 9 | COMPLETED("주문 완료"), 10 | READY_FOR_SHIPMENT("배송 준비중"), 11 | SHIPPING("배송중"), 12 | DELIVERED("배송 완료"), 13 | PURCHASE_CONFIRMED("구매 확정"), 14 | CANCELED("주문 취소"); 15 | 16 | private final String description; 17 | 18 | private OrderState(String description) { 19 | this.description = description; 20 | } 21 | 22 | public String getDescription() { 23 | return description; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /service/order/server/src/main/java/com/sparta/order/server/domain/model/vo/OrderType.java: -------------------------------------------------------------------------------- 1 | package com.sparta.order.server.domain.model.vo; 2 | 3 | import lombok.Getter; 4 | 5 | @Getter 6 | public enum OrderType { 7 | 8 | STANDARD("기본"), 9 | PREORDER("사전예약"), 10 | RAFFLE("래플"); 11 | 12 | private final String description; 13 | 14 | private OrderType(String description) { 15 | this.description = description; 16 | } 17 | 18 | public String getDescription() { 19 | return description; 20 | } 21 | 22 | public String getPrefix() { 23 | return this.name().substring(0, 1); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /service/order/server/src/main/java/com/sparta/order/server/domain/repository/OrderProductRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.order.server.domain.repository; 2 | 3 | import com.sparta.order.server.domain.model.Order; 4 | import com.sparta.order.server.domain.model.OrderProduct; 5 | import java.util.List; 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | import org.springframework.stereotype.Repository; 8 | 9 | @Repository 10 | public interface OrderProductRepository extends JpaRepository { 11 | 12 | List findByOrder(Order order); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /service/order/server/src/main/java/com/sparta/order/server/domain/repository/OrderRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.order.server.domain.repository; 2 | 3 | import com.sparta.order.server.domain.model.Order; 4 | import java.util.Optional; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.data.jpa.repository.Query; 7 | import org.springframework.stereotype.Repository; 8 | 9 | @Repository 10 | public interface OrderRepository extends JpaRepository, OrderRepositoryCustom { 11 | 12 | boolean existsByOrderNo(String orderNo); 13 | 14 | @Query("SELECT o FROM Order o LEFT JOIN FETCH o.orderProducts WHERE o.orderId = :orderId") 15 | Optional findById(Long orderId); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /service/order/server/src/main/java/com/sparta/order/server/domain/repository/OrderRepositoryCustom.java: -------------------------------------------------------------------------------- 1 | package com.sparta.order.server.domain.repository; 2 | 3 | import com.sparta.order.server.domain.model.Order; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | 7 | public interface OrderRepositoryCustom { 8 | 9 | Page getMyOrder(Pageable pageable, Long userId, String keyword); 10 | 11 | Page getAllOrder(Pageable pageable, Long orderUserId, String productId); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /service/order/server/src/main/java/com/sparta/order/server/exception/CartErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.sparta.order.server.exception; 2 | 3 | import lombok.Getter; 4 | import org.springframework.http.HttpStatus; 5 | 6 | @Getter 7 | public enum CartErrorCode { 8 | 9 | INSUFFICIENT_STOCK(HttpStatus.BAD_REQUEST, "상품의 재고가 부족합니다."), 10 | PRODUCT_NOT_IN_CART(HttpStatus.BAD_REQUEST, "장바구니에 해당 상품이 존재하지 않습니다."), 11 | CART_NOT_FOUND(HttpStatus.BAD_REQUEST, "존재하지 않는 장바구니입니다."), 12 | USER_NOT_FOUND(HttpStatus.BAD_REQUEST, "존재하지 않는 사용자입니다. : [%s]"); 13 | 14 | private final HttpStatus status; 15 | private final String message; 16 | 17 | CartErrorCode(HttpStatus status, String message) { 18 | this.status = status; 19 | this.message = message; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /service/order/server/src/main/java/com/sparta/order/server/exception/CartException.java: -------------------------------------------------------------------------------- 1 | package com.sparta.order.server.exception; 2 | 3 | import com.sparta.common.domain.exception.BusinessException; 4 | 5 | public class CartException extends BusinessException { 6 | 7 | private final CartErrorCode errorCode; 8 | 9 | public CartException(CartErrorCode errorCode, Object... args) { 10 | super(errorCode.getStatus().name(), errorCode.getMessage(), args); 11 | this.errorCode = errorCode; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /service/order/server/src/main/java/com/sparta/order/server/exception/OrderException.java: -------------------------------------------------------------------------------- 1 | package com.sparta.order.server.exception; 2 | 3 | import com.sparta.common.domain.exception.BusinessException; 4 | 5 | public class OrderException extends BusinessException { 6 | 7 | private final OrderErrorCode errorCode; 8 | 9 | public OrderException(OrderErrorCode errorCode, Object... args) { 10 | super(errorCode.getStatus().name(), errorCode.getMessage(), args); 11 | this.errorCode = errorCode; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /service/order/server/src/main/java/com/sparta/order/server/infrastructure/client/PaymentClient.java: -------------------------------------------------------------------------------- 1 | package com.sparta.order.server.infrastructure.client; 2 | 3 | import com.sparta.payment_dto.infrastructure.PaymentInternalDto; 4 | import org.springframework.cloud.openfeign.FeignClient; 5 | import org.springframework.web.bind.annotation.GetMapping; 6 | import org.springframework.web.bind.annotation.PathVariable; 7 | import org.springframework.web.bind.annotation.PostMapping; 8 | import org.springframework.web.bind.annotation.RequestBody; 9 | 10 | @FeignClient(name = "payment") 11 | public interface PaymentClient { 12 | 13 | @PostMapping("/internal/payments") 14 | void payment(@RequestBody PaymentInternalDto.Create createRequest); 15 | 16 | @PostMapping("/internal/payments/cancel") 17 | void cancelPayment(@RequestBody PaymentInternalDto.Cancel cancelRequest); 18 | 19 | @GetMapping("/internal/payments/{orderId}") 20 | PaymentInternalDto.Get getPayment(@PathVariable(name = "orderId") Long orderId); 21 | 22 | } 23 | -------------------------------------------------------------------------------- /service/order/server/src/main/java/com/sparta/order/server/infrastructure/client/ProductClient.java: -------------------------------------------------------------------------------- 1 | package com.sparta.order.server.infrastructure.client; 2 | 3 | import com.sparta.product_dto.ProductDto; 4 | import java.util.List; 5 | import java.util.Map; 6 | import org.springframework.cloud.openfeign.FeignClient; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.PostMapping; 9 | import org.springframework.web.bind.annotation.RequestBody; 10 | import org.springframework.web.bind.annotation.RequestParam; 11 | 12 | @FeignClient(name = "product") 13 | public interface ProductClient { 14 | 15 | @GetMapping("/internal/products") 16 | List getProductList(@RequestParam(name = "productIds") List productIds); 17 | 18 | @PostMapping("/internal/products/reduce-stock") 19 | void updateStock(@RequestBody Map productQuantities); 20 | 21 | @PostMapping("/internal/products/rollback-stock") 22 | void rollbackStock(@RequestBody Map productQuantities); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /service/order/server/src/main/java/com/sparta/order/server/infrastructure/client/UserClient.java: -------------------------------------------------------------------------------- 1 | package com.sparta.order.server.infrastructure.client; 2 | 3 | import com.sparta.user.user_dto.infrastructure.AddressDto; 4 | import com.sparta.user.user_dto.infrastructure.PointHistoryDto; 5 | import com.sparta.user.user_dto.infrastructure.UserDto; 6 | import org.springframework.cloud.openfeign.FeignClient; 7 | import org.springframework.web.bind.annotation.DeleteMapping; 8 | import org.springframework.web.bind.annotation.GetMapping; 9 | import org.springframework.web.bind.annotation.PathVariable; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestBody; 12 | import org.springframework.web.bind.annotation.RequestParam; 13 | 14 | @FeignClient(name = "user") 15 | public interface UserClient { 16 | 17 | @GetMapping("/internal/users/user-id") 18 | UserDto getUser(@RequestParam(value = "userId") Long userId); 19 | 20 | @PostMapping("/internal/users/point") 21 | Long createPointHistory(@RequestBody PointHistoryDto request); 22 | 23 | @DeleteMapping("/internal/users/point/{pointHistoryId}") 24 | void rollbackPoint(@PathVariable Long pointHistoryId); 25 | 26 | @GetMapping("/internal/address/{addressId}") 27 | AddressDto getAddress(@PathVariable(name = "addressId") Long addressId); 28 | 29 | 30 | } 31 | -------------------------------------------------------------------------------- /service/order/server/src/main/java/com/sparta/order/server/infrastructure/configuration/QueryDslConfig.java: -------------------------------------------------------------------------------- 1 | package com.sparta.order.server.infrastructure.configuration; 2 | 3 | import com.querydsl.jpa.impl.JPAQueryFactory; 4 | import jakarta.persistence.EntityManager; 5 | import jakarta.persistence.PersistenceContext; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | @Configuration 10 | public class QueryDslConfig { 11 | 12 | @PersistenceContext 13 | private EntityManager entityManager; 14 | 15 | @Bean 16 | public JPAQueryFactory jpaQueryFactory() { 17 | return new JPAQueryFactory(entityManager); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /service/order/server/src/main/java/com/sparta/order/server/infrastructure/event/PaymentCompletedEvent.java: -------------------------------------------------------------------------------- 1 | package com.sparta.order.server.infrastructure.event; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | 9 | @Getter 10 | @Setter 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | @Builder 14 | public class PaymentCompletedEvent { 15 | 16 | private Long orderId; 17 | private Long paymentId; 18 | private Long userId; 19 | private Long amount; 20 | private Boolean success; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /service/order/server/src/main/java/com/sparta/order/server/presentation/controller/OrderInternalController.java: -------------------------------------------------------------------------------- 1 | package com.sparta.order.server.presentation.controller; 2 | 3 | import com.sparta.order.server.application.service.OrderService; 4 | import dto.NotificationOrderDto; 5 | import lombok.RequiredArgsConstructor; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RequestParam; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | @Slf4j 13 | @RestController 14 | @RequestMapping("/internal/orders") 15 | @RequiredArgsConstructor 16 | public class OrderInternalController { 17 | 18 | private final OrderService orderService; 19 | 20 | @GetMapping 21 | public NotificationOrderDto getOrder(@RequestParam(value = "orderId") Long orderId) { 22 | return orderService.getNotificationOrder(orderId); 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /service/order/server/src/main/resources/application-prod.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: ${DB_URL}/order 4 | username: ${DB_USERNAME} 5 | password: ${DB_PASSWORD} 6 | driver-class-name: com.mysql.cj.jdbc.Driver 7 | 8 | jpa: 9 | hibernate: 10 | ddl-auto: update 11 | properties: 12 | hibernate: 13 | dialect: org.hibernate.dialect.MySQLDialect 14 | kafka: 15 | bootstrap-servers: kafka:9092 16 | consumer: 17 | group-id: order-service-group 18 | auto-offset-reset: earliest 19 | key-deserializer: org.springframework.kafka.support.serializer.ErrorHandlingDeserializer 20 | value-deserializer: org.springframework.kafka.support.serializer.ErrorHandlingDeserializer 21 | properties: 22 | spring.deserializer.key.delegate.class: org.apache.kafka.common.serialization.StringDeserializer 23 | spring.deserializer.value.delegate.class: org.springframework.kafka.support.serializer.JsonDeserializer 24 | spring.json.trusted.packages: '*' 25 | 26 | data: 27 | redis: 28 | host: cart-cache 29 | port: 6379 30 | username: default 31 | password: systempass 32 | 33 | eureka: 34 | client: 35 | service-url: 36 | defaultZone: http://eureka-service:19090/eureka/ 37 | -------------------------------------------------------------------------------- /service/order/server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 19071 3 | 4 | spring: 5 | application: 6 | name: order 7 | profiles: 8 | active: local 9 | 10 | management: 11 | endpoints: 12 | web: 13 | exposure: 14 | include: health, info 15 | -------------------------------------------------------------------------------- /service/order/server/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{yyyy-MM-dd HH:mm:ss.SSS} springboot-elk [%thread] %-5level %logger{36} - %msg%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | logstash01:50000 14 | 15 | 16 | 17 | 18 | UTC 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /service/order/server/src/test/java/com/sparta/order/server/OrderApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sparta.order.server; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class OrderApplicationTests { 8 | 9 | @Test 10 | void contextLoads() {} 11 | } 12 | -------------------------------------------------------------------------------- /service/payment/payment_dto/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /service/payment/payment_dto/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.3.4' 4 | id 'io.spring.dependency-management' version '1.1.6' 5 | } 6 | 7 | group = 'com.sparta' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | bootJar.enabled = false 11 | 12 | java { 13 | toolchain { 14 | languageVersion = JavaLanguageVersion.of(17) 15 | } 16 | } 17 | 18 | configurations { 19 | compileOnly { 20 | extendsFrom annotationProcessor 21 | } 22 | } 23 | 24 | repositories { 25 | mavenCentral() 26 | } 27 | 28 | dependencies { 29 | implementation 'org.springframework.boot:spring-boot-starter' 30 | compileOnly 'org.projectlombok:lombok' 31 | annotationProcessor 'org.projectlombok:lombok' 32 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 33 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 34 | } 35 | 36 | tasks.named('test') { 37 | useJUnitPlatform() 38 | } 39 | -------------------------------------------------------------------------------- /service/payment/payment_dto/src/main/java/com/sparta/payment_dto/PaymentDtoApplication.java: -------------------------------------------------------------------------------- 1 | package com.sparta.payment_dto; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class PaymentDtoApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(PaymentDtoApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /service/payment/payment_dto/src/test/java/com/sparta/payment_dto/PaymentDtoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sparta.payment_dto; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class PaymentDtoApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /service/payment/server/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /service/payment/server/src/main/java/com/sparta/payment/PaymentApplication.java: -------------------------------------------------------------------------------- 1 | package com.sparta.payment; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.openfeign.EnableFeignClients; 6 | 7 | @SpringBootApplication 8 | @EnableFeignClients 9 | public class PaymentApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(PaymentApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /service/payment/server/src/main/java/com/sparta/payment/domain/entity/PaymentState.java: -------------------------------------------------------------------------------- 1 | package com.sparta.payment.domain.entity; 2 | 3 | public enum PaymentState { 4 | // 결제 완료, 결제 대기, 결제 실패, 결제 취소, 환불 대기, 환불 완료 5 | PAYMENT, PENDING, FAILED, CANCEL, REFUND_PENDING, REFUND 6 | 7 | } 8 | -------------------------------------------------------------------------------- /service/payment/server/src/main/java/com/sparta/payment/domain/repository/PaymentHistoryRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.payment.domain.repository; 2 | 3 | import com.sparta.payment.domain.entity.PaymentHistory; 4 | import java.util.List; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | import org.springframework.stereotype.Repository; 7 | 8 | @Repository 9 | public interface PaymentHistoryRepository extends JpaRepository { 10 | 11 | List findByPayment_PaymentId(Long paymentId); 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /service/payment/server/src/main/java/com/sparta/payment/domain/repository/PaymentRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.payment.domain.repository; 2 | 3 | import com.sparta.payment.domain.entity.Payment; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface PaymentRepository extends JpaRepository, PaymentRepositoryCustom { 9 | 10 | Payment findByPaymentKey(String paymentKey); 11 | 12 | Payment findByOrderId(Long orderId); 13 | 14 | Payment findByPaymentId(Long paymentId); 15 | 16 | } 17 | -------------------------------------------------------------------------------- /service/payment/server/src/main/java/com/sparta/payment/domain/repository/PaymentRepositoryCustom.java: -------------------------------------------------------------------------------- 1 | package com.sparta.payment.domain.repository; 2 | 3 | import com.sparta.payment.domain.entity.Payment; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | 7 | public interface PaymentRepositoryCustom { 8 | 9 | Page findBySearchOption(Pageable pageable, String userId, String paymentKey, 10 | String paymentId, String orderId, String state); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /service/payment/server/src/main/java/com/sparta/payment/exception/PaymentErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.sparta.payment.exception; 2 | 3 | import lombok.Getter; 4 | import org.springframework.http.HttpStatus; 5 | 6 | @Getter 7 | public enum PaymentErrorCode { 8 | INVALID_PARAMETER(HttpStatus.INTERNAL_SERVER_ERROR, "결제중 오류가 발생했습니다."), 9 | PAYMENT_NOT_FOUND(HttpStatus.NOT_FOUND, "결제 정보를 찾을 수 없습니다."), 10 | ; 11 | 12 | private final HttpStatus status; 13 | private final String message; 14 | 15 | PaymentErrorCode(HttpStatus status, String message) { 16 | this.status = status; 17 | this.message = message; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /service/payment/server/src/main/java/com/sparta/payment/exception/PaymentException.java: -------------------------------------------------------------------------------- 1 | package com.sparta.payment.exception; 2 | 3 | import com.sparta.common.domain.exception.BusinessException; 4 | 5 | public class PaymentException extends BusinessException { 6 | 7 | public PaymentException(PaymentErrorCode errorCode) { 8 | super(errorCode.getStatus().name(), errorCode.getMessage()); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /service/payment/server/src/main/java/com/sparta/payment/exception/PaymentExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.sparta.payment.exception; 2 | 3 | import com.sparta.common.domain.response.ApiResponse; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.web.bind.annotation.ExceptionHandler; 6 | import org.springframework.web.bind.annotation.RestControllerAdvice; 7 | 8 | @RestControllerAdvice 9 | @Slf4j 10 | public class PaymentExceptionHandler { 11 | 12 | @ExceptionHandler(PaymentException.class) 13 | public ApiResponse handleException(PaymentException e) { 14 | log.error(e.getMessage()); 15 | return ApiResponse.error(e.getStatusName(), e.getMessage()); 16 | 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /service/payment/server/src/main/java/com/sparta/payment/infrastructure/client/MessageClient.java: -------------------------------------------------------------------------------- 1 | package com.sparta.payment.infrastructure.client; 2 | 3 | import com.sparta.slack_dto.infrastructure.MessageInternalDto; 4 | import org.springframework.cloud.openfeign.FeignClient; 5 | import org.springframework.web.bind.annotation.PostMapping; 6 | import org.springframework.web.bind.annotation.RequestBody; 7 | 8 | @FeignClient(name = "slack") 9 | public interface MessageClient { 10 | 11 | @PostMapping("/internal/message") 12 | void sendMessage(@RequestBody MessageInternalDto.Create messageRequest); 13 | 14 | 15 | } 16 | -------------------------------------------------------------------------------- /service/payment/server/src/main/java/com/sparta/payment/infrastructure/config/QuerydslConfing.java: -------------------------------------------------------------------------------- 1 | package com.sparta.payment.infrastructure.config; 2 | 3 | import com.querydsl.jpa.impl.JPAQueryFactory; 4 | import jakarta.persistence.EntityManager; 5 | import jakarta.persistence.PersistenceContext; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | @Configuration 10 | public class QuerydslConfing { 11 | 12 | @PersistenceContext 13 | private EntityManager entityManager; 14 | 15 | @Bean 16 | public JPAQueryFactory jpaQueryFactory() { 17 | return new JPAQueryFactory(entityManager); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /service/payment/server/src/main/java/com/sparta/payment/infrastructure/event/PaymentCompletedEvent.java: -------------------------------------------------------------------------------- 1 | package com.sparta.payment.infrastructure.event; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Builder; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import lombok.Setter; 8 | 9 | @Getter 10 | @Setter 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | @Builder 14 | public class PaymentCompletedEvent { 15 | 16 | private Long orderId; 17 | private Long paymentId; 18 | private Long userId; 19 | private Long amount; 20 | private Boolean success; 21 | 22 | } 23 | -------------------------------------------------------------------------------- /service/payment/server/src/main/java/com/sparta/payment/presentation/dto/PaymentHistoryResponse.java: -------------------------------------------------------------------------------- 1 | package com.sparta.payment.presentation.dto; 2 | 3 | 4 | import com.sparta.payment.domain.entity.PaymentState; 5 | import java.time.LocalDateTime; 6 | import lombok.Builder; 7 | import lombok.Getter; 8 | import lombok.Setter; 9 | 10 | public class PaymentHistoryResponse { 11 | 12 | @Getter 13 | @Setter 14 | @Builder 15 | public static class Get { 16 | 17 | private PaymentState type; 18 | private String cancelReason; 19 | private Long amount; 20 | private LocalDateTime createdAt; 21 | 22 | 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /service/payment/server/src/main/java/com/sparta/payment/presentation/dto/PaymentRequest.java: -------------------------------------------------------------------------------- 1 | package com.sparta.payment.presentation.dto; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | public class PaymentRequest { 7 | 8 | @Getter 9 | @Setter 10 | public static class Create { 11 | 12 | private Long userId; 13 | private Long orderId; 14 | private String orderName; 15 | private String email; 16 | private Long amount; 17 | 18 | } 19 | 20 | @Getter 21 | @Setter 22 | public static class CreateExt extends Create { 23 | 24 | private String flowMode = "DIRECT"; 25 | private String easyPay = "토스페이"; 26 | private String method = ""; 27 | private String successUrl; 28 | private String failUrl; 29 | 30 | } 31 | 32 | @Getter 33 | @Setter 34 | public static class Confirm { 35 | 36 | private String paymentKey; 37 | private Long orderId; 38 | private Long amount; 39 | 40 | } 41 | 42 | @Getter 43 | @Setter 44 | public static class Cancel { 45 | 46 | private Long orderId; 47 | private String cancelReason; 48 | 49 | } 50 | 51 | @Getter 52 | @Setter 53 | public static class Search { 54 | 55 | private String keyword; 56 | private Long userId; 57 | private String startDate; 58 | private String endDate; 59 | 60 | 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /service/payment/server/src/main/resources/application-local.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: payment 4 | datasource: 5 | url: { LOCAL_DB_URL } 6 | username: { LOCAL_DB_USERNAME } 7 | password: { LOCAL_DB_PASSWORD } 8 | driver-class-name: com.mysql.cj.jdbc.Driver 9 | jpa: 10 | hibernate: 11 | ddl-auto: update 12 | show-sql: false 13 | database-platform: org.hibernate.dialect.MySQLDialect 14 | kafka: 15 | bootstrap-servers: localhost:9092 16 | producer: 17 | key-serializer: org.apache.kafka.common.serialization.StringSerializer 18 | value-serializer: org.springframework.kafka.support.serializer.JsonSerializer 19 | 20 | server: 21 | port: 19061 22 | 23 | eureka: 24 | client: 25 | service-url: 26 | defaultZone: http://localhost:19090/eureka/ 27 | 28 | TOSS_SECRET_KEY: { TOSS_SECRET_KEY } 29 | 30 | PAYMENT: 31 | SUCCESS_URL: http://localhost:19061/payments/success 32 | FAIL_URL: http://localhost:19061/payments/fail 33 | -------------------------------------------------------------------------------- /service/payment/server/src/main/resources/application-prod.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: payment 4 | datasource: 5 | url: ${DB_URL}/payment 6 | username: ${DB_USERNAME} 7 | password: ${DB_PASSWORD} 8 | driver-class-name: com.mysql.cj.jdbc.Driver 9 | jpa: 10 | hibernate: 11 | ddl-auto: update 12 | show-sql: false 13 | database-platform: org.hibernate.dialect.MySQLDialect 14 | kafka: 15 | bootstrap-servers: kafka:9092 16 | producer: 17 | key-serializer: org.apache.kafka.common.serialization.StringSerializer 18 | value-serializer: org.springframework.kafka.support.serializer.JsonSerializer 19 | 20 | 21 | eureka: 22 | client: 23 | service-url: 24 | defaultZone: http://eureka-service:19090/eureka/ 25 | 26 | TOSS_SECRET_KEY: ${TOSS_SECRET_KEY} 27 | 28 | PAYMENT: 29 | SUCCESS_URL: ${EC2_HOST}:19061/payments/success 30 | FAIL_URL: ${EC2_HOST}:19061/payments/fail 31 | -------------------------------------------------------------------------------- /service/payment/server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 19061 3 | 4 | management: 5 | endpoints: 6 | web: 7 | exposure: 8 | include: health, info 9 | 10 | spring: 11 | profiles: 12 | include: local 13 | -------------------------------------------------------------------------------- /service/payment/server/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{yyyy-MM-dd HH:mm:ss.SSS} springboot-elk [%thread] %-5level %logger{36} - %msg%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | logstash01:50000 14 | 15 | 16 | 17 | 18 | UTC 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /service/payment/server/src/test/java/com/sparta/payment/server/PaymentApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sparta.payment.server; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class PaymentApplicationTests { 8 | 9 | @Test 10 | void contextLoads() {} 11 | } 12 | -------------------------------------------------------------------------------- /service/product/product_dto/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /service/product/product_dto/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.3.4' 4 | id 'io.spring.dependency-management' version '1.1.6' 5 | } 6 | 7 | group = 'com.sparta.product' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | bootJar.enabled = false 11 | 12 | java { 13 | toolchain { 14 | languageVersion = JavaLanguageVersion.of(17) 15 | } 16 | } 17 | 18 | configurations { 19 | compileOnly { 20 | extendsFrom annotationProcessor 21 | } 22 | } 23 | 24 | repositories { 25 | mavenCentral() 26 | } 27 | 28 | dependencies { 29 | implementation 'org.springframework.boot:spring-boot-starter' 30 | compileOnly 'org.projectlombok:lombok' 31 | annotationProcessor 'org.projectlombok:lombok' 32 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 33 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 34 | } 35 | 36 | tasks.named('test') { 37 | useJUnitPlatform() 38 | } 39 | -------------------------------------------------------------------------------- /service/product/product_dto/src/main/java/com/sparta/product_dto/ProductDto.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product_dto; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.List; 5 | import java.util.UUID; 6 | import lombok.Builder; 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | 10 | @Getter 11 | @NoArgsConstructor 12 | public class ProductDto { 13 | private UUID productId; 14 | private String productName; 15 | private BigDecimal originalPrice; 16 | private BigDecimal discountedPrice; 17 | private Double discountPercent; 18 | private int stock; 19 | private List tags; 20 | 21 | @Builder 22 | private ProductDto( 23 | UUID productId, 24 | String productName, 25 | BigDecimal originalPrice, 26 | BigDecimal discountedPrice, 27 | Double discountPercent, 28 | int stock, 29 | List tags, 30 | boolean isCoupon) { 31 | this.productId = productId; 32 | this.productName = productName; 33 | this.originalPrice = originalPrice; 34 | this.discountedPrice = discountedPrice; 35 | this.discountPercent = discountPercent; 36 | this.stock = stock; 37 | this.tags = tags; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /service/product/product_dto/src/main/java/com/sparta/product_dto/ProductDtoApplication.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product_dto; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class ProductDtoApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(ProductDtoApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /service/product/product_dto/src/main/java/com/sparta/product_dto/ProductReadRequest.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product_dto; 2 | 3 | import java.util.List; 4 | 5 | public record ProductReadRequest(List productIds) {} 6 | -------------------------------------------------------------------------------- /service/product/product_dto/src/test/java/com/sparta/product_dto/ProductDtoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product_dto; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class ProductDtoApplicationTests { 8 | 9 | @Test 10 | void contextLoads() {} 11 | } 12 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/ProductServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.scheduling.annotation.EnableAsync; 6 | 7 | @SpringBootApplication 8 | @EnableAsync 9 | public class ProductServerApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(ProductServerApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/application/category/CategoryCache.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.application.category; 2 | 3 | import com.sparta.product.presentation.response.CategoryResponse; 4 | import java.util.List; 5 | 6 | public interface CategoryCache { 7 | List fetchAndCacheCategories(); 8 | 9 | void clearCache(); 10 | } 11 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/application/dto/ImgDto.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.application.dto; 2 | 3 | public record ImgDto(String originImgUrl, String detailImgUrl, String thumbnailImgUrl) {} 4 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/application/preorder/PreOrderCacheService.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.application.preorder; 2 | 3 | import com.sparta.product.domain.model.PreOrder; 4 | import com.sparta.product.domain.model.PreOrderState; 5 | import com.sparta.product.infrastructure.utils.PreOrderRedisDto; 6 | import com.sparta.product.presentation.exception.ProductErrorCode; 7 | import com.sparta.product.presentation.exception.ProductServerException; 8 | import lombok.RequiredArgsConstructor; 9 | import org.springframework.cache.annotation.Cacheable; 10 | import org.springframework.stereotype.Service; 11 | 12 | @Service 13 | @RequiredArgsConstructor 14 | public class PreOrderCacheService { 15 | private final PreOrderService preOrderService; 16 | 17 | @Cacheable(cacheNames = "preOrder", key = "#preOrderId") 18 | public PreOrderRedisDto getPreOrderCache(Long preOrderId) { 19 | PreOrder preOrder = preOrderService.findPreOrderByPreOrderId(preOrderId); 20 | validatePreOrder(preOrder); 21 | return new PreOrderRedisDto(preOrder); 22 | } 23 | 24 | private void validatePreOrder(PreOrder preOrder) { 25 | if (preOrder.getState() != PreOrderState.OPEN_FOR_ORDER) 26 | throw new ProductServerException(ProductErrorCode.NOT_OPEN_FOR_PREORDER); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/application/preorder/PreOrderFacadeService.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.application.preorder; 2 | 3 | import com.sparta.common.domain.entity.KafkaTopicConstant; 4 | import com.sparta.product.infrastructure.messaging.PreOrderProducer; 5 | import com.sparta.product.infrastructure.utils.PreOrderRedisDto; 6 | import dto.OrderCreateRequest; 7 | import lombok.RequiredArgsConstructor; 8 | import org.springframework.stereotype.Service; 9 | import org.springframework.transaction.annotation.Transactional; 10 | 11 | @Service 12 | @RequiredArgsConstructor 13 | public class PreOrderFacadeService { 14 | private final PreOrderProducer preOrderProducer; 15 | private final PreOrderLockService preOrderLockService; 16 | 17 | @Transactional 18 | public void preOrder(Long preOrderId, Long addressId, Long userId) { 19 | PreOrderRedisDto cachedData = preOrderLockService.reservation(preOrderId, userId); 20 | OrderCreateRequest createRequest = PreOrderMapper.toDto(cachedData.productId(), addressId); 21 | preOrderProducer.send( 22 | KafkaTopicConstant.PROCESS_PREORDER, Long.toString(userId), createRequest); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/application/preorder/PreOrderMapper.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.application.preorder; 2 | 3 | import com.sparta.product.domain.model.PreOrder; 4 | import com.sparta.product.presentation.request.PreOrderCreateRequest; 5 | import dto.OrderCreateRequest; 6 | import dto.OrderProductInfo; 7 | import java.math.BigDecimal; 8 | import java.util.List; 9 | 10 | public class PreOrderMapper { 11 | 12 | public static PreOrder toEntity(PreOrderCreateRequest request) { 13 | return PreOrder.builder() 14 | .productId(request.productId()) 15 | .preOrderTitle(request.preOrderTitle()) 16 | .startDateTime(request.startDateTime()) 17 | .endDateTime(request.endDateTime()) 18 | .releaseDateTime(request.releaseDateTime()) 19 | .availableQuantity(request.availableQuantity()) 20 | .build(); 21 | } 22 | 23 | public static OrderCreateRequest toDto(String productId, Long addressId) { 24 | OrderProductInfo orderProduct = new OrderProductInfo(productId, 1, null); 25 | return new OrderCreateRequest("PREORDER", List.of(orderProduct), BigDecimal.ZERO, addressId); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/application/product/ImageService.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.application.product; 2 | 3 | import java.io.IOException; 4 | import org.springframework.web.multipart.MultipartFile; 5 | 6 | public interface ImageService { 7 | String uploadImage(String type, MultipartFile file) throws IOException; 8 | 9 | String generateFileName(String originName); 10 | 11 | void deleteImage(String imgUrl); 12 | } 13 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/domain/model/PreOrderState.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.domain.model; 2 | 3 | public enum PreOrderState { 4 | INITIALIZED, 5 | OPEN_FOR_ORDER, 6 | CANCELLED, 7 | COMPLETED 8 | } 9 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/domain/model/SortOption.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.domain.model; 2 | 3 | import co.elastic.clients.elasticsearch._types.SortOrder; 4 | import lombok.Getter; 5 | import lombok.RequiredArgsConstructor; 6 | 7 | @Getter 8 | @RequiredArgsConstructor 9 | public enum SortOption { 10 | MAX_PRICE("discountedPrice", SortOrder.Desc), 11 | MIN_PRICE("discountedPrice", SortOrder.Asc), 12 | SALES("salesCount", SortOrder.Desc), 13 | NEWEST("createdAt", SortOrder.Desc), 14 | REVIEW("reviewCount", SortOrder.Desc); 15 | 16 | private final String field; 17 | private final SortOrder order; 18 | } 19 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/domain/repository/ElasticSearchRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.domain.repository; 2 | 3 | import com.sparta.product.infrastructure.utils.ProductSearchDto; 4 | import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; 5 | 6 | public interface ElasticSearchRepository 7 | extends ElasticsearchRepository {} 8 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/domain/repository/cassandra/ProductRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.domain.repository.cassandra; 2 | 3 | import com.sparta.product.domain.model.Product; 4 | import java.math.BigDecimal; 5 | import java.util.List; 6 | import java.util.Optional; 7 | import java.util.UUID; 8 | import org.springframework.data.cassandra.repository.CassandraRepository; 9 | import org.springframework.data.cassandra.repository.Query; 10 | import org.springframework.data.domain.Pageable; 11 | import org.springframework.stereotype.Repository; 12 | 13 | @Repository 14 | public interface ProductRepository extends CassandraRepository { 15 | Optional findByProductIdAndIsDeletedFalse(UUID productId); 16 | 17 | @Query( 18 | "SELECT * FROM \"P_PRODUCT\" WHERE " 19 | + "(categoryId = ?0) AND " 20 | + "(brandName = ?1) AND " 21 | + "(originalPrice >= ?2) AND " 22 | + "(originalPrice <= ?3) AND " 23 | + "(size = ?4) AND " 24 | + "(mainColor = ?5) ALLOW FILTERING") 25 | List findAllByFilters( 26 | Long categoryId, 27 | String brandName, 28 | BigDecimal minPrice, 29 | BigDecimal maxPrice, 30 | String productSize, 31 | String mainColor, 32 | Pageable pageable); 33 | } 34 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/domain/repository/jpa/CategoryRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.domain.repository.jpa; 2 | 3 | import com.sparta.product.domain.model.Category; 4 | import java.util.List; 5 | import java.util.Optional; 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | import org.springframework.data.jpa.repository.Query; 8 | 9 | public interface CategoryRepository extends JpaRepository { 10 | Optional findByCategoryId(Long categoryId); 11 | 12 | boolean existsByCategoryId(Long categoryId); 13 | 14 | @Query("SELECT c FROM Category c LEFT JOIN FETCH c.subCategories") 15 | List findAllWithSubCategories(); 16 | } 17 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/domain/repository/jpa/PreOrderRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.domain.repository.jpa; 2 | 3 | import com.sparta.product.domain.model.PreOrder; 4 | import java.util.Optional; 5 | import org.springframework.data.domain.Page; 6 | import org.springframework.data.domain.Pageable; 7 | import org.springframework.data.jpa.repository.JpaRepository; 8 | import org.springframework.stereotype.Repository; 9 | 10 | @Repository 11 | public interface PreOrderRepository extends JpaRepository { 12 | Optional findByPreOrderIdAndIsPublicTrue(Long preOrderId); 13 | 14 | Page findAllByIsPublicTrue(Pageable pageable); 15 | } 16 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/domain/repository/redis/RedisRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.domain.repository.redis; 2 | 3 | import lombok.RequiredArgsConstructor; 4 | import org.springframework.data.redis.core.RedisTemplate; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | @RequiredArgsConstructor 9 | public class RedisRepository { 10 | private final RedisTemplate redisTemplate; 11 | 12 | public Long sAdd(String key, String value) { 13 | return redisTemplate.opsForSet().add(key, value); 14 | } 15 | 16 | public Long sCard(String key) { 17 | return redisTemplate.opsForSet().size(key); 18 | } 19 | 20 | public Boolean sIsMember(String key, String value) { 21 | return redisTemplate.opsForSet().isMember(key, value); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/infrastructure/configuration/AuditAwareImpl.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.infrastructure.configuration; 2 | 3 | import java.util.Optional; 4 | import org.springframework.data.domain.AuditorAware; 5 | import org.springframework.security.core.Authentication; 6 | import org.springframework.security.core.context.SecurityContextHolder; 7 | 8 | public class AuditAwareImpl implements AuditorAware { 9 | 10 | @Override 11 | public Optional getCurrentAuditor() { 12 | Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 13 | if (null == authentication || !authentication.isAuthenticated()) { 14 | return Optional.empty(); 15 | } 16 | String username = authentication.getName(); 17 | return Optional.of(username); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/infrastructure/configuration/KafkaConfig.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.infrastructure.configuration; 2 | 3 | import com.sparta.product.infrastructure.messaging.PreOrderProducer; 4 | import lombok.RequiredArgsConstructor; 5 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 6 | import org.springframework.context.annotation.Bean; 7 | import org.springframework.context.annotation.Configuration; 8 | import org.springframework.kafka.core.KafkaTemplate; 9 | 10 | @ConditionalOnProperty(value = "kafka.enabled", matchIfMissing = true) 11 | @RequiredArgsConstructor 12 | @Configuration 13 | public class KafkaConfig { 14 | private final KafkaTemplate kafkaTemplate; 15 | 16 | @Bean 17 | public PreOrderProducer preOrderProducer() { 18 | return new PreOrderProducer(kafkaTemplate); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/infrastructure/configuration/RedissonConfig.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.infrastructure.configuration; 2 | 3 | import org.redisson.Redisson; 4 | import org.redisson.api.RedissonClient; 5 | import org.redisson.config.Config; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | @Configuration 11 | public class RedissonConfig { 12 | private static final String REDIS_URL_PREFIX = "redis://"; 13 | 14 | @Value("${spring.data.redis.host}") 15 | private String host; 16 | 17 | @Value("${spring.data.redis.port}") 18 | private int port; 19 | 20 | @Bean 21 | RedissonClient redissonClient() { 22 | Config config = new Config(); 23 | config.useSingleServer().setAddress(REDIS_URL_PREFIX + host + ":" + port); 24 | return Redisson.create(config); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/infrastructure/configuration/RepositoryConfig.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.infrastructure.configuration; 2 | 3 | import org.springframework.context.annotation.Bean; 4 | import org.springframework.context.annotation.Configuration; 5 | import org.springframework.data.cassandra.config.EnableCassandraAuditing; 6 | import org.springframework.data.cassandra.repository.config.EnableCassandraRepositories; 7 | import org.springframework.data.domain.AuditorAware; 8 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing; 9 | import org.springframework.data.jpa.repository.config.EnableJpaRepositories; 10 | 11 | @Configuration 12 | @EnableJpaRepositories(basePackages = "com.sparta.product.domain.repository.jpa") 13 | @EnableCassandraRepositories(basePackages = "com.sparta.product.domain.repository.cassandra") 14 | @EnableCassandraAuditing 15 | @EnableJpaAuditing 16 | public class RepositoryConfig { 17 | @Bean 18 | public AuditorAware auditorProvider() { 19 | return new AuditAwareImpl(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/infrastructure/configuration/S3Config.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.infrastructure.configuration; 2 | 3 | import com.amazonaws.auth.AWSStaticCredentialsProvider; 4 | import com.amazonaws.auth.BasicAWSCredentials; 5 | import com.amazonaws.services.s3.AmazonS3; 6 | import com.amazonaws.services.s3.AmazonS3ClientBuilder; 7 | import org.springframework.beans.factory.annotation.Value; 8 | import org.springframework.context.annotation.Bean; 9 | import org.springframework.context.annotation.Configuration; 10 | import org.springframework.context.annotation.Lazy; 11 | 12 | @Configuration 13 | public class S3Config { 14 | 15 | @Value("${aws.credentials.access-key}") 16 | public String accessKey; 17 | 18 | @Value("${aws.credentials.secret-key}") 19 | public String secretKey; 20 | 21 | @Value("${aws.credentials.region}") 22 | public String s3Region; 23 | 24 | @Bean 25 | @Lazy 26 | public AmazonS3 s3Client() { 27 | BasicAWSCredentials awsCredentials = new BasicAWSCredentials(accessKey, secretKey); 28 | return AmazonS3ClientBuilder.standard() 29 | .withCredentials(new AWSStaticCredentialsProvider(awsCredentials)) 30 | .withRegion(s3Region) 31 | .build(); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/infrastructure/messaging/PreOrderProducer.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.infrastructure.messaging; 2 | 3 | import dto.OrderCreateRequest; 4 | import lombok.RequiredArgsConstructor; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.springframework.kafka.core.KafkaTemplate; 7 | 8 | @RequiredArgsConstructor 9 | @Slf4j(topic = "PreOrderProducer in Product server") 10 | public class PreOrderProducer { 11 | private final KafkaTemplate kafkaTemplate; 12 | 13 | public void send(String topic, String userId, OrderCreateRequest request) { 14 | kafkaTemplate.send(topic, userId, request); 15 | log.info( 16 | "send preorderRequest of {} to order server", 17 | request.getOrderProductInfos().get(0).getProductId()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/infrastructure/utils/RedisUtils.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.infrastructure.utils; 2 | 3 | public class RedisUtils { 4 | public static String getRedisKeyOfPreOrder(long preOrderId) { 5 | return "preorder.request.%s".formatted(preOrderId); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/presentation/exception/ProductErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.presentation.exception; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import org.springframework.http.HttpStatus; 6 | 7 | @Getter 8 | @RequiredArgsConstructor 9 | public enum ProductErrorCode { 10 | NOT_FOUND_PRODUCT(HttpStatus.NOT_FOUND, "상품이 존재하지 않습니다"), 11 | NOT_FOUND_CATEGORY(HttpStatus.NOT_FOUND, "카테고리가 존재하지 않습니다"), 12 | NOT_FOUND_PREORDER(HttpStatus.NOT_FOUND, "사전예약정보가 존재하지 않습니다"), 13 | 14 | PREORDER_QUANTITY_CONFLICT(HttpStatus.CONFLICT, "예약가능수량이 재고량보다 많습니다"), 15 | NOT_OPEN_FOR_PREORDER(HttpStatus.CONFLICT, "오픈된 사전예약건이 아닙니다"), 16 | 17 | INVALID_PREORDER_DATETIME(HttpStatus.FORBIDDEN, "예약가능한 시간이 아닙니다"), 18 | ALREADY_PREORDER(HttpStatus.CONFLICT, "이미 해당 사전예약 주문이 완료되었습니다"), 19 | EXCEED_PREORDER_QUANTITY(HttpStatus.CONFLICT, "사전예약가능 수량을 초과하였습니다"), 20 | 21 | INVALID_PERMISSION(HttpStatus.FORBIDDEN, "요청 권한이 없습니다"), 22 | INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "내부 서버 오류입니다"), 23 | 24 | STOCK_NOT_AVAILABLE(HttpStatus.CONFLICT, "재고가 부족합니다."); 25 | 26 | private final HttpStatus status; 27 | private final String message; 28 | } 29 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/presentation/exception/ProductServerException.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.presentation.exception; 2 | 3 | import com.sparta.common.domain.exception.BusinessException; 4 | import lombok.Getter; 5 | 6 | @Getter 7 | public class ProductServerException extends BusinessException { 8 | private final ProductErrorCode errorCode; 9 | 10 | public ProductServerException(ProductErrorCode errorCode) { 11 | super(errorCode.getStatus().name(), errorCode.getMessage()); 12 | this.errorCode = errorCode; 13 | } 14 | 15 | public ProductServerException(ProductErrorCode errorCode, Object... args) { 16 | super(errorCode.getStatus().name(), errorCode.getMessage(), args); 17 | this.errorCode = errorCode; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/presentation/request/CategoryCreateRequest.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.presentation.request; 2 | 3 | import jakarta.validation.constraints.NotBlank; 4 | 5 | public record CategoryCreateRequest( 6 | @NotBlank(message = "카테고리명은 필수입니다") String name, Long parentCategoryId) {} 7 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/presentation/request/CategoryUpdateRequest.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.presentation.request; 2 | 3 | import jakarta.validation.constraints.NotBlank; 4 | 5 | public record CategoryUpdateRequest( 6 | @NotBlank(message = "카테고리명은 필수입니다") String name, Long parentCategoryId) {} 7 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/presentation/request/PreOrderCreateRequest.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.presentation.request; 2 | 3 | import jakarta.validation.constraints.NotBlank; 4 | import jakarta.validation.constraints.NotNull; 5 | import java.time.LocalDateTime; 6 | import java.util.UUID; 7 | 8 | public record PreOrderCreateRequest( 9 | @NotNull(message = "상품아이디는 필수입니다") UUID productId, 10 | @NotBlank(message = "사전예약주문타이틀은 필수입니다") String preOrderTitle, 11 | @NotNull(message = "사전예약시작일자는 필수입니다") LocalDateTime startDateTime, 12 | @NotNull(message = "사전예약종료일자는 필수입니다") LocalDateTime endDateTime, 13 | @NotNull(message = "사전예약발송일자는 필수입니다") LocalDateTime releaseDateTime, 14 | @NotNull(message = "사전예약수량은 필수입니다") Integer availableQuantity) {} 15 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/presentation/request/PreOrderUpdateRequest.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.presentation.request; 2 | 3 | import jakarta.validation.constraints.NotBlank; 4 | import jakarta.validation.constraints.NotNull; 5 | import java.time.LocalDateTime; 6 | import java.util.UUID; 7 | 8 | public record PreOrderUpdateRequest( 9 | @NotNull(message = "사전예약상품아이디는 필수입니다") Long preOrderId, 10 | @NotNull(message = "상품아이디는 필수입니다") UUID productId, 11 | @NotBlank(message = "사전예약주문타이틀은 필수입니다") String preOrderTitle, 12 | @NotNull(message = "사전예약시작일자는 필수입니다") LocalDateTime startDateTime, 13 | @NotNull(message = "사전예약종료일자는 필수입니다") LocalDateTime endDateTime, 14 | @NotNull(message = "사전예약발송일자는 필수입니다") LocalDateTime releaseDateTime, 15 | @NotNull(message = "사전예약수량은 필수입니다") Integer availableQuantity) {} 16 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/presentation/request/ProductCreateRequest.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.presentation.request; 2 | 3 | import jakarta.validation.constraints.NotBlank; 4 | import jakarta.validation.constraints.NotNull; 5 | import java.math.BigDecimal; 6 | import java.util.List; 7 | 8 | public record ProductCreateRequest( 9 | @NotNull(message = "카테고리아이디는 필수입니다") Long categoryId, 10 | @NotBlank(message = "상품이름은 필수입니다") String productName, 11 | @NotBlank(message = "브랜드이름은 필수입니다") String brandName, 12 | @NotBlank(message = "메인컬러는 필수입니다") String mainColor, 13 | @NotBlank(message = "상품사이즈는 필수입니다") String size, 14 | @NotNull(message = "상품가격은 필수입니다") BigDecimal originalPrice, 15 | Double discountPercent, 16 | @NotNull(message = "상품재고수량은 필수입니다") Integer stock, 17 | @NotBlank(message = "상품설명은 필수입니다") String description, 18 | @NotNull(message = "상품이름은 필수입니다") Integer limitCountPerUser, 19 | List tags) {} 20 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/presentation/request/ProductUpdateRequest.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.presentation.request; 2 | 3 | import jakarta.validation.constraints.NotBlank; 4 | import jakarta.validation.constraints.NotNull; 5 | import java.math.BigDecimal; 6 | import java.util.List; 7 | import java.util.UUID; 8 | 9 | public record ProductUpdateRequest( 10 | @NotNull(message = "상품아이디는 필수입니다") UUID productId, 11 | @NotNull(message = "카테고리아이디는 필수입니다") Long categoryId, 12 | @NotBlank(message = "상품이름은 필수입니다") String productName, 13 | @NotBlank(message = "브랜드이름은 필수입니다") String brandName, 14 | @NotBlank(message = "메인컬러는 필수입니다") String mainColor, 15 | @NotBlank(message = "상품사이즈는 필수입니다") String size, 16 | @NotNull(message = "상품가격은 필수입니다") BigDecimal originalPrice, 17 | Double discountPercent, 18 | @NotNull(message = "상품재고수량은 필수입니다") Integer stock, 19 | @NotBlank(message = "상품설명은 필수입니다") String description, 20 | @NotNull(message = "상품이름은 필수입니다") Integer limitCountPerUser, 21 | @NotNull(message = "공개여부는 필수입니다") Boolean isPublic, 22 | List tags) {} 23 | -------------------------------------------------------------------------------- /service/product/server/src/main/java/com/sparta/product/presentation/response/CategoryResponse.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product.presentation.response; 2 | 3 | import com.sparta.product.domain.model.Category; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | 9 | @Getter 10 | @NoArgsConstructor 11 | public class CategoryResponse { 12 | private Long categoryId; 13 | private String name; 14 | private List subCategories; 15 | 16 | public CategoryResponse(Long categoryId, String name, List subCategories) { 17 | this.categoryId = categoryId; 18 | this.name = name; 19 | this.subCategories = subCategories; 20 | } 21 | 22 | public static CategoryResponse fromEntity(Category category) { 23 | return new CategoryResponse( 24 | category.getCategoryId(), 25 | category.getName(), 26 | category.getSubCategories().stream() 27 | .map(CategoryResponse::fromEntity) 28 | .collect(Collectors.toList())); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/product/server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 19081 3 | 4 | spring: 5 | application: 6 | name: product 7 | profiles: 8 | active: local 9 | 10 | management: 11 | endpoints: 12 | web: 13 | exposure: 14 | include: health, info 15 | -------------------------------------------------------------------------------- /service/product/server/src/test/java/com/sparta/product/ProductServerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sparta.product; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | //@SpringBootTest 6 | class ProductServerApplicationTests { 7 | 8 | @Test 9 | void contextLoads() {} 10 | } 11 | -------------------------------------------------------------------------------- /service/promotion/server/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | bin/ 16 | !**/src/main/**/bin/ 17 | !**/src/test/**/bin/ 18 | 19 | ### IntelliJ IDEA ### 20 | .idea 21 | *.iws 22 | *.iml 23 | *.ipr 24 | out/ 25 | !**/src/main/**/out/ 26 | !**/src/test/**/out/ 27 | 28 | ### NetBeans ### 29 | /nbproject/private/ 30 | /nbbuild/ 31 | /dist/ 32 | /nbdist/ 33 | /.nb-gradle/ 34 | 35 | ### VS Code ### 36 | .vscode/ 37 | -------------------------------------------------------------------------------- /service/promotion/server/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sasaping/sasaping-system/ec6f8346458a507fd2af222f61c33ba8b1c580b1/service/promotion/server/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /service/promotion/server/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/PromotionApplication.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.cloud.openfeign.EnableFeignClients; 6 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing; 7 | 8 | @EnableFeignClients 9 | @EnableJpaAuditing 10 | @SpringBootApplication 11 | public class PromotionApplication { 12 | 13 | public static void main(String[] args) { 14 | SpringApplication.run(PromotionApplication.class, args); 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/application/service/DistributedLockComponent.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server.application.service; 2 | 3 | import java.util.concurrent.TimeUnit; 4 | import lombok.RequiredArgsConstructor; 5 | import lombok.extern.slf4j.Slf4j; 6 | import org.aspectj.lang.annotation.Aspect; 7 | import org.redisson.api.RLock; 8 | import org.redisson.api.RedissonClient; 9 | import org.springframework.stereotype.Component; 10 | 11 | @Aspect 12 | @Component 13 | @RequiredArgsConstructor 14 | @Slf4j(topic = "DistributedLockComponent") 15 | public class DistributedLockComponent { 16 | 17 | private final RedissonClient redissonClient; 18 | 19 | public void execute( 20 | String lockName, long waitMilliSecond, long leaseMilliSecond, Runnable logic) { 21 | RLock lock = redissonClient.getLock(lockName); 22 | try { 23 | boolean isLocked = lock.tryLock(waitMilliSecond, leaseMilliSecond, TimeUnit.MILLISECONDS); 24 | if (!isLocked) { 25 | throw new IllegalStateException("[" + lockName + "] lock 획득 실패"); 26 | } 27 | logic.run(); 28 | } catch (InterruptedException e) { 29 | log.error(e.getMessage(), e); 30 | throw new RuntimeException(e); 31 | } finally { 32 | if (lock.isHeldByCurrentThread()) { 33 | lock.unlock(); 34 | } 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/application/service/UserService.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server.application.service; 2 | 3 | import com.sparta.user.user_dto.infrastructure.UserDto; 4 | 5 | public interface UserService { 6 | 7 | UserDto getUserByUserId(Long userId); 8 | 9 | } 10 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/domain/model/vo/CouponType.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server.domain.model.vo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonValue; 5 | import com.sparta.promotion.server.exception.PromotionErrorCode; 6 | import com.sparta.promotion.server.exception.PromotionException; 7 | import java.util.Arrays; 8 | import lombok.AccessLevel; 9 | import lombok.AllArgsConstructor; 10 | 11 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 12 | public enum CouponType { 13 | TIER("TIER"), 14 | EVENT("EVENT"); 15 | 16 | private String type; 17 | 18 | @JsonValue 19 | public String getType() { 20 | return this.type; 21 | } 22 | 23 | @JsonCreator 24 | public static CouponType from(String type) { 25 | return Arrays.stream(CouponType.values()) 26 | .filter(t -> t.getType().equals(type)) 27 | .findFirst() 28 | .orElseThrow(() -> new PromotionException(PromotionErrorCode.INVALID_COUPON_TYPE)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/domain/model/vo/DiscountType.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server.domain.model.vo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonValue; 5 | import com.sparta.promotion.server.exception.PromotionErrorCode; 6 | import com.sparta.promotion.server.exception.PromotionException; 7 | import java.util.Arrays; 8 | import lombok.AccessLevel; 9 | import lombok.AllArgsConstructor; 10 | 11 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 12 | public enum DiscountType { 13 | PRICE("PRICE"), 14 | PERCENTAGE("PERCENTAGE"); 15 | 16 | private String discountType; 17 | 18 | @JsonValue 19 | public String getDiscountType() { 20 | return this.discountType; 21 | } 22 | 23 | @JsonCreator 24 | public static DiscountType from(String type) { 25 | return Arrays.stream(DiscountType.values()) 26 | .filter(t -> t.getDiscountType().equals(type)) 27 | .findFirst() 28 | .orElseThrow(() -> new PromotionException(PromotionErrorCode.INVALID_DISCOUNT_TYPE)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/domain/repository/CouponRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server.domain.repository; 2 | 3 | import com.sparta.promotion.server.domain.model.Coupon; 4 | import java.util.Optional; 5 | import org.springframework.data.domain.Page; 6 | import org.springframework.data.domain.Pageable; 7 | 8 | public interface CouponRepository { 9 | 10 | Coupon save(Coupon coupon); 11 | 12 | Optional findById(Long couponId); 13 | 14 | Optional findByIdWithPessimisticLock(Long couponId); 15 | 16 | Page findAll(Pageable pageable); 17 | 18 | void delete(Coupon coupon); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/domain/repository/EventRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server.domain.repository; 2 | 3 | import com.sparta.promotion.server.domain.model.Event; 4 | import java.util.List; 5 | import java.util.Optional; 6 | import org.springframework.data.domain.Page; 7 | import org.springframework.data.domain.Pageable; 8 | import org.springframework.data.jpa.repository.JpaRepository; 9 | import org.springframework.data.jpa.repository.Query; 10 | import org.springframework.stereotype.Repository; 11 | 12 | @Repository 13 | public interface EventRepository extends JpaRepository { 14 | 15 | @Query("SELECT e FROM Event e WHERE e.id = :id AND e.is_deleted = false") 16 | Optional findById(Long id); 17 | 18 | @Query("SELECT e FROM Event e WHERE e.is_deleted = false") 19 | List findAll(); 20 | 21 | @Query("SELECT e FROM Event e WHERE e.is_deleted = false") 22 | Page findAll(Pageable pageable); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/domain/repository/UserCouponRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server.domain.repository; 2 | 3 | import com.sparta.promotion.server.domain.model.UserCoupon; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | import org.springframework.stereotype.Repository; 7 | 8 | @Repository 9 | public interface UserCouponRepository { 10 | 11 | UserCoupon save(UserCoupon userCoupon); 12 | 13 | Page findByUserId(Long userId, Pageable pageable); 14 | 15 | UserCoupon findByUserIdAndCouponId(Long userId, Long couponId); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/exception/PromotionErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server.exception; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import org.springframework.http.HttpStatus; 6 | 7 | @Getter 8 | @RequiredArgsConstructor 9 | public enum PromotionErrorCode { 10 | INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "내부 서버 오류"), 11 | 12 | EVENT_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 이벤트를 찾을 수 없습니다"), 13 | 14 | INVALID_COUPON_TYPE(HttpStatus.NOT_FOUND, "해당 쿠폰 종류가 없습니다."), 15 | INVALID_DISCOUNT_TYPE(HttpStatus.NOT_FOUND, "해당 할인 타입이 없습니다."), 16 | COUPON_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 쿠폰을 찾을 수 없습니다."), 17 | INSUFFICIENT_COUPON(HttpStatus.BAD_REQUEST, "쿠폰 수량이 부족합니다."), 18 | USER_COUPON_NOT_FOUND(HttpStatus.NOT_FOUND, "사용자 쿠폰을 찾을 수 없습니다."), 19 | COUPON_ALREADY_USED(HttpStatus.BAD_REQUEST, "쿠폰이 이미 사용되었습니다."), 20 | COUPON_NOT_USED(HttpStatus.BAD_REQUEST, "쿠폰이 사용되지 않았습니다."); 21 | 22 | private final HttpStatus status; 23 | private final String message; 24 | } 25 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/exception/PromotionException.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server.exception; 2 | 3 | import com.sparta.common.domain.exception.BusinessException; 4 | import lombok.Getter; 5 | 6 | @Getter 7 | public class PromotionException extends BusinessException { 8 | 9 | PromotionErrorCode errorCode; 10 | 11 | public PromotionException(PromotionErrorCode errorCode) { 12 | super(errorCode.getStatus().name(), errorCode.getMessage()); 13 | this.errorCode = errorCode; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/infrastructure/configuration/RedissonConfig.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server.infrastructure.configuration; 2 | 3 | import org.redisson.Redisson; 4 | import org.redisson.api.RedissonClient; 5 | import org.redisson.config.Config; 6 | import org.springframework.beans.factory.annotation.Value; 7 | import org.springframework.context.annotation.Bean; 8 | import org.springframework.context.annotation.Configuration; 9 | 10 | @Configuration 11 | public class RedissonConfig { 12 | 13 | private static final String REDIS_URL_PREFIX = "redis://"; 14 | 15 | @Value("${spring.data.redis.host}") 16 | private String host; 17 | 18 | @Value("${spring.data.redis.port}") 19 | private int port; 20 | 21 | @Bean 22 | RedissonClient redissonClient() { 23 | Config config = new Config(); 24 | config.useSingleServer().setAddress(REDIS_URL_PREFIX + host + ":" + port); 25 | return Redisson.create(config); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/infrastructure/configuration/UserFeignConfig.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server.infrastructure.configuration; 2 | 3 | import com.sparta.promotion.server.infrastructure.feign.UserErrorDecoder; 4 | import feign.Logger; 5 | import feign.codec.ErrorDecoder; 6 | import org.springframework.context.annotation.Bean; 7 | 8 | public class UserFeignConfig { 9 | 10 | @Bean 11 | public ErrorDecoder errorDecoder() { 12 | return new UserErrorDecoder(); 13 | } 14 | 15 | @Bean 16 | public Logger.Level feignLoggerLevel() { 17 | return Logger.Level.FULL; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/infrastructure/feign/UserClient.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server.infrastructure.feign; 2 | 3 | import com.sparta.promotion.server.application.service.UserService; 4 | import com.sparta.promotion.server.infrastructure.configuration.UserFeignConfig; 5 | import com.sparta.user.user_dto.infrastructure.UserDto; 6 | import org.springframework.cloud.openfeign.FeignClient; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RequestParam; 9 | 10 | @FeignClient(name = "user", configuration = UserFeignConfig.class) 11 | public interface UserClient extends UserService { 12 | 13 | @GetMapping("/internal/users/user-id") 14 | UserDto getUserByUserId(@RequestParam(value = "userId") Long userId); 15 | 16 | 17 | } 18 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/infrastructure/feign/UserErrorDecoder.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server.infrastructure.feign; 2 | 3 | import com.sparta.promotion.server.exception.PromotionErrorCode; 4 | import com.sparta.promotion.server.exception.PromotionException; 5 | import feign.Response; 6 | import feign.codec.ErrorDecoder; 7 | 8 | public class UserErrorDecoder implements ErrorDecoder { 9 | 10 | @Override 11 | public Exception decode(String methodKey, Response response) { 12 | return new PromotionException(PromotionErrorCode.INTERNAL_SERVER_ERROR); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/infrastructure/repository/JpaCouponRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server.infrastructure.repository; 2 | 3 | import com.sparta.promotion.server.domain.model.Coupon; 4 | import jakarta.persistence.LockModeType; 5 | import java.util.Optional; 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | import org.springframework.data.jpa.repository.Lock; 8 | import org.springframework.data.jpa.repository.Query; 9 | import org.springframework.data.repository.query.Param; 10 | 11 | public interface JpaCouponRepository extends JpaRepository { 12 | 13 | @Lock(LockModeType.PESSIMISTIC_WRITE) 14 | @Query("SELECT c FROM Coupon c WHERE c.id = :couponId") 15 | Optional findByIdWithPessimisticLock(@Param("couponId") Long couponId); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/infrastructure/repository/JpaUserCouponRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server.infrastructure.repository; 2 | 3 | import com.sparta.promotion.server.domain.model.UserCoupon; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | 8 | public interface JpaUserCouponRepository extends JpaRepository { 9 | 10 | Page findAllByUserId(Long userId, Pageable pageable); 11 | 12 | UserCoupon findByUserIdAndCouponId(Long userId, Long couponId); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/infrastructure/repository/UserCouponRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server.infrastructure.repository; 2 | 3 | import com.sparta.promotion.server.domain.model.UserCoupon; 4 | import com.sparta.promotion.server.domain.repository.UserCouponRepository; 5 | import lombok.RequiredArgsConstructor; 6 | import org.springframework.data.domain.Page; 7 | import org.springframework.data.domain.Pageable; 8 | import org.springframework.stereotype.Repository; 9 | 10 | @RequiredArgsConstructor 11 | @Repository 12 | public class UserCouponRepositoryImpl implements UserCouponRepository { 13 | 14 | private final JpaUserCouponRepository jpaUserCouponRepository; 15 | 16 | @Override 17 | public UserCoupon save(UserCoupon userCoupon) { 18 | return jpaUserCouponRepository.save(userCoupon); 19 | } 20 | 21 | @Override 22 | public Page findByUserId(Long userId, Pageable pageable) { 23 | return jpaUserCouponRepository.findAllByUserId(userId, pageable); 24 | } 25 | 26 | @Override 27 | public UserCoupon findByUserIdAndCouponId(Long userId, Long couponId) { 28 | return jpaUserCouponRepository.findByUserIdAndCouponId(userId, couponId); 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/presentation/controller/CouponInternalController.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server.presentation.controller; 2 | 3 | import com.sparta.promotion.server.application.service.CouponService; 4 | import lombok.RequiredArgsConstructor; 5 | import org.springframework.web.bind.annotation.PatchMapping; 6 | import org.springframework.web.bind.annotation.PathVariable; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | import org.springframework.web.bind.annotation.RequestParam; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | @RequiredArgsConstructor 12 | @RequestMapping("/internal/coupons") 13 | @RestController 14 | public class CouponInternalController { 15 | 16 | private final CouponService couponService; 17 | 18 | @PatchMapping("/{couponId}/use") 19 | public void useCoupon( 20 | @PathVariable(name = "couponId") Long couponId, 21 | @RequestParam(name = "userId") Long userId) { 22 | couponService.useCoupon(couponId, userId); 23 | } 24 | 25 | @PatchMapping("/{couponId}/refund") 26 | public void refundCoupon( 27 | @PathVariable(name = "couponId") Long couponId, 28 | @RequestParam(name = "userId") Long userId) { 29 | couponService.refundCoupon(couponId, userId); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/presentation/request/EventRequest.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server.presentation.request; 2 | 3 | import jakarta.validation.constraints.NotBlank; 4 | import jakarta.validation.constraints.Size; 5 | import java.time.LocalDateTime; 6 | import lombok.Getter; 7 | import lombok.Setter; 8 | 9 | public class EventRequest { 10 | 11 | @Getter 12 | @Setter 13 | public static class Create { 14 | 15 | @NotBlank(message = "이벤트 제목은 필수입니다") 16 | @Size(max = 100) 17 | private String title; 18 | private String imgUrl; 19 | @NotBlank(message = "이벤트 내용은 필수입니다") 20 | private String content; 21 | @NotBlank(message = "이벤트 시작일은 필수입니다") 22 | private LocalDateTime startAt; 23 | @NotBlank(message = "이벤트 종료일은 필수입니다") 24 | private LocalDateTime endAt; 25 | 26 | } 27 | 28 | @Getter 29 | @Setter 30 | public static class Update { 31 | 32 | @NotBlank(message = "이벤트 제목은 필수입니다") 33 | @Size(max = 100) 34 | private String title; 35 | private String imgUrl; 36 | @NotBlank(message = "이벤트 내용은 필수입니다") 37 | private String content; 38 | @NotBlank(message = "이벤트 시작일은 필수입니다") 39 | private LocalDateTime startAt; 40 | @NotBlank(message = "이벤트 종료일은 필수입니다") 41 | private LocalDateTime endAt; 42 | 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/java/com/sparta/promotion/server/presentation/response/EventResponse.java: -------------------------------------------------------------------------------- 1 | package com.sparta.promotion.server.presentation.response; 2 | 3 | import com.sparta.promotion.server.domain.model.Event; 4 | import lombok.Getter; 5 | import lombok.Setter; 6 | 7 | 8 | public class EventResponse { 9 | 10 | @Getter 11 | @Setter 12 | public static class Get { 13 | 14 | private Long id; 15 | private String title; 16 | private String imgUrl; 17 | private String content; 18 | private String startAt; 19 | private String endAt; 20 | 21 | public static Get from(Event event) { 22 | Get response = new Get(); 23 | response.id = event.getId(); 24 | response.title = event.getTitle(); 25 | response.imgUrl = event.getImg_url(); 26 | response.content = event.getContent(); 27 | response.startAt = event.getStart_at().toString(); 28 | response.endAt = event.getEnd_at().toString(); 29 | return response; 30 | } 31 | 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 19021 3 | 4 | spring: 5 | application: 6 | name: promotion 7 | profiles: 8 | default: local 9 | 10 | management: 11 | endpoints: 12 | web: 13 | exposure: 14 | include: health, info 15 | -------------------------------------------------------------------------------- /service/promotion/server/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{yyyy-MM-dd HH:mm:ss.SSS} springboot-elk [%thread] %-5level %logger{36} - %msg%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | logstash01:50000 14 | 15 | 16 | 17 | 18 | UTC 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /service/promotion/server/src/test/resources/application-test.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:mysql://localhost:3306/promotion 4 | username: user 5 | password: password 6 | driver-class-name: com.mysql.cj.jdbc.Driver 7 | 8 | jpa: 9 | hibernate: 10 | ddl-auto: update 11 | properties: 12 | hibernate: 13 | dialect: org.hibernate.dialect.MySQLDialect 14 | 15 | data: 16 | redis: 17 | host: localhost 18 | port: 6381 19 | 20 | eureka: 21 | client: 22 | enabled: false # 단위 테스트 시에는 유레카 클라이언트를 사용하지 않음 23 | -------------------------------------------------------------------------------- /service/search/server/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /service/search/server/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sasaping/sasaping-system/ec6f8346458a507fd2af222f61c33ba8b1c580b1/service/search/server/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /service/search/server/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /service/search/server/src/main/java/com/sparta/server/SearchApplication.java: -------------------------------------------------------------------------------- 1 | package com.sparta.server; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class SearchApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(SearchApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /service/search/server/src/main/java/com/sparta/server/domain/ProductSearchDto.java: -------------------------------------------------------------------------------- 1 | package com.sparta.server.domain; 2 | 3 | import java.math.BigDecimal; 4 | import java.util.List; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | import org.springframework.data.annotation.Id; 8 | import org.springframework.data.elasticsearch.annotations.Document; 9 | 10 | @Getter 11 | @NoArgsConstructor 12 | @Document(indexName = "sasaping-ecommerce-products") 13 | public class ProductSearchDto { 14 | 15 | @Id private String productId; 16 | private Long categoryId; 17 | private String productName; 18 | private String brandName; 19 | private String mainColor; 20 | private String size; 21 | private BigDecimal originalPrice; 22 | private BigDecimal discountedPrice; 23 | private Double discountPercent; 24 | private String description; 25 | private String thumbnailImgUrl; 26 | private double averageRating; 27 | private boolean isPublic; 28 | private boolean soldout; 29 | private List tags; 30 | private Long reviewCount; 31 | private Long salesCount; 32 | private boolean isDeleted; 33 | private String createdAt; 34 | } 35 | -------------------------------------------------------------------------------- /service/search/server/src/main/java/com/sparta/server/domain/SortOption.java: -------------------------------------------------------------------------------- 1 | package com.sparta.server.domain; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import org.springframework.data.domain.Sort; 6 | 7 | @Getter 8 | @RequiredArgsConstructor 9 | public enum SortOption { 10 | RELEVANCE("_score", Sort.Direction.DESC), 11 | PRICE_LOW_TO_HIGH("discountedPrice", Sort.Direction.ASC), 12 | PRICE_HIGH_TO_LOW("discountedPrice", Sort.Direction.DESC), 13 | NEWEST("createdAt", Sort.Direction.DESC), 14 | OLDEST("createdAt", Sort.Direction.ASC), 15 | NAME_A_TO_Z("productName.keyword", Sort.Direction.ASC), 16 | NAME_Z_TO_A("productName.keyword", Sort.Direction.DESC), 17 | REVIEW("reviewCount", Sort.Direction.DESC), 18 | BEST_SELLING("salesCount", Sort.Direction.DESC); 19 | 20 | private final String field; 21 | private final Sort.Direction direction; 22 | 23 | public Sort getSort() { 24 | return Sort.by(direction, field); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /service/search/server/src/main/java/com/sparta/server/exception/SearchErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.sparta.server.exception; 2 | 3 | import lombok.Getter; 4 | import org.springframework.http.HttpStatus; 5 | 6 | @Getter 7 | public enum SearchErrorCode { 8 | SEARCH_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "검색 중 오류가 발생했습니다."), 9 | KEYWORD_IS_EMPTY(HttpStatus.BAD_REQUEST, "검색어가 비어있습니다."), 10 | ; 11 | 12 | private final HttpStatus status; 13 | private final String message; 14 | 15 | SearchErrorCode(HttpStatus status, String message) { 16 | this.status = status; 17 | this.message = message; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /service/search/server/src/main/java/com/sparta/server/exception/SearchException.java: -------------------------------------------------------------------------------- 1 | package com.sparta.server.exception; 2 | 3 | import com.sparta.common.domain.exception.BusinessException; 4 | 5 | public class SearchException extends BusinessException { 6 | 7 | public SearchException(SearchErrorCode errorCode) { 8 | super(errorCode.getStatus().name(), errorCode.getMessage()); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /service/search/server/src/main/java/com/sparta/server/exception/SearchExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.sparta.server.exception; 2 | 3 | import com.sparta.common.domain.response.ApiResponse; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.web.bind.annotation.ExceptionHandler; 6 | import org.springframework.web.bind.annotation.RestControllerAdvice; 7 | 8 | @RestControllerAdvice 9 | @Slf4j 10 | public class SearchExceptionHandler { 11 | 12 | @ExceptionHandler(SearchException.class) 13 | public ApiResponse handleException(SearchException e) { 14 | log.error(e.getMessage()); 15 | return ApiResponse.error(e.getStatusName(), e.getMessage()); 16 | 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /service/search/server/src/main/resources/application-local.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | driver-class-name: com.mysql.cj.jdbc.Driver 4 | url: jdbc:mysql://{LOCAL_DB_URL} 5 | username: { LOCAL_DB_USER } 6 | password: { LOCAL_DB_PASSWORD } 7 | jpa: 8 | database: MYSQL 9 | hibernate: 10 | ddl-auto: update 11 | show-sql: true 12 | database-platform: org.hibernate.dialect.MySQL8Dialect 13 | elasticsearch: 14 | rest: 15 | host: localhost 16 | port: 9200 17 | uris: http://localhost:9200 18 | fingerprint: 20:6A:9C:EF:BE:4B:8A:CF:70:B6:F9:49:B1:CD:F8:18:0A:DC:62:43:08:01:C2:2F:EC:89:68:95:63:06:69:88 19 | account: elastic 20 | password: elastic-password 21 | 22 | product: 23 | search-index: "sasaping-ecommerce-products" 24 | 25 | 26 | eureka: 27 | client: 28 | service-url: 29 | defaultZone: http://localhost:19090/eureka/ 30 | -------------------------------------------------------------------------------- /service/search/server/src/main/resources/application-prod.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: ${DB_URL}/product 4 | username: ${DB_USERNAME} 5 | password: ${DB_PASSWORD} 6 | driver-class-name: com.mysql.cj.jdbc.Driver 7 | jpa: 8 | database: MYSQL 9 | hibernate: 10 | ddl-auto: update 11 | show-sql: true 12 | database-platform: org.hibernate.dialect.MySQL8Dialect 13 | elasticsearch: 14 | rest: 15 | host: es01 16 | port: 9200 17 | uris: http://es01:9200 18 | fingerprint: ${ELASTIC_FINGERPRINT} 19 | account: elastic 20 | password: ${ELASTIC_PASSWORD} 21 | 22 | product: 23 | search-index: "sasaping-ecommerce-products" 24 | 25 | eureka: 26 | client: 27 | service-url: 28 | defaultZone: http://eureka-service:19090/eureka/ 29 | -------------------------------------------------------------------------------- /service/search/server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 19011 3 | 4 | spring: 5 | application: 6 | name: search 7 | profiles: 8 | include: local 9 | 10 | management: 11 | endpoints: 12 | web: 13 | exposure: 14 | include: health, info 15 | -------------------------------------------------------------------------------- /service/search/server/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{yyyy-MM-dd HH:mm:ss.SSS} springboot-elk [%thread] %-5level %logger{36} - %msg%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | logstash01:50000 14 | 15 | 16 | 17 | 18 | UTC 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /service/search/server/src/test/java/com/sparta/server/SearchApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sparta.server; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class SearchApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /service/slack/server/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /service/slack/server/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sasaping/sasaping-system/ec6f8346458a507fd2af222f61c33ba8b1c580b1/service/slack/server/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /service/slack/server/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /service/slack/server/src/main/java/com/sparta/slack/SlackApplication.java: -------------------------------------------------------------------------------- 1 | package com.sparta.slack; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing; 6 | 7 | @SpringBootApplication 8 | @EnableJpaAuditing 9 | public class SlackApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(SlackApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /service/slack/server/src/main/java/com/sparta/slack/application/dto/MessageRequest.java: -------------------------------------------------------------------------------- 1 | package com.sparta.slack.application.dto; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | public class MessageRequest { 7 | 8 | @Getter 9 | @Setter 10 | public static class Create { 11 | 12 | private String receiverEmail; 13 | private String message; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /service/slack/server/src/main/java/com/sparta/slack/application/dto/MessageResponse.java: -------------------------------------------------------------------------------- 1 | package com.sparta.slack.application.dto; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | public class MessageResponse { 7 | 8 | @Getter 9 | @Setter 10 | public static class Create { 11 | 12 | private String receiverEmail; 13 | private String message; 14 | 15 | public Create(MessageRequest.Create messageRequest) { 16 | this.receiverEmail = messageRequest.getReceiverEmail(); 17 | this.message = messageRequest.getMessage(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /service/slack/server/src/main/java/com/sparta/slack/domain/repository/MessageRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.slack.domain.repository; 2 | 3 | import com.sparta.slack.domain.entity.Message; 4 | import org.springframework.data.jpa.repository.JpaRepository; 5 | import org.springframework.stereotype.Repository; 6 | 7 | @Repository 8 | public interface MessageRepository extends JpaRepository {} 9 | -------------------------------------------------------------------------------- /service/slack/server/src/main/java/com/sparta/slack/exception/MessageErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.sparta.slack.exception; 2 | 3 | import lombok.Getter; 4 | import org.springframework.http.HttpStatus; 5 | 6 | @Getter 7 | public enum MessageErrorCode { 8 | USER_NOT_FOUND(HttpStatus.BAD_REQUEST, "사용자를 찾을 수 없습니다."), 9 | INVALID_PARAMETER(HttpStatus.INTERNAL_SERVER_ERROR, "파라미터가 잘못되었습니다."), 10 | ; 11 | 12 | private final HttpStatus status; 13 | private final String message; 14 | 15 | MessageErrorCode(HttpStatus status, String message) { 16 | this.status = status; 17 | this.message = message; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /service/slack/server/src/main/java/com/sparta/slack/exception/MessageException.java: -------------------------------------------------------------------------------- 1 | package com.sparta.slack.exception; 2 | 3 | import com.sparta.common.domain.exception.BusinessException; 4 | 5 | public class MessageException extends BusinessException { 6 | 7 | public MessageException(MessageErrorCode errorCode) { 8 | super(errorCode.getStatus().name(), errorCode.getMessage()); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /service/slack/server/src/main/java/com/sparta/slack/exception/MessageExceptionHandler.java: -------------------------------------------------------------------------------- 1 | package com.sparta.slack.exception; 2 | 3 | import com.sparta.common.domain.response.ApiResponse; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.web.bind.annotation.ExceptionHandler; 6 | import org.springframework.web.bind.annotation.RestControllerAdvice; 7 | 8 | @RestControllerAdvice 9 | @Slf4j 10 | public class MessageExceptionHandler { 11 | 12 | @ExceptionHandler(MessageException.class) 13 | public ApiResponse handleException(MessageException e) { 14 | log.error(e.getMessage()); 15 | return ApiResponse.error(e.getStatusName(), e.getMessage()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /service/slack/server/src/main/java/com/sparta/slack/presentation/controller/MessageController.java: -------------------------------------------------------------------------------- 1 | package com.sparta.slack.presentation.controller; 2 | 3 | import com.sparta.slack.application.dto.MessageRequest; 4 | import com.sparta.slack.application.service.MessageService; 5 | import lombok.RequiredArgsConstructor; 6 | import lombok.extern.slf4j.Slf4j; 7 | import org.springframework.web.bind.annotation.PostMapping; 8 | import org.springframework.web.bind.annotation.RequestBody; 9 | import org.springframework.web.bind.annotation.RequestMapping; 10 | import org.springframework.web.bind.annotation.RestController; 11 | 12 | @RestController 13 | @Slf4j 14 | @RequiredArgsConstructor 15 | @RequestMapping("/internal/message") 16 | public class MessageController { 17 | 18 | private final MessageService messageService; 19 | 20 | @PostMapping("") 21 | public void sendMessage(@RequestBody MessageRequest.Create messageRequest) { 22 | messageService.sendMessage(messageRequest); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /service/slack/server/src/main/resources/application-local.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: slack 4 | datasource: 5 | url: jdbc:mysql://localhost:3306/{LOCAL_DB_NAME} 6 | username: { LOCAL_DB_USERNAME } 7 | password: { LOCAL_DB_PASSWORD } 8 | driver-class-name: com.mysql.cj.jdbc.Driver 9 | jpa: 10 | hibernate: 11 | ddl-auto: update 12 | show-sql: false 13 | database-platform: org.hibernate.dialect.MySQLDialect 14 | 15 | server: 16 | port: 19031 17 | 18 | eureka: 19 | client: 20 | service-url: 21 | defaultZone: http://localhost:19090/eureka/ 22 | 23 | SLACK_TOKEN: { SLACK_TOKEN } 24 | -------------------------------------------------------------------------------- /service/slack/server/src/main/resources/application-prod.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | application: 3 | name: slack 4 | datasource: 5 | url: ${DB_URL}/payment 6 | username: ${DB_USERNAME} 7 | password: ${DB_PASSWORD} 8 | driver-class-name: com.mysql.cj.jdbc.Driver 9 | jpa: 10 | hibernate: 11 | ddl-auto: update 12 | show-sql: false 13 | database-platform: org.hibernate.dialect.MySQLDialect 14 | 15 | 16 | 17 | eureka: 18 | client: 19 | service-url: 20 | defaultZone: http://eureka-service:19090/eureka/ 21 | 22 | SLACK_TOKEN: ${SLACK_TOKEN} 23 | -------------------------------------------------------------------------------- /service/slack/server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 19031 3 | 4 | management: 5 | endpoints: 6 | web: 7 | exposure: 8 | include: health, info 9 | 10 | spring: 11 | profiles: 12 | include: local 13 | -------------------------------------------------------------------------------- /service/slack/server/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | %d{yyyy-MM-dd HH:mm:ss.SSS} springboot-elk [%thread] %-5level %logger{36} - %msg%n 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | logstash01:50000 14 | 15 | 16 | 17 | 18 | UTC 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /service/slack/server/src/test/java/com/sparta/slack/SlackApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sparta.slack; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class SlackApplicationTests { 8 | 9 | @Test 10 | void contextLoads() {} 11 | } 12 | -------------------------------------------------------------------------------- /service/slack/slack_dto/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /service/slack/slack_dto/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.3.4' 4 | id 'io.spring.dependency-management' version '1.1.6' 5 | } 6 | 7 | group = 'com.sparta' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | bootJar.enabled = false 11 | 12 | java { 13 | toolchain { 14 | languageVersion = JavaLanguageVersion.of(17) 15 | } 16 | } 17 | 18 | configurations { 19 | compileOnly { 20 | extendsFrom annotationProcessor 21 | } 22 | } 23 | 24 | repositories { 25 | mavenCentral() 26 | } 27 | 28 | dependencies { 29 | implementation 'org.springframework.boot:spring-boot-starter' 30 | compileOnly 'org.projectlombok:lombok' 31 | annotationProcessor 'org.projectlombok:lombok' 32 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 33 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 34 | } 35 | 36 | tasks.named('test') { 37 | useJUnitPlatform() 38 | } 39 | -------------------------------------------------------------------------------- /service/slack/slack_dto/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sasaping/sasaping-system/ec6f8346458a507fd2af222f61c33ba8b1c580b1/service/slack/slack_dto/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /service/slack/slack_dto/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /service/slack/slack_dto/src/main/java/com/sparta/slack_dto/SlackDtoApplication.java: -------------------------------------------------------------------------------- 1 | package com.sparta.slack_dto; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class SlackDtoApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(SlackDtoApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /service/slack/slack_dto/src/main/java/com/sparta/slack_dto/infrastructure/MessageInternalDto.java: -------------------------------------------------------------------------------- 1 | package com.sparta.slack_dto.infrastructure; 2 | 3 | import lombok.Getter; 4 | import lombok.Setter; 5 | 6 | public class MessageInternalDto { 7 | 8 | @Getter 9 | @Setter 10 | public static class Create { 11 | 12 | private String receiverEmail; 13 | private String message; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /service/slack/slack_dto/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=slack_dto 2 | -------------------------------------------------------------------------------- /service/slack/slack_dto/src/test/java/com/sparta/slack_dto/SlackDtoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.sparta.slack_dto; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class SlackDtoApplicationTests { 8 | 9 | @Test 10 | void contextLoads() {} 11 | } 12 | -------------------------------------------------------------------------------- /service/user/server/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/UserApplication.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.data.jpa.repository.config.EnableJpaAuditing; 6 | 7 | @EnableJpaAuditing 8 | @SpringBootApplication 9 | public class UserApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(UserApplication.class, args); 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/application/dto/AddressResponse.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.application.dto; 2 | 3 | import com.sparta.user.domain.model.Address; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | 9 | public class AddressResponse { 10 | 11 | @Getter 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | @Builder 15 | public static class Get { 16 | 17 | private Long id; 18 | private Long userId; 19 | private String alias; 20 | private String recipient; 21 | private String phoneNumber; 22 | private String zipcode; 23 | private String address; 24 | private Boolean isDefault; 25 | 26 | public static AddressResponse.Get of(Address address) { 27 | return Get.builder() 28 | .id(address.getId()) 29 | .userId(address.getUser().getId()) 30 | .alias(address.getAlias()) 31 | .recipient(address.getRecipient()) 32 | .phoneNumber(address.getPhoneNumber()) 33 | .zipcode(address.getZipcode()) 34 | .address(address.getAddress()) 35 | .isDefault(address.getIsDefault()) 36 | .build(); 37 | } 38 | 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/application/dto/PointResponse.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.application.dto; 2 | 3 | import com.sparta.user.domain.model.PointHistory; 4 | import java.math.BigDecimal; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | 10 | public class PointResponse { 11 | 12 | @Getter 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | @Builder 16 | public static class Get { 17 | 18 | private Long pointHistoryId; 19 | private Long userId; 20 | private Long orderId; 21 | private BigDecimal point; 22 | private String type; 23 | 24 | public static PointResponse.Get of(PointHistory pointHistory) { 25 | return PointResponse.Get.builder() 26 | .pointHistoryId(pointHistory.getId()) 27 | .userId(pointHistory.getUser().getId()) 28 | .orderId(pointHistory.getOrderId()) 29 | .point(pointHistory.getPoint()) 30 | .type(pointHistory.getType().name()) 31 | .build(); 32 | } 33 | 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/application/dto/TierResponse.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.application.dto; 2 | 3 | import com.sparta.user.domain.model.Tier; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | 9 | public class TierResponse { 10 | 11 | @Getter 12 | @NoArgsConstructor 13 | @AllArgsConstructor 14 | @Builder 15 | public static class Get { 16 | 17 | private Long tierId; 18 | private String name; 19 | private Long thresholdPrice; 20 | 21 | public static Get of(Tier tier) { 22 | return Get.builder() 23 | .tierId(tier.getId()) 24 | .name(tier.getName()) 25 | .thresholdPrice(tier.getThresholdPrice()) 26 | .build(); 27 | } 28 | 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/application/dto/UserResponse.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.application.dto; 2 | 3 | import com.sparta.user.domain.model.User; 4 | import java.math.BigDecimal; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | 10 | public class UserResponse { 11 | 12 | @Getter 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | @Builder 16 | public static class Info { 17 | 18 | private Long userId; 19 | private String username; 20 | private String role; 21 | private BigDecimal point; 22 | 23 | public static Info of(User user) { 24 | return Info.builder() 25 | .userId(user.getId()) 26 | .username(user.getUsername()) 27 | .role(user.getRole().name()) 28 | .point(user.getPoint()) 29 | .build(); 30 | } 31 | 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/application/dto/UserTierResponse.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.application.dto; 2 | 3 | import com.sparta.user.domain.model.Tier; 4 | import com.sparta.user.domain.model.User; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Builder; 7 | import lombok.Getter; 8 | import lombok.NoArgsConstructor; 9 | 10 | public class UserTierResponse { 11 | 12 | @Getter 13 | @NoArgsConstructor 14 | @AllArgsConstructor 15 | @Builder 16 | public static class Get { 17 | 18 | private Long userId; 19 | private String username; 20 | private String tier; 21 | 22 | public static Get of(User user, Tier tier) { 23 | return Get.builder() 24 | .userId(user.getId()) 25 | .username(user.getUsername()) 26 | .tier(tier.getName()) 27 | .build(); 28 | } 29 | 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/domain/model/vo/PointHistoryType.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.domain.model.vo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonValue; 5 | import com.sparta.user.exception.UserErrorCode; 6 | import com.sparta.user.exception.UserException; 7 | import java.util.Arrays; 8 | import lombok.AccessLevel; 9 | import lombok.AllArgsConstructor; 10 | import lombok.Getter; 11 | 12 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 13 | @Getter 14 | public enum PointHistoryType { 15 | EARN("적립"), 16 | USE("사용"), 17 | REFUND("환불"); 18 | 19 | private final String type; 20 | 21 | @JsonValue 22 | public String getType() { 23 | return this.type; 24 | } 25 | 26 | @JsonCreator 27 | public static PointHistoryType from(String type) { 28 | return Arrays.stream(PointHistoryType.values()) 29 | .filter(t -> t.getType().equals(type)) 30 | .findFirst() 31 | .orElseThrow(() -> new UserException(UserErrorCode.INVALID_POINT_HISTORY_TYPE)); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/domain/model/vo/UserRole.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.domain.model.vo; 2 | 3 | import com.fasterxml.jackson.annotation.JsonCreator; 4 | import com.fasterxml.jackson.annotation.JsonValue; 5 | import lombok.AccessLevel; 6 | import lombok.AllArgsConstructor; 7 | import lombok.Getter; 8 | 9 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 10 | @Getter 11 | public enum UserRole { 12 | ROLE_ADMIN("관리자"), 13 | ROLE_MANAGER("매니저"), 14 | ROLE_USER("사용자"); 15 | 16 | private final String role; 17 | 18 | @JsonCreator 19 | public static UserRole fromString(String role) { 20 | for (UserRole userRole : UserRole.values()) { 21 | if (userRole.role.equals(role)) { 22 | return userRole; 23 | } 24 | } 25 | return null; 26 | } 27 | 28 | @JsonValue 29 | public String getRole() { 30 | return role; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/domain/repository/AddressRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.domain.repository; 2 | 3 | import com.sparta.user.domain.model.Address; 4 | import java.util.List; 5 | import java.util.Optional; 6 | import org.springframework.stereotype.Repository; 7 | 8 | @Repository 9 | public interface AddressRepository { 10 | 11 | Address save(Address address); 12 | 13 | Optional
findById(Long addressId); 14 | 15 | List
findAllByUserId(Long userId); 16 | 17 | List
findAll(); 18 | 19 | void delete(Address address); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/domain/repository/PointHistoryRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.domain.repository; 2 | 3 | import com.sparta.user.domain.model.PointHistory; 4 | import java.util.Optional; 5 | import org.springframework.data.domain.Page; 6 | import org.springframework.data.domain.Pageable; 7 | import org.springframework.stereotype.Repository; 8 | 9 | @Repository 10 | public interface PointHistoryRepository { 11 | 12 | PointHistory save(PointHistory pointHistory); 13 | 14 | Page findAllByUserId(Long userId, Pageable pageable); 15 | 16 | Optional findById(Long pointHistoryId); 17 | 18 | void rollback(PointHistory pointHistory); 19 | 20 | Page findAll(Pageable pageable); 21 | 22 | void delete(PointHistory pointHistory); 23 | 24 | } 25 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/domain/repository/TierRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.domain.repository; 2 | 3 | import com.sparta.user.domain.model.Tier; 4 | import java.util.List; 5 | import java.util.Optional; 6 | import org.springframework.stereotype.Repository; 7 | 8 | @Repository 9 | public interface TierRepository { 10 | 11 | Tier save(Tier tier); 12 | 13 | Optional findByName(String name); 14 | 15 | List findAll(); 16 | 17 | Optional findById(Long tierId); 18 | 19 | void delete(Tier tier); 20 | 21 | } 22 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/domain/repository/UserRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.domain.repository; 2 | 3 | import com.sparta.user.domain.model.User; 4 | import java.util.Collection; 5 | import java.util.Optional; 6 | import org.springframework.stereotype.Repository; 7 | 8 | @Repository 9 | public interface UserRepository { 10 | 11 | User save(User user); 12 | 13 | Optional findByUsername(String username); 14 | 15 | Optional findById(Long userId); 16 | 17 | Collection findAllByIsDeletedFalse(); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/domain/repository/UserTierRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.domain.repository; 2 | 3 | import com.sparta.user.domain.model.UserTier; 4 | import java.util.Optional; 5 | import org.springframework.data.domain.Page; 6 | import org.springframework.data.domain.Pageable; 7 | import org.springframework.stereotype.Repository; 8 | 9 | @Repository 10 | public interface UserTierRepository { 11 | 12 | UserTier save(UserTier userTier); 13 | 14 | Optional findByUserId(Long id); 15 | 16 | Page findAll(Pageable pageable); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/exception/UserControllerAdvice.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.exception; 2 | 3 | import com.sparta.common.domain.response.ApiResponse; 4 | import lombok.extern.slf4j.Slf4j; 5 | import org.springframework.http.ResponseEntity; 6 | import org.springframework.web.bind.annotation.ControllerAdvice; 7 | import org.springframework.web.bind.annotation.ExceptionHandler; 8 | 9 | @Slf4j 10 | @ControllerAdvice 11 | public class UserControllerAdvice { 12 | 13 | @ExceptionHandler(UserException.class) 14 | public ResponseEntity businessExceptionHandler(UserException e) { 15 | UserErrorCode errorCode = e.getErrorCode(); 16 | log.error("Error occurs in UserServer : {}", e.getErrorCode()); 17 | return ResponseEntity.status(errorCode.getStatus()) 18 | .body(ApiResponse.error(errorCode.getStatus().name(), errorCode.getMessage())); 19 | } 20 | 21 | @ExceptionHandler(RuntimeException.class) 22 | public ResponseEntity runtimeExceptionHandler(RuntimeException e) { 23 | log.error("Error occurs in UserServer : {}", e.getMessage()); 24 | return ResponseEntity.status(UserErrorCode.INTERNAL_SERVER_ERROR.getStatus()) 25 | .body( 26 | ApiResponse.error( 27 | UserErrorCode.INTERNAL_SERVER_ERROR.getStatus().name(), e.getMessage())); 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/exception/UserErrorCode.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.exception; 2 | 3 | import lombok.Getter; 4 | import lombok.RequiredArgsConstructor; 5 | import org.springframework.http.HttpStatus; 6 | 7 | @Getter 8 | @RequiredArgsConstructor 9 | public enum UserErrorCode { 10 | USER_NOT_FOUND(HttpStatus.NOT_FOUND, "사용자를 찾을 수 없습니다."), 11 | USER_CONFLICT(HttpStatus.CONFLICT, "이미 존재하는 사용자입니다."), 12 | INVAILD_PASSWORD(HttpStatus.BAD_REQUEST, "비밀번호가 일치하지 않습니다."), 13 | 14 | INVALID_POINT_HISTORY_TYPE(HttpStatus.NOT_FOUND, "포인트 타입을 찾을 수 없습니다."), 15 | INSUFFICIENT_POINTS(HttpStatus.BAD_REQUEST, "포인트가 부족합니다."), 16 | POINT_HISTORY_NOT_FOUND(HttpStatus.NOT_FOUND, "포인트 내역을 찾을 수 없습니다."), 17 | INVAILD_POINT_USER(HttpStatus.BAD_REQUEST, "자신의 포인트 내역이 아닙니다."), 18 | 19 | TIER_CONFLICT(HttpStatus.CONFLICT, "이미 존재하는 등급입니다."), 20 | TIER_NOT_FOUND(HttpStatus.NOT_FOUND, "등급을 찾을 수 없습니다."), 21 | 22 | ADDRESS_NOT_FOUND(HttpStatus.NOT_FOUND, "배송지를 찾을 수 없습니다."), 23 | 24 | INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "내부 서버 에러 입니다."), 25 | USER_TIER_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 사용자의 등급을 찾을 수 없습니다."); 26 | 27 | private final HttpStatus status; 28 | private final String message; 29 | } 30 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/exception/UserException.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.exception; 2 | 3 | import com.sparta.common.domain.exception.BusinessException; 4 | import lombok.Getter; 5 | 6 | @Getter 7 | public class UserException extends BusinessException { 8 | 9 | private final UserErrorCode errorCode; 10 | 11 | public UserException(UserErrorCode errorCode) { 12 | super(errorCode.getStatus().name(), errorCode.getMessage()); 13 | this.errorCode = errorCode; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/infrastructure/repository/AddressRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.infrastructure.repository; 2 | 3 | import com.sparta.user.domain.model.Address; 4 | import com.sparta.user.domain.repository.AddressRepository; 5 | import java.util.List; 6 | import java.util.Optional; 7 | import lombok.RequiredArgsConstructor; 8 | import org.springframework.stereotype.Repository; 9 | 10 | @RequiredArgsConstructor 11 | @Repository 12 | public class AddressRepositoryImpl implements AddressRepository { 13 | 14 | private final JpaAddressRepository jpaAddressRepository; 15 | 16 | @Override 17 | public Address save(Address address) { 18 | return jpaAddressRepository.save(address); 19 | } 20 | 21 | @Override 22 | public Optional
findById(Long addressId) { 23 | return jpaAddressRepository.findById(addressId); 24 | } 25 | 26 | @Override 27 | public List
findAllByUserId(Long userId) { 28 | return jpaAddressRepository.findAllByUserId(userId); 29 | } 30 | 31 | @Override 32 | public List
findAll() { 33 | return jpaAddressRepository.findAll(); 34 | } 35 | 36 | @Override 37 | public void delete(Address address) { 38 | jpaAddressRepository.delete(address); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/infrastructure/repository/JpaAddressRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.infrastructure.repository; 2 | 3 | import com.sparta.user.domain.model.Address; 4 | import java.util.List; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | public interface JpaAddressRepository extends JpaRepository { 8 | 9 | List
findAllByUserId(Long userId); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/infrastructure/repository/JpaPointHistoryRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.infrastructure.repository; 2 | 3 | import com.sparta.user.domain.model.PointHistory; 4 | import org.springframework.data.domain.Page; 5 | import org.springframework.data.domain.Pageable; 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | 8 | public interface JpaPointHistoryRepository extends JpaRepository { 9 | 10 | Page findAllByUserId(Long userId, Pageable pageable); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/infrastructure/repository/JpaTierRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.infrastructure.repository; 2 | 3 | import com.sparta.user.domain.model.Tier; 4 | import java.util.Optional; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | public interface JpaTierRepository extends JpaRepository { 8 | 9 | Optional findByName(String name); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/infrastructure/repository/JpaUserRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.infrastructure.repository; 2 | 3 | import com.sparta.user.domain.model.User; 4 | import java.util.Collection; 5 | import java.util.Optional; 6 | import org.springframework.data.jpa.repository.JpaRepository; 7 | 8 | public interface JpaUserRepository extends JpaRepository { 9 | 10 | Optional findByUsername(String username); 11 | 12 | Collection findAllByIsDeletedFalse(); 13 | 14 | } 15 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/infrastructure/repository/JpaUserTierRepository.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.infrastructure.repository; 2 | 3 | import com.sparta.user.domain.model.UserTier; 4 | import java.util.Optional; 5 | import org.springframework.data.jpa.repository.JpaRepository; 6 | 7 | public interface JpaUserTierRepository extends JpaRepository { 8 | 9 | Optional findByUserId(Long userId); 10 | 11 | } 12 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/infrastructure/repository/TierRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.infrastructure.repository; 2 | 3 | import com.sparta.user.domain.model.Tier; 4 | import com.sparta.user.domain.repository.TierRepository; 5 | import java.util.List; 6 | import java.util.Optional; 7 | import lombok.RequiredArgsConstructor; 8 | import org.springframework.stereotype.Repository; 9 | 10 | @RequiredArgsConstructor 11 | @Repository 12 | public class TierRepositoryImpl implements TierRepository { 13 | 14 | private final JpaTierRepository jpaTierRepository; 15 | 16 | @Override 17 | public Tier save(Tier tier) { 18 | return jpaTierRepository.save(tier); 19 | } 20 | 21 | @Override 22 | public Optional findByName(String name) { 23 | return jpaTierRepository.findByName(name); 24 | } 25 | 26 | @Override 27 | public List findAll() { 28 | return jpaTierRepository.findAll(); 29 | } 30 | 31 | @Override 32 | public Optional findById(Long tierId) { 33 | return jpaTierRepository.findById(tierId); 34 | } 35 | 36 | @Override 37 | public void delete(Tier tier) { 38 | jpaTierRepository.delete(tier); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/infrastructure/repository/UserRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.infrastructure.repository; 2 | 3 | import com.sparta.user.domain.model.User; 4 | import com.sparta.user.domain.repository.UserRepository; 5 | import java.util.Collection; 6 | import java.util.Optional; 7 | import lombok.RequiredArgsConstructor; 8 | import org.springframework.stereotype.Repository; 9 | 10 | @RequiredArgsConstructor 11 | @Repository 12 | public class UserRepositoryImpl implements UserRepository { 13 | 14 | private final JpaUserRepository jpaUserRepository; 15 | 16 | @Override 17 | public User save(User user) { 18 | return jpaUserRepository.save(user); 19 | } 20 | 21 | @Override 22 | public Optional findByUsername(String username) { 23 | return jpaUserRepository.findByUsername(username); 24 | } 25 | 26 | @Override 27 | public Optional findById(Long userId) { 28 | return jpaUserRepository.findById(userId); 29 | } 30 | 31 | @Override 32 | public Collection findAllByIsDeletedFalse() { 33 | return jpaUserRepository.findAllByIsDeletedFalse(); 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/infrastructure/repository/UserTierRepositoryImpl.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.infrastructure.repository; 2 | 3 | import com.sparta.user.domain.model.UserTier; 4 | import com.sparta.user.domain.repository.UserTierRepository; 5 | import java.util.Optional; 6 | import lombok.RequiredArgsConstructor; 7 | import org.springframework.data.domain.Page; 8 | import org.springframework.data.domain.Pageable; 9 | import org.springframework.stereotype.Repository; 10 | 11 | @RequiredArgsConstructor 12 | @Repository 13 | public class UserTierRepositoryImpl implements UserTierRepository { 14 | 15 | private final JpaUserTierRepository jpaUserTierRepository; 16 | 17 | @Override 18 | public UserTier save(UserTier userTier) { 19 | return jpaUserTierRepository.save(userTier); 20 | } 21 | 22 | @Override 23 | public Optional findByUserId(Long userId) { 24 | return jpaUserTierRepository.findByUserId(userId); 25 | } 26 | 27 | @Override 28 | public Page findAll(Pageable pageable) { 29 | return jpaUserTierRepository.findAll(pageable); 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/presentation/controller/AddressInternalController.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.presentation.controller; 2 | 3 | import com.sparta.user.application.service.AddressService; 4 | import com.sparta.user.user_dto.infrastructure.AddressDto; 5 | import lombok.RequiredArgsConstructor; 6 | import org.springframework.web.bind.annotation.GetMapping; 7 | import org.springframework.web.bind.annotation.PathVariable; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RestController; 10 | 11 | @RequiredArgsConstructor 12 | @RequestMapping("/internal/address") 13 | @RestController 14 | public class AddressInternalController { 15 | 16 | private final AddressService addressService; 17 | 18 | @GetMapping("/{addressId}") 19 | public AddressDto getAddress(@PathVariable(name = "addressId") Long addressId) { 20 | return addressService.getAddress(addressId); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/presentation/request/AddressRequest.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.presentation.request; 2 | 3 | import jakarta.validation.constraints.NotNull; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | 8 | public class AddressRequest { 9 | 10 | @Getter 11 | @NoArgsConstructor 12 | @AllArgsConstructor 13 | public static class Create { 14 | 15 | @NotNull 16 | private String alias; 17 | @NotNull 18 | private String recipient; 19 | @NotNull 20 | private String phoneNumber; 21 | @NotNull 22 | private String zipcode; 23 | @NotNull 24 | private String address; 25 | @NotNull 26 | private Boolean isDefault; 27 | 28 | } 29 | 30 | @Getter 31 | @NoArgsConstructor 32 | @AllArgsConstructor 33 | public static class Update { 34 | 35 | @NotNull 36 | private String alias; 37 | @NotNull 38 | private String recipient; 39 | @NotNull 40 | private String phoneNumber; 41 | @NotNull 42 | private String zipcode; 43 | @NotNull 44 | private String address; 45 | @NotNull 46 | private Boolean isDefault; 47 | 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /service/user/server/src/main/java/com/sparta/user/presentation/request/TierRequest.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.presentation.request; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Getter; 5 | import lombok.NoArgsConstructor; 6 | 7 | public class TierRequest { 8 | 9 | @Getter 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public static class Create { 13 | 14 | private String name; 15 | private Long thresholdPrice; 16 | 17 | } 18 | 19 | @Getter 20 | @NoArgsConstructor 21 | @AllArgsConstructor 22 | public static class Update { 23 | 24 | private String name; 25 | private Long thresholdPrice; 26 | 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /service/user/server/src/main/resources/application-local.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:mysql://localhost:3306/user 4 | username: user 5 | password: password 6 | driver-class-name: com.mysql.cj.jdbc.Driver 7 | 8 | jpa: 9 | hibernate: 10 | ddl-auto: update 11 | properties: 12 | hibernate: 13 | dialect: org.hibernate.dialect.MySQLDialect 14 | 15 | eureka: 16 | client: 17 | service-url: 18 | defaultZone: http://localhost:19090/eureka/ 19 | -------------------------------------------------------------------------------- /service/user/server/src/main/resources/application-prod.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: ${DB_URL}/user 4 | username: ${DB_USERNAME} 5 | password: ${DB_PASSWORD} 6 | driver-class-name: com.mysql.cj.jdbc.Driver 7 | 8 | jpa: 9 | hibernate: 10 | ddl-auto: update 11 | properties: 12 | hibernate: 13 | dialect: org.hibernate.dialect.MySQLDialect 14 | 15 | eureka: 16 | client: 17 | service-url: 18 | defaultZone: http://eureka-service:19090/eureka/ 19 | -------------------------------------------------------------------------------- /service/user/server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 19092 3 | 4 | spring: 5 | application: 6 | name: user 7 | profiles: 8 | active: local 9 | 10 | management: 11 | endpoints: 12 | web: 13 | exposure: 14 | include: health, info 15 | -------------------------------------------------------------------------------- /service/user/server/src/test/java/com/sparta/user/http/TierApiTest.http: -------------------------------------------------------------------------------- 1 | @Port=19091 2 | @Token=Bearer eyJhbGciOiJIUzI1NiJ9.eyJVU0VSX1JPTEUiOiJST0xFX0FETUlOIiwiVVNFUl9JRCI6NywiVVNFUl9OQU1FIjoibmV3VXNlciIsImlhdCI6MTcyODI5MjM2NywiZXhwIjoxNzMxODkyMzY3fQ.Kvp1JJLpjxjRX4N8Nt46QP-_1jAnSzVvSISordEMHN8 3 | 4 | ### 등급 생성1 5 | POST http://localhost:{{Port}}/api/tier 6 | Content-Type: application/json 7 | Authorization: {{Token}} 8 | 9 | { 10 | "name": "골드핑", 11 | "thresholdPrice": 150000 12 | } 13 | 14 | ### 등급 생성2 15 | POST http://localhost:{{Port}}/api/tier 16 | Content-Type: application/json 17 | Authorization: {{Token}} 18 | 19 | { 20 | "name": "실버핑", 21 | "thresholdPrice": 100000 22 | } 23 | 24 | ### 등급 생성3 25 | POST http://localhost:{{Port}}/api/tier 26 | Content-Type: application/json 27 | Authorization: {{Token}} 28 | 29 | { 30 | "name": "애기핑", 31 | "thresholdPrice": 50000 32 | } 33 | 34 | ### 등급 조회 35 | GET http://localhost:{{Port}}/api/tier 36 | Authorization: {{Token}} 37 | 38 | ### 등급 수정 39 | @tierId = 1 40 | PATCH localhost:{{Port}}/api/tier/{{tierId}} 41 | Content-Type: application/json 42 | Authorization: {{Token}} 43 | 44 | { 45 | "name": "골드핑그르르", 46 | "thresholdPrice": 200000 47 | } 48 | 49 | ### 등급 삭제 50 | DELETE localhost:{{Port}}/api/tier/{{tierId}} 51 | Authorization: {{Token}} 52 | -------------------------------------------------------------------------------- /service/user/server/src/test/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | datasource: 3 | url: jdbc:mysql://localhost:3306/user 4 | username: user 5 | password: password 6 | driver-class-name: com.mysql.cj.jdbc.Driver 7 | 8 | jpa: 9 | hibernate: 10 | ddl-auto: update 11 | properties: 12 | hibernate: 13 | dialect: org.hibernate.dialect.MySQLDialect 14 | 15 | eureka: 16 | client: 17 | enabled: false # 단위 테스트 시에는 유레카 클라이언트를 사용하지 않음 18 | -------------------------------------------------------------------------------- /service/user/user_dto/.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | build/ 3 | !gradle/wrapper/gradle-wrapper.jar 4 | !**/src/main/**/build/ 5 | !**/src/test/**/build/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | bin/ 16 | !**/src/main/**/bin/ 17 | !**/src/test/**/bin/ 18 | 19 | ### IntelliJ IDEA ### 20 | .idea 21 | *.iws 22 | *.iml 23 | *.ipr 24 | out/ 25 | !**/src/main/**/out/ 26 | !**/src/test/**/out/ 27 | 28 | ### NetBeans ### 29 | /nbproject/private/ 30 | /nbbuild/ 31 | /dist/ 32 | /nbdist/ 33 | /.nb-gradle/ 34 | 35 | ### VS Code ### 36 | .vscode/ 37 | -------------------------------------------------------------------------------- /service/user/user_dto/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'java' 3 | id 'org.springframework.boot' version '3.3.4' 4 | id 'io.spring.dependency-management' version '1.1.6' 5 | } 6 | 7 | group = 'com.sparta.user' 8 | version = '0.0.1-SNAPSHOT' 9 | 10 | bootJar.enabled = false 11 | 12 | java { 13 | toolchain { 14 | languageVersion = JavaLanguageVersion.of(17) 15 | } 16 | } 17 | 18 | configurations { 19 | compileOnly { 20 | extendsFrom annotationProcessor 21 | } 22 | } 23 | 24 | repositories { 25 | mavenCentral() 26 | } 27 | 28 | dependencies { 29 | implementation 'org.springframework.boot:spring-boot-starter' 30 | compileOnly 'org.projectlombok:lombok' 31 | annotationProcessor 'org.projectlombok:lombok' 32 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 33 | testRuntimeOnly 'org.junit.platform:junit-platform-launcher' 34 | } 35 | 36 | tasks.named('test') { 37 | useJUnitPlatform() 38 | } 39 | -------------------------------------------------------------------------------- /service/user/user_dto/src/main/java/com/sparta/user/user_dto/UserDtoApplication.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.user_dto; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class UserDtoApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(UserDtoApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /service/user/user_dto/src/main/java/com/sparta/user/user_dto/infrastructure/AddressDto.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.user_dto.infrastructure; 2 | 3 | import lombok.AccessLevel; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Builder; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | 9 | @Getter 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | @Builder(access = AccessLevel.PRIVATE) 13 | public class AddressDto { 14 | 15 | private Long addressId; 16 | private Long userId; 17 | private String alias; 18 | private String recipient; 19 | private String phoneNumber; 20 | private String zipcode; 21 | private String address; 22 | private Boolean isDefault; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /service/user/user_dto/src/main/java/com/sparta/user/user_dto/infrastructure/PointHistoryDto.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.user_dto.infrastructure; 2 | 3 | import java.math.BigDecimal; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Getter; 6 | import lombok.NoArgsConstructor; 7 | 8 | @Getter 9 | @NoArgsConstructor 10 | @AllArgsConstructor 11 | public class PointHistoryDto { 12 | 13 | private Long userId; 14 | private Long orderId; 15 | private BigDecimal point; 16 | private String type; 17 | private String description; 18 | 19 | } 20 | -------------------------------------------------------------------------------- /service/user/user_dto/src/main/java/com/sparta/user/user_dto/infrastructure/UserDto.java: -------------------------------------------------------------------------------- 1 | package com.sparta.user.user_dto.infrastructure; 2 | 3 | import java.math.BigDecimal; 4 | import lombok.AccessLevel; 5 | import lombok.AllArgsConstructor; 6 | import lombok.Getter; 7 | import lombok.NoArgsConstructor; 8 | 9 | @Getter 10 | @NoArgsConstructor 11 | @AllArgsConstructor 12 | public class UserDto { 13 | 14 | private Long userId; 15 | private String username; 16 | private String password; 17 | private String email; 18 | private String role; 19 | private BigDecimal point; 20 | 21 | @AllArgsConstructor(access = AccessLevel.PRIVATE) 22 | @Getter 23 | public enum UserRole { 24 | ROLE_ADMIN("관리자"), 25 | ROLE_MANAGER("매니저"), 26 | ROLE_USER("사용자"); 27 | 28 | private final String role; 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'sasaping' 2 | 3 | include(':common:domain') 4 | 5 | include(':service:user:server') 6 | include(':service:user:user_dto') 7 | 8 | include(':service:product:server') 9 | include(':service:product:product_dto') 10 | 11 | include(':service:payment:server') 12 | include(':service:payment:payment_dto') 13 | 14 | include(':service:eureka:server') 15 | include(':service:gateway:server') 16 | 17 | include(':service:auth:server') 18 | include(':service:auth:auth_dto') 19 | 20 | include(':service:order:server') 21 | include(':service:order:dto') 22 | 23 | include(':service:notification:server') 24 | include(':service:notification:notification_dto') 25 | 26 | include(':service:slack:server') 27 | include(':service:slack:slack_dto') 28 | 29 | include(':service:promotion:server') 30 | 31 | include(':service:search:server') 32 | -------------------------------------------------------------------------------- /stop-used-port.sh: -------------------------------------------------------------------------------- 1 | # 점검할 포트 목록 2 | # EX) PORTS=(19091 19092) 3 | PORTS=(19091 19061) 4 | 5 | for PORT in "${PORTS[@]}"; do 6 | # 포트가 사용 중인지 확인 7 | PID=$(lsof -t -i :$PORT) 8 | 9 | # 포트가 사용 중이면 프로세스 종료 10 | if [ -n "$PID" ]; then 11 | echo "포트 $PORT 사용 중. PID: $PID. 프로세스 종료 중..." 12 | kill -9 $PID 13 | echo "PID $PID 종료 완료." 14 | else 15 | echo "포트 $PORT 사용 가능." 16 | fi 17 | done 18 | --------------------------------------------------------------------------------