From 97c3e1598c043c49cc6617b79b49148212e20f4b Mon Sep 17 00:00:00 2001 From: pricelees Date: Tue, 30 Sep 2025 00:39:13 +0000 Subject: [PATCH] =?UTF-8?q?[#48]=20Tosspay=20mocking=20=EC=84=9C=EB=B2=84?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84=EC=9D=84=20=EC=9C=84=ED=95=9C=20=EB=A9=80?= =?UTF-8?q?=ED=8B=B0=EB=AA=A8=EB=93=88=20=EC=A0=84=ED=99=98=20(#49)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## 📝 관련 이슈 및 PR **PR과 관련된 이슈 번호** - #48 ## ✨ 작업 내용 - Tosspay mocking 서버를 해당 프로젝트 내 구현할 때 각 서비스간 구분이 수월하도록 모듈 분리 - 분리하는 과정에서 추후 공통적으로 활용될 수 있다고 판단한 기능들은 common 모듈로 분리 - 일부 테스트 보완 ## 🧪 테스트 스크린샷 2025-09-29 22.05.25.png - 전체 테스트 후 클래스 커버리지 기준 100% 달성 확인 ## 📚 참고 자료 및 기타 Reviewed-on: https://gitea.pricelees.me/pricelees/roomescape-refactored/pulls/49 Co-authored-by: pricelees Co-committed-by: pricelees --- build.gradle.kts | 115 +++------ common/log/build.gradle.kts | 12 + .../sangdol/common/log/constant/LogType.kt | 9 + .../message/AbstractLogMaskingConverter.kt | 27 +- .../MDCAwareSlowQueryListenerWithoutParams.kt | 2 +- .../log/sql/SlowQueryDataSourceFactory.kt | 20 ++ .../log/AbstractLogMaskingConverterTest.kt | 55 +++++ ...AwareSlowQueryListenerWithoutParamsTest.kt | 10 +- common/persistence/build.gradle.kts | 29 +++ .../common/persistence/AuditingBaseEntity.kt | 28 +-- .../sangdol/common/persistence/IDGenerator.kt | 13 + .../persistence/PersistableBaseEntity.kt | 25 ++ .../common/persistence/PersistenceConfig.kt | 44 ++++ .../persistence}/TransactionExecutionUtil.kt | 16 +- .../common/persistence/BaseEntityTest.kt | 53 ++++ .../common/persistence/TestApplication.kt | 6 + .../persistence/TestAuditingBaseEntity.kt | 12 + .../persistence/TestPersistableBaseEntity.kt | 12 + .../TransactionExecutionUtilTest.kt | 75 ++++++ .../src/test/resources/application.yaml | 18 ++ common/types/build.gradle.kts | 3 + .../types}/exception/CommonErrorCode.kt | 4 +- .../common/types}/exception/ErrorCode.kt | 4 +- .../types}/exception/RoomescapeException.kt | 4 +- .../sangdol/common/types/web/ApiResponses.kt | 6 +- .../sangdol/common/types/web/HttpStatus.kt | 24 ++ common/utils/build.gradle.kts | 7 + .../common/utils/MdcPrincipalIdUtil.kt | 7 +- .../sangdol/common/utils/MdcStartTimeUtil.kt | 25 ++ .../common/utils/MdcPrincipalIdUtilTest.kt | 28 +++ .../common/utils/MdcStartTimeUtilTest.kt | 34 +++ common/web/build.gradle.kts | 28 +++ .../web/asepct}/ControllerLoggingAspect.kt | 51 ++-- .../common/web}/config/JacksonConfig.kt | 17 +- .../common/web/config/WebLoggingConfig.kt | 23 +- .../web/exception/GlobalExceptionhandler.kt | 81 +++--- .../web/servlet}/HttpRequestLoggingFilter.kt | 16 +- .../web/support/log/LogPayloadBuilder.kt | 75 ++++++ .../web/support/log/WebLogMessageConverter.kt | 49 ++++ .../common/web}/config/JacksonConfigTest.kt | 16 +- .../web/support/log/LogPayloadBuilderTest.kt | 233 ++++++++++++++++++ .../support/log/WebLogMessageConverterTest.kt | 166 +++++++++++++ service/build.gradle.kts | 63 +++++ .../roomescape/RoomescapeApplication.kt | 6 +- .../roomescape/admin/business/AdminService.kt | 21 +- .../admin/business/dto/AdminLoginDTO.kt | 39 +++ .../admin/exception/AdminException.kt | 8 +- .../infrastructure/persistence/AdminEntity.kt | 4 +- .../persistence/AdminRepository.kt | 2 +- .../roomescape/auth/business/AuthService.kt | 18 +- .../auth/business/LoginHistoryService.kt | 17 +- .../sangdol}/roomescape/auth/docs/AuthAPI.kt | 14 +- .../auth/exception/AuthErrorCode.kt | 6 +- .../auth/exception/AuthException.kt | 4 +- .../auth/infrastructure/jwt/JwtUtils.kt | 6 +- .../persistence/LoginHistoryEntity.kt | 6 +- .../persistence/LoginHistoryRepository.kt | 2 +- .../roomescape/auth/web/AuthController.kt | 12 +- .../sangdol}/roomescape/auth/web/AuthDTO.kt | 25 +- .../auth/web/support/AuthAnnotations.kt | 6 +- .../auth/web/support/CookieUtils.kt | 2 +- .../support/interceptors/AdminInterceptor.kt | 26 +- .../support/interceptors/UserInterceptor.kt | 18 +- .../support/resolver/UserContextResolver.kt | 14 +- .../config/RoomescapeLogMaskingConverter.kt | 9 + .../common/config/SlowQueryLoggerConfig.kt | 20 +- .../roomescape/common/config/SwaggerConfig.kt | 15 ++ .../roomescape/common/config/WebMvcConfig.kt | 8 +- .../roomescape/common/types/AuditingInfo.kt | 19 ++ .../common/types/CurrentUserContext.kt | 6 + .../payment/business/PaymentService.kt | 21 +- .../payment/business/PaymentWriter.kt | 25 +- .../roomescape/payment/docs/PaymentAPI.kt | 16 +- .../payment/exception/PaymentErrorCode.kt | 6 +- .../payment/exception/PaymentException.kt | 4 +- .../infrastructure/client/PaymentConfig.kt | 2 +- .../client/PaymentProperties.kt | 2 +- .../infrastructure/client/TosspayCancelDTO.kt | 6 +- .../infrastructure/client/TosspayClient.kt | 6 +- .../client/TosspayConfirmDTO.kt | 16 +- .../client/TosspayErrorResponse.kt | 2 +- .../infrastructure/common/PaymentTypes.kt | 6 +- .../persistence/CanceledPaymentEntity.kt | 4 +- .../persistence/CanceledPaymentRepository.kt | 2 +- .../persistence/PaymentDetailEntity.kt | 6 +- .../persistence/PaymentDetailRepository.kt | 2 +- .../persistence/PaymentEntity.kt | 10 +- .../persistence/PaymentRepository.kt | 2 +- .../payment/web/PaymentController.kt | 12 +- .../roomescape/payment/web/PaymentDTO.kt | 14 +- .../region/business/RegionService.kt | 10 +- .../roomescape/region/docs/RegionAPI.kt | 12 +- .../region/exception/RegionException.kt | 8 +- .../persistence/RegionEntity.kt | 2 +- .../persistence/RegionRepository.kt | 2 +- .../roomescape/region/web/RegionController.kt | 8 +- .../roomescape/region/web/RegionDTO.kt | 2 +- .../business/ReservationService.kt | 41 ++- .../business/ReservationValidator.kt | 14 +- .../reservation/docs/ReservationAPI.kt | 14 +- .../exception/ReservationErrorCode.kt | 6 +- .../exception/ReservationException.kt | 9 + .../persistence/CanceledReservationEntity.kt | 4 +- .../CanceledReservationRepository.kt | 2 +- .../persistence/ReservationEntity.kt | 4 +- .../persistence/ReservationRepository.kt | 2 +- .../reservation/web/ReservationController.kt | 12 +- .../reservation/web/ReservationDto.kt | 16 +- .../schedule/business/ScheduleService.kt | 37 ++- .../schedule/business/ScheduleValidator.kt | 14 +- .../business/domain/ScheduleOverview.kt | 6 +- .../roomescape/schedule/docs/ScheduleAPI.kt | 20 +- .../schedule/exception/ScheduleErrorCode.kt | 6 +- .../schedule/exception/ScheduleException.kt | 4 +- .../persistence/ScheduleEntity.kt | 8 +- .../persistence/ScheduleRepository.kt | 8 +- .../schedule/web/AdminScheduleController.kt | 12 +- .../schedule/web/AdminScheduleDto.kt | 6 +- .../schedule/web/ScheduleController.kt | 10 +- .../roomescape/schedule/web/ScheduleDto.kt | 10 +- .../roomescape/store/business/StoreService.kt | 31 ++- .../store/business/StoreValidator.kt | 12 +- .../roomescape/store/docs/StoreAPI.kt | 14 +- .../store/exception/StoreException.kt | 8 +- .../infrastructure/persistence/StoreEntity.kt | 4 +- .../persistence/StoreRepository.kt | 6 +- .../store/web/AdminStoreController.kt | 8 +- .../roomescape/store/web/AdminStoreDto.kt | 12 +- .../roomescape/store/web/StoreController.kt | 8 +- .../sangdol}/roomescape/store/web/StoreDTO.kt | 4 +- .../roomescape/theme/business}/DateUtils.kt | 2 +- .../roomescape/theme/business/ThemeService.kt | 26 +- .../theme/business/ThemeValidator.kt | 12 +- .../theme/business/domain/ThemeInfo.kt | 2 +- .../roomescape/theme/docs/ThemeApi.kt | 14 +- .../theme/exception/ThemeErrorCode.kt | 6 +- .../theme/exception/ThemeException.kt | 4 +- .../infrastructure/persistence/ThemeEntity.kt | 4 +- .../persistence/ThemeRepository.kt | 4 +- .../theme/web/AdminThemeController.kt | 8 +- .../roomescape/theme/web/AdminThemeDto.kt | 12 +- .../roomescape/theme/web/ThemeController.kt | 8 +- .../sangdol}/roomescape/theme/web/ThemeDto.kt | 10 +- .../roomescape/user/business/UserService.kt | 31 ++- .../roomescape/user/business/UserValidator.kt | 8 +- .../user/business/dto/UserLoginDTO.kt | 27 ++ .../sangdol}/roomescape/user/docs/UserAPI.kt | 16 +- .../user/exception/UserException.kt | 8 +- .../persistence/UserEntities.kt | 4 +- .../persistence/UserRepositories.kt | 2 +- .../roomescape/user/web/UserController.kt | 12 +- .../sangdol}/roomescape/user/web/UserDTO.kt | 6 +- .../main/resources/application-deploy.yaml | 0 .../main/resources/application-local.yaml | 0 .../src}/main/resources/application.yaml | 0 .../src}/main/resources/logback-deploy.xml | 2 +- .../src}/main/resources/logback-local.xml | 4 +- .../src}/main/resources/logback-spring.xml | 0 .../main/resources/schema/region-data.sql | 0 .../src}/main/resources/schema/schema-h2.sql | 0 .../main/resources/schema/schema-mysql.sql | 0 .../sangdol}/data/DefaultDataInitializer.kt | 75 +++--- .../com/sangdol}/data/PopulationDataParser.kt | 17 +- .../sangdol}/roomescape/auth/AuthApiTest.kt | 34 +-- .../auth/FailOnSaveLoginHistoryTest.kt | 18 +- .../sangdol}/roomescape/auth/JwtUtilsTest.kt | 15 +- .../roomescape/payment/PaymentAPITest.kt | 28 +-- .../roomescape/payment/PaymentTypeTest.kt | 148 +++++++++++ .../payment/SampleTosspayConstant.kt | 2 +- .../roomescape/payment/TosspayClientTest.kt | 16 +- .../roomescape/region/RegionApiFailTest.kt | 10 +- .../roomescape/region/RegionApiSuccessTest.kt | 8 +- .../reservation/ReservationApiTest.kt | 42 ++-- .../schedule/AdminScheduleApiTest.kt | 31 ++- .../roomescape/schedule/ScheduleApiTest.kt | 18 +- .../roomescape/store/AdminStoreApiTest.kt | 24 +- .../sangdol}/roomescape/store/StoreApiTest.kt | 10 +- .../roomescape/supports/DummyInitializer.kt | 73 +++--- .../sangdol}/roomescape/supports/Fixtures.kt | 76 +++--- .../roomescape/supports/KotestConfig.kt | 18 +- .../roomescape/supports/RestAssuredUtils.kt | 11 +- .../roomescape/supports/TestAuthUtil.kt | 22 +- .../roomescape/supports/TestDatabaseUtil.kt | 2 +- .../sangdol}/roomescape/supports/TestUtil.kt | 2 +- .../roomescape/theme/AdminThemeApiTest.kt | 28 +-- .../roomescape/theme}/DateUtilsTest.kt | 5 +- .../sangdol}/roomescape/theme/ThemeApiTest.kt | 27 +- .../sangdol}/roomescape/user/UserApiTest.kt | 28 +-- .../resources/application-test-mysql.yaml | 0 .../src}/test/resources/application-test.yaml | 0 .../src}/test/resources/logback-test.xml | 0 settings.gradle | 9 + .../roomescape/common/config/JpaConfig.kt | 20 -- .../roomescape/common/config/SwaggerConfig.kt | 78 ------ .../roomescape/common/config/TsidConfig.kt | 17 -- .../kotlin/roomescape/common/dto/AuditDto.kt | 22 -- .../roomescape/common/dto/CommonAuth.kt | 69 ------ .../common/log/ApiLogMessageConverter.kt | 85 ------- .../exception/ReservationException.kt | 9 - src/main/resources/login.http | 55 ----- src/main/resources/test.http | 4 - .../common/log/ApiLogMessageConverterTest.kt | 68 ----- .../log/RoomescapeLogMaskingConverterTest.kt | 77 ------ 203 files changed, 2383 insertions(+), 1608 deletions(-) create mode 100644 common/log/build.gradle.kts create mode 100644 common/log/src/main/kotlin/com/sangdol/common/log/constant/LogType.kt rename src/main/kotlin/roomescape/common/log/RoomescapeLogMaskingConverter.kt => common/log/src/main/kotlin/com/sangdol/common/log/message/AbstractLogMaskingConverter.kt (76%) rename {src/main/kotlin/roomescape/common/log => common/log/src/main/kotlin/com/sangdol/common/log/sql}/MDCAwareSlowQueryListenerWithoutParams.kt (97%) create mode 100644 common/log/src/main/kotlin/com/sangdol/common/log/sql/SlowQueryDataSourceFactory.kt create mode 100644 common/log/src/test/kotlin/com/sangdol/common/log/AbstractLogMaskingConverterTest.kt rename {src/test/kotlin/roomescape => common/log/src/test/kotlin/com/sangdol}/common/log/MDCAwareSlowQueryListenerWithoutParamsTest.kt (71%) create mode 100644 common/persistence/build.gradle.kts rename src/main/kotlin/roomescape/common/entity/BaseEntity.kt => common/persistence/src/main/kotlin/com/sangdol/common/persistence/AuditingBaseEntity.kt (60%) create mode 100644 common/persistence/src/main/kotlin/com/sangdol/common/persistence/IDGenerator.kt create mode 100644 common/persistence/src/main/kotlin/com/sangdol/common/persistence/PersistableBaseEntity.kt create mode 100644 common/persistence/src/main/kotlin/com/sangdol/common/persistence/PersistenceConfig.kt rename {src/main/kotlin/roomescape/common/util => common/persistence/src/main/kotlin/com/sangdol/common/persistence}/TransactionExecutionUtil.kt (51%) create mode 100644 common/persistence/src/test/kotlin/com/sangdol/common/persistence/BaseEntityTest.kt create mode 100644 common/persistence/src/test/kotlin/com/sangdol/common/persistence/TestApplication.kt create mode 100644 common/persistence/src/test/kotlin/com/sangdol/common/persistence/TestAuditingBaseEntity.kt create mode 100644 common/persistence/src/test/kotlin/com/sangdol/common/persistence/TestPersistableBaseEntity.kt create mode 100644 common/persistence/src/test/kotlin/com/sangdol/common/persistence/TransactionExecutionUtilTest.kt create mode 100644 common/persistence/src/test/resources/application.yaml create mode 100644 common/types/build.gradle.kts rename {src/main/kotlin/roomescape/common => common/types/src/main/kotlin/com/sangdol/common/types}/exception/CommonErrorCode.kt (85%) rename {src/main/kotlin/roomescape/common => common/types/src/main/kotlin/com/sangdol/common/types}/exception/ErrorCode.kt (54%) rename {src/main/kotlin/roomescape/common => common/types/src/main/kotlin/com/sangdol/common/types}/exception/RoomescapeException.kt (62%) rename src/main/kotlin/roomescape/common/dto/response/CommonApiResponse.kt => common/types/src/main/kotlin/com/sangdol/common/types/web/ApiResponses.kt (62%) create mode 100644 common/types/src/main/kotlin/com/sangdol/common/types/web/HttpStatus.kt create mode 100644 common/utils/build.gradle.kts rename src/main/kotlin/roomescape/common/util/MDCUtils.kt => common/utils/src/main/kotlin/com/sangdol/common/utils/MdcPrincipalIdUtil.kt (80%) create mode 100644 common/utils/src/main/kotlin/com/sangdol/common/utils/MdcStartTimeUtil.kt create mode 100644 common/utils/src/test/kotlin/com/sangdol/common/utils/MdcPrincipalIdUtilTest.kt create mode 100644 common/utils/src/test/kotlin/com/sangdol/common/utils/MdcStartTimeUtilTest.kt create mode 100644 common/web/build.gradle.kts rename {src/main/kotlin/roomescape/common/log => common/web/src/main/kotlin/com/sangdol/common/web/asepct}/ControllerLoggingAspect.kt (63%) rename {src/main/kotlin/roomescape/common => common/web/src/main/kotlin/com/sangdol/common/web}/config/JacksonConfig.kt (87%) rename src/main/kotlin/roomescape/common/log/LogConfiguration.kt => common/web/src/main/kotlin/com/sangdol/common/web/config/WebLoggingConfig.kt (50%) rename src/main/kotlin/roomescape/common/exception/ExceptionControllerAdvice.kt => common/web/src/main/kotlin/com/sangdol/common/web/exception/GlobalExceptionhandler.kt (54%) rename {src/main/kotlin/roomescape/common/log => common/web/src/main/kotlin/com/sangdol/common/web/servlet}/HttpRequestLoggingFilter.kt (73%) create mode 100644 common/web/src/main/kotlin/com/sangdol/common/web/support/log/LogPayloadBuilder.kt create mode 100644 common/web/src/main/kotlin/com/sangdol/common/web/support/log/WebLogMessageConverter.kt rename {src/test/kotlin/roomescape/common => common/web/src/test/kotlin/com/sangdol/common/web}/config/JacksonConfigTest.kt (91%) create mode 100644 common/web/src/test/kotlin/com/sangdol/common/web/support/log/LogPayloadBuilderTest.kt create mode 100644 common/web/src/test/kotlin/com/sangdol/common/web/support/log/WebLogMessageConverterTest.kt create mode 100644 service/build.gradle.kts rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/RoomescapeApplication.kt (74%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/admin/business/AdminService.kt (73%) create mode 100644 service/src/main/kotlin/com/sangdol/roomescape/admin/business/dto/AdminLoginDTO.kt rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/admin/exception/AdminException.kt (66%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/admin/infrastructure/persistence/AdminEntity.kt (91%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/admin/infrastructure/persistence/AdminRepository.kt (73%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/auth/business/AuthService.kt (87%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/auth/business/LoginHistoryService.kt (81%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/auth/docs/AuthAPI.kt (71%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/auth/exception/AuthErrorCode.kt (85%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/auth/exception/AuthException.kt (60%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/auth/infrastructure/jwt/JwtUtils.kt (93%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/auth/infrastructure/persistence/LoginHistoryEntity.kt (78%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/auth/infrastructure/persistence/LoginHistoryRepository.kt (77%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/auth/web/AuthController.kt (77%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/auth/web/AuthDTO.kt (52%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/auth/web/support/AuthAnnotations.kt (71%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/auth/web/support/CookieUtils.kt (85%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/auth/web/support/interceptors/AdminInterceptor.kt (83%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/auth/web/support/interceptors/UserInterceptor.kt (77%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/auth/web/support/resolver/UserContextResolver.kt (79%) create mode 100644 service/src/main/kotlin/com/sangdol/roomescape/common/config/RoomescapeLogMaskingConverter.kt rename src/main/kotlin/roomescape/common/log/ProxyDataSourceConfig.kt => service/src/main/kotlin/com/sangdol/roomescape/common/config/SlowQueryLoggerConfig.kt (70%) create mode 100644 service/src/main/kotlin/com/sangdol/roomescape/common/config/SwaggerConfig.kt rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/common/config/WebMvcConfig.kt (75%) create mode 100644 service/src/main/kotlin/com/sangdol/roomescape/common/types/AuditingInfo.kt create mode 100644 service/src/main/kotlin/com/sangdol/roomescape/common/types/CurrentUserContext.kt rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/business/PaymentService.kt (87%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/business/PaymentWriter.kt (79%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/docs/PaymentAPI.kt (69%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/exception/PaymentErrorCode.kt (89%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/exception/PaymentException.kt (60%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/infrastructure/client/PaymentConfig.kt (96%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/infrastructure/client/PaymentProperties.kt (81%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/infrastructure/client/TosspayCancelDTO.kt (90%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/infrastructure/client/TosspayClient.kt (96%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/infrastructure/client/TosspayConfirmDTO.kt (84%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/infrastructure/client/TosspayErrorResponse.kt (57%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/infrastructure/common/PaymentTypes.kt (97%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/infrastructure/persistence/CanceledPaymentEntity.kt (80%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/infrastructure/persistence/CanceledPaymentRepository.kt (76%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/infrastructure/persistence/PaymentDetailEntity.kt (90%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/infrastructure/persistence/PaymentDetailRepository.kt (75%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/infrastructure/persistence/PaymentEntity.kt (67%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/infrastructure/persistence/PaymentRepository.kt (75%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/web/PaymentController.kt (74%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/payment/web/PaymentDTO.kt (89%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/region/business/RegionService.kt (91%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/region/docs/RegionAPI.kt (78%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/region/exception/RegionException.kt (77%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/region/infrastructure/persistence/RegionEntity.kt (86%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/region/infrastructure/persistence/RegionRepository.kt (95%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/region/web/RegionController.kt (87%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/region/web/RegionDTO.kt (91%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/reservation/business/ReservationService.kt (84%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/reservation/business/ReservationValidator.kt (74%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/reservation/docs/ReservationAPI.kt (83%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/reservation/exception/ReservationErrorCode.kt (82%) create mode 100644 service/src/main/kotlin/com/sangdol/roomescape/reservation/exception/ReservationException.kt rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/reservation/infrastructure/persistence/CanceledReservationEntity.kt (81%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/reservation/infrastructure/persistence/CanceledReservationRepository.kt (68%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt (85%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt (78%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/reservation/web/ReservationController.kt (85%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/reservation/web/ReservationDto.kt (85%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/schedule/business/ScheduleService.kt (85%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/schedule/business/ScheduleValidator.kt (85%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/schedule/business/domain/ScheduleOverview.kt (75%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/schedule/docs/ScheduleAPI.kt (84%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/schedule/exception/ScheduleErrorCode.kt (84%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/schedule/exception/ScheduleException.kt (58%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/schedule/infrastructure/persistence/ScheduleEntity.kt (87%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/schedule/infrastructure/persistence/ScheduleRepository.kt (86%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/schedule/web/AdminScheduleController.kt (86%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/schedule/web/AdminScheduleDto.kt (86%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/schedule/web/ScheduleController.kt (78%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/schedule/web/ScheduleDto.kt (84%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/store/business/StoreService.kt (84%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/store/business/StoreValidator.kt (85%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/store/docs/StoreAPI.kt (85%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/store/exception/StoreException.kt (82%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/store/infrastructure/persistence/StoreEntity.kt (88%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/store/infrastructure/persistence/StoreRepository.kt (76%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/store/web/AdminStoreController.kt (87%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/store/web/AdminStoreDto.kt (74%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/store/web/StoreController.kt (84%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/store/web/StoreDTO.kt (84%) rename {src/main/kotlin/roomescape/common/util => service/src/main/kotlin/com/sangdol/roomescape/theme/business}/DateUtils.kt (85%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/theme/business/ThemeService.kt (89%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/theme/business/ThemeValidator.kt (92%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/theme/business/domain/ThemeInfo.kt (86%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/theme/docs/ThemeApi.kt (88%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/theme/exception/ThemeErrorCode.kt (89%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/theme/exception/ThemeException.kt (60%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/theme/infrastructure/persistence/ThemeEntity.kt (92%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/theme/infrastructure/persistence/ThemeRepository.kt (92%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/theme/web/AdminThemeController.kt (90%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/theme/web/AdminThemeDto.kt (90%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/theme/web/ThemeController.kt (79%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/theme/web/ThemeDto.kt (87%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/user/business/UserService.kt (77%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/user/business/UserValidator.kt (80%) create mode 100644 service/src/main/kotlin/com/sangdol/roomescape/user/business/dto/UserLoginDTO.kt rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/user/docs/UserAPI.kt (66%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/user/exception/UserException.kt (74%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/user/infrastructure/persistence/UserEntities.kt (84%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/user/infrastructure/persistence/UserRepositories.kt (84%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/user/web/UserController.kt (72%) rename {src/main/kotlin => service/src/main/kotlin/com/sangdol}/roomescape/user/web/UserDTO.kt (83%) rename {src => service/src}/main/resources/application-deploy.yaml (100%) rename {src => service/src}/main/resources/application-local.yaml (100%) rename {src => service/src}/main/resources/application.yaml (100%) rename {src => service/src}/main/resources/logback-deploy.xml (97%) rename {src => service/src}/main/resources/logback-local.xml (82%) rename {src => service/src}/main/resources/logback-spring.xml (100%) rename {src => service/src}/main/resources/schema/region-data.sql (100%) rename {src => service/src}/main/resources/schema/schema-h2.sql (100%) rename {src => service/src}/main/resources/schema/schema-mysql.sql (100%) rename {src/test/kotlin/roomescape => service/src/test/kotlin/com/sangdol}/data/DefaultDataInitializer.kt (93%) rename {src/test/kotlin/roomescape => service/src/test/kotlin/com/sangdol}/data/PopulationDataParser.kt (94%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/auth/AuthApiTest.kt (88%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/auth/FailOnSaveLoginHistoryTest.kt (78%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/auth/JwtUtilsTest.kt (88%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/payment/PaymentAPITest.kt (94%) create mode 100644 service/src/test/kotlin/com/sangdol/roomescape/payment/PaymentTypeTest.kt rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/payment/SampleTosspayConstant.kt (99%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/payment/TosspayClientTest.kt (93%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/region/RegionApiFailTest.kt (83%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/region/RegionApiSuccessTest.kt (87%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/reservation/ReservationApiTest.kt (93%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/schedule/AdminScheduleApiTest.kt (96%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/schedule/ScheduleApiTest.kt (88%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/store/AdminStoreApiTest.kt (96%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/store/StoreApiTest.kt (93%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/supports/DummyInitializer.kt (71%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/supports/Fixtures.kt (80%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/supports/KotestConfig.kt (78%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/supports/RestAssuredUtils.kt (91%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/supports/TestAuthUtil.kt (85%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/supports/TestDatabaseUtil.kt (98%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/supports/TestUtil.kt (95%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/theme/AdminThemeApiTest.kt (97%) rename {src/test/kotlin/roomescape/common/util => service/src/test/kotlin/com/sangdol/roomescape/theme}/DateUtilsTest.kt (80%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/theme/ThemeApiTest.kt (85%) rename {src/test/kotlin => service/src/test/kotlin/com/sangdol}/roomescape/user/UserApiTest.kt (90%) rename {src => service/src}/test/resources/application-test-mysql.yaml (100%) rename {src => service/src}/test/resources/application-test.yaml (100%) rename {src => service/src}/test/resources/logback-test.xml (100%) create mode 100644 settings.gradle delete mode 100644 src/main/kotlin/roomescape/common/config/JpaConfig.kt delete mode 100644 src/main/kotlin/roomescape/common/config/SwaggerConfig.kt delete mode 100644 src/main/kotlin/roomescape/common/config/TsidConfig.kt delete mode 100644 src/main/kotlin/roomescape/common/dto/AuditDto.kt delete mode 100644 src/main/kotlin/roomescape/common/dto/CommonAuth.kt delete mode 100644 src/main/kotlin/roomescape/common/log/ApiLogMessageConverter.kt delete mode 100644 src/main/kotlin/roomescape/reservation/exception/ReservationException.kt delete mode 100644 src/main/resources/login.http delete mode 100644 src/main/resources/test.http delete mode 100644 src/test/kotlin/roomescape/common/log/ApiLogMessageConverterTest.kt delete mode 100644 src/test/kotlin/roomescape/common/log/RoomescapeLogMaskingConverterTest.kt diff --git a/build.gradle.kts b/build.gradle.kts index c6a792f2..5f4b11d5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,99 +1,58 @@ +import org.jetbrains.kotlin.gradle.plugin.KaptExtension import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { val springBootVersion = "3.5.3" val kotlinVersion = "2.2.0" - id("org.springframework.boot") version springBootVersion - id("io.spring.dependency-management") version "1.1.7" - kotlin("jvm") version kotlinVersion - kotlin("plugin.spring") version kotlinVersion - kotlin("plugin.jpa") version kotlinVersion - kotlin("kapt") version kotlinVersion + id("io.spring.dependency-management") version "1.1.7" apply false + id("org.springframework.boot") version springBootVersion apply false + kotlin("jvm") version kotlinVersion apply false + kotlin("kapt") version kotlinVersion apply false + kotlin("plugin.spring") version kotlinVersion apply false + kotlin("plugin.jpa") version kotlinVersion apply false } group = "com.sangdol" version = "0.0.1-SNAPSHOT" -java { - toolchain { - languageVersion = JavaLanguageVersion.of(17) +allprojects { + repositories { + mavenCentral() } } -tasks.jar { - enabled = false -} +subprojects { + apply(plugin = "org.jetbrains.kotlin.jvm") + apply(plugin = "org.jetbrains.kotlin.kapt") + apply(plugin = "io.spring.dependency-management") -kapt { - keepJavacAnnotationProcessors = true -} + extensions.configure { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 + } -repositories { - mavenCentral() -} + extensions.configure { + keepJavacAnnotationProcessors = true + } -dependencies { - // Spring - implementation("org.springframework.boot:spring-boot-starter-web") - implementation("org.springframework.boot:spring-boot-starter-data-jpa") - implementation("org.springframework.boot:spring-boot-starter-validation") + dependencies { + add("implementation", "io.github.oshai:kotlin-logging-jvm:7.0.3") + add("implementation", "io.kotest:kotest-runner-junit5:5.9.1") + add("implementation", "ch.qos.logback:logback-classic:1.5.18") + } - // API docs - implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.9") + tasks.withType { + useJUnitPlatform() + } - // DB - implementation("com.github.f4b6a3:tsid-creator:5.2.6") - runtimeOnly("com.h2database:h2") - runtimeOnly("com.mysql:mysql-connector-j") - - // Jwt - implementation("io.jsonwebtoken:jjwt:0.12.6") - - // Logging - implementation("io.github.oshai:kotlin-logging-jvm:7.0.3") - implementation("net.logstash.logback:logstash-logback-encoder:8.1") - implementation("com.github.loki4j:loki-logback-appender:2.0.0") - implementation("net.ttddyy.observation:datasource-micrometer-spring-boot:1.1.1") - - // Observability - implementation("org.springframework.boot:spring-boot-starter-actuator") - implementation("io.micrometer:micrometer-tracing-bridge-otel") - implementation("io.opentelemetry:opentelemetry-exporter-otlp") - runtimeOnly("io.micrometer:micrometer-registry-prometheus") - - // Kotlin - implementation("org.jetbrains.kotlin:kotlin-reflect") - implementation("com.fasterxml.jackson.module:jackson-module-kotlin") - implementation("io.github.oshai:kotlin-logging-jvm:7.0.3") - - // Test - testImplementation("org.springframework.boot:spring-boot-starter-test") - testImplementation("io.mockk:mockk:1.14.4") - testImplementation("com.ninja-squad:springmockk:4.0.2") - - // Kotest - testImplementation("io.kotest:kotest-runner-junit5:5.9.1") - testImplementation("io.kotest.extensions:kotest-extensions-spring:1.3.0") - - // RestAssured - testImplementation("io.rest-assured:rest-assured:5.5.5") - testImplementation("io.rest-assured:kotlin-extensions:5.5.5") - - // etc - implementation("org.apache.poi:poi-ooxml:5.2.3") -} - -tasks.withType { - useJUnitPlatform() -} - -tasks.withType { - compilerOptions { - freeCompilerArgs.addAll( - "-Xjsr305=strict", - "-Xannotation-default-target=param-property" - ) - jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17) + tasks.withType { + compilerOptions { + freeCompilerArgs.addAll( + "-Xjsr305=strict", + "-Xannotation-default-target=param-property" + ) + jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17) + } } } diff --git a/common/log/build.gradle.kts b/common/log/build.gradle.kts new file mode 100644 index 00000000..7146ccca --- /dev/null +++ b/common/log/build.gradle.kts @@ -0,0 +1,12 @@ +dependencies { + implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.20.0") + implementation("net.ttddyy.observation:datasource-micrometer-spring-boot:1.1.2") + + testImplementation("io.mockk:mockk:1.14.4") + + implementation(project(":common:utils")) +} + +tasks.named("jar") { + enabled = true +} diff --git a/common/log/src/main/kotlin/com/sangdol/common/log/constant/LogType.kt b/common/log/src/main/kotlin/com/sangdol/common/log/constant/LogType.kt new file mode 100644 index 00000000..8717b69c --- /dev/null +++ b/common/log/src/main/kotlin/com/sangdol/common/log/constant/LogType.kt @@ -0,0 +1,9 @@ +package com.sangdol.common.log.constant + +enum class LogType { + INCOMING_HTTP_REQUEST, + CONTROLLER_INVOKED, + SUCCEED, + APPLICATION_FAILURE, + UNHANDLED_EXCEPTION +} diff --git a/src/main/kotlin/roomescape/common/log/RoomescapeLogMaskingConverter.kt b/common/log/src/main/kotlin/com/sangdol/common/log/message/AbstractLogMaskingConverter.kt similarity index 76% rename from src/main/kotlin/roomescape/common/log/RoomescapeLogMaskingConverter.kt rename to common/log/src/main/kotlin/com/sangdol/common/log/message/AbstractLogMaskingConverter.kt index 104eeba9..42e117ef 100644 --- a/src/main/kotlin/roomescape/common/log/RoomescapeLogMaskingConverter.kt +++ b/common/log/src/main/kotlin/com/sangdol/common/log/message/AbstractLogMaskingConverter.kt @@ -1,4 +1,4 @@ -package roomescape.common.log +package com.sangdol.common.log.message import ch.qos.logback.classic.pattern.MessageConverter import ch.qos.logback.classic.spi.ILoggingEvent @@ -7,13 +7,14 @@ import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.node.ArrayNode import com.fasterxml.jackson.databind.node.ObjectNode import com.fasterxml.jackson.databind.node.TextNode -import roomescape.common.config.JacksonConfig -private const val MASK: String = "****" -private val SENSITIVE_KEYS = setOf("password", "accessToken", "phone") -private val objectMapper: ObjectMapper = JacksonConfig().objectMapper() +abstract class AbstractLogMaskingConverter( + val sensitiveKeys: Set, + val objectMapper: ObjectMapper +) : MessageConverter() { + + val mask: String = "****" -class RoomescapeLogMaskingConverter : MessageConverter() { override fun convert(event: ILoggingEvent): String { val message: String = event.formattedMessage @@ -35,13 +36,13 @@ class RoomescapeLogMaskingConverter : MessageConverter() { .toString() private fun maskedPlainMessage(message: String): String { - val keys: String = SENSITIVE_KEYS.joinToString("|") - val regex = Regex("(?i)($keys)(\\s*=\\s*)([^(,|\"|?)\\s]+)") + val keys: String = sensitiveKeys.joinToString("|") + val regex = Regex("(?i)($keys)(\\s*[:=]\\s*)([^(,|\"|?)]+)") return regex.replace(message) { matchResult -> val key = matchResult.groupValues[1] val delimiter = matchResult.groupValues[2] - val maskedValue = maskValue(matchResult.groupValues[3]) + val maskedValue = maskValue(matchResult.groupValues[3].trim()) "${key}${delimiter}${maskedValue}" } @@ -51,7 +52,7 @@ class RoomescapeLogMaskingConverter : MessageConverter() { node?.forEachEntry { key, childNode -> when { childNode.isValueNode -> { - if (key in SENSITIVE_KEYS) (node as ObjectNode).put(key, maskValue(childNode.asText())) + if (key in sensitiveKeys) (node as ObjectNode).put(key, maskValue(childNode.asText())) } childNode.isObject -> maskRecursive(childNode) @@ -72,10 +73,6 @@ class RoomescapeLogMaskingConverter : MessageConverter() { } private fun maskValue(value: String): String { - return if (value.length <= 2) { - MASK - } else { - "${value.first()}$MASK${value.last()}" - } + return "${value.first()}$mask${value.last()}" } } diff --git a/src/main/kotlin/roomescape/common/log/MDCAwareSlowQueryListenerWithoutParams.kt b/common/log/src/main/kotlin/com/sangdol/common/log/sql/MDCAwareSlowQueryListenerWithoutParams.kt similarity index 97% rename from src/main/kotlin/roomescape/common/log/MDCAwareSlowQueryListenerWithoutParams.kt rename to common/log/src/main/kotlin/com/sangdol/common/log/sql/MDCAwareSlowQueryListenerWithoutParams.kt index bbc44024..ecd79d13 100644 --- a/src/main/kotlin/roomescape/common/log/MDCAwareSlowQueryListenerWithoutParams.kt +++ b/common/log/src/main/kotlin/com/sangdol/common/log/sql/MDCAwareSlowQueryListenerWithoutParams.kt @@ -1,4 +1,4 @@ -package roomescape.common.log +package com.sangdol.common.log.sql import net.ttddyy.dsproxy.ExecutionInfo import net.ttddyy.dsproxy.QueryInfo diff --git a/common/log/src/main/kotlin/com/sangdol/common/log/sql/SlowQueryDataSourceFactory.kt b/common/log/src/main/kotlin/com/sangdol/common/log/sql/SlowQueryDataSourceFactory.kt new file mode 100644 index 00000000..60467751 --- /dev/null +++ b/common/log/src/main/kotlin/com/sangdol/common/log/sql/SlowQueryDataSourceFactory.kt @@ -0,0 +1,20 @@ +package com.sangdol.common.log.sql + +import net.ttddyy.dsproxy.listener.logging.SLF4JLogLevel +import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder +import javax.sql.DataSource + +object SlowQueryDataSourceFactory { + + fun create(dataSource: DataSource, loggerName: String, logLevel: String, thresholdMs: Long): DataSource { + val mdcAwareListener = MDCAwareSlowQueryListenerWithoutParams( + logLevel = SLF4JLogLevel.nullSafeValueOf(logLevel.uppercase()), + thresholdMs = thresholdMs + ) + + return ProxyDataSourceBuilder.create(dataSource) + .name(loggerName) + .listener(mdcAwareListener) + .buildProxy() + } +} \ No newline at end of file diff --git a/common/log/src/test/kotlin/com/sangdol/common/log/AbstractLogMaskingConverterTest.kt b/common/log/src/test/kotlin/com/sangdol/common/log/AbstractLogMaskingConverterTest.kt new file mode 100644 index 00000000..eeb74b46 --- /dev/null +++ b/common/log/src/test/kotlin/com/sangdol/common/log/AbstractLogMaskingConverterTest.kt @@ -0,0 +1,55 @@ +package com.sangdol.common.log + +import ch.qos.logback.classic.spi.ILoggingEvent +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.sangdol.common.log.message.AbstractLogMaskingConverter +import io.kotest.assertions.assertSoftly +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.equals.shouldBeEqual +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldContain +import io.mockk.every +import io.mockk.mockk + +class TestLogMaskingConverter : AbstractLogMaskingConverter( + sensitiveKeys = setOf("account", "address"), + objectMapper = jacksonObjectMapper() +) + +class AbstractLogMaskingConverterTest : FunSpec({ + + val converter = TestLogMaskingConverter() + val event: ILoggingEvent = mockk() + val account = "sangdol@example.com" + val address = "서울특별시 강북구 수유1동 123-456" + + context("sensitiveKeys=${converter.sensitiveKeys}에 있는 항목은 가린다.") { + context("평문 로그를 처리할 때, 여러 key / value가 있는 경우 서로 간의 구분자는 trim 처리한다.") { + listOf(":", "=", " : ", " = ").forEach { keyValueDelimiter -> + listOf(",", ", ").forEach { valueDelimiter -> + test("key1${keyValueDelimiter}value1${valueDelimiter}key2${keyValueDelimiter}value2 형식을 처리한다.") { + every { + event.formattedMessage + } returns "account$keyValueDelimiter$account${valueDelimiter}address$keyValueDelimiter$address" + + assertSoftly(converter.convert(event)) { + this shouldBe "account${keyValueDelimiter}${account.first()}${converter.mask}${account.last()}${valueDelimiter}address${keyValueDelimiter}${address.first()}${converter.mask}${address.last()}" + } + } + } + } + } + + context("JSON 로그") { + test("정상 처리") { + val json = "{\"request_body\":{\"account\":\"%s\",\"address\":\"%s\"}}" + + every { + event.formattedMessage + } returns json.format(account, address) + + converter.convert(event) shouldBeEqual json.format("${account.first()}${converter.mask}${account.last()}", "${address.first()}${converter.mask}${address.last()}") + } + } + } +}) diff --git a/src/test/kotlin/roomescape/common/log/MDCAwareSlowQueryListenerWithoutParamsTest.kt b/common/log/src/test/kotlin/com/sangdol/common/log/MDCAwareSlowQueryListenerWithoutParamsTest.kt similarity index 71% rename from src/test/kotlin/roomescape/common/log/MDCAwareSlowQueryListenerWithoutParamsTest.kt rename to common/log/src/test/kotlin/com/sangdol/common/log/MDCAwareSlowQueryListenerWithoutParamsTest.kt index ac224f63..2d160784 100644 --- a/src/test/kotlin/roomescape/common/log/MDCAwareSlowQueryListenerWithoutParamsTest.kt +++ b/common/log/src/test/kotlin/com/sangdol/common/log/MDCAwareSlowQueryListenerWithoutParamsTest.kt @@ -1,5 +1,7 @@ -package roomescape.common.log +package com.sangdol.common.log +import com.sangdol.common.log.sql.SlowQueryPredicate +import com.sangdol.common.log.sql.SqlLogFormatter import io.kotest.assertions.assertSoftly import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe @@ -18,9 +20,9 @@ class MDCAwareSlowQueryListenerWithoutParamsTest : StringSpec({ val slowQueryPredicate = SlowQueryPredicate(thresholdMs = slowQueryThreshold) assertSoftly(slowQueryPredicate) { - it.test(slowQueryThreshold) shouldBe true - it.test(slowQueryThreshold + 1) shouldBe true - it.test(slowQueryThreshold - 1) shouldBe false + this.test(slowQueryThreshold) shouldBe true + this.test(slowQueryThreshold + 1) shouldBe true + this.test(slowQueryThreshold - 1) shouldBe false } } }) diff --git a/common/persistence/build.gradle.kts b/common/persistence/build.gradle.kts new file mode 100644 index 00000000..bf2cb2ad --- /dev/null +++ b/common/persistence/build.gradle.kts @@ -0,0 +1,29 @@ +import org.springframework.boot.gradle.tasks.bundling.BootJar + +plugins { + id("org.springframework.boot") + kotlin("plugin.spring") + kotlin("plugin.jpa") +} + +dependencies { + implementation("org.springframework.boot:spring-boot-starter-data-jpa") + implementation("com.github.f4b6a3:tsid-creator:5.2.6") + + testRuntimeOnly("com.h2database:h2") + testImplementation("org.springframework.boot:spring-boot-starter-test") + testImplementation("io.kotest:kotest-runner-junit5:5.9.1") + testImplementation("io.kotest.extensions:kotest-extensions-spring:1.3.0") + testImplementation("io.mockk:mockk:1.14.4") + + implementation(project(":common:utils")) + implementation(project(":common:types")) +} + +tasks.named("bootJar") { + enabled = false +} + +tasks.named("jar") { + enabled = true +} \ No newline at end of file diff --git a/src/main/kotlin/roomescape/common/entity/BaseEntity.kt b/common/persistence/src/main/kotlin/com/sangdol/common/persistence/AuditingBaseEntity.kt similarity index 60% rename from src/main/kotlin/roomescape/common/entity/BaseEntity.kt rename to common/persistence/src/main/kotlin/com/sangdol/common/persistence/AuditingBaseEntity.kt index 707d2249..a9fca2c7 100644 --- a/src/main/kotlin/roomescape/common/entity/BaseEntity.kt +++ b/common/persistence/src/main/kotlin/com/sangdol/common/persistence/AuditingBaseEntity.kt @@ -1,14 +1,14 @@ -package roomescape.common.entity +package com.sangdol.common.persistence -import jakarta.persistence.* +import jakarta.persistence.Column +import jakarta.persistence.EntityListeners +import jakarta.persistence.MappedSuperclass import org.springframework.data.annotation.CreatedBy import org.springframework.data.annotation.CreatedDate import org.springframework.data.annotation.LastModifiedBy import org.springframework.data.annotation.LastModifiedDate -import org.springframework.data.domain.Persistable import org.springframework.data.jpa.domain.support.AuditingEntityListener import java.time.LocalDateTime -import kotlin.jvm.Transient @MappedSuperclass @EntityListeners(AuditingEntityListener::class) @@ -31,23 +31,3 @@ abstract class AuditingBaseEntity( @LastModifiedBy var updatedBy: Long = 0L } - -@MappedSuperclass -abstract class PersistableBaseEntity( - @Id - @Column(name = "id") - private val _id: Long, - - @Transient - private var isNewEntity: Boolean = true -) : Persistable { - - @PostLoad - @PrePersist - fun markNotNew() { - isNewEntity = false - } - - override fun getId(): Long = _id - override fun isNew(): Boolean = isNewEntity -} diff --git a/common/persistence/src/main/kotlin/com/sangdol/common/persistence/IDGenerator.kt b/common/persistence/src/main/kotlin/com/sangdol/common/persistence/IDGenerator.kt new file mode 100644 index 00000000..ba6778ff --- /dev/null +++ b/common/persistence/src/main/kotlin/com/sangdol/common/persistence/IDGenerator.kt @@ -0,0 +1,13 @@ +package com.sangdol.common.persistence + +import com.github.f4b6a3.tsid.TsidFactory + +interface IDGenerator { + fun create(): Long +} + +class TsidIDGenerator( + private val tsidFactory: TsidFactory +) : IDGenerator { + override fun create(): Long = tsidFactory.create().toLong() +} diff --git a/common/persistence/src/main/kotlin/com/sangdol/common/persistence/PersistableBaseEntity.kt b/common/persistence/src/main/kotlin/com/sangdol/common/persistence/PersistableBaseEntity.kt new file mode 100644 index 00000000..73973f7c --- /dev/null +++ b/common/persistence/src/main/kotlin/com/sangdol/common/persistence/PersistableBaseEntity.kt @@ -0,0 +1,25 @@ +package com.sangdol.common.persistence + +import jakarta.persistence.* +import org.springframework.data.domain.Persistable +import kotlin.jvm.Transient + +@MappedSuperclass +abstract class PersistableBaseEntity( + @Id + @Column(name = "id") + private val _id: Long, + + @Transient + private var isNewEntity: Boolean = true +) : Persistable { + + @PostLoad + @PrePersist + fun markNotNew() { + isNewEntity = false + } + + override fun getId(): Long = _id + override fun isNew(): Boolean = isNewEntity +} diff --git a/common/persistence/src/main/kotlin/com/sangdol/common/persistence/PersistenceConfig.kt b/common/persistence/src/main/kotlin/com/sangdol/common/persistence/PersistenceConfig.kt new file mode 100644 index 00000000..08ac9cca --- /dev/null +++ b/common/persistence/src/main/kotlin/com/sangdol/common/persistence/PersistenceConfig.kt @@ -0,0 +1,44 @@ +package com.sangdol.common.persistence + +import com.github.f4b6a3.tsid.TsidFactory +import com.sangdol.common.utils.MdcPrincipalIdUtil +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Primary +import org.springframework.data.domain.AuditorAware +import org.springframework.data.jpa.repository.config.EnableJpaAuditing +import org.springframework.transaction.PlatformTransactionManager +import java.util.* + +@Configuration +@EnableJpaAuditing +class PersistenceConfig { + + @Value("\${POD_NAME:app-0}") + private lateinit var podName: String + + @Bean + fun auditorAware(): AuditorAware = MdcAuditorAware() + + @Bean + @Primary + fun idGenerator(): IDGenerator { + val node = podName.substringAfterLast("-").toInt() + + val tsidFactory = TsidFactory.builder().withNode(node).build() + + return TsidIDGenerator(tsidFactory) + } + + @Bean + fun transactionExecutionUtil( + transactionManager: PlatformTransactionManager + ): TransactionExecutionUtil { + return TransactionExecutionUtil(transactionManager) + } +} + +class MdcAuditorAware : AuditorAware { + override fun getCurrentAuditor(): Optional = MdcPrincipalIdUtil.extractAsOptionalLongOrEmpty() +} diff --git a/src/main/kotlin/roomescape/common/util/TransactionExecutionUtil.kt b/common/persistence/src/main/kotlin/com/sangdol/common/persistence/TransactionExecutionUtil.kt similarity index 51% rename from src/main/kotlin/roomescape/common/util/TransactionExecutionUtil.kt rename to common/persistence/src/main/kotlin/com/sangdol/common/persistence/TransactionExecutionUtil.kt index 28a980e5..e2bda131 100644 --- a/src/main/kotlin/roomescape/common/util/TransactionExecutionUtil.kt +++ b/common/persistence/src/main/kotlin/com/sangdol/common/persistence/TransactionExecutionUtil.kt @@ -1,31 +1,19 @@ -package roomescape.common.util +package com.sangdol.common.persistence -import io.github.oshai.kotlinlogging.KLogger -import io.github.oshai.kotlinlogging.KotlinLogging -import org.springframework.stereotype.Component import org.springframework.transaction.PlatformTransactionManager import org.springframework.transaction.TransactionDefinition import org.springframework.transaction.support.TransactionTemplate -import roomescape.common.exception.CommonErrorCode -import roomescape.common.exception.RoomescapeException -private val log: KLogger = KotlinLogging.logger {} - -@Component class TransactionExecutionUtil( private val transactionManager: PlatformTransactionManager ) { - fun withNewTransaction(isReadOnly: Boolean, action: () -> T): T { + fun withNewTransaction(isReadOnly: Boolean, action: () -> T?): T? { val transactionTemplate = TransactionTemplate(transactionManager).apply { this.isReadOnly = isReadOnly this.propagationBehavior = TransactionDefinition.PROPAGATION_REQUIRES_NEW } return transactionTemplate.execute { action() } - ?: run { - log.error { "[TransactionExecutionUtil.withNewTransaction] 트랜잭션 작업 중 예상치 못한 null 반환 " } - throw RoomescapeException(CommonErrorCode.UNEXPECTED_SERVER_ERROR) - } } } diff --git a/common/persistence/src/test/kotlin/com/sangdol/common/persistence/BaseEntityTest.kt b/common/persistence/src/test/kotlin/com/sangdol/common/persistence/BaseEntityTest.kt new file mode 100644 index 00000000..f0acd755 --- /dev/null +++ b/common/persistence/src/test/kotlin/com/sangdol/common/persistence/BaseEntityTest.kt @@ -0,0 +1,53 @@ +package com.sangdol.common.persistence + +import com.sangdol.common.utils.MdcPrincipalIdUtil +import io.kotest.assertions.assertSoftly +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.date.shouldBeBefore +import io.kotest.matchers.equality.shouldBeEqualUsingFields +import io.kotest.matchers.nulls.shouldNotBeNull +import io.kotest.matchers.shouldBe +import org.springframework.boot.test.context.SpringBootTest +import java.time.LocalDateTime + +@SpringBootTest +class BaseEntityTest( + private val testPersistableBaseEntityRepository: TestPersistableBaseEntityRepository, + private val testAuditingBaseEntityRepository: TestAuditingBaseEntityRepository, + private val idGenerator: IDGenerator +) : FunSpec({ + context("TestPersistableBaseEntityRepository") { + test("PK를 지정하여 INSERT 쿼리를 한번만 전송한다.") { + val entity = TestPersistableBaseEntity(idGenerator.create(), "hello").also { + testPersistableBaseEntityRepository.saveAndFlush(it) + } + + testPersistableBaseEntityRepository.findById(entity.id).also { + it.shouldNotBeNull() + it.get() shouldBeEqualUsingFields entity + } + } + } + + context("TestAuditingBaseEntityRepository") { + test("Entity 저장 후 Audit 정보를 확인한다.") { + val id = idGenerator.create() + .also { + MdcPrincipalIdUtil.set(it.toString()) + }.also { + testAuditingBaseEntityRepository.saveAndFlush(TestAuditingBaseEntity(it, "hello")) + } + + testAuditingBaseEntityRepository.findById(id).also { + it.shouldNotBeNull() + + assertSoftly(it.get()) { + this.createdAt shouldBeBefore LocalDateTime.now() + this.updatedAt shouldBeBefore LocalDateTime.now() + this.createdBy shouldBe id + this.updatedBy shouldBe id + } + } + } + } +}) diff --git a/common/persistence/src/test/kotlin/com/sangdol/common/persistence/TestApplication.kt b/common/persistence/src/test/kotlin/com/sangdol/common/persistence/TestApplication.kt new file mode 100644 index 00000000..b2b4176c --- /dev/null +++ b/common/persistence/src/test/kotlin/com/sangdol/common/persistence/TestApplication.kt @@ -0,0 +1,6 @@ +package com.sangdol.common.persistence + +import org.springframework.boot.autoconfigure.SpringBootApplication + +@SpringBootApplication +class TestApplication \ No newline at end of file diff --git a/common/persistence/src/test/kotlin/com/sangdol/common/persistence/TestAuditingBaseEntity.kt b/common/persistence/src/test/kotlin/com/sangdol/common/persistence/TestAuditingBaseEntity.kt new file mode 100644 index 00000000..f58ecf77 --- /dev/null +++ b/common/persistence/src/test/kotlin/com/sangdol/common/persistence/TestAuditingBaseEntity.kt @@ -0,0 +1,12 @@ +package com.sangdol.common.persistence + +import jakarta.persistence.Entity +import org.springframework.data.jpa.repository.JpaRepository + +@Entity +class TestAuditingBaseEntity( + id: Long, + val name: String +): AuditingBaseEntity(id) + +interface TestAuditingBaseEntityRepository: JpaRepository \ No newline at end of file diff --git a/common/persistence/src/test/kotlin/com/sangdol/common/persistence/TestPersistableBaseEntity.kt b/common/persistence/src/test/kotlin/com/sangdol/common/persistence/TestPersistableBaseEntity.kt new file mode 100644 index 00000000..ac97c1c2 --- /dev/null +++ b/common/persistence/src/test/kotlin/com/sangdol/common/persistence/TestPersistableBaseEntity.kt @@ -0,0 +1,12 @@ +package com.sangdol.common.persistence + +import jakarta.persistence.Entity +import org.springframework.data.jpa.repository.JpaRepository + +@Entity +class TestPersistableBaseEntity( + id: Long, + val name: String +): PersistableBaseEntity(id) + +interface TestPersistableBaseEntityRepository: JpaRepository \ No newline at end of file diff --git a/common/persistence/src/test/kotlin/com/sangdol/common/persistence/TransactionExecutionUtilTest.kt b/common/persistence/src/test/kotlin/com/sangdol/common/persistence/TransactionExecutionUtilTest.kt new file mode 100644 index 00000000..64f4faa6 --- /dev/null +++ b/common/persistence/src/test/kotlin/com/sangdol/common/persistence/TransactionExecutionUtilTest.kt @@ -0,0 +1,75 @@ +package com.sangdol.common.persistence + +import io.kotest.assertions.assertSoftly +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.equality.shouldBeEqualUsingFields +import io.kotest.matchers.nulls.shouldNotBeNull +import io.kotest.matchers.shouldBe +import io.mockk.clearMocks +import io.mockk.every +import io.mockk.mockk +import io.mockk.slot +import io.mockk.verify +import org.junit.jupiter.api.assertThrows +import org.springframework.transaction.PlatformTransactionManager +import org.springframework.transaction.TransactionDefinition +import org.springframework.transaction.TransactionStatus +import org.springframework.transaction.support.DefaultTransactionDefinition + +class TransactionExecutionUtilTest() : FunSpec() { + private val transactionManager = mockk(relaxed = true) + private val transactionExecutionUtil = TransactionExecutionUtil(transactionManager) + + init { + context("withNewTransaction") { + + beforeTest { + clearMocks(transactionManager) + } + + val body = TestPersistableBaseEntity(123458192L, "hello") + + test("지정한 action이 성공하면, 해당 값을 반환하고 트랜잭션을 커밋한다.") { + transactionExecutionUtil.withNewTransaction(isReadOnly = false) { + body + }.also { + it.shouldNotBeNull() + it shouldBeEqualUsingFields body + verify { transactionManager.commit(any()) } + verify(exactly = 0) { transactionManager.rollback(any()) } + } + } + + test("지정한 action 실행 도중 예외가 발생하면, 예외를 던지고 트랜잭션을 롤백한다.") { + assertThrows { + transactionExecutionUtil.withNewTransaction(isReadOnly = false) { + throw RuntimeException() + } + }.also { + verify { transactionManager.rollback(any()) } + verify(exactly = 0) { transactionManager.commit(any()) } + } + } + + test("isReadOnly=true 지정시 읽기 전용 트랜잭션으로 실행한다.") { + val transactionStatus = mockk(relaxed = true) + val transactionDefinitionSlot = slot() + + every { + transactionManager.getTransaction(capture(transactionDefinitionSlot)) + } returns transactionStatus + + transactionExecutionUtil.withNewTransaction(isReadOnly = true) { + "hello" + }.also { + assertSoftly(transactionDefinitionSlot.captured) { + this.isReadOnly shouldBe true + this.propagationBehavior shouldBe DefaultTransactionDefinition.PROPAGATION_REQUIRES_NEW + } + + verify { transactionManager.commit(any()) } + } + } + } + } +} diff --git a/common/persistence/src/test/resources/application.yaml b/common/persistence/src/test/resources/application.yaml new file mode 100644 index 00000000..3a39be3c --- /dev/null +++ b/common/persistence/src/test/resources/application.yaml @@ -0,0 +1,18 @@ +spring: + jpa: + properties: + hibernate: + format_sql: true + hibernate: + ddl-auto: create-drop + show-sql: true + h2: + console: + enabled: true + path: /h2-console + datasource: + hikari: + jdbc-url: jdbc:h2:mem:database + driver-class-name: org.h2.Driver + username: sa + password: \ No newline at end of file diff --git a/common/types/build.gradle.kts b/common/types/build.gradle.kts new file mode 100644 index 00000000..469d6467 --- /dev/null +++ b/common/types/build.gradle.kts @@ -0,0 +1,3 @@ +tasks.named("jar") { + enabled = true +} \ No newline at end of file diff --git a/src/main/kotlin/roomescape/common/exception/CommonErrorCode.kt b/common/types/src/main/kotlin/com/sangdol/common/types/exception/CommonErrorCode.kt similarity index 85% rename from src/main/kotlin/roomescape/common/exception/CommonErrorCode.kt rename to common/types/src/main/kotlin/com/sangdol/common/types/exception/CommonErrorCode.kt index 5711c7af..f84bf289 100644 --- a/src/main/kotlin/roomescape/common/exception/CommonErrorCode.kt +++ b/common/types/src/main/kotlin/com/sangdol/common/types/exception/CommonErrorCode.kt @@ -1,6 +1,6 @@ -package roomescape.common.exception +package com.sangdol.common.types.exception -import org.springframework.http.HttpStatus +import com.sangdol.common.types.web.HttpStatus enum class CommonErrorCode( override val httpStatus: HttpStatus, diff --git a/src/main/kotlin/roomescape/common/exception/ErrorCode.kt b/common/types/src/main/kotlin/com/sangdol/common/types/exception/ErrorCode.kt similarity index 54% rename from src/main/kotlin/roomescape/common/exception/ErrorCode.kt rename to common/types/src/main/kotlin/com/sangdol/common/types/exception/ErrorCode.kt index 1f08d3b5..d48fbb17 100644 --- a/src/main/kotlin/roomescape/common/exception/ErrorCode.kt +++ b/common/types/src/main/kotlin/com/sangdol/common/types/exception/ErrorCode.kt @@ -1,6 +1,6 @@ -package roomescape.common.exception +package com.sangdol.common.types.exception -import org.springframework.http.HttpStatus +import com.sangdol.common.types.web.HttpStatus interface ErrorCode { val httpStatus: HttpStatus diff --git a/src/main/kotlin/roomescape/common/exception/RoomescapeException.kt b/common/types/src/main/kotlin/com/sangdol/common/types/exception/RoomescapeException.kt similarity index 62% rename from src/main/kotlin/roomescape/common/exception/RoomescapeException.kt rename to common/types/src/main/kotlin/com/sangdol/common/types/exception/RoomescapeException.kt index 4dc157ba..c35294fa 100644 --- a/src/main/kotlin/roomescape/common/exception/RoomescapeException.kt +++ b/common/types/src/main/kotlin/com/sangdol/common/types/exception/RoomescapeException.kt @@ -1,6 +1,6 @@ -package roomescape.common.exception +package com.sangdol.common.types.exception open class RoomescapeException( open val errorCode: ErrorCode, override val message: String = errorCode.message -) : RuntimeException(message) +) : RuntimeException(message) \ No newline at end of file diff --git a/src/main/kotlin/roomescape/common/dto/response/CommonApiResponse.kt b/common/types/src/main/kotlin/com/sangdol/common/types/web/ApiResponses.kt similarity index 62% rename from src/main/kotlin/roomescape/common/dto/response/CommonApiResponse.kt rename to common/types/src/main/kotlin/com/sangdol/common/types/web/ApiResponses.kt index 6f625907..c31f1808 100644 --- a/src/main/kotlin/roomescape/common/dto/response/CommonApiResponse.kt +++ b/common/types/src/main/kotlin/com/sangdol/common/types/web/ApiResponses.kt @@ -1,9 +1,7 @@ -package roomescape.common.dto.response +package com.sangdol.common.types.web -import com.fasterxml.jackson.annotation.JsonInclude -import roomescape.common.exception.ErrorCode +import com.sangdol.common.types.exception.ErrorCode -@JsonInclude(JsonInclude.Include.NON_NULL) data class CommonApiResponse( val data: T? = null, ) diff --git a/common/types/src/main/kotlin/com/sangdol/common/types/web/HttpStatus.kt b/common/types/src/main/kotlin/com/sangdol/common/types/web/HttpStatus.kt new file mode 100644 index 00000000..35764d15 --- /dev/null +++ b/common/types/src/main/kotlin/com/sangdol/common/types/web/HttpStatus.kt @@ -0,0 +1,24 @@ +package com.sangdol.common.types.web + +enum class HttpStatus( + val code: Int +) { + OK(200), + CREATED(201), + NO_CONTENT(204), + BAD_REQUEST(400), + UNAUTHORIZED(401), + FORBIDDEN(403), + NOT_FOUND(404), + CONFLICT(409), + INTERNAL_SERVER_ERROR(500) + ; + + fun isClientError(): Boolean { + return code in 400..<500 + } + + fun value(): Int { + return code + } +} diff --git a/common/utils/build.gradle.kts b/common/utils/build.gradle.kts new file mode 100644 index 00000000..d725bc73 --- /dev/null +++ b/common/utils/build.gradle.kts @@ -0,0 +1,7 @@ +dependencies { + implementation("org.slf4j:slf4j-api:2.0.17") +} + +tasks.named("jar") { + enabled = true +} diff --git a/src/main/kotlin/roomescape/common/util/MDCUtils.kt b/common/utils/src/main/kotlin/com/sangdol/common/utils/MdcPrincipalIdUtil.kt similarity index 80% rename from src/main/kotlin/roomescape/common/util/MDCUtils.kt rename to common/utils/src/main/kotlin/com/sangdol/common/utils/MdcPrincipalIdUtil.kt index 6283c605..f96e2b06 100644 --- a/src/main/kotlin/roomescape/common/util/MDCUtils.kt +++ b/common/utils/src/main/kotlin/com/sangdol/common/utils/MdcPrincipalIdUtil.kt @@ -1,11 +1,10 @@ -package roomescape.common.util +package com.sangdol.common.utils import org.slf4j.MDC import java.util.* -private const val MDC_PRINCIPAL_ID_KEY = "principal_id" - -object MdcPrincipalId { +object MdcPrincipalIdUtil { + const val MDC_PRINCIPAL_ID_KEY = "principal_id" fun extractAsLongOrNull(): Long? { return MDC.get(MDC_PRINCIPAL_ID_KEY)?.toLong() diff --git a/common/utils/src/main/kotlin/com/sangdol/common/utils/MdcStartTimeUtil.kt b/common/utils/src/main/kotlin/com/sangdol/common/utils/MdcStartTimeUtil.kt new file mode 100644 index 00000000..0e15ecfe --- /dev/null +++ b/common/utils/src/main/kotlin/com/sangdol/common/utils/MdcStartTimeUtil.kt @@ -0,0 +1,25 @@ +package com.sangdol.common.utils + +import org.slf4j.MDC + +object MdcStartTimeUtil { + const val MDC_START_TIME_KEY = "start_time" + + fun extractDurationMsOrNull(): Long? { + return extractOrNull()?.let { System.currentTimeMillis() - it } + } + + fun setCurrentTime() { + extractOrNull() ?: run { + MDC.put(MDC_START_TIME_KEY, System.currentTimeMillis().toString()) + } + } + + fun clear() { + MDC.remove(MDC_START_TIME_KEY) + } + + private fun extractOrNull(): Long? { + return MDC.get(MDC_START_TIME_KEY)?.toLong() + } +} diff --git a/common/utils/src/test/kotlin/com/sangdol/common/utils/MdcPrincipalIdUtilTest.kt b/common/utils/src/test/kotlin/com/sangdol/common/utils/MdcPrincipalIdUtilTest.kt new file mode 100644 index 00000000..043d4646 --- /dev/null +++ b/common/utils/src/test/kotlin/com/sangdol/common/utils/MdcPrincipalIdUtilTest.kt @@ -0,0 +1,28 @@ +package com.sangdol.common.utils + +import io.kotest.core.spec.style.StringSpec +import io.kotest.matchers.shouldBe +import java.util.* + +class MdcPrincipalIdUtilTest : StringSpec({ + + val id = 1872847943L + + "값을 설정한다." { + MdcPrincipalIdUtil.set(id.toString()).also { + MdcPrincipalIdUtil.extractAsLongOrNull() shouldBe id + MdcPrincipalIdUtil.extractAsOptionalLongOrEmpty() shouldBe Optional.of(id) + } + } + + "값을 제거한다." { + MdcPrincipalIdUtil.set(id.toString()).also { + MdcPrincipalIdUtil.extractAsLongOrNull() shouldBe id + } + + MdcPrincipalIdUtil.clear().also { + MdcPrincipalIdUtil.extractAsLongOrNull() shouldBe null + MdcPrincipalIdUtil.extractAsOptionalLongOrEmpty() shouldBe Optional.empty() + } + } +}) diff --git a/common/utils/src/test/kotlin/com/sangdol/common/utils/MdcStartTimeUtilTest.kt b/common/utils/src/test/kotlin/com/sangdol/common/utils/MdcStartTimeUtilTest.kt new file mode 100644 index 00000000..0f57e753 --- /dev/null +++ b/common/utils/src/test/kotlin/com/sangdol/common/utils/MdcStartTimeUtilTest.kt @@ -0,0 +1,34 @@ +package com.sangdol.common.utils + +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.nulls.shouldNotBeNull +import io.kotest.matchers.shouldBe + +class MdcStartTimeUtilTest : FunSpec({ + + test("기존에 등록된 startTime 값을 기준으로 duration_ms를 구한다.") { + MdcStartTimeUtil.setCurrentTime() + MdcStartTimeUtil.extractDurationMsOrNull().shouldNotBeNull() + MdcStartTimeUtil.clear() + } + + test("기존에 등록된 startTime 값이 없으면 duration_ms는 null이다.") { + MdcStartTimeUtil.extractDurationMsOrNull() shouldBe null + } + + test("현재 시간을 등록한다.") { + MdcStartTimeUtil.setCurrentTime() + MdcStartTimeUtil.extractDurationMsOrNull().shouldNotBeNull() + MdcStartTimeUtil.clear() + } + + test("등록된 시간을 지운다.") { + MdcStartTimeUtil.setCurrentTime().also { + MdcStartTimeUtil.extractDurationMsOrNull().shouldNotBeNull() + } + + MdcStartTimeUtil.clear().also { + MdcStartTimeUtil.extractDurationMsOrNull() shouldBe null + } + } +}) diff --git a/common/web/build.gradle.kts b/common/web/build.gradle.kts new file mode 100644 index 00000000..53c7f14b --- /dev/null +++ b/common/web/build.gradle.kts @@ -0,0 +1,28 @@ +import org.gradle.kotlin.dsl.named +import org.springframework.boot.gradle.tasks.bundling.BootJar + +plugins { + id("org.springframework.boot") + kotlin("plugin.spring") +} + +dependencies { + implementation("org.springframework.boot:spring-boot-starter-web") + implementation("org.springframework.boot:spring-boot-starter-aop") + implementation("com.fasterxml.jackson.module:jackson-module-kotlin") + + testImplementation("io.kotest:kotest-runner-junit5:5.9.1") + testImplementation("io.mockk:mockk:1.14.4") + + implementation(project(":common:log")) + implementation(project(":common:utils")) + implementation(project(":common:types")) +} + +tasks.named("bootJar") { + enabled = false +} + +tasks.named("jar") { + enabled = true +} diff --git a/src/main/kotlin/roomescape/common/log/ControllerLoggingAspect.kt b/common/web/src/main/kotlin/com/sangdol/common/web/asepct/ControllerLoggingAspect.kt similarity index 63% rename from src/main/kotlin/roomescape/common/log/ControllerLoggingAspect.kt rename to common/web/src/main/kotlin/com/sangdol/common/web/asepct/ControllerLoggingAspect.kt index a56c19de..68d87803 100644 --- a/src/main/kotlin/roomescape/common/log/ControllerLoggingAspect.kt +++ b/common/web/src/main/kotlin/com/sangdol/common/web/asepct/ControllerLoggingAspect.kt @@ -1,5 +1,7 @@ -package roomescape.common.log +package com.sangdol.common.web.asepct +import com.sangdol.common.log.constant.LogType +import com.sangdol.common.web.support.log.WebLogMessageConverter import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import jakarta.servlet.http.HttpServletRequest @@ -9,7 +11,6 @@ import org.aspectj.lang.annotation.Around import org.aspectj.lang.annotation.Aspect import org.aspectj.lang.annotation.Pointcut import org.aspectj.lang.reflect.MethodSignature -import org.slf4j.MDC import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestBody @@ -21,19 +22,17 @@ private val log: KLogger = KotlinLogging.logger {} @Aspect class ControllerLoggingAspect( - private val messageConverter: ApiLogMessageConverter, + private val messageConverter: WebLogMessageConverter, ) { - @Pointcut("execution(* roomescape..web..*Controller*.*(..))") + @Pointcut("execution(* com.sangdol..web..*Controller*.*(..))") fun allController() { } @Around("allController()") fun logAPICalls(joinPoint: ProceedingJoinPoint): Any? { - val startTime: Long = MDC.get("startTime").toLongOrNull() ?: System.currentTimeMillis() - val controllerPayload: Map = parsePayload(joinPoint) - val servletRequest: HttpServletRequest = servletRequest() + val controllerPayload: Map = parseControllerPayload(joinPoint) log.info { messageConverter.convertToControllerInvokedMessage(servletRequest, controllerPayload) @@ -41,29 +40,22 @@ class ControllerLoggingAspect( try { return joinPoint.proceed() - .also { logSuccess(servletRequest.getEndpoint(), startTime, it) } + .also { logSuccess(servletRequest, it as ResponseEntity<*>) } } catch (e: Exception) { throw e } } - private fun logSuccess(endpoint: String, startTime: Long, result: Any) { - val responseEntity = result as ResponseEntity<*> - var convertResponseMessageRequest = ConvertResponseMessageRequest( - type = LogType.CONTROLLER_SUCCESS, - endpoint = endpoint, - httpStatus = responseEntity.statusCode.value(), - startTime = startTime, + private fun logSuccess(servletRequest: HttpServletRequest, result: ResponseEntity<*>) { + val body: Any? = if (log.isDebugEnabled()) result.body else null + + val logMessage = messageConverter.convertToResponseMessage( + type = LogType.SUCCEED, + servletRequest = servletRequest, + httpStatusCode = result.statusCode.value(), + responseBody = body, ) - if (log.isDebugEnabled()) { - convertResponseMessageRequest = convertResponseMessageRequest.copy( - body = responseEntity.body - ) - } - - val logMessage = messageConverter.convertToResponseMessage(convertResponseMessageRequest) - log.info { logMessage } } @@ -71,14 +63,16 @@ class ControllerLoggingAspect( return (RequestContextHolder.currentRequestAttributes() as ServletRequestAttributes).request } - private fun parsePayload(joinPoint: JoinPoint): Map { + private fun parseControllerPayload(joinPoint: JoinPoint): Map { val signature = joinPoint.signature as MethodSignature val args = joinPoint.args - val payload = mutableMapOf() - payload["controller_method"] = joinPoint.signature.toShortString() + val payload = mutableMapOf( + "controller_method" to joinPoint.signature.toShortString() + ) val requestParams: MutableMap = mutableMapOf() val pathVariables: MutableMap = mutableMapOf() + signature.method.parameters.forEachIndexed { index, parameter -> val arg = args[index] @@ -93,9 +87,10 @@ class ControllerLoggingAspect( parameter.getAnnotation(RequestParam::class.java)?.let { requestParams[parameter.name] = arg } + }.also { + if (pathVariables.isNotEmpty()) payload["path_variable"] = pathVariables + if (requestParams.isNotEmpty()) payload["request_param"] = requestParams } - if (pathVariables.isNotEmpty()) payload["path_variable"] = pathVariables - if (requestParams.isNotEmpty()) payload["request_param"] = requestParams return payload } diff --git a/src/main/kotlin/roomescape/common/config/JacksonConfig.kt b/common/web/src/main/kotlin/com/sangdol/common/web/config/JacksonConfig.kt similarity index 87% rename from src/main/kotlin/roomescape/common/config/JacksonConfig.kt rename to common/web/src/main/kotlin/com/sangdol/common/web/config/JacksonConfig.kt index 3550aed7..fb6eb907 100644 --- a/src/main/kotlin/roomescape/common/config/JacksonConfig.kt +++ b/common/web/src/main/kotlin/com/sangdol/common/web/config/JacksonConfig.kt @@ -1,4 +1,4 @@ -package roomescape.common.config +package com.sangdol.common.web.config import com.fasterxml.jackson.core.JsonGenerator import com.fasterxml.jackson.databind.DeserializationFeature @@ -14,7 +14,11 @@ import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer import com.fasterxml.jackson.module.kotlin.kotlinModule import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration -import java.time.* +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalTime +import java.time.OffsetDateTime +import java.time.ZoneId import java.time.format.DateTimeFormatter @Configuration @@ -23,6 +27,9 @@ class JacksonConfig { companion object { private val ISO_OFFSET_DATE_TIME_FORMATTER: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX") + + private val LOCAL_TIME_FORMATTER: DateTimeFormatter = + DateTimeFormatter.ofPattern("HH:mm") } @Bean @@ -43,11 +50,11 @@ class JacksonConfig { ) .addSerializer( LocalTime::class.java, - LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm")) + LocalTimeSerializer(LOCAL_TIME_FORMATTER) ) .addDeserializer( LocalTime::class.java, - LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm")) + LocalTimeDeserializer(LOCAL_TIME_FORMATTER) ) as JavaTimeModule private fun dateTimeModule(): SimpleModule { @@ -80,4 +87,4 @@ class JacksonConfig { gen.writeString(value.format(ISO_OFFSET_DATE_TIME_FORMATTER)) } } -} +} \ No newline at end of file diff --git a/src/main/kotlin/roomescape/common/log/LogConfiguration.kt b/common/web/src/main/kotlin/com/sangdol/common/web/config/WebLoggingConfig.kt similarity index 50% rename from src/main/kotlin/roomescape/common/log/LogConfiguration.kt rename to common/web/src/main/kotlin/com/sangdol/common/web/config/WebLoggingConfig.kt index 5905b7c6..9539657e 100644 --- a/src/main/kotlin/roomescape/common/log/LogConfiguration.kt +++ b/common/web/src/main/kotlin/com/sangdol/common/web/config/WebLoggingConfig.kt @@ -1,6 +1,9 @@ -package roomescape.common.log +package com.sangdol.common.web.config import com.fasterxml.jackson.databind.ObjectMapper +import com.sangdol.common.web.asepct.ControllerLoggingAspect +import com.sangdol.common.web.servlet.HttpRequestLoggingFilter +import com.sangdol.common.web.support.log.WebLogMessageConverter import org.springframework.boot.web.servlet.FilterRegistrationBean import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @@ -9,27 +12,27 @@ import org.springframework.core.Ordered import org.springframework.web.filter.OncePerRequestFilter @Configuration -class LogConfiguration { +class WebLoggingConfig { @Bean - @DependsOn(value = ["apiLogMessageConverter"]) + @DependsOn(value = ["webLogMessageConverter"]) fun filterRegistrationBean( - apiLogMessageConverter: ApiLogMessageConverter + webLogMessageConverter: WebLogMessageConverter ): FilterRegistrationBean { - val filter = HttpRequestLoggingFilter(apiLogMessageConverter) + val filter = HttpRequestLoggingFilter(webLogMessageConverter) return FilterRegistrationBean(filter) .apply { this.order = Ordered.HIGHEST_PRECEDENCE + 2 } } @Bean - @DependsOn(value = ["apiLogMessageConverter"]) - fun apiLoggingAspect(apiLogMessageConverter: ApiLogMessageConverter): ControllerLoggingAspect { - return ControllerLoggingAspect(apiLogMessageConverter) + @DependsOn(value = ["webLogMessageConverter"]) + fun apiLoggingAspect(webLogMessageConverter: WebLogMessageConverter): ControllerLoggingAspect { + return ControllerLoggingAspect(webLogMessageConverter) } @Bean - fun apiLogMessageConverter(objectMapper: ObjectMapper): ApiLogMessageConverter { - return ApiLogMessageConverter(objectMapper) + fun webLogMessageConverter(objectMapper: ObjectMapper): WebLogMessageConverter { + return WebLogMessageConverter(objectMapper) } } diff --git a/src/main/kotlin/roomescape/common/exception/ExceptionControllerAdvice.kt b/common/web/src/main/kotlin/com/sangdol/common/web/exception/GlobalExceptionhandler.kt similarity index 54% rename from src/main/kotlin/roomescape/common/exception/ExceptionControllerAdvice.kt rename to common/web/src/main/kotlin/com/sangdol/common/web/exception/GlobalExceptionhandler.kt index b7f0d101..a790a4d2 100644 --- a/src/main/kotlin/roomescape/common/exception/ExceptionControllerAdvice.kt +++ b/common/web/src/main/kotlin/com/sangdol/common/web/exception/GlobalExceptionhandler.kt @@ -1,27 +1,26 @@ -package roomescape.common.exception +package com.sangdol.common.web.exception +import com.sangdol.common.log.constant.LogType +import com.sangdol.common.types.exception.CommonErrorCode +import com.sangdol.common.types.exception.ErrorCode +import com.sangdol.common.types.exception.RoomescapeException +import com.sangdol.common.types.web.CommonErrorResponse +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.common.web.support.log.WebLogMessageConverter import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import jakarta.servlet.http.HttpServletRequest -import org.slf4j.MDC -import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity import org.springframework.http.converter.HttpMessageNotReadableException import org.springframework.web.bind.MethodArgumentNotValidException import org.springframework.web.bind.annotation.ExceptionHandler import org.springframework.web.bind.annotation.RestControllerAdvice -import roomescape.auth.exception.AuthException -import roomescape.common.dto.response.CommonErrorResponse -import roomescape.common.log.ApiLogMessageConverter -import roomescape.common.log.ConvertResponseMessageRequest -import roomescape.common.log.LogType -import roomescape.common.log.getEndpoint private val log: KLogger = KotlinLogging.logger {} @RestControllerAdvice -class ExceptionControllerAdvice( - private val messageConverter: ApiLogMessageConverter +class GlobalExceptionHandler( + private val messageConverter: WebLogMessageConverter ) { @ExceptionHandler(value = [RoomescapeException::class]) fun handleRoomException( @@ -32,17 +31,10 @@ class ExceptionControllerAdvice( val httpStatus: HttpStatus = errorCode.httpStatus val errorResponse = CommonErrorResponse(errorCode) - val type = if (e is AuthException) LogType.AUTHENTICATION_FAILURE else LogType.APPLICATION_FAILURE - logException( - type = type, - servletRequest = servletRequest, - httpStatus = httpStatus.value(), - errorResponse = errorResponse, - exception = e - ) + logException(servletRequest, httpStatus, errorResponse, e) return ResponseEntity - .status(httpStatus) + .status(httpStatus.value()) .body(errorResponse) } @@ -51,29 +43,24 @@ class ExceptionControllerAdvice( servletRequest: HttpServletRequest, e: Exception ): ResponseEntity { - val message: String = if (e is MethodArgumentNotValidException) { + if (e is MethodArgumentNotValidException) { e.bindingResult.allErrors .mapNotNull { it.defaultMessage } .joinToString(", ") } else { e.message!! + }.also { + log.warn { "[ExceptionControllerAdvice] Invalid Request Value Exception occurred: $it" } } - log.debug { "[ExceptionControllerAdvice] Invalid Request Value Exception occurred: $message" } val errorCode: ErrorCode = CommonErrorCode.INVALID_INPUT_VALUE val httpStatus: HttpStatus = errorCode.httpStatus val errorResponse = CommonErrorResponse(errorCode) - logException( - type = LogType.APPLICATION_FAILURE, - servletRequest = servletRequest, - httpStatus = httpStatus.value(), - errorResponse = errorResponse, - exception = e - ) + logException(servletRequest, httpStatus, errorResponse, e) return ResponseEntity - .status(httpStatus) + .status(httpStatus.value()) .body(errorResponse) } @@ -88,39 +75,29 @@ class ExceptionControllerAdvice( val httpStatus: HttpStatus = errorCode.httpStatus val errorResponse = CommonErrorResponse(errorCode) - logException( - type = LogType.UNHANDLED_EXCEPTION, - servletRequest = servletRequest, - httpStatus = httpStatus.value(), - errorResponse = errorResponse, - exception = e - ) + logException(servletRequest, httpStatus, errorResponse, e) return ResponseEntity - .status(httpStatus) + .status(httpStatus.value()) .body(errorResponse) } private fun logException( - type: LogType, servletRequest: HttpServletRequest, - httpStatus: Int, + httpStatus: HttpStatus, errorResponse: CommonErrorResponse, exception: Exception ) { - val commonRequest = ConvertResponseMessageRequest( - type = type, - endpoint = servletRequest.getEndpoint(), - httpStatus = httpStatus, - startTime = MDC.get("startTime")?.toLongOrNull(), - body = errorResponse, - ) + val type = if (httpStatus.isClientError()) LogType.APPLICATION_FAILURE else LogType.UNHANDLED_EXCEPTION + val actualException: Exception? = if (errorResponse.message == exception.message) null else exception - val logMessage = if (errorResponse.message == exception.message) { - messageConverter.convertToResponseMessage(commonRequest) - } else { - messageConverter.convertToResponseMessage(commonRequest.copy(exception = exception)) - } + val logMessage = messageConverter.convertToResponseMessage( + type = type, + servletRequest = servletRequest, + httpStatusCode = httpStatus.value(), + responseBody = errorResponse, + exception = actualException + ) log.warn { logMessage } } diff --git a/src/main/kotlin/roomescape/common/log/HttpRequestLoggingFilter.kt b/common/web/src/main/kotlin/com/sangdol/common/web/servlet/HttpRequestLoggingFilter.kt similarity index 73% rename from src/main/kotlin/roomescape/common/log/HttpRequestLoggingFilter.kt rename to common/web/src/main/kotlin/com/sangdol/common/web/servlet/HttpRequestLoggingFilter.kt index 70442684..a5e45a5d 100644 --- a/src/main/kotlin/roomescape/common/log/HttpRequestLoggingFilter.kt +++ b/common/web/src/main/kotlin/com/sangdol/common/web/servlet/HttpRequestLoggingFilter.kt @@ -1,20 +1,21 @@ -package roomescape.common.log +package com.sangdol.common.web.servlet +import com.sangdol.common.utils.MdcPrincipalIdUtil +import com.sangdol.common.utils.MdcStartTimeUtil +import com.sangdol.common.web.support.log.WebLogMessageConverter import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import jakarta.servlet.FilterChain import jakarta.servlet.http.HttpServletRequest import jakarta.servlet.http.HttpServletResponse -import org.slf4j.MDC import org.springframework.web.filter.OncePerRequestFilter import org.springframework.web.util.ContentCachingRequestWrapper import org.springframework.web.util.ContentCachingResponseWrapper -import roomescape.common.util.MdcPrincipalId private val log: KLogger = KotlinLogging.logger {} class HttpRequestLoggingFilter( - private val messageConverter: ApiLogMessageConverter + private val messageConverter: WebLogMessageConverter ) : OncePerRequestFilter() { override fun doFilterInternal( request: HttpServletRequest, @@ -26,15 +27,14 @@ class HttpRequestLoggingFilter( val cachedRequest = ContentCachingRequestWrapper(request) val cachedResponse = ContentCachingResponseWrapper(response) - val startTime = System.currentTimeMillis() - MDC.put("startTime", startTime.toString()) + MdcStartTimeUtil.setCurrentTime() try { filterChain.doFilter(cachedRequest, cachedResponse) cachedResponse.copyBodyToResponse() } finally { - MDC.remove("startTime") - MdcPrincipalId.clear() + MdcStartTimeUtil.clear() + MdcPrincipalIdUtil.clear() } } } diff --git a/common/web/src/main/kotlin/com/sangdol/common/web/support/log/LogPayloadBuilder.kt b/common/web/src/main/kotlin/com/sangdol/common/web/support/log/LogPayloadBuilder.kt new file mode 100644 index 00000000..03dbe179 --- /dev/null +++ b/common/web/src/main/kotlin/com/sangdol/common/web/support/log/LogPayloadBuilder.kt @@ -0,0 +1,75 @@ +package com.sangdol.common.web.support.log + +import com.sangdol.common.log.constant.LogType +import com.sangdol.common.utils.MdcPrincipalIdUtil +import com.sangdol.common.utils.MdcStartTimeUtil +import jakarta.servlet.http.HttpServletRequest + +class LogPayloadBuilder( + private val type: LogType, + private val servletRequest: HttpServletRequest, + private val payload: MutableMap = mutableMapOf("type" to type) +) { + fun endpoint(): LogPayloadBuilder { + payload["endpoint"] = "${servletRequest.method} ${servletRequest.requestURI}" + return this + } + + fun clientIp(): LogPayloadBuilder { + servletRequest.remoteAddr?.let { payload["client_ip"] = it } + return this + } + + fun userAgent(): LogPayloadBuilder { + servletRequest.getHeader("User-Agent")?.let { payload["user_agent"] = it } + return this + } + + fun queryString(): LogPayloadBuilder { + servletRequest.queryString?.let { payload["query_params"] = it } + return this + } + + fun httpStatus(statusCode: Int?): LogPayloadBuilder { + statusCode?.let { payload["status_code"] = it } + + return this + } + + fun responseBody(body: Any?): LogPayloadBuilder { + body?.let { payload["response_body"] = it } + + return this + } + + fun durationMs(): LogPayloadBuilder { + MdcStartTimeUtil.extractDurationMsOrNull()?.let { payload["duration_ms"] = it } + return this + } + + fun principalId(): LogPayloadBuilder { + MdcPrincipalIdUtil.extractAsLongOrNull() + ?.let { payload["principal_id"] = it } + ?: run { payload["principal_id"] = "UNKNOWN" } + + return this + } + + fun exception(exception: Exception?): LogPayloadBuilder { + exception?.let { + payload["exception"] = mapOf( + "class" to it.javaClass.simpleName, + "message" to it.message + ) + } + + return this + } + + fun additionalPayloads(payload: Map): LogPayloadBuilder { + this.payload.putAll(payload) + return this + } + + fun build(): Map = payload +} diff --git a/common/web/src/main/kotlin/com/sangdol/common/web/support/log/WebLogMessageConverter.kt b/common/web/src/main/kotlin/com/sangdol/common/web/support/log/WebLogMessageConverter.kt new file mode 100644 index 00000000..1a2c47a7 --- /dev/null +++ b/common/web/src/main/kotlin/com/sangdol/common/web/support/log/WebLogMessageConverter.kt @@ -0,0 +1,49 @@ +package com.sangdol.common.web.support.log + +import com.fasterxml.jackson.databind.ObjectMapper +import com.sangdol.common.log.constant.LogType +import jakarta.servlet.http.HttpServletRequest + +class WebLogMessageConverter( + private val objectMapper: ObjectMapper +) { + fun convertToHttpRequestMessage(servletRequest: HttpServletRequest): String { + val payload = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .endpoint() + .queryString() + .clientIp() + .userAgent() + .build() + + return objectMapper.writeValueAsString(payload) + } + + fun convertToControllerInvokedMessage(servletRequest: HttpServletRequest, controllerPayload: Map): String { + val payload = LogPayloadBuilder(type = LogType.CONTROLLER_INVOKED, servletRequest = servletRequest) + .endpoint() + .principalId() + .additionalPayloads(controllerPayload) + .build() + + return objectMapper.writeValueAsString(payload) + } + + fun convertToResponseMessage( + type: LogType, + servletRequest: HttpServletRequest, + httpStatusCode: Int, + responseBody: Any? = null, + exception: Exception? = null, + ): String { + val payload = LogPayloadBuilder(type = type, servletRequest = servletRequest) + .endpoint() + .httpStatus(httpStatusCode) + .durationMs() + .principalId() + .responseBody(responseBody) + .exception(exception) + .build() + + return objectMapper.writeValueAsString(payload) + } +} diff --git a/src/test/kotlin/roomescape/common/config/JacksonConfigTest.kt b/common/web/src/test/kotlin/com/sangdol/common/web/config/JacksonConfigTest.kt similarity index 91% rename from src/test/kotlin/roomescape/common/config/JacksonConfigTest.kt rename to common/web/src/test/kotlin/com/sangdol/common/web/config/JacksonConfigTest.kt index c4129dc2..19af86d1 100644 --- a/src/test/kotlin/roomescape/common/config/JacksonConfigTest.kt +++ b/common/web/src/test/kotlin/com/sangdol/common/web/config/JacksonConfigTest.kt @@ -1,4 +1,4 @@ -package roomescape.common.config +package com.sangdol.common.web.config import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.exc.InvalidFormatException @@ -6,11 +6,15 @@ import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.kotest.matchers.string.shouldContain -import java.time.* +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalTime +import java.time.OffsetDateTime +import java.time.ZoneOffset -class JacksonConfigTest( - private val objectMapper: ObjectMapper = JacksonConfig().objectMapper() -) : FunSpec({ +class JacksonConfigTest : FunSpec({ + + val objectMapper: ObjectMapper = JacksonConfig().objectMapper() context("날짜는 yyyy-mm-dd 형식이다.") { val date = "2025-07-14" @@ -85,4 +89,4 @@ class JacksonConfigTest( serialized shouldBe "\"2025-07-14T12:30:00+09:00\"" } } -}) +}) \ No newline at end of file diff --git a/common/web/src/test/kotlin/com/sangdol/common/web/support/log/LogPayloadBuilderTest.kt b/common/web/src/test/kotlin/com/sangdol/common/web/support/log/LogPayloadBuilderTest.kt new file mode 100644 index 00000000..0b905efa --- /dev/null +++ b/common/web/src/test/kotlin/com/sangdol/common/web/support/log/LogPayloadBuilderTest.kt @@ -0,0 +1,233 @@ +package com.sangdol.common.web.support.log + +import com.sangdol.common.log.constant.LogType +import com.sangdol.common.utils.MdcPrincipalIdUtil +import com.sangdol.common.utils.MdcStartTimeUtil +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.nulls.shouldNotBeNull +import io.kotest.matchers.shouldBe +import io.mockk.clearMocks +import io.mockk.every +import io.mockk.mockk +import jakarta.servlet.http.HttpServletRequest + +class LogPayloadBuilderTest : FunSpec({ + val servletRequest: HttpServletRequest = mockk() + + lateinit var method: String + lateinit var requestUri: String + lateinit var remoteAddr: String + lateinit var userAgent: String + lateinit var queryString: String + + beforeTest { + method = "GET".also { every { servletRequest.method } returns it } + requestUri = "/converter/test".also { every { servletRequest.requestURI } returns it } + remoteAddr = "localhost".also { every { servletRequest.remoteAddr } returns it } + userAgent = "Mozilla/5.0".also { every { servletRequest.getHeader("User-Agent") } returns it } + queryString = "key=value".also { every { servletRequest.queryString } returns it } + } + + afterSpec { + clearMocks(servletRequest) + } + + context("endpoint") { + test("정상 응답") { + val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .endpoint() + .build() + + result["endpoint"] shouldBe "$method $requestUri" + } + + test("ServletRequest에서 null이 반환되면 그대로 들어간다.") { + every { servletRequest.method } returns null + every { servletRequest.requestURI } returns null + + val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .endpoint() + .build() + + result["endpoint"] shouldBe "null null" + } + } + + context("clientIp") { + test("정상 응답") { + val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .clientIp() + .build() + + result["client_ip"] shouldBe remoteAddr + } + + test("ServletRequest에서 null이 반환되면 추가되지 않는다.") { + every { servletRequest.remoteAddr } returns null + + val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .clientIp() + .build() + + result["client_ip"] shouldBe null + } + } + + context("userAgent") { + test("정상 응답") { + val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .userAgent() + .build() + + result["user_agent"] shouldBe userAgent + } + + test("ServletRequest에서 null이 반환되면 추가되지 않는다.") { + every { servletRequest.getHeader("User-Agent") } returns null + + val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .userAgent() + .build() + + result["user_agent"] shouldBe null + } + } + + context("queryString") { + test("정상 응답") { + val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .queryString() + .build() + + result["query_params"] shouldBe queryString + } + + test("ServletRequest에서 null이 반환되면 추가되지 않는다.") { + every { servletRequest.queryString } returns null + + val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .queryString() + .build() + + result["query_params"] shouldBe null + } + } + + context("httpStatus") { + test("정상 응답") { + val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .httpStatus(200) + .build() + + result["status_code"] shouldBe 200 + } + + test("null을 입력하면 추가되지 않는다.") { + val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .httpStatus(null) + .build() + + result["status_code"] shouldBe null + } + } + + context("responseBody") { + test("정상 응답") { + val body = mapOf("key" to "value") + val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .responseBody(body) + .build() + + result["response_body"] shouldBe body + } + + test("null을 입력하면 추가되지 않는다.") { + val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .responseBody(null) + .build() + + result["response_body"] shouldBe null + } + } + + context("durationMs") { + test("정상 응답") { + MdcStartTimeUtil.setCurrentTime() + + val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .durationMs() + .build() + + result["duration_ms"].shouldNotBeNull() + MdcStartTimeUtil.clear() + } + + test("MDC에서 값을 가져올 수 없으면 추가되지 않는다.") { + val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .durationMs() + .build() + + result["duration_ms"] shouldBe null + } + } + + context("principalId") { + test("정상 응답") { + val principalId = 759980174446956066L.also { + MdcPrincipalIdUtil.set(it.toString()) + } + + val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .principalId() + .build() + + result["principal_id"] shouldBe principalId + MdcPrincipalIdUtil.clear() + } + + test("MDC에서 값을 가져올 수 없으면 UNKNOWN 으로 표기된다.") { + val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .principalId() + .build() + + result["principal_id"] shouldBe "UNKNOWN" + } + } + + context("exception") { + test("정상 응답") { + val exception = RuntimeException("hello") + val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .exception(exception) + .build() + + result["exception"] shouldBe mapOf( + "class" to exception.javaClass.simpleName, + "message" to exception.message + ) + } + + test("null을 입력하면 추가되지 않는다.") { + val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .exception(null) + .build() + + result["exception"] shouldBe null + } + } + + context("additionalPayloads") { + test("정상 응답") { + val payload = mapOf( + "key1" to "value1", + "key2" to "value2" + ) + val result = LogPayloadBuilder(type = LogType.INCOMING_HTTP_REQUEST, servletRequest = servletRequest) + .additionalPayloads(payload) + .build() + + result["key1"] shouldBe "value1" + result["key2"] shouldBe "value2" + } + } +}) diff --git a/common/web/src/test/kotlin/com/sangdol/common/web/support/log/WebLogMessageConverterTest.kt b/common/web/src/test/kotlin/com/sangdol/common/web/support/log/WebLogMessageConverterTest.kt new file mode 100644 index 00000000..84a1f62d --- /dev/null +++ b/common/web/src/test/kotlin/com/sangdol/common/web/support/log/WebLogMessageConverterTest.kt @@ -0,0 +1,166 @@ +package com.sangdol.common.web.support.log + +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.sangdol.common.log.constant.LogType +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.common.utils.MdcPrincipalIdUtil +import com.sangdol.common.utils.MdcStartTimeUtil +import io.kotest.assertions.assertSoftly +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.nulls.shouldNotBeNull +import io.kotest.matchers.shouldBe +import io.mockk.clearMocks +import io.mockk.every +import io.mockk.mockk +import jakarta.servlet.http.HttpServletRequest + +class WebLogMessageConverterTest : FunSpec({ + + val objectMapper = jacksonObjectMapper() + val converter = WebLogMessageConverter(objectMapper) + val servletRequest: HttpServletRequest = mockk() + + lateinit var method: String + lateinit var requestUri: String + lateinit var remoteAddr: String + lateinit var userAgent: String + lateinit var queryString: String + + beforeTest { + method = "GET".also { every { servletRequest.method } returns it } + requestUri = "/converter/test".also { every { servletRequest.requestURI } returns it } + remoteAddr = "localhost".also { every { servletRequest.remoteAddr } returns it } + userAgent = "Mozilla/5.0".also { every { servletRequest.getHeader("User-Agent") } returns it } + queryString = "key=value".also { every { servletRequest.queryString } returns it } + } + + afterSpec { + clearMocks(servletRequest) + } + + context("Http 요청 메시지를 변환한다.") { + test("정상 응답") { + val result = converter.convertToHttpRequestMessage(servletRequest) + + result shouldBe """ + {"type":"${LogType.INCOMING_HTTP_REQUEST.name}","endpoint":"$method $requestUri","query_params":"$queryString","client_ip":"$remoteAddr","user_agent":"$userAgent"} + """.trimIndent() + } + } + + context("Controller 요청 메시지를 변환한다") { + val principalId = 759980174446956066L.also { + MdcPrincipalIdUtil.set(it.toString()) + } + + test("정상 응답") { + val controllerPayload: Map = mapOf( + "controller_method" to "ThemeController.findThemeById(..)", + "path_variable" to mapOf("id" to "7599801744469560667") + ) + + val result = converter.convertToControllerInvokedMessage(servletRequest, controllerPayload) + + result shouldBe """ + {"type":"${LogType.CONTROLLER_INVOKED.name}","endpoint":"$method $requestUri","principal_id":$principalId,"controller_method":"${controllerPayload["controller_method"]}","path_variable":{"id":"${7599801744469560667}"}} + """.trimIndent() + } + } + + context("응답 메시지를 변환한다.") { + val principalId = 7599801744469560666 + + val body = mapOf( + "id" to 7599801744469560667, + "name" to "sangdol" + ) + + val exception = RuntimeException("hello") + + beforeTest { + MdcPrincipalIdUtil.set(principalId.toString()) + MdcStartTimeUtil.setCurrentTime() + } + + afterTest { + MdcPrincipalIdUtil.clear() + MdcStartTimeUtil.clear() + } + + test("응답 본문을 포함한다.") { + val result = converter.convertToResponseMessage( + type = LogType.SUCCEED, + servletRequest = servletRequest, + httpStatusCode = HttpStatus.OK.value(), + responseBody = body + ) + + assertSoftly(objectMapper.readValue(result, LinkedHashMap::class.java)) { + this["type"] shouldBe LogType.SUCCEED.name + this["endpoint"] shouldBe "$method $requestUri" + this["status_code"] shouldBe HttpStatus.OK.value() + this["duration_ms"].shouldNotBeNull() + this["principal_id"] shouldBe principalId + this["response_body"] shouldBe body + this["exception"] shouldBe null + } + } + + test("예외를 포함한다.") { + val result = converter.convertToResponseMessage( + type = LogType.SUCCEED, + servletRequest = servletRequest, + httpStatusCode = HttpStatus.OK.value(), + exception = exception + ) + + assertSoftly(objectMapper.readValue(result, LinkedHashMap::class.java)) { + this["type"] shouldBe LogType.SUCCEED.name + this["endpoint"] shouldBe "$method $requestUri" + this["status_code"] shouldBe HttpStatus.OK.value() + this["duration_ms"].shouldNotBeNull() + this["principal_id"] shouldBe principalId + this["response_body"] shouldBe null + this["exception"] shouldBe mapOf("class" to exception.javaClass.simpleName, "message" to exception.message) + } + } + + test("예외 + 응답 본문을 모두 포함한다.") { + val result = converter.convertToResponseMessage( + type = LogType.SUCCEED, + servletRequest = servletRequest, + httpStatusCode = HttpStatus.OK.value(), + responseBody = body, + exception = exception + ) + + assertSoftly(objectMapper.readValue(result, LinkedHashMap::class.java)) { + this["type"] shouldBe LogType.SUCCEED.name + this["endpoint"] shouldBe "$method $requestUri" + this["status_code"] shouldBe HttpStatus.OK.value() + this["duration_ms"].shouldNotBeNull() + this["principal_id"] shouldBe principalId + this["response_body"] shouldBe body + this["exception"] shouldBe mapOf("class" to exception.javaClass.simpleName, "message" to exception.message) + } + } + + test("예외, 응답 본문 모두 제외한다.") { + val result = converter.convertToResponseMessage( + type = LogType.SUCCEED, + servletRequest = servletRequest, + httpStatusCode = HttpStatus.OK.value(), + ) + + assertSoftly(objectMapper.readValue(result, LinkedHashMap::class.java)) { + this["type"] shouldBe LogType.SUCCEED.name + this["endpoint"] shouldBe "$method $requestUri" + this["status_code"] shouldBe HttpStatus.OK.value() + this["duration_ms"].shouldNotBeNull() + this["principal_id"] shouldBe principalId + this["response_body"] shouldBe null + this["exception"] shouldBe null + } + } + } +}) diff --git a/service/build.gradle.kts b/service/build.gradle.kts new file mode 100644 index 00000000..6fea963e --- /dev/null +++ b/service/build.gradle.kts @@ -0,0 +1,63 @@ +plugins { + id("org.springframework.boot") + kotlin("plugin.spring") + kotlin("plugin.jpa") +} + +dependencies { + // Spring + implementation("org.springframework.boot:spring-boot-starter-web") + implementation("org.springframework.boot:spring-boot-starter-data-jpa") + implementation("org.springframework.boot:spring-boot-starter-validation") + + // API docs + implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.13") + + // DB + implementation("com.github.f4b6a3:tsid-creator:5.2.6") + runtimeOnly("com.h2database:h2") + runtimeOnly("com.mysql:mysql-connector-j") + + // Jwt + implementation("io.jsonwebtoken:jjwt:0.12.6") + + // Logging + implementation("net.logstash.logback:logstash-logback-encoder:8.1") + implementation("com.github.loki4j:loki-logback-appender:2.0.0") + implementation("net.ttddyy.observation:datasource-micrometer-spring-boot:1.1.1") + + // Observability + implementation("org.springframework.boot:spring-boot-starter-actuator") + implementation("io.micrometer:micrometer-tracing-bridge-otel") + implementation("io.opentelemetry:opentelemetry-exporter-otlp") + runtimeOnly("io.micrometer:micrometer-registry-prometheus") + + // Kotlin + implementation("org.jetbrains.kotlin:kotlin-reflect") + + // Test + testImplementation("org.springframework.boot:spring-boot-starter-test") + testImplementation("io.mockk:mockk:1.14.4") + testImplementation("com.ninja-squad:springmockk:4.0.2") + + // Kotest + testImplementation("io.kotest.extensions:kotest-extensions-spring:1.3.0") + + // RestAssured + testImplementation("io.rest-assured:rest-assured:5.5.5") + testImplementation("io.rest-assured:kotlin-extensions:5.5.5") + + // etc + implementation("org.apache.poi:poi-ooxml:5.2.3") + + // submodules + implementation(project(":common:persistence")) + implementation(project(":common:utils")) + implementation(project(":common:types")) + implementation(project(":common:log")) + implementation(project(":common:web")) +} + +tasks.named("jar") { + enabled = false +} diff --git a/src/main/kotlin/roomescape/RoomescapeApplication.kt b/service/src/main/kotlin/com/sangdol/roomescape/RoomescapeApplication.kt similarity index 74% rename from src/main/kotlin/roomescape/RoomescapeApplication.kt rename to service/src/main/kotlin/com/sangdol/roomescape/RoomescapeApplication.kt index aca20d20..c8b5682f 100644 --- a/src/main/kotlin/roomescape/RoomescapeApplication.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/RoomescapeApplication.kt @@ -1,10 +1,12 @@ -package roomescape +package com.sangdol.roomescape import org.springframework.boot.Banner import org.springframework.boot.SpringApplication import org.springframework.boot.autoconfigure.SpringBootApplication -@SpringBootApplication +@SpringBootApplication( + scanBasePackages = ["com.sangdol.roomescape", "com.sangdol.common"] +) class RoomescapeApplication fun main(args: Array) { diff --git a/src/main/kotlin/roomescape/admin/business/AdminService.kt b/service/src/main/kotlin/com/sangdol/roomescape/admin/business/AdminService.kt similarity index 73% rename from src/main/kotlin/roomescape/admin/business/AdminService.kt rename to service/src/main/kotlin/com/sangdol/roomescape/admin/business/AdminService.kt index 96faa073..e59c22d2 100644 --- a/src/main/kotlin/roomescape/admin/business/AdminService.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/admin/business/AdminService.kt @@ -1,17 +1,16 @@ -package roomescape.admin.business +package com.sangdol.roomescape.admin.business +import com.sangdol.roomescape.common.types.Auditor +import com.sangdol.roomescape.admin.business.dto.AdminLoginCredentials +import com.sangdol.roomescape.admin.business.dto.toCredentials +import com.sangdol.roomescape.admin.exception.AdminErrorCode +import com.sangdol.roomescape.admin.exception.AdminException +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminRepository import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional -import roomescape.admin.exception.AdminErrorCode -import roomescape.admin.exception.AdminException -import roomescape.admin.infrastructure.persistence.AdminRepository -import roomescape.common.dto.AdminLoginCredentials -import roomescape.common.dto.AuditConstant -import roomescape.common.dto.OperatorInfo -import roomescape.common.dto.toCredentials private val log: KLogger = KotlinLogging.logger {} @@ -35,16 +34,16 @@ class AdminService( } @Transactional(readOnly = true) - fun findOperatorOrUnknown(id: Long): OperatorInfo { + fun findOperatorOrUnknown(id: Long): Auditor { log.info { "[AdminService.findOperatorById] 작업자 정보 조회 시작: id=${id}" } return adminRepository.findByIdOrNull(id)?.let { admin -> - OperatorInfo(admin.id, admin.name).also { + Auditor(admin.id, admin.name).also { log.info { "[AdminService.findOperatorById] 작업자 정보 조회 완료: id=${admin.id}, name=${admin.name}" } } } ?: run { log.warn { "[AdminService.findOperatorById] 작업자 정보 조회 실패. id=${id}" } - AuditConstant.UNKNOWN_OPERATOR + Auditor.UNKNOWN } } } diff --git a/service/src/main/kotlin/com/sangdol/roomescape/admin/business/dto/AdminLoginDTO.kt b/service/src/main/kotlin/com/sangdol/roomescape/admin/business/dto/AdminLoginDTO.kt new file mode 100644 index 00000000..d9d6c4f7 --- /dev/null +++ b/service/src/main/kotlin/com/sangdol/roomescape/admin/business/dto/AdminLoginDTO.kt @@ -0,0 +1,39 @@ +package com.sangdol.roomescape.admin.business.dto + +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminEntity +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminPermissionLevel +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminType +import com.sangdol.roomescape.auth.web.LoginCredentials +import com.sangdol.roomescape.auth.web.LoginSuccessResponse + +data class AdminLoginCredentials( + override val id: Long, + override val password: String, + override val name: String, + val type: AdminType, + val storeId: Long?, + val permissionLevel: AdminPermissionLevel, +) : LoginCredentials() { + override fun toResponse(accessToken: String) = AdminLoginSuccessResponse( + accessToken = accessToken, + name = name, + type = type, + storeId = storeId + ) +} + +fun AdminEntity.toCredentials() = AdminLoginCredentials( + id = this.id, + password = this.password, + name = this.name, + type = this.type, + storeId = this.storeId, + permissionLevel = this.permissionLevel +) + +data class AdminLoginSuccessResponse( + override val accessToken: String, + override val name: String, + val type: AdminType, + val storeId: Long?, +) : LoginSuccessResponse() \ No newline at end of file diff --git a/src/main/kotlin/roomescape/admin/exception/AdminException.kt b/service/src/main/kotlin/com/sangdol/roomescape/admin/exception/AdminException.kt similarity index 66% rename from src/main/kotlin/roomescape/admin/exception/AdminException.kt rename to service/src/main/kotlin/com/sangdol/roomescape/admin/exception/AdminException.kt index a9bfcc8c..08ad5b8e 100644 --- a/src/main/kotlin/roomescape/admin/exception/AdminException.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/admin/exception/AdminException.kt @@ -1,8 +1,8 @@ -package roomescape.admin.exception +package com.sangdol.roomescape.admin.exception -import org.springframework.http.HttpStatus -import roomescape.common.exception.ErrorCode -import roomescape.common.exception.RoomescapeException +import com.sangdol.common.types.exception.ErrorCode +import com.sangdol.common.types.exception.RoomescapeException +import com.sangdol.common.types.web.HttpStatus class AdminException( override val errorCode: AdminErrorCode, diff --git a/src/main/kotlin/roomescape/admin/infrastructure/persistence/AdminEntity.kt b/service/src/main/kotlin/com/sangdol/roomescape/admin/infrastructure/persistence/AdminEntity.kt similarity index 91% rename from src/main/kotlin/roomescape/admin/infrastructure/persistence/AdminEntity.kt rename to service/src/main/kotlin/com/sangdol/roomescape/admin/infrastructure/persistence/AdminEntity.kt index 85387596..9a5c61e2 100644 --- a/src/main/kotlin/roomescape/admin/infrastructure/persistence/AdminEntity.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/admin/infrastructure/persistence/AdminEntity.kt @@ -1,8 +1,8 @@ -package roomescape.admin.infrastructure.persistence +package com.sangdol.roomescape.admin.infrastructure.persistence +import com.sangdol.common.persistence.AuditingBaseEntity import jakarta.persistence.* import org.springframework.data.jpa.domain.support.AuditingEntityListener -import roomescape.common.entity.AuditingBaseEntity @Entity @Table(name = "admin") diff --git a/src/main/kotlin/roomescape/admin/infrastructure/persistence/AdminRepository.kt b/service/src/main/kotlin/com/sangdol/roomescape/admin/infrastructure/persistence/AdminRepository.kt similarity index 73% rename from src/main/kotlin/roomescape/admin/infrastructure/persistence/AdminRepository.kt rename to service/src/main/kotlin/com/sangdol/roomescape/admin/infrastructure/persistence/AdminRepository.kt index 7520c23c..e0c071fd 100644 --- a/src/main/kotlin/roomescape/admin/infrastructure/persistence/AdminRepository.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/admin/infrastructure/persistence/AdminRepository.kt @@ -1,4 +1,4 @@ -package roomescape.admin.infrastructure.persistence +package com.sangdol.roomescape.admin.infrastructure.persistence import org.springframework.data.jpa.repository.JpaRepository diff --git a/src/main/kotlin/roomescape/auth/business/AuthService.kt b/service/src/main/kotlin/com/sangdol/roomescape/auth/business/AuthService.kt similarity index 87% rename from src/main/kotlin/roomescape/auth/business/AuthService.kt rename to service/src/main/kotlin/com/sangdol/roomescape/auth/business/AuthService.kt index 5366af04..22cff9a8 100644 --- a/src/main/kotlin/roomescape/auth/business/AuthService.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/auth/business/AuthService.kt @@ -1,19 +1,15 @@ -package roomescape.auth.business +package com.sangdol.roomescape.auth.business +import com.sangdol.roomescape.admin.business.AdminService +import com.sangdol.roomescape.auth.exception.AuthErrorCode +import com.sangdol.roomescape.auth.exception.AuthException +import com.sangdol.roomescape.auth.infrastructure.jwt.JwtUtils +import com.sangdol.roomescape.auth.web.* +import com.sangdol.roomescape.user.business.UserService import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional -import roomescape.admin.business.AdminService -import roomescape.auth.exception.AuthErrorCode -import roomescape.auth.exception.AuthException -import roomescape.auth.infrastructure.jwt.JwtUtils -import roomescape.auth.web.LoginContext -import roomescape.auth.web.LoginRequest -import roomescape.auth.web.LoginSuccessResponse -import roomescape.common.dto.LoginCredentials -import roomescape.common.dto.PrincipalType -import roomescape.user.business.UserService private val log: KLogger = KotlinLogging.logger {} diff --git a/src/main/kotlin/roomescape/auth/business/LoginHistoryService.kt b/service/src/main/kotlin/com/sangdol/roomescape/auth/business/LoginHistoryService.kt similarity index 81% rename from src/main/kotlin/roomescape/auth/business/LoginHistoryService.kt rename to service/src/main/kotlin/com/sangdol/roomescape/auth/business/LoginHistoryService.kt index af7a06dc..6cbed9bd 100644 --- a/src/main/kotlin/roomescape/auth/business/LoginHistoryService.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/auth/business/LoginHistoryService.kt @@ -1,23 +1,22 @@ -package roomescape.auth.business +package com.sangdol.roomescape.auth.business -import com.github.f4b6a3.tsid.TsidFactory +import com.sangdol.common.persistence.IDGenerator +import com.sangdol.roomescape.auth.infrastructure.persistence.LoginHistoryEntity +import com.sangdol.roomescape.auth.infrastructure.persistence.LoginHistoryRepository +import com.sangdol.roomescape.auth.web.LoginContext +import com.sangdol.roomescape.auth.web.PrincipalType import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Propagation import org.springframework.transaction.annotation.Transactional -import roomescape.auth.infrastructure.persistence.LoginHistoryEntity -import roomescape.auth.infrastructure.persistence.LoginHistoryRepository -import roomescape.auth.web.LoginContext -import roomescape.common.config.next -import roomescape.common.dto.PrincipalType private val log: KLogger = KotlinLogging.logger {} @Service class LoginHistoryService( private val loginHistoryRepository: LoginHistoryRepository, - private val tsidFactory: TsidFactory, + private val idGenerator: IDGenerator, ) { @Transactional(propagation = Propagation.REQUIRES_NEW) fun createSuccessHistory( @@ -47,7 +46,7 @@ class LoginHistoryService( runCatching { LoginHistoryEntity( - id = tsidFactory.next(), + id = idGenerator.create(), principalId = principalId, principalType = principalType, success = success, diff --git a/src/main/kotlin/roomescape/auth/docs/AuthAPI.kt b/service/src/main/kotlin/com/sangdol/roomescape/auth/docs/AuthAPI.kt similarity index 71% rename from src/main/kotlin/roomescape/auth/docs/AuthAPI.kt rename to service/src/main/kotlin/com/sangdol/roomescape/auth/docs/AuthAPI.kt index 5571a169..65a2c016 100644 --- a/src/main/kotlin/roomescape/auth/docs/AuthAPI.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/auth/docs/AuthAPI.kt @@ -1,5 +1,11 @@ -package roomescape.auth.docs +package com.sangdol.roomescape.auth.docs +import com.sangdol.common.types.web.CommonApiResponse +import com.sangdol.roomescape.common.types.CurrentUserContext +import com.sangdol.roomescape.auth.web.LoginRequest +import com.sangdol.roomescape.auth.web.LoginSuccessResponse +import com.sangdol.roomescape.auth.web.support.Public +import com.sangdol.roomescape.auth.web.support.User import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.responses.ApiResponses @@ -8,12 +14,6 @@ import jakarta.servlet.http.HttpServletResponse import jakarta.validation.Valid import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.RequestBody -import roomescape.auth.web.LoginRequest -import roomescape.auth.web.LoginSuccessResponse -import roomescape.auth.web.support.Public -import roomescape.auth.web.support.User -import roomescape.common.dto.CurrentUserContext -import roomescape.common.dto.response.CommonApiResponse interface AuthAPI { diff --git a/src/main/kotlin/roomescape/auth/exception/AuthErrorCode.kt b/service/src/main/kotlin/com/sangdol/roomescape/auth/exception/AuthErrorCode.kt similarity index 85% rename from src/main/kotlin/roomescape/auth/exception/AuthErrorCode.kt rename to service/src/main/kotlin/com/sangdol/roomescape/auth/exception/AuthErrorCode.kt index 40781ac5..2da82e04 100644 --- a/src/main/kotlin/roomescape/auth/exception/AuthErrorCode.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/auth/exception/AuthErrorCode.kt @@ -1,7 +1,7 @@ -package roomescape.auth.exception +package com.sangdol.roomescape.auth.exception -import org.springframework.http.HttpStatus -import roomescape.common.exception.ErrorCode +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.common.types.exception.ErrorCode enum class AuthErrorCode( override val httpStatus: HttpStatus, diff --git a/src/main/kotlin/roomescape/auth/exception/AuthException.kt b/service/src/main/kotlin/com/sangdol/roomescape/auth/exception/AuthException.kt similarity index 60% rename from src/main/kotlin/roomescape/auth/exception/AuthException.kt rename to service/src/main/kotlin/com/sangdol/roomescape/auth/exception/AuthException.kt index 83295bdf..4b233149 100644 --- a/src/main/kotlin/roomescape/auth/exception/AuthException.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/auth/exception/AuthException.kt @@ -1,6 +1,6 @@ -package roomescape.auth.exception +package com.sangdol.roomescape.auth.exception -import roomescape.common.exception.RoomescapeException +import com.sangdol.common.types.exception.RoomescapeException class AuthException( override val errorCode: AuthErrorCode, diff --git a/src/main/kotlin/roomescape/auth/infrastructure/jwt/JwtUtils.kt b/service/src/main/kotlin/com/sangdol/roomescape/auth/infrastructure/jwt/JwtUtils.kt similarity index 93% rename from src/main/kotlin/roomescape/auth/infrastructure/jwt/JwtUtils.kt rename to service/src/main/kotlin/com/sangdol/roomescape/auth/infrastructure/jwt/JwtUtils.kt index b68d612b..ba34b687 100644 --- a/src/main/kotlin/roomescape/auth/infrastructure/jwt/JwtUtils.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/auth/infrastructure/jwt/JwtUtils.kt @@ -1,4 +1,4 @@ -package roomescape.auth.infrastructure.jwt +package com.sangdol.roomescape.auth.infrastructure.jwt import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging @@ -8,8 +8,8 @@ import io.jsonwebtoken.Jwts import io.jsonwebtoken.security.Keys import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Component -import roomescape.auth.exception.AuthErrorCode -import roomescape.auth.exception.AuthException +import com.sangdol.roomescape.auth.exception.AuthErrorCode +import com.sangdol.roomescape.auth.exception.AuthException import java.util.* import javax.crypto.SecretKey diff --git a/src/main/kotlin/roomescape/auth/infrastructure/persistence/LoginHistoryEntity.kt b/service/src/main/kotlin/com/sangdol/roomescape/auth/infrastructure/persistence/LoginHistoryEntity.kt similarity index 78% rename from src/main/kotlin/roomescape/auth/infrastructure/persistence/LoginHistoryEntity.kt rename to service/src/main/kotlin/com/sangdol/roomescape/auth/infrastructure/persistence/LoginHistoryEntity.kt index 126e6a9e..8d8b2e67 100644 --- a/src/main/kotlin/roomescape/auth/infrastructure/persistence/LoginHistoryEntity.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/auth/infrastructure/persistence/LoginHistoryEntity.kt @@ -1,10 +1,10 @@ -package roomescape.auth.infrastructure.persistence +package com.sangdol.roomescape.auth.infrastructure.persistence +import com.sangdol.common.persistence.PersistableBaseEntity +import com.sangdol.roomescape.auth.web.PrincipalType import jakarta.persistence.* import org.springframework.data.annotation.CreatedDate import org.springframework.data.jpa.domain.support.AuditingEntityListener -import roomescape.common.dto.PrincipalType -import roomescape.common.entity.PersistableBaseEntity import java.time.LocalDateTime @Entity diff --git a/src/main/kotlin/roomescape/auth/infrastructure/persistence/LoginHistoryRepository.kt b/service/src/main/kotlin/com/sangdol/roomescape/auth/infrastructure/persistence/LoginHistoryRepository.kt similarity index 77% rename from src/main/kotlin/roomescape/auth/infrastructure/persistence/LoginHistoryRepository.kt rename to service/src/main/kotlin/com/sangdol/roomescape/auth/infrastructure/persistence/LoginHistoryRepository.kt index 8eef79a6..562d0eda 100644 --- a/src/main/kotlin/roomescape/auth/infrastructure/persistence/LoginHistoryRepository.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/auth/infrastructure/persistence/LoginHistoryRepository.kt @@ -1,4 +1,4 @@ -package roomescape.auth.infrastructure.persistence +package com.sangdol.roomescape.auth.infrastructure.persistence import org.springframework.data.jpa.repository.JpaRepository diff --git a/src/main/kotlin/roomescape/auth/web/AuthController.kt b/service/src/main/kotlin/com/sangdol/roomescape/auth/web/AuthController.kt similarity index 77% rename from src/main/kotlin/roomescape/auth/web/AuthController.kt rename to service/src/main/kotlin/com/sangdol/roomescape/auth/web/AuthController.kt index 7e173128..b335e36a 100644 --- a/src/main/kotlin/roomescape/auth/web/AuthController.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/auth/web/AuthController.kt @@ -1,16 +1,16 @@ -package roomescape.auth.web +package com.sangdol.roomescape.auth.web +import com.sangdol.common.types.web.CommonApiResponse +import com.sangdol.roomescape.auth.business.AuthService +import com.sangdol.roomescape.auth.docs.AuthAPI +import com.sangdol.roomescape.auth.web.support.User +import com.sangdol.roomescape.common.types.CurrentUserContext import jakarta.servlet.http.HttpServletRequest import jakarta.servlet.http.HttpServletResponse import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController -import roomescape.auth.business.AuthService -import roomescape.auth.docs.AuthAPI -import roomescape.auth.web.support.User -import roomescape.common.dto.CurrentUserContext -import roomescape.common.dto.response.CommonApiResponse @RestController @RequestMapping("/auth") diff --git a/src/main/kotlin/roomescape/auth/web/AuthDTO.kt b/service/src/main/kotlin/com/sangdol/roomescape/auth/web/AuthDTO.kt similarity index 52% rename from src/main/kotlin/roomescape/auth/web/AuthDTO.kt rename to service/src/main/kotlin/com/sangdol/roomescape/auth/web/AuthDTO.kt index a1622c26..2069f004 100644 --- a/src/main/kotlin/roomescape/auth/web/AuthDTO.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/auth/web/AuthDTO.kt @@ -1,8 +1,11 @@ -package roomescape.auth.web +package com.sangdol.roomescape.auth.web +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminType import jakarta.servlet.http.HttpServletRequest -import roomescape.admin.infrastructure.persistence.AdminType -import roomescape.common.dto.PrincipalType + +enum class PrincipalType { + USER, ADMIN +} data class LoginContext( val ipAddress: String, @@ -25,14 +28,10 @@ abstract class LoginSuccessResponse { abstract val name: String } -data class UserLoginSuccessResponse( - override val accessToken: String, - override val name: String, -) : LoginSuccessResponse() +abstract class LoginCredentials { + abstract val id: Long + abstract val password: String + abstract val name: String -data class AdminLoginSuccessResponse( - override val accessToken: String, - override val name: String, - val type: AdminType, - val storeId: Long?, -) : LoginSuccessResponse() + abstract fun toResponse(accessToken: String): LoginSuccessResponse +} diff --git a/src/main/kotlin/roomescape/auth/web/support/AuthAnnotations.kt b/service/src/main/kotlin/com/sangdol/roomescape/auth/web/support/AuthAnnotations.kt similarity index 71% rename from src/main/kotlin/roomescape/auth/web/support/AuthAnnotations.kt rename to service/src/main/kotlin/com/sangdol/roomescape/auth/web/support/AuthAnnotations.kt index 712f0b5e..1351aaa5 100644 --- a/src/main/kotlin/roomescape/auth/web/support/AuthAnnotations.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/auth/web/support/AuthAnnotations.kt @@ -1,7 +1,7 @@ -package roomescape.auth.web.support +package com.sangdol.roomescape.auth.web.support -import roomescape.admin.infrastructure.persistence.AdminType -import roomescape.admin.infrastructure.persistence.Privilege +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminType +import com.sangdol.roomescape.admin.infrastructure.persistence.Privilege @Target(AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.RUNTIME) diff --git a/src/main/kotlin/roomescape/auth/web/support/CookieUtils.kt b/service/src/main/kotlin/com/sangdol/roomescape/auth/web/support/CookieUtils.kt similarity index 85% rename from src/main/kotlin/roomescape/auth/web/support/CookieUtils.kt rename to service/src/main/kotlin/com/sangdol/roomescape/auth/web/support/CookieUtils.kt index 4b0b2b71..2ef93547 100644 --- a/src/main/kotlin/roomescape/auth/web/support/CookieUtils.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/auth/web/support/CookieUtils.kt @@ -1,4 +1,4 @@ -package roomescape.auth.web.support +package com.sangdol.roomescape.auth.web.support import jakarta.servlet.http.HttpServletRequest diff --git a/src/main/kotlin/roomescape/auth/web/support/interceptors/AdminInterceptor.kt b/service/src/main/kotlin/com/sangdol/roomescape/auth/web/support/interceptors/AdminInterceptor.kt similarity index 83% rename from src/main/kotlin/roomescape/auth/web/support/interceptors/AdminInterceptor.kt rename to service/src/main/kotlin/com/sangdol/roomescape/auth/web/support/interceptors/AdminInterceptor.kt index 4b521df0..7de82394 100644 --- a/src/main/kotlin/roomescape/auth/web/support/interceptors/AdminInterceptor.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/auth/web/support/interceptors/AdminInterceptor.kt @@ -1,4 +1,4 @@ -package roomescape.auth.web.support.interceptors +package com.sangdol.roomescape.auth.web.support.interceptors import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging @@ -7,17 +7,17 @@ import jakarta.servlet.http.HttpServletResponse import org.springframework.stereotype.Component import org.springframework.web.method.HandlerMethod import org.springframework.web.servlet.HandlerInterceptor -import roomescape.admin.infrastructure.persistence.AdminPermissionLevel -import roomescape.admin.infrastructure.persistence.AdminType -import roomescape.admin.infrastructure.persistence.Privilege -import roomescape.auth.business.CLAIM_ADMIN_TYPE_KEY -import roomescape.auth.business.CLAIM_PERMISSION_KEY -import roomescape.auth.exception.AuthErrorCode -import roomescape.auth.exception.AuthException -import roomescape.auth.infrastructure.jwt.JwtUtils -import roomescape.auth.web.support.AdminOnly -import roomescape.auth.web.support.accessToken -import roomescape.common.util.MdcPrincipalId +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminPermissionLevel +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminType +import com.sangdol.roomescape.admin.infrastructure.persistence.Privilege +import com.sangdol.roomescape.auth.business.CLAIM_ADMIN_TYPE_KEY +import com.sangdol.roomescape.auth.business.CLAIM_PERMISSION_KEY +import com.sangdol.roomescape.auth.exception.AuthErrorCode +import com.sangdol.roomescape.auth.exception.AuthException +import com.sangdol.roomescape.auth.infrastructure.jwt.JwtUtils +import com.sangdol.roomescape.auth.web.support.AdminOnly +import com.sangdol.roomescape.auth.web.support.accessToken +import com.sangdol.common.utils.MdcPrincipalIdUtil private val log: KLogger = KotlinLogging.logger {} @@ -38,7 +38,7 @@ class AdminInterceptor( try { run { - val id: String = jwtUtils.extractSubject(token).also { MdcPrincipalId.set(it) } + val id: String = jwtUtils.extractSubject(token).also { MdcPrincipalIdUtil.set(it) } val type: AdminType = validateTypeAndGet(token, annotation.type) val permission: AdminPermissionLevel = validatePermissionAndGet(token, annotation.privilege) diff --git a/src/main/kotlin/roomescape/auth/web/support/interceptors/UserInterceptor.kt b/service/src/main/kotlin/com/sangdol/roomescape/auth/web/support/interceptors/UserInterceptor.kt similarity index 77% rename from src/main/kotlin/roomescape/auth/web/support/interceptors/UserInterceptor.kt rename to service/src/main/kotlin/com/sangdol/roomescape/auth/web/support/interceptors/UserInterceptor.kt index 4db11d08..8be0d99c 100644 --- a/src/main/kotlin/roomescape/auth/web/support/interceptors/UserInterceptor.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/auth/web/support/interceptors/UserInterceptor.kt @@ -1,4 +1,4 @@ -package roomescape.auth.web.support.interceptors +package com.sangdol.roomescape.auth.web.support.interceptors import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging @@ -7,13 +7,13 @@ import jakarta.servlet.http.HttpServletResponse import org.springframework.stereotype.Component import org.springframework.web.method.HandlerMethod import org.springframework.web.servlet.HandlerInterceptor -import roomescape.auth.business.CLAIM_ADMIN_TYPE_KEY -import roomescape.auth.exception.AuthErrorCode -import roomescape.auth.exception.AuthException -import roomescape.auth.infrastructure.jwt.JwtUtils -import roomescape.auth.web.support.UserOnly -import roomescape.auth.web.support.accessToken -import roomescape.common.util.MdcPrincipalId +import com.sangdol.roomescape.auth.business.CLAIM_ADMIN_TYPE_KEY +import com.sangdol.roomescape.auth.exception.AuthErrorCode +import com.sangdol.roomescape.auth.exception.AuthException +import com.sangdol.roomescape.auth.infrastructure.jwt.JwtUtils +import com.sangdol.roomescape.auth.web.support.UserOnly +import com.sangdol.roomescape.auth.web.support.accessToken +import com.sangdol.common.utils.MdcPrincipalIdUtil private val log: KLogger = KotlinLogging.logger {} @@ -33,7 +33,7 @@ class UserInterceptor( val token: String? = request.accessToken() try { - val id: String = jwtUtils.extractSubject(token).also { MdcPrincipalId.set(it) } + val id: String = jwtUtils.extractSubject(token).also { MdcPrincipalIdUtil.set(it) } /** * CLAIM_ADMIN_TYPE_KEY 가 존재하면 관리자 토큰임 diff --git a/src/main/kotlin/roomescape/auth/web/support/resolver/UserContextResolver.kt b/service/src/main/kotlin/com/sangdol/roomescape/auth/web/support/resolver/UserContextResolver.kt similarity index 79% rename from src/main/kotlin/roomescape/auth/web/support/resolver/UserContextResolver.kt rename to service/src/main/kotlin/com/sangdol/roomescape/auth/web/support/resolver/UserContextResolver.kt index 7c731c5d..ea47d16b 100644 --- a/src/main/kotlin/roomescape/auth/web/support/resolver/UserContextResolver.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/auth/web/support/resolver/UserContextResolver.kt @@ -1,4 +1,4 @@ -package roomescape.auth.web.support.resolver +package com.sangdol.roomescape.auth.web.support.resolver import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging @@ -9,12 +9,12 @@ import org.springframework.web.bind.support.WebDataBinderFactory import org.springframework.web.context.request.NativeWebRequest import org.springframework.web.method.support.HandlerMethodArgumentResolver import org.springframework.web.method.support.ModelAndViewContainer -import roomescape.auth.exception.AuthErrorCode -import roomescape.auth.exception.AuthException -import roomescape.auth.infrastructure.jwt.JwtUtils -import roomescape.auth.web.support.User -import roomescape.auth.web.support.accessToken -import roomescape.user.business.UserService +import com.sangdol.roomescape.auth.exception.AuthErrorCode +import com.sangdol.roomescape.auth.exception.AuthException +import com.sangdol.roomescape.auth.infrastructure.jwt.JwtUtils +import com.sangdol.roomescape.auth.web.support.User +import com.sangdol.roomescape.auth.web.support.accessToken +import com.sangdol.roomescape.user.business.UserService private val log: KLogger = KotlinLogging.logger {} diff --git a/service/src/main/kotlin/com/sangdol/roomescape/common/config/RoomescapeLogMaskingConverter.kt b/service/src/main/kotlin/com/sangdol/roomescape/common/config/RoomescapeLogMaskingConverter.kt new file mode 100644 index 00000000..9e6c10e0 --- /dev/null +++ b/service/src/main/kotlin/com/sangdol/roomescape/common/config/RoomescapeLogMaskingConverter.kt @@ -0,0 +1,9 @@ +package com.sangdol.roomescape.common.config + +import com.sangdol.common.web.config.JacksonConfig +import com.sangdol.common.log.message.AbstractLogMaskingConverter + +class RoomescapeLogMaskingConverter: AbstractLogMaskingConverter( + sensitiveKeys = setOf("password", "accessToken", "phone"), + objectMapper = JacksonConfig().objectMapper() +) diff --git a/src/main/kotlin/roomescape/common/log/ProxyDataSourceConfig.kt b/service/src/main/kotlin/com/sangdol/roomescape/common/config/SlowQueryLoggerConfig.kt similarity index 70% rename from src/main/kotlin/roomescape/common/log/ProxyDataSourceConfig.kt rename to service/src/main/kotlin/com/sangdol/roomescape/common/config/SlowQueryLoggerConfig.kt index b0300f54..3e599e9b 100644 --- a/src/main/kotlin/roomescape/common/log/ProxyDataSourceConfig.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/common/config/SlowQueryLoggerConfig.kt @@ -1,8 +1,7 @@ -package roomescape.common.log +package com.sangdol.roomescape.common.config +import com.sangdol.common.log.sql.SlowQueryDataSourceFactory import com.zaxxer.hikari.HikariDataSource -import net.ttddyy.dsproxy.listener.logging.SLF4JLogLevel -import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder import org.springframework.beans.factory.annotation.Qualifier import org.springframework.boot.context.properties.ConfigurationProperties import org.springframework.boot.context.properties.EnableConfigurationProperties @@ -23,15 +22,12 @@ class ProxyDataSourceConfig { fun dataSource( @Qualifier("actualDataSource") actualDataSource: DataSource, properties: SlowQueryProperties - ): DataSource = ProxyDataSourceBuilder.create(actualDataSource) - .name(properties.loggerName) - .listener( - MDCAwareSlowQueryListenerWithoutParams( - logLevel = SLF4JLogLevel.nullSafeValueOf(properties.logLevel.uppercase()), - thresholdMs = properties.thresholdMs - ) - ) - .buildProxy() + ): DataSource = SlowQueryDataSourceFactory.create( + dataSource = actualDataSource, + loggerName = properties.loggerName, + logLevel = properties.logLevel, + thresholdMs = properties.thresholdMs + ) @Bean @ConfigurationProperties(prefix = "spring.datasource.hikari") diff --git a/service/src/main/kotlin/com/sangdol/roomescape/common/config/SwaggerConfig.kt b/service/src/main/kotlin/com/sangdol/roomescape/common/config/SwaggerConfig.kt new file mode 100644 index 00000000..509a0192 --- /dev/null +++ b/service/src/main/kotlin/com/sangdol/roomescape/common/config/SwaggerConfig.kt @@ -0,0 +1,15 @@ +package com.sangdol.roomescape.common.config + +import io.swagger.v3.oas.models.OpenAPI +import io.swagger.v3.oas.models.info.Info +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@Configuration +class SwaggerConfig { + + @Bean + fun openAPI(): OpenAPI { + return OpenAPI() + } +} diff --git a/src/main/kotlin/roomescape/common/config/WebMvcConfig.kt b/service/src/main/kotlin/com/sangdol/roomescape/common/config/WebMvcConfig.kt similarity index 75% rename from src/main/kotlin/roomescape/common/config/WebMvcConfig.kt rename to service/src/main/kotlin/com/sangdol/roomescape/common/config/WebMvcConfig.kt index 96eb747c..2bf615eb 100644 --- a/src/main/kotlin/roomescape/common/config/WebMvcConfig.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/common/config/WebMvcConfig.kt @@ -1,12 +1,12 @@ -package roomescape.common.config +package com.sangdol.roomescape.common.config import org.springframework.context.annotation.Configuration import org.springframework.web.method.support.HandlerMethodArgumentResolver import org.springframework.web.servlet.config.annotation.InterceptorRegistry import org.springframework.web.servlet.config.annotation.WebMvcConfigurer -import roomescape.auth.web.support.interceptors.AdminInterceptor -import roomescape.auth.web.support.interceptors.UserInterceptor -import roomescape.auth.web.support.resolver.UserContextResolver +import com.sangdol.roomescape.auth.web.support.interceptors.AdminInterceptor +import com.sangdol.roomescape.auth.web.support.interceptors.UserInterceptor +import com.sangdol.roomescape.auth.web.support.resolver.UserContextResolver @Configuration class WebMvcConfig( diff --git a/service/src/main/kotlin/com/sangdol/roomescape/common/types/AuditingInfo.kt b/service/src/main/kotlin/com/sangdol/roomescape/common/types/AuditingInfo.kt new file mode 100644 index 00000000..83693c60 --- /dev/null +++ b/service/src/main/kotlin/com/sangdol/roomescape/common/types/AuditingInfo.kt @@ -0,0 +1,19 @@ +package com.sangdol.roomescape.common.types + +import java.time.LocalDateTime + +data class Auditor( + val id: Long, + val name: String, +) { + companion object { + val UNKNOWN = Auditor(0, "Unknown") + } +} + +data class AuditingInfo( + val createdAt: LocalDateTime, + val createdBy: Auditor, + val updatedAt: LocalDateTime, + val updatedBy: Auditor, +) diff --git a/service/src/main/kotlin/com/sangdol/roomescape/common/types/CurrentUserContext.kt b/service/src/main/kotlin/com/sangdol/roomescape/common/types/CurrentUserContext.kt new file mode 100644 index 00000000..e7d9e684 --- /dev/null +++ b/service/src/main/kotlin/com/sangdol/roomescape/common/types/CurrentUserContext.kt @@ -0,0 +1,6 @@ +package com.sangdol.roomescape.common.types + +data class CurrentUserContext( + val id: Long, + val name: String, +) diff --git a/src/main/kotlin/roomescape/payment/business/PaymentService.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/business/PaymentService.kt similarity index 87% rename from src/main/kotlin/roomescape/payment/business/PaymentService.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/business/PaymentService.kt index 2d483898..8336919c 100644 --- a/src/main/kotlin/roomescape/payment/business/PaymentService.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/business/PaymentService.kt @@ -1,17 +1,17 @@ -package roomescape.payment.business +package com.sangdol.roomescape.payment.business import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional -import roomescape.common.util.TransactionExecutionUtil -import roomescape.payment.exception.PaymentErrorCode -import roomescape.payment.exception.PaymentException -import roomescape.payment.infrastructure.client.PaymentClientCancelResponse -import roomescape.payment.infrastructure.client.PaymentClientConfirmResponse -import roomescape.payment.infrastructure.client.TosspayClient -import roomescape.payment.infrastructure.persistence.* -import roomescape.payment.web.* +import com.sangdol.common.persistence.TransactionExecutionUtil +import com.sangdol.roomescape.payment.exception.PaymentErrorCode +import com.sangdol.roomescape.payment.exception.PaymentException +import com.sangdol.roomescape.payment.infrastructure.client.PaymentClientCancelResponse +import com.sangdol.roomescape.payment.infrastructure.client.PaymentClientConfirmResponse +import com.sangdol.roomescape.payment.infrastructure.client.TosspayClient +import com.sangdol.roomescape.payment.infrastructure.persistence.* +import com.sangdol.roomescape.payment.web.* private val log: KLogger = KotlinLogging.logger {} @@ -41,6 +41,9 @@ class PaymentService( val detail: PaymentDetailEntity = paymentWriter.createDetail(clientConfirmResponse, payment.id) PaymentCreateResponse(paymentId = payment.id, detailId = detail.id) + } ?: run { + log.warn { "[PaymentService.confirm] 결제 확정 중 예상치 못한 null 반환" } + throw PaymentException(PaymentErrorCode.PAYMENT_UNEXPECTED_ERROR) } } diff --git a/src/main/kotlin/roomescape/payment/business/PaymentWriter.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/business/PaymentWriter.kt similarity index 79% rename from src/main/kotlin/roomescape/payment/business/PaymentWriter.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/business/PaymentWriter.kt index 60a7473f..06226ec4 100644 --- a/src/main/kotlin/roomescape/payment/business/PaymentWriter.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/business/PaymentWriter.kt @@ -1,16 +1,15 @@ -package roomescape.payment.business +package com.sangdol.roomescape.payment.business -import com.github.f4b6a3.tsid.TsidFactory +import com.sangdol.common.persistence.IDGenerator +import com.sangdol.roomescape.payment.exception.PaymentErrorCode +import com.sangdol.roomescape.payment.exception.PaymentException +import com.sangdol.roomescape.payment.infrastructure.client.* +import com.sangdol.roomescape.payment.infrastructure.common.PaymentMethod +import com.sangdol.roomescape.payment.infrastructure.common.PaymentType +import com.sangdol.roomescape.payment.infrastructure.persistence.* import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.stereotype.Component -import roomescape.common.config.next -import roomescape.payment.exception.PaymentErrorCode -import roomescape.payment.exception.PaymentException -import roomescape.payment.infrastructure.client.* -import roomescape.payment.infrastructure.common.PaymentMethod -import roomescape.payment.infrastructure.common.PaymentType -import roomescape.payment.infrastructure.persistence.* import java.time.LocalDateTime private val log: KLogger = KotlinLogging.logger {} @@ -20,7 +19,7 @@ class PaymentWriter( private val paymentRepository: PaymentRepository, private val paymentDetailRepository: PaymentDetailRepository, private val canceledPaymentRepository: CanceledPaymentRepository, - private val tsidFactory: TsidFactory, + private val idGenerator: IDGenerator, ) { fun createPayment( @@ -32,7 +31,7 @@ class PaymentWriter( log.info { "[PaymentWriterV2.createPayment] 결제 승인 및 결제 정보 저장 시작: reservationId=${reservationId}, paymentKey=${paymentClientConfirmResponse.paymentKey}" } return paymentClientConfirmResponse.toEntity( - id = tsidFactory.next(), reservationId, orderId, paymentType + id = idGenerator.create(), reservationId, orderId, paymentType ).also { paymentRepository.save(it) log.info { "[PaymentWriterV2.createPayment] 결제 승인 및 결제 정보 저장 완료: reservationId=${reservationId}, payment.id=${it.id}" } @@ -44,7 +43,7 @@ class PaymentWriter( paymentId: Long, ): PaymentDetailEntity { val method: PaymentMethod = paymentResponse.method - val id = tsidFactory.next() + val id = idGenerator.create() if (method == PaymentMethod.TRANSFER) { return paymentDetailRepository.save(paymentResponse.toTransferDetailEntity(id, paymentId)) @@ -69,7 +68,7 @@ class PaymentWriter( paymentRepository.save(payment.apply { this.cancel() }) return cancelResponse.cancels.toEntity( - id = tsidFactory.next(), + id = idGenerator.create(), paymentId = payment.id, cancelRequestedAt = requestedAt, canceledBy = userId diff --git a/src/main/kotlin/roomescape/payment/docs/PaymentAPI.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/docs/PaymentAPI.kt similarity index 69% rename from src/main/kotlin/roomescape/payment/docs/PaymentAPI.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/docs/PaymentAPI.kt index 708cec30..171df140 100644 --- a/src/main/kotlin/roomescape/payment/docs/PaymentAPI.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/docs/PaymentAPI.kt @@ -1,5 +1,12 @@ -package roomescape.payment.docs +package com.sangdol.roomescape.payment.docs +import com.sangdol.common.types.web.CommonApiResponse +import com.sangdol.roomescape.auth.web.support.User +import com.sangdol.roomescape.auth.web.support.UserOnly +import com.sangdol.roomescape.common.types.CurrentUserContext +import com.sangdol.roomescape.payment.web.PaymentCancelRequest +import com.sangdol.roomescape.payment.web.PaymentConfirmRequest +import com.sangdol.roomescape.payment.web.PaymentCreateResponse import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.responses.ApiResponses @@ -7,13 +14,6 @@ import jakarta.validation.Valid import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestParam -import roomescape.auth.web.support.User -import roomescape.auth.web.support.UserOnly -import roomescape.common.dto.CurrentUserContext -import roomescape.common.dto.response.CommonApiResponse -import roomescape.payment.web.PaymentCancelRequest -import roomescape.payment.web.PaymentConfirmRequest -import roomescape.payment.web.PaymentCreateResponse interface PaymentAPI { diff --git a/src/main/kotlin/roomescape/payment/exception/PaymentErrorCode.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/exception/PaymentErrorCode.kt similarity index 89% rename from src/main/kotlin/roomescape/payment/exception/PaymentErrorCode.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/exception/PaymentErrorCode.kt index 77188954..9d2ea09a 100644 --- a/src/main/kotlin/roomescape/payment/exception/PaymentErrorCode.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/exception/PaymentErrorCode.kt @@ -1,7 +1,7 @@ -package roomescape.payment.exception +package com.sangdol.roomescape.payment.exception -import org.springframework.http.HttpStatus -import roomescape.common.exception.ErrorCode +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.common.types.exception.ErrorCode enum class PaymentErrorCode( override val httpStatus: HttpStatus, diff --git a/src/main/kotlin/roomescape/payment/exception/PaymentException.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/exception/PaymentException.kt similarity index 60% rename from src/main/kotlin/roomescape/payment/exception/PaymentException.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/exception/PaymentException.kt index 20ad4208..3bddd08c 100644 --- a/src/main/kotlin/roomescape/payment/exception/PaymentException.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/exception/PaymentException.kt @@ -1,6 +1,6 @@ -package roomescape.payment.exception +package com.sangdol.roomescape.payment.exception -import roomescape.common.exception.RoomescapeException +import com.sangdol.common.types.exception.RoomescapeException class PaymentException( override val errorCode: PaymentErrorCode, diff --git a/src/main/kotlin/roomescape/payment/infrastructure/client/PaymentConfig.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/client/PaymentConfig.kt similarity index 96% rename from src/main/kotlin/roomescape/payment/infrastructure/client/PaymentConfig.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/client/PaymentConfig.kt index ea8e2b18..231f6624 100644 --- a/src/main/kotlin/roomescape/payment/infrastructure/client/PaymentConfig.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/client/PaymentConfig.kt @@ -1,4 +1,4 @@ -package roomescape.payment.infrastructure.client +package com.sangdol.roomescape.payment.infrastructure.client import org.springframework.boot.context.properties.EnableConfigurationProperties import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder diff --git a/src/main/kotlin/roomescape/payment/infrastructure/client/PaymentProperties.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/client/PaymentProperties.kt similarity index 81% rename from src/main/kotlin/roomescape/payment/infrastructure/client/PaymentProperties.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/client/PaymentProperties.kt index 4b1873b8..52f8c729 100644 --- a/src/main/kotlin/roomescape/payment/infrastructure/client/PaymentProperties.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/client/PaymentProperties.kt @@ -1,4 +1,4 @@ -package roomescape.payment.infrastructure.client +package com.sangdol.roomescape.payment.infrastructure.client import org.springframework.boot.context.properties.ConfigurationProperties diff --git a/src/main/kotlin/roomescape/payment/infrastructure/client/TosspayCancelDTO.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/client/TosspayCancelDTO.kt similarity index 90% rename from src/main/kotlin/roomescape/payment/infrastructure/client/TosspayCancelDTO.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/client/TosspayCancelDTO.kt index 551e7ae5..a4077b27 100644 --- a/src/main/kotlin/roomescape/payment/infrastructure/client/TosspayCancelDTO.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/client/TosspayCancelDTO.kt @@ -1,11 +1,11 @@ -package roomescape.payment.infrastructure.client +package com.sangdol.roomescape.payment.infrastructure.client import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.databind.DeserializationContext import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.annotation.JsonDeserialize -import roomescape.payment.infrastructure.common.PaymentStatus -import roomescape.payment.infrastructure.persistence.CanceledPaymentEntity +import com.sangdol.roomescape.payment.infrastructure.common.PaymentStatus +import com.sangdol.roomescape.payment.infrastructure.persistence.CanceledPaymentEntity import java.time.LocalDateTime import java.time.OffsetDateTime diff --git a/src/main/kotlin/roomescape/payment/infrastructure/client/TosspayClient.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/client/TosspayClient.kt similarity index 96% rename from src/main/kotlin/roomescape/payment/infrastructure/client/TosspayClient.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/client/TosspayClient.kt index 1a1fdb86..49194b30 100644 --- a/src/main/kotlin/roomescape/payment/infrastructure/client/TosspayClient.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/client/TosspayClient.kt @@ -1,6 +1,8 @@ -package roomescape.payment.infrastructure.client +package com.sangdol.roomescape.payment.infrastructure.client import com.fasterxml.jackson.databind.ObjectMapper +import com.sangdol.roomescape.payment.exception.PaymentErrorCode +import com.sangdol.roomescape.payment.exception.PaymentException import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.http.HttpMethod @@ -10,8 +12,6 @@ import org.springframework.http.client.ClientHttpResponse import org.springframework.stereotype.Component import org.springframework.web.client.ResponseErrorHandler import org.springframework.web.client.RestClient -import roomescape.payment.exception.PaymentErrorCode -import roomescape.payment.exception.PaymentException import java.net.URI private val log: KLogger = KotlinLogging.logger {} diff --git a/src/main/kotlin/roomescape/payment/infrastructure/client/TosspayConfirmDTO.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/client/TosspayConfirmDTO.kt similarity index 84% rename from src/main/kotlin/roomescape/payment/infrastructure/client/TosspayConfirmDTO.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/client/TosspayConfirmDTO.kt index ebe0ef20..ebcf0719 100644 --- a/src/main/kotlin/roomescape/payment/infrastructure/client/TosspayConfirmDTO.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/client/TosspayConfirmDTO.kt @@ -1,12 +1,12 @@ -package roomescape.payment.infrastructure.client +package com.sangdol.roomescape.payment.infrastructure.client -import roomescape.payment.exception.PaymentErrorCode -import roomescape.payment.exception.PaymentException -import roomescape.payment.infrastructure.common.* -import roomescape.payment.infrastructure.persistence.PaymentBankTransferDetailEntity -import roomescape.payment.infrastructure.persistence.PaymentCardDetailEntity -import roomescape.payment.infrastructure.persistence.PaymentEasypayPrepaidDetailEntity -import roomescape.payment.infrastructure.persistence.PaymentEntity +import com.sangdol.roomescape.payment.exception.PaymentErrorCode +import com.sangdol.roomescape.payment.exception.PaymentException +import com.sangdol.roomescape.payment.infrastructure.common.* +import com.sangdol.roomescape.payment.infrastructure.persistence.PaymentBankTransferDetailEntity +import com.sangdol.roomescape.payment.infrastructure.persistence.PaymentCardDetailEntity +import com.sangdol.roomescape.payment.infrastructure.persistence.PaymentEasypayPrepaidDetailEntity +import com.sangdol.roomescape.payment.infrastructure.persistence.PaymentEntity import java.time.OffsetDateTime data class PaymentClientConfirmResponse( diff --git a/src/main/kotlin/roomescape/payment/infrastructure/client/TosspayErrorResponse.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/client/TosspayErrorResponse.kt similarity index 57% rename from src/main/kotlin/roomescape/payment/infrastructure/client/TosspayErrorResponse.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/client/TosspayErrorResponse.kt index fbb20ccc..7a504395 100644 --- a/src/main/kotlin/roomescape/payment/infrastructure/client/TosspayErrorResponse.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/client/TosspayErrorResponse.kt @@ -1,4 +1,4 @@ -package roomescape.payment.infrastructure.client +package com.sangdol.roomescape.payment.infrastructure.client data class TosspayErrorResponse( val code: String, diff --git a/src/main/kotlin/roomescape/payment/infrastructure/common/PaymentTypes.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/common/PaymentTypes.kt similarity index 97% rename from src/main/kotlin/roomescape/payment/infrastructure/common/PaymentTypes.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/common/PaymentTypes.kt index 6ecabb80..44ef401f 100644 --- a/src/main/kotlin/roomescape/payment/infrastructure/common/PaymentTypes.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/common/PaymentTypes.kt @@ -1,10 +1,10 @@ -package roomescape.payment.infrastructure.common +package com.sangdol.roomescape.payment.infrastructure.common import com.fasterxml.jackson.annotation.JsonCreator import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging -import roomescape.payment.exception.PaymentErrorCode -import roomescape.payment.exception.PaymentException +import com.sangdol.roomescape.payment.exception.PaymentErrorCode +import com.sangdol.roomescape.payment.exception.PaymentException private val log: KLogger = KotlinLogging.logger {} diff --git a/src/main/kotlin/roomescape/payment/infrastructure/persistence/CanceledPaymentEntity.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/persistence/CanceledPaymentEntity.kt similarity index 80% rename from src/main/kotlin/roomescape/payment/infrastructure/persistence/CanceledPaymentEntity.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/persistence/CanceledPaymentEntity.kt index f9085e7c..4db2e14d 100644 --- a/src/main/kotlin/roomescape/payment/infrastructure/persistence/CanceledPaymentEntity.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/persistence/CanceledPaymentEntity.kt @@ -1,8 +1,8 @@ -package roomescape.payment.infrastructure.persistence +package com.sangdol.roomescape.payment.infrastructure.persistence +import com.sangdol.common.persistence.PersistableBaseEntity import jakarta.persistence.Entity import jakarta.persistence.Table -import roomescape.common.entity.PersistableBaseEntity import java.time.LocalDateTime import java.time.OffsetDateTime diff --git a/src/main/kotlin/roomescape/payment/infrastructure/persistence/CanceledPaymentRepository.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/persistence/CanceledPaymentRepository.kt similarity index 76% rename from src/main/kotlin/roomescape/payment/infrastructure/persistence/CanceledPaymentRepository.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/persistence/CanceledPaymentRepository.kt index 75028118..720ed28f 100644 --- a/src/main/kotlin/roomescape/payment/infrastructure/persistence/CanceledPaymentRepository.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/persistence/CanceledPaymentRepository.kt @@ -1,4 +1,4 @@ -package roomescape.payment.infrastructure.persistence +package com.sangdol.roomescape.payment.infrastructure.persistence import org.springframework.data.jpa.repository.JpaRepository diff --git a/src/main/kotlin/roomescape/payment/infrastructure/persistence/PaymentDetailEntity.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/persistence/PaymentDetailEntity.kt similarity index 90% rename from src/main/kotlin/roomescape/payment/infrastructure/persistence/PaymentDetailEntity.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/persistence/PaymentDetailEntity.kt index 807aaaf3..0e06f775 100644 --- a/src/main/kotlin/roomescape/payment/infrastructure/persistence/PaymentDetailEntity.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/persistence/PaymentDetailEntity.kt @@ -1,8 +1,8 @@ -package roomescape.payment.infrastructure.persistence +package com.sangdol.roomescape.payment.infrastructure.persistence +import com.sangdol.common.persistence.PersistableBaseEntity +import com.sangdol.roomescape.payment.infrastructure.common.* import jakarta.persistence.* -import roomescape.common.entity.PersistableBaseEntity -import roomescape.payment.infrastructure.common.* @Entity @Table(name = "payment_detail") diff --git a/src/main/kotlin/roomescape/payment/infrastructure/persistence/PaymentDetailRepository.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/persistence/PaymentDetailRepository.kt similarity index 75% rename from src/main/kotlin/roomescape/payment/infrastructure/persistence/PaymentDetailRepository.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/persistence/PaymentDetailRepository.kt index 0efd93ae..a53d5d15 100644 --- a/src/main/kotlin/roomescape/payment/infrastructure/persistence/PaymentDetailRepository.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/persistence/PaymentDetailRepository.kt @@ -1,4 +1,4 @@ -package roomescape.payment.infrastructure.persistence +package com.sangdol.roomescape.payment.infrastructure.persistence import org.springframework.data.jpa.repository.JpaRepository diff --git a/src/main/kotlin/roomescape/payment/infrastructure/persistence/PaymentEntity.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/persistence/PaymentEntity.kt similarity index 67% rename from src/main/kotlin/roomescape/payment/infrastructure/persistence/PaymentEntity.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/persistence/PaymentEntity.kt index 748dad84..48aa5587 100644 --- a/src/main/kotlin/roomescape/payment/infrastructure/persistence/PaymentEntity.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/persistence/PaymentEntity.kt @@ -1,13 +1,13 @@ -package roomescape.payment.infrastructure.persistence +package com.sangdol.roomescape.payment.infrastructure.persistence +import com.sangdol.common.persistence.PersistableBaseEntity +import com.sangdol.roomescape.payment.infrastructure.common.PaymentMethod +import com.sangdol.roomescape.payment.infrastructure.common.PaymentStatus +import com.sangdol.roomescape.payment.infrastructure.common.PaymentType import jakarta.persistence.Entity import jakarta.persistence.EnumType import jakarta.persistence.Enumerated import jakarta.persistence.Table -import roomescape.common.entity.PersistableBaseEntity -import roomescape.payment.infrastructure.common.PaymentMethod -import roomescape.payment.infrastructure.common.PaymentStatus -import roomescape.payment.infrastructure.common.PaymentType import java.time.OffsetDateTime @Entity diff --git a/src/main/kotlin/roomescape/payment/infrastructure/persistence/PaymentRepository.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/persistence/PaymentRepository.kt similarity index 75% rename from src/main/kotlin/roomescape/payment/infrastructure/persistence/PaymentRepository.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/persistence/PaymentRepository.kt index 9b872d25..d90002f3 100644 --- a/src/main/kotlin/roomescape/payment/infrastructure/persistence/PaymentRepository.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/infrastructure/persistence/PaymentRepository.kt @@ -1,4 +1,4 @@ -package roomescape.payment.infrastructure.persistence +package com.sangdol.roomescape.payment.infrastructure.persistence import org.springframework.data.jpa.repository.JpaRepository diff --git a/src/main/kotlin/roomescape/payment/web/PaymentController.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/web/PaymentController.kt similarity index 74% rename from src/main/kotlin/roomescape/payment/web/PaymentController.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/web/PaymentController.kt index 82082159..f4830f20 100644 --- a/src/main/kotlin/roomescape/payment/web/PaymentController.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/web/PaymentController.kt @@ -1,13 +1,13 @@ -package roomescape.payment.web +package com.sangdol.roomescape.payment.web +import com.sangdol.common.types.web.CommonApiResponse +import com.sangdol.roomescape.auth.web.support.User +import com.sangdol.roomescape.common.types.CurrentUserContext +import com.sangdol.roomescape.payment.business.PaymentService +import com.sangdol.roomescape.payment.docs.PaymentAPI import jakarta.validation.Valid import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* -import roomescape.auth.web.support.User -import roomescape.common.dto.CurrentUserContext -import roomescape.common.dto.response.CommonApiResponse -import roomescape.payment.business.PaymentService -import roomescape.payment.docs.PaymentAPI @RestController @RequestMapping("/payments") diff --git a/src/main/kotlin/roomescape/payment/web/PaymentDTO.kt b/service/src/main/kotlin/com/sangdol/roomescape/payment/web/PaymentDTO.kt similarity index 89% rename from src/main/kotlin/roomescape/payment/web/PaymentDTO.kt rename to service/src/main/kotlin/com/sangdol/roomescape/payment/web/PaymentDTO.kt index 11a6af92..1e39f186 100644 --- a/src/main/kotlin/roomescape/payment/web/PaymentDTO.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/payment/web/PaymentDTO.kt @@ -1,11 +1,11 @@ -package roomescape.payment.web +package com.sangdol.roomescape.payment.web -import roomescape.payment.exception.PaymentErrorCode -import roomescape.payment.exception.PaymentException -import roomescape.payment.infrastructure.common.PaymentStatus -import roomescape.payment.infrastructure.common.PaymentType -import roomescape.payment.infrastructure.persistence.* -import roomescape.payment.web.PaymentDetailResponse.* +import com.sangdol.roomescape.payment.exception.PaymentErrorCode +import com.sangdol.roomescape.payment.exception.PaymentException +import com.sangdol.roomescape.payment.infrastructure.common.PaymentStatus +import com.sangdol.roomescape.payment.infrastructure.common.PaymentType +import com.sangdol.roomescape.payment.infrastructure.persistence.* +import com.sangdol.roomescape.payment.web.PaymentDetailResponse.* import java.time.LocalDateTime import java.time.OffsetDateTime diff --git a/src/main/kotlin/roomescape/region/business/RegionService.kt b/service/src/main/kotlin/com/sangdol/roomescape/region/business/RegionService.kt similarity index 91% rename from src/main/kotlin/roomescape/region/business/RegionService.kt rename to service/src/main/kotlin/com/sangdol/roomescape/region/business/RegionService.kt index 25966644..de6f1111 100644 --- a/src/main/kotlin/roomescape/region/business/RegionService.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/region/business/RegionService.kt @@ -1,13 +1,13 @@ -package roomescape.region.business +package com.sangdol.roomescape.region.business import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional -import roomescape.region.exception.RegionErrorCode -import roomescape.region.exception.RegionException -import roomescape.region.infrastructure.persistence.RegionRepository -import roomescape.region.web.* +import com.sangdol.roomescape.region.exception.RegionErrorCode +import com.sangdol.roomescape.region.exception.RegionException +import com.sangdol.roomescape.region.infrastructure.persistence.RegionRepository +import com.sangdol.roomescape.region.web.* private val log: KLogger = KotlinLogging.logger {} diff --git a/src/main/kotlin/roomescape/region/docs/RegionAPI.kt b/service/src/main/kotlin/com/sangdol/roomescape/region/docs/RegionAPI.kt similarity index 78% rename from src/main/kotlin/roomescape/region/docs/RegionAPI.kt rename to service/src/main/kotlin/com/sangdol/roomescape/region/docs/RegionAPI.kt index b3486732..16fef1ce 100644 --- a/src/main/kotlin/roomescape/region/docs/RegionAPI.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/region/docs/RegionAPI.kt @@ -1,15 +1,15 @@ -package roomescape.region.docs +package com.sangdol.roomescape.region.docs +import com.sangdol.common.types.web.CommonApiResponse +import com.sangdol.roomescape.auth.web.support.Public +import com.sangdol.roomescape.region.web.RegionCodeResponse +import com.sangdol.roomescape.region.web.SidoListResponse +import com.sangdol.roomescape.region.web.SigunguListResponse import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.responses.ApiResponses import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.RequestParam -import roomescape.auth.web.support.Public -import roomescape.common.dto.response.CommonApiResponse -import roomescape.region.web.RegionCodeResponse -import roomescape.region.web.SidoListResponse -import roomescape.region.web.SigunguListResponse interface RegionAPI { diff --git a/src/main/kotlin/roomescape/region/exception/RegionException.kt b/service/src/main/kotlin/com/sangdol/roomescape/region/exception/RegionException.kt similarity index 77% rename from src/main/kotlin/roomescape/region/exception/RegionException.kt rename to service/src/main/kotlin/com/sangdol/roomescape/region/exception/RegionException.kt index 9bee2e9a..b7201c9b 100644 --- a/src/main/kotlin/roomescape/region/exception/RegionException.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/region/exception/RegionException.kt @@ -1,8 +1,8 @@ -package roomescape.region.exception +package com.sangdol.roomescape.region.exception -import org.springframework.http.HttpStatus -import roomescape.common.exception.ErrorCode -import roomescape.common.exception.RoomescapeException +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.common.types.exception.ErrorCode +import com.sangdol.common.types.exception.RoomescapeException class RegionException( override val errorCode: RegionErrorCode, diff --git a/src/main/kotlin/roomescape/region/infrastructure/persistence/RegionEntity.kt b/service/src/main/kotlin/com/sangdol/roomescape/region/infrastructure/persistence/RegionEntity.kt similarity index 86% rename from src/main/kotlin/roomescape/region/infrastructure/persistence/RegionEntity.kt rename to service/src/main/kotlin/com/sangdol/roomescape/region/infrastructure/persistence/RegionEntity.kt index 00d967a4..3b61291d 100644 --- a/src/main/kotlin/roomescape/region/infrastructure/persistence/RegionEntity.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/region/infrastructure/persistence/RegionEntity.kt @@ -1,4 +1,4 @@ -package roomescape.region.infrastructure.persistence +package com.sangdol.roomescape.region.infrastructure.persistence import jakarta.persistence.Entity import jakarta.persistence.Id diff --git a/src/main/kotlin/roomescape/region/infrastructure/persistence/RegionRepository.kt b/service/src/main/kotlin/com/sangdol/roomescape/region/infrastructure/persistence/RegionRepository.kt similarity index 95% rename from src/main/kotlin/roomescape/region/infrastructure/persistence/RegionRepository.kt rename to service/src/main/kotlin/com/sangdol/roomescape/region/infrastructure/persistence/RegionRepository.kt index 03b1f585..d9baa855 100644 --- a/src/main/kotlin/roomescape/region/infrastructure/persistence/RegionRepository.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/region/infrastructure/persistence/RegionRepository.kt @@ -1,4 +1,4 @@ -package roomescape.region.infrastructure.persistence +package com.sangdol.roomescape.region.infrastructure.persistence import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.Query diff --git a/src/main/kotlin/roomescape/region/web/RegionController.kt b/service/src/main/kotlin/com/sangdol/roomescape/region/web/RegionController.kt similarity index 87% rename from src/main/kotlin/roomescape/region/web/RegionController.kt rename to service/src/main/kotlin/com/sangdol/roomescape/region/web/RegionController.kt index ea4d50c0..26caa3b5 100644 --- a/src/main/kotlin/roomescape/region/web/RegionController.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/region/web/RegionController.kt @@ -1,13 +1,13 @@ -package roomescape.region.web +package com.sangdol.roomescape.region.web +import com.sangdol.common.types.web.CommonApiResponse +import com.sangdol.roomescape.region.business.RegionService +import com.sangdol.roomescape.region.docs.RegionAPI import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController -import roomescape.common.dto.response.CommonApiResponse -import roomescape.region.business.RegionService -import roomescape.region.docs.RegionAPI @RestController @RequestMapping("/regions") diff --git a/src/main/kotlin/roomescape/region/web/RegionDTO.kt b/service/src/main/kotlin/com/sangdol/roomescape/region/web/RegionDTO.kt similarity index 91% rename from src/main/kotlin/roomescape/region/web/RegionDTO.kt rename to service/src/main/kotlin/com/sangdol/roomescape/region/web/RegionDTO.kt index dee2523a..eccfb75a 100644 --- a/src/main/kotlin/roomescape/region/web/RegionDTO.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/region/web/RegionDTO.kt @@ -1,4 +1,4 @@ -package roomescape.region.web +package com.sangdol.roomescape.region.web data class SidoResponse( val code: String, diff --git a/src/main/kotlin/roomescape/reservation/business/ReservationService.kt b/service/src/main/kotlin/com/sangdol/roomescape/reservation/business/ReservationService.kt similarity index 84% rename from src/main/kotlin/roomescape/reservation/business/ReservationService.kt rename to service/src/main/kotlin/com/sangdol/roomescape/reservation/business/ReservationService.kt index 346ac043..f26baa16 100644 --- a/src/main/kotlin/roomescape/reservation/business/ReservationService.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/reservation/business/ReservationService.kt @@ -1,28 +1,25 @@ -package roomescape.reservation.business +package com.sangdol.roomescape.reservation.business -import com.github.f4b6a3.tsid.TsidFactory +import com.sangdol.common.persistence.IDGenerator +import com.sangdol.roomescape.common.types.CurrentUserContext +import com.sangdol.roomescape.payment.business.PaymentService +import com.sangdol.roomescape.payment.web.PaymentWithDetailResponse +import com.sangdol.roomescape.reservation.exception.ReservationErrorCode +import com.sangdol.roomescape.reservation.exception.ReservationException +import com.sangdol.roomescape.reservation.infrastructure.persistence.* +import com.sangdol.roomescape.reservation.web.* +import com.sangdol.roomescape.schedule.business.ScheduleService +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus +import com.sangdol.roomescape.schedule.web.ScheduleOverviewResponse +import com.sangdol.roomescape.schedule.web.ScheduleUpdateRequest +import com.sangdol.roomescape.theme.business.ThemeService +import com.sangdol.roomescape.user.business.UserService +import com.sangdol.roomescape.user.web.UserContactResponse import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional -import roomescape.common.config.next -import roomescape.common.dto.CurrentUserContext -import roomescape.common.util.DateUtils -import roomescape.payment.business.PaymentService -import roomescape.payment.web.PaymentWithDetailResponse -import roomescape.reservation.exception.ReservationErrorCode -import roomescape.reservation.exception.ReservationException -import roomescape.reservation.infrastructure.persistence.* -import roomescape.reservation.web.* -import roomescape.schedule.business.ScheduleService -import roomescape.schedule.infrastructure.persistence.ScheduleStatus -import roomescape.schedule.web.ScheduleOverviewResponse -import roomescape.schedule.web.ScheduleUpdateRequest -import roomescape.theme.business.ThemeService -import roomescape.user.business.UserService -import roomescape.user.web.UserContactResponse -import java.time.LocalDate import java.time.LocalDateTime private val log: KLogger = KotlinLogging.logger {} @@ -35,7 +32,7 @@ class ReservationService( private val userService: UserService, private val themeService: ThemeService, private val canceledReservationRepository: CanceledReservationRepository, - private val tsidFactory: TsidFactory, + private val idGenerator: IDGenerator, private val paymentService: PaymentService ) { @@ -48,7 +45,7 @@ class ReservationService( validateCanCreate(request) - val reservation: ReservationEntity = request.toEntity(id = tsidFactory.next(), userId = user.id) + val reservation: ReservationEntity = request.toEntity(id = idGenerator.create(), userId = user.id) return PendingReservationCreateResponse(reservationRepository.save(reservation).id) .also { log.info { "[ReservationService.createPendingReservation] Pending 예약 생성 완료: reservationId=${it}, schedule=${request.scheduleId}" } } @@ -143,7 +140,7 @@ class ReservationService( } CanceledReservationEntity( - id = tsidFactory.next(), + id = idGenerator.create(), reservationId = reservation.id, canceledBy = user.id, cancelReason = cancelReason, diff --git a/src/main/kotlin/roomescape/reservation/business/ReservationValidator.kt b/service/src/main/kotlin/com/sangdol/roomescape/reservation/business/ReservationValidator.kt similarity index 74% rename from src/main/kotlin/roomescape/reservation/business/ReservationValidator.kt rename to service/src/main/kotlin/com/sangdol/roomescape/reservation/business/ReservationValidator.kt index 9263adfa..28fdc5d6 100644 --- a/src/main/kotlin/roomescape/reservation/business/ReservationValidator.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/reservation/business/ReservationValidator.kt @@ -1,14 +1,14 @@ -package roomescape.reservation.business +package com.sangdol.roomescape.reservation.business import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.stereotype.Component -import roomescape.reservation.exception.ReservationErrorCode -import roomescape.reservation.exception.ReservationException -import roomescape.reservation.web.PendingReservationCreateRequest -import roomescape.schedule.infrastructure.persistence.ScheduleStatus -import roomescape.schedule.web.ScheduleSummaryResponse -import roomescape.theme.web.ThemeInfoResponse +import com.sangdol.roomescape.reservation.exception.ReservationErrorCode +import com.sangdol.roomescape.reservation.exception.ReservationException +import com.sangdol.roomescape.reservation.web.PendingReservationCreateRequest +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus +import com.sangdol.roomescape.schedule.web.ScheduleSummaryResponse +import com.sangdol.roomescape.theme.web.ThemeInfoResponse private val log: KLogger = KotlinLogging.logger {} diff --git a/src/main/kotlin/roomescape/reservation/docs/ReservationAPI.kt b/service/src/main/kotlin/com/sangdol/roomescape/reservation/docs/ReservationAPI.kt similarity index 83% rename from src/main/kotlin/roomescape/reservation/docs/ReservationAPI.kt rename to service/src/main/kotlin/com/sangdol/roomescape/reservation/docs/ReservationAPI.kt index 7481e3e4..2d53eecf 100644 --- a/src/main/kotlin/roomescape/reservation/docs/ReservationAPI.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/reservation/docs/ReservationAPI.kt @@ -1,5 +1,10 @@ -package roomescape.reservation.docs +package com.sangdol.roomescape.reservation.docs +import com.sangdol.common.types.web.CommonApiResponse +import com.sangdol.roomescape.common.types.CurrentUserContext +import com.sangdol.roomescape.auth.web.support.User +import com.sangdol.roomescape.auth.web.support.UserOnly +import com.sangdol.roomescape.reservation.web.* import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.responses.ApiResponses @@ -7,13 +12,6 @@ import jakarta.validation.Valid import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestBody -import org.springframework.web.bind.annotation.RequestParam -import roomescape.auth.web.support.Public -import roomescape.auth.web.support.User -import roomescape.auth.web.support.UserOnly -import roomescape.common.dto.CurrentUserContext -import roomescape.common.dto.response.CommonApiResponse -import roomescape.reservation.web.* interface ReservationAPI { @Operation(summary = "결제 전 임시 예약 저장") diff --git a/src/main/kotlin/roomescape/reservation/exception/ReservationErrorCode.kt b/service/src/main/kotlin/com/sangdol/roomescape/reservation/exception/ReservationErrorCode.kt similarity index 82% rename from src/main/kotlin/roomescape/reservation/exception/ReservationErrorCode.kt rename to service/src/main/kotlin/com/sangdol/roomescape/reservation/exception/ReservationErrorCode.kt index 942b9984..a91594e7 100644 --- a/src/main/kotlin/roomescape/reservation/exception/ReservationErrorCode.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/reservation/exception/ReservationErrorCode.kt @@ -1,7 +1,7 @@ -package roomescape.reservation.exception +package com.sangdol.roomescape.reservation.exception -import org.springframework.http.HttpStatus -import roomescape.common.exception.ErrorCode +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.common.types.exception.ErrorCode enum class ReservationErrorCode( override val httpStatus: HttpStatus, diff --git a/service/src/main/kotlin/com/sangdol/roomescape/reservation/exception/ReservationException.kt b/service/src/main/kotlin/com/sangdol/roomescape/reservation/exception/ReservationException.kt new file mode 100644 index 00000000..f3cb36ab --- /dev/null +++ b/service/src/main/kotlin/com/sangdol/roomescape/reservation/exception/ReservationException.kt @@ -0,0 +1,9 @@ +package com.sangdol.roomescape.reservation.exception + +import com.sangdol.common.types.exception.ErrorCode +import com.sangdol.common.types.exception.RoomescapeException + +class ReservationException( + override val errorCode: ErrorCode, + override val message: String = errorCode.message +) : RoomescapeException(errorCode, message) diff --git a/src/main/kotlin/roomescape/reservation/infrastructure/persistence/CanceledReservationEntity.kt b/service/src/main/kotlin/com/sangdol/roomescape/reservation/infrastructure/persistence/CanceledReservationEntity.kt similarity index 81% rename from src/main/kotlin/roomescape/reservation/infrastructure/persistence/CanceledReservationEntity.kt rename to service/src/main/kotlin/com/sangdol/roomescape/reservation/infrastructure/persistence/CanceledReservationEntity.kt index 84ac475e..81832831 100644 --- a/src/main/kotlin/roomescape/reservation/infrastructure/persistence/CanceledReservationEntity.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/reservation/infrastructure/persistence/CanceledReservationEntity.kt @@ -1,10 +1,10 @@ -package roomescape.reservation.infrastructure.persistence +package com.sangdol.roomescape.reservation.infrastructure.persistence +import com.sangdol.common.persistence.PersistableBaseEntity import jakarta.persistence.Entity import jakarta.persistence.EnumType import jakarta.persistence.Enumerated import jakarta.persistence.Table -import roomescape.common.entity.PersistableBaseEntity import java.time.LocalDateTime @Entity diff --git a/src/main/kotlin/roomescape/reservation/infrastructure/persistence/CanceledReservationRepository.kt b/service/src/main/kotlin/com/sangdol/roomescape/reservation/infrastructure/persistence/CanceledReservationRepository.kt similarity index 68% rename from src/main/kotlin/roomescape/reservation/infrastructure/persistence/CanceledReservationRepository.kt rename to service/src/main/kotlin/com/sangdol/roomescape/reservation/infrastructure/persistence/CanceledReservationRepository.kt index 5508bc11..2d1063c9 100644 --- a/src/main/kotlin/roomescape/reservation/infrastructure/persistence/CanceledReservationRepository.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/reservation/infrastructure/persistence/CanceledReservationRepository.kt @@ -1,4 +1,4 @@ -package roomescape.reservation.infrastructure.persistence +package com.sangdol.roomescape.reservation.infrastructure.persistence import org.springframework.data.jpa.repository.JpaRepository diff --git a/src/main/kotlin/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt b/service/src/main/kotlin/com/sangdol/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt similarity index 85% rename from src/main/kotlin/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt rename to service/src/main/kotlin/com/sangdol/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt index dfd87710..0bccb252 100644 --- a/src/main/kotlin/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/reservation/infrastructure/persistence/ReservationEntity.kt @@ -1,10 +1,10 @@ -package roomescape.reservation.infrastructure.persistence +package com.sangdol.roomescape.reservation.infrastructure.persistence +import com.sangdol.common.persistence.AuditingBaseEntity import jakarta.persistence.Entity import jakarta.persistence.EnumType import jakarta.persistence.Enumerated import jakarta.persistence.Table -import roomescape.common.entity.AuditingBaseEntity @Entity @Table(name = "reservation") diff --git a/src/main/kotlin/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt b/service/src/main/kotlin/com/sangdol/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt similarity index 78% rename from src/main/kotlin/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt rename to service/src/main/kotlin/com/sangdol/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt index af90de13..e9dbdcde 100644 --- a/src/main/kotlin/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt @@ -1,4 +1,4 @@ -package roomescape.reservation.infrastructure.persistence +package com.sangdol.roomescape.reservation.infrastructure.persistence import org.springframework.data.jpa.repository.JpaRepository diff --git a/src/main/kotlin/roomescape/reservation/web/ReservationController.kt b/service/src/main/kotlin/com/sangdol/roomescape/reservation/web/ReservationController.kt similarity index 85% rename from src/main/kotlin/roomescape/reservation/web/ReservationController.kt rename to service/src/main/kotlin/com/sangdol/roomescape/reservation/web/ReservationController.kt index 15105419..b218ea2b 100644 --- a/src/main/kotlin/roomescape/reservation/web/ReservationController.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/reservation/web/ReservationController.kt @@ -1,13 +1,13 @@ -package roomescape.reservation.web +package com.sangdol.roomescape.reservation.web +import com.sangdol.common.types.web.CommonApiResponse +import com.sangdol.roomescape.common.types.CurrentUserContext +import com.sangdol.roomescape.auth.web.support.User +import com.sangdol.roomescape.reservation.business.ReservationService +import com.sangdol.roomescape.reservation.docs.ReservationAPI import jakarta.validation.Valid import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* -import roomescape.auth.web.support.User -import roomescape.common.dto.CurrentUserContext -import roomescape.common.dto.response.CommonApiResponse -import roomescape.reservation.business.ReservationService -import roomescape.reservation.docs.ReservationAPI @RestController @RequestMapping("/reservations") diff --git a/src/main/kotlin/roomescape/reservation/web/ReservationDto.kt b/service/src/main/kotlin/com/sangdol/roomescape/reservation/web/ReservationDto.kt similarity index 85% rename from src/main/kotlin/roomescape/reservation/web/ReservationDto.kt rename to service/src/main/kotlin/com/sangdol/roomescape/reservation/web/ReservationDto.kt index 7990de1e..2349b81b 100644 --- a/src/main/kotlin/roomescape/reservation/web/ReservationDto.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/reservation/web/ReservationDto.kt @@ -1,11 +1,11 @@ -package roomescape.reservation.web +package com.sangdol.roomescape.reservation.web import jakarta.validation.constraints.NotEmpty -import roomescape.payment.web.PaymentWithDetailResponse -import roomescape.reservation.infrastructure.persistence.ReservationEntity -import roomescape.reservation.infrastructure.persistence.ReservationStatus -import roomescape.schedule.web.ScheduleOverviewResponse -import roomescape.user.web.UserContactResponse +import com.sangdol.roomescape.payment.web.PaymentWithDetailResponse +import com.sangdol.roomescape.reservation.infrastructure.persistence.ReservationEntity +import com.sangdol.roomescape.reservation.infrastructure.persistence.ReservationStatus +import com.sangdol.roomescape.schedule.web.ScheduleOverviewResponse +import com.sangdol.roomescape.user.web.UserContactResponse import java.time.LocalDate import java.time.LocalDateTime import java.time.LocalTime @@ -99,7 +99,3 @@ fun ReservationEntity.toReservationDetailRetrieveResponse( data class ReservationCancelRequest( val cancelReason: String ) - -data class MostReservedThemeIdListResponse( - val themeIds: List -) diff --git a/src/main/kotlin/roomescape/schedule/business/ScheduleService.kt b/service/src/main/kotlin/com/sangdol/roomescape/schedule/business/ScheduleService.kt similarity index 85% rename from src/main/kotlin/roomescape/schedule/business/ScheduleService.kt rename to service/src/main/kotlin/com/sangdol/roomescape/schedule/business/ScheduleService.kt index e72f7c6d..3adfedcb 100644 --- a/src/main/kotlin/roomescape/schedule/business/ScheduleService.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/schedule/business/ScheduleService.kt @@ -1,23 +1,22 @@ -package roomescape.schedule.business +package com.sangdol.roomescape.schedule.business import ScheduleException -import com.github.f4b6a3.tsid.TsidFactory +import com.sangdol.common.persistence.IDGenerator +import com.sangdol.roomescape.common.types.AuditingInfo +import com.sangdol.roomescape.common.types.Auditor +import com.sangdol.roomescape.admin.business.AdminService +import com.sangdol.roomescape.schedule.business.domain.ScheduleOverview +import com.sangdol.roomescape.schedule.exception.ScheduleErrorCode +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleEntity +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleEntityFactory +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleRepository +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus +import com.sangdol.roomescape.schedule.web.* import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional -import roomescape.admin.business.AdminService -import roomescape.common.config.next -import roomescape.common.dto.AuditInfo -import roomescape.common.dto.OperatorInfo -import roomescape.schedule.business.domain.ScheduleOverview -import roomescape.schedule.exception.ScheduleErrorCode -import roomescape.schedule.infrastructure.persistence.ScheduleEntity -import roomescape.schedule.infrastructure.persistence.ScheduleEntityFactory -import roomescape.schedule.infrastructure.persistence.ScheduleRepository -import roomescape.schedule.infrastructure.persistence.ScheduleStatus -import roomescape.schedule.web.* import java.time.LocalDate private val log: KLogger = KotlinLogging.logger {} @@ -35,7 +34,7 @@ private val log: KLogger = KotlinLogging.logger {} class ScheduleService( private val scheduleRepository: ScheduleRepository, private val scheduleValidator: ScheduleValidator, - private val tsidFactory: TsidFactory, + private val idGenerator: IDGenerator, private val adminService: AdminService ) { // ======================================== @@ -90,15 +89,15 @@ class ScheduleService( } @Transactional(readOnly = true) - fun findScheduleAudit(id: Long): AuditInfo { + fun findScheduleAudit(id: Long): AuditingInfo { log.info { "[ScheduleService.findDetail] 일정 감사 정보 조회 시작: id=$id" } val schedule: ScheduleEntity = findOrThrow(id) - val createdBy: OperatorInfo = adminService.findOperatorOrUnknown(schedule.createdBy) - val updatedBy: OperatorInfo = adminService.findOperatorOrUnknown(schedule.updatedBy) + val createdBy: Auditor = adminService.findOperatorOrUnknown(schedule.createdBy) + val updatedBy: Auditor = adminService.findOperatorOrUnknown(schedule.updatedBy) - return AuditInfo(schedule.createdAt, createdBy, schedule.updatedAt, updatedBy) + return AuditingInfo(schedule.createdAt, createdBy, schedule.updatedAt, updatedBy) .also { log.info { "[ScheduleService.findDetail] 일정 감사 정보 조회 완료: id=$id" } } } @@ -112,7 +111,7 @@ class ScheduleService( scheduleValidator.validateCanCreate(storeId, request) val schedule = ScheduleEntityFactory.create( - id = tsidFactory.next(), + id = idGenerator.create(), date = request.date, time = request.time, storeId = storeId, diff --git a/src/main/kotlin/roomescape/schedule/business/ScheduleValidator.kt b/service/src/main/kotlin/com/sangdol/roomescape/schedule/business/ScheduleValidator.kt similarity index 85% rename from src/main/kotlin/roomescape/schedule/business/ScheduleValidator.kt rename to service/src/main/kotlin/com/sangdol/roomescape/schedule/business/ScheduleValidator.kt index d04dede1..daab707d 100644 --- a/src/main/kotlin/roomescape/schedule/business/ScheduleValidator.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/schedule/business/ScheduleValidator.kt @@ -1,15 +1,15 @@ -package roomescape.schedule.business +package com.sangdol.roomescape.schedule.business import ScheduleException import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.stereotype.Component -import roomescape.schedule.exception.ScheduleErrorCode -import roomescape.schedule.infrastructure.persistence.ScheduleEntity -import roomescape.schedule.infrastructure.persistence.ScheduleRepository -import roomescape.schedule.infrastructure.persistence.ScheduleStatus -import roomescape.schedule.web.ScheduleCreateRequest -import roomescape.schedule.web.ScheduleUpdateRequest +import com.sangdol.roomescape.schedule.exception.ScheduleErrorCode +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleEntity +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleRepository +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus +import com.sangdol.roomescape.schedule.web.ScheduleCreateRequest +import com.sangdol.roomescape.schedule.web.ScheduleUpdateRequest import java.time.LocalDate import java.time.LocalDateTime import java.time.LocalTime diff --git a/src/main/kotlin/roomescape/schedule/business/domain/ScheduleOverview.kt b/service/src/main/kotlin/com/sangdol/roomescape/schedule/business/domain/ScheduleOverview.kt similarity index 75% rename from src/main/kotlin/roomescape/schedule/business/domain/ScheduleOverview.kt rename to service/src/main/kotlin/com/sangdol/roomescape/schedule/business/domain/ScheduleOverview.kt index de099149..311c3b20 100644 --- a/src/main/kotlin/roomescape/schedule/business/domain/ScheduleOverview.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/schedule/business/domain/ScheduleOverview.kt @@ -1,7 +1,7 @@ -package roomescape.schedule.business.domain +package com.sangdol.roomescape.schedule.business.domain -import roomescape.schedule.infrastructure.persistence.ScheduleStatus -import roomescape.theme.infrastructure.persistence.Difficulty +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus +import com.sangdol.roomescape.theme.infrastructure.persistence.Difficulty import java.time.LocalDate import java.time.LocalTime diff --git a/src/main/kotlin/roomescape/schedule/docs/ScheduleAPI.kt b/service/src/main/kotlin/com/sangdol/roomescape/schedule/docs/ScheduleAPI.kt similarity index 84% rename from src/main/kotlin/roomescape/schedule/docs/ScheduleAPI.kt rename to service/src/main/kotlin/com/sangdol/roomescape/schedule/docs/ScheduleAPI.kt index 58141027..9e2c4ea7 100644 --- a/src/main/kotlin/roomescape/schedule/docs/ScheduleAPI.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/schedule/docs/ScheduleAPI.kt @@ -1,5 +1,13 @@ -package roomescape.schedule.docs +package com.sangdol.roomescape.schedule.docs +import com.sangdol.roomescape.common.types.AuditingInfo +import com.sangdol.common.types.web.CommonApiResponse +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminType +import com.sangdol.roomescape.admin.infrastructure.persistence.Privilege +import com.sangdol.roomescape.auth.web.support.AdminOnly +import com.sangdol.roomescape.auth.web.support.Public +import com.sangdol.roomescape.auth.web.support.UserOnly +import com.sangdol.roomescape.schedule.web.* import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.responses.ApiResponses @@ -9,14 +17,6 @@ import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestParam -import roomescape.admin.infrastructure.persistence.AdminType -import roomescape.admin.infrastructure.persistence.Privilege -import roomescape.auth.web.support.AdminOnly -import roomescape.auth.web.support.Public -import roomescape.auth.web.support.UserOnly -import roomescape.common.dto.AuditInfo -import roomescape.common.dto.response.CommonApiResponse -import roomescape.schedule.web.* import java.time.LocalDate interface AdminScheduleAPI { @@ -35,7 +35,7 @@ interface AdminScheduleAPI { @ApiResponses(ApiResponse(responseCode = "200", useReturnTypeSchema = true)) fun findScheduleAudit( @PathVariable("id") id: Long - ): ResponseEntity> + ): ResponseEntity> @AdminOnly(type = AdminType.STORE, privilege = Privilege.CREATE) @Operation(summary = "일정 생성") diff --git a/src/main/kotlin/roomescape/schedule/exception/ScheduleErrorCode.kt b/service/src/main/kotlin/com/sangdol/roomescape/schedule/exception/ScheduleErrorCode.kt similarity index 84% rename from src/main/kotlin/roomescape/schedule/exception/ScheduleErrorCode.kt rename to service/src/main/kotlin/com/sangdol/roomescape/schedule/exception/ScheduleErrorCode.kt index 696d6630..0194f2fa 100644 --- a/src/main/kotlin/roomescape/schedule/exception/ScheduleErrorCode.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/schedule/exception/ScheduleErrorCode.kt @@ -1,7 +1,7 @@ -package roomescape.schedule.exception +package com.sangdol.roomescape.schedule.exception -import org.springframework.http.HttpStatus -import roomescape.common.exception.ErrorCode +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.common.types.exception.ErrorCode enum class ScheduleErrorCode( override val httpStatus: HttpStatus, diff --git a/src/main/kotlin/roomescape/schedule/exception/ScheduleException.kt b/service/src/main/kotlin/com/sangdol/roomescape/schedule/exception/ScheduleException.kt similarity index 58% rename from src/main/kotlin/roomescape/schedule/exception/ScheduleException.kt rename to service/src/main/kotlin/com/sangdol/roomescape/schedule/exception/ScheduleException.kt index a9655a8f..6133383a 100644 --- a/src/main/kotlin/roomescape/schedule/exception/ScheduleException.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/schedule/exception/ScheduleException.kt @@ -1,5 +1,5 @@ -import roomescape.common.exception.ErrorCode -import roomescape.common.exception.RoomescapeException +import com.sangdol.common.types.exception.ErrorCode +import com.sangdol.common.types.exception.RoomescapeException class ScheduleException( override val errorCode: ErrorCode, diff --git a/src/main/kotlin/roomescape/schedule/infrastructure/persistence/ScheduleEntity.kt b/service/src/main/kotlin/com/sangdol/roomescape/schedule/infrastructure/persistence/ScheduleEntity.kt similarity index 87% rename from src/main/kotlin/roomescape/schedule/infrastructure/persistence/ScheduleEntity.kt rename to service/src/main/kotlin/com/sangdol/roomescape/schedule/infrastructure/persistence/ScheduleEntity.kt index a8023d00..fde4b384 100644 --- a/src/main/kotlin/roomescape/schedule/infrastructure/persistence/ScheduleEntity.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/schedule/infrastructure/persistence/ScheduleEntity.kt @@ -1,12 +1,12 @@ -package roomescape.schedule.infrastructure.persistence +package com.sangdol.roomescape.schedule.infrastructure.persistence +import com.sangdol.common.persistence.PersistableBaseEntity +import com.sangdol.common.utils.MdcPrincipalIdUtil import jakarta.persistence.* import org.springframework.data.annotation.CreatedBy import org.springframework.data.annotation.CreatedDate import org.springframework.data.annotation.LastModifiedDate import org.springframework.data.jpa.domain.support.AuditingEntityListener -import roomescape.common.entity.PersistableBaseEntity -import roomescape.common.util.MdcPrincipalId import java.time.LocalDate import java.time.LocalDateTime import java.time.LocalTime @@ -53,7 +53,7 @@ class ScheduleEntity( } fun updateLastModifiedBy() { - MdcPrincipalId.extractAsLongOrNull()?.also { this.updatedBy = it } + MdcPrincipalIdUtil.extractAsLongOrNull()?.also { this.updatedBy = it } } } diff --git a/src/main/kotlin/roomescape/schedule/infrastructure/persistence/ScheduleRepository.kt b/service/src/main/kotlin/com/sangdol/roomescape/schedule/infrastructure/persistence/ScheduleRepository.kt similarity index 86% rename from src/main/kotlin/roomescape/schedule/infrastructure/persistence/ScheduleRepository.kt rename to service/src/main/kotlin/com/sangdol/roomescape/schedule/infrastructure/persistence/ScheduleRepository.kt index 3189b1aa..82080181 100644 --- a/src/main/kotlin/roomescape/schedule/infrastructure/persistence/ScheduleRepository.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/schedule/infrastructure/persistence/ScheduleRepository.kt @@ -1,8 +1,8 @@ -package roomescape.schedule.infrastructure.persistence +package com.sangdol.roomescape.schedule.infrastructure.persistence import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.Query -import roomescape.schedule.business.domain.ScheduleOverview +import com.sangdol.roomescape.schedule.business.domain.ScheduleOverview import java.time.LocalDate import java.time.LocalTime @@ -26,7 +26,7 @@ interface ScheduleRepository : JpaRepository { @Query( """ SELECT - new roomescape.schedule.business.domain.ScheduleOverview( + new com.sangdol.roomescape.schedule.business.domain.ScheduleOverview( s._id, st._id, st.name, @@ -57,7 +57,7 @@ interface ScheduleRepository : JpaRepository { @Query( """ SELECT - new roomescape.schedule.business.domain.ScheduleOverview( + new com.sangdol.roomescape.schedule.business.domain.ScheduleOverview( s._id, st._id, st.name, diff --git a/src/main/kotlin/roomescape/schedule/web/AdminScheduleController.kt b/service/src/main/kotlin/com/sangdol/roomescape/schedule/web/AdminScheduleController.kt similarity index 86% rename from src/main/kotlin/roomescape/schedule/web/AdminScheduleController.kt rename to service/src/main/kotlin/com/sangdol/roomescape/schedule/web/AdminScheduleController.kt index 39b7c5b2..3c7b89d4 100644 --- a/src/main/kotlin/roomescape/schedule/web/AdminScheduleController.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/schedule/web/AdminScheduleController.kt @@ -1,13 +1,13 @@ -package roomescape.schedule.web +package com.sangdol.roomescape.schedule.web +import com.sangdol.roomescape.common.types.AuditingInfo +import com.sangdol.common.types.web.CommonApiResponse +import com.sangdol.roomescape.schedule.business.ScheduleService +import com.sangdol.roomescape.schedule.docs.AdminScheduleAPI import jakarta.validation.Valid import org.springframework.format.annotation.DateTimeFormat import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* -import roomescape.common.dto.AuditInfo -import roomescape.common.dto.response.CommonApiResponse -import roomescape.schedule.business.ScheduleService -import roomescape.schedule.docs.AdminScheduleAPI import java.time.LocalDate @RestController @@ -29,7 +29,7 @@ class AdminScheduleController( @GetMapping("/schedules/{id}/audits") override fun findScheduleAudit( @PathVariable("id") id: Long - ): ResponseEntity> { + ): ResponseEntity> { val response = scheduleService.findScheduleAudit(id) return ResponseEntity.ok(CommonApiResponse(response)) diff --git a/src/main/kotlin/roomescape/schedule/web/AdminScheduleDto.kt b/service/src/main/kotlin/com/sangdol/roomescape/schedule/web/AdminScheduleDto.kt similarity index 86% rename from src/main/kotlin/roomescape/schedule/web/AdminScheduleDto.kt rename to service/src/main/kotlin/com/sangdol/roomescape/schedule/web/AdminScheduleDto.kt index 47d17915..fec62160 100644 --- a/src/main/kotlin/roomescape/schedule/web/AdminScheduleDto.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/schedule/web/AdminScheduleDto.kt @@ -1,7 +1,7 @@ -package roomescape.schedule.web +package com.sangdol.roomescape.schedule.web -import roomescape.schedule.business.domain.ScheduleOverview -import roomescape.schedule.infrastructure.persistence.ScheduleStatus +import com.sangdol.roomescape.schedule.business.domain.ScheduleOverview +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus import java.time.LocalDate import java.time.LocalTime diff --git a/src/main/kotlin/roomescape/schedule/web/ScheduleController.kt b/service/src/main/kotlin/com/sangdol/roomescape/schedule/web/ScheduleController.kt similarity index 78% rename from src/main/kotlin/roomescape/schedule/web/ScheduleController.kt rename to service/src/main/kotlin/com/sangdol/roomescape/schedule/web/ScheduleController.kt index a57d30f4..1c5d8c2b 100644 --- a/src/main/kotlin/roomescape/schedule/web/ScheduleController.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/schedule/web/ScheduleController.kt @@ -1,12 +1,12 @@ -package roomescape.schedule.web +package com.sangdol.roomescape.schedule.web +import com.sangdol.common.types.web.CommonApiResponse +import com.sangdol.roomescape.schedule.business.ScheduleService +import com.sangdol.roomescape.schedule.docs.PublicScheduleAPI +import com.sangdol.roomescape.schedule.docs.UserScheduleAPI import org.springframework.format.annotation.DateTimeFormat import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* -import roomescape.common.dto.response.CommonApiResponse -import roomescape.schedule.business.ScheduleService -import roomescape.schedule.docs.PublicScheduleAPI -import roomescape.schedule.docs.UserScheduleAPI import java.time.LocalDate @RestController diff --git a/src/main/kotlin/roomescape/schedule/web/ScheduleDto.kt b/service/src/main/kotlin/com/sangdol/roomescape/schedule/web/ScheduleDto.kt similarity index 84% rename from src/main/kotlin/roomescape/schedule/web/ScheduleDto.kt rename to service/src/main/kotlin/com/sangdol/roomescape/schedule/web/ScheduleDto.kt index 10f4f03e..9085c299 100644 --- a/src/main/kotlin/roomescape/schedule/web/ScheduleDto.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/schedule/web/ScheduleDto.kt @@ -1,9 +1,9 @@ -package roomescape.schedule.web +package com.sangdol.roomescape.schedule.web -import roomescape.schedule.business.domain.ScheduleOverview -import roomescape.schedule.infrastructure.persistence.ScheduleEntity -import roomescape.schedule.infrastructure.persistence.ScheduleStatus -import roomescape.theme.infrastructure.persistence.Difficulty +import com.sangdol.roomescape.schedule.business.domain.ScheduleOverview +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleEntity +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus +import com.sangdol.roomescape.theme.infrastructure.persistence.Difficulty import java.time.LocalDate import java.time.LocalTime diff --git a/src/main/kotlin/roomescape/store/business/StoreService.kt b/service/src/main/kotlin/com/sangdol/roomescape/store/business/StoreService.kt similarity index 84% rename from src/main/kotlin/roomescape/store/business/StoreService.kt rename to service/src/main/kotlin/com/sangdol/roomescape/store/business/StoreService.kt index 8cbaebc4..8dd3acc9 100644 --- a/src/main/kotlin/roomescape/store/business/StoreService.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/store/business/StoreService.kt @@ -1,20 +1,19 @@ -package roomescape.store.business +package com.sangdol.roomescape.store.business -import com.github.f4b6a3.tsid.TsidFactory +import com.sangdol.common.persistence.IDGenerator +import com.sangdol.roomescape.common.types.AuditingInfo +import com.sangdol.roomescape.admin.business.AdminService +import com.sangdol.roomescape.region.business.RegionService +import com.sangdol.roomescape.store.exception.StoreErrorCode +import com.sangdol.roomescape.store.exception.StoreException +import com.sangdol.roomescape.store.infrastructure.persistence.StoreEntity +import com.sangdol.roomescape.store.infrastructure.persistence.StoreRepository +import com.sangdol.roomescape.store.infrastructure.persistence.StoreStatus +import com.sangdol.roomescape.store.web.* import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional -import roomescape.admin.business.AdminService -import roomescape.common.config.next -import roomescape.common.dto.AuditInfo -import roomescape.region.business.RegionService -import roomescape.store.exception.StoreErrorCode -import roomescape.store.exception.StoreException -import roomescape.store.infrastructure.persistence.StoreEntity -import roomescape.store.infrastructure.persistence.StoreRepository -import roomescape.store.infrastructure.persistence.StoreStatus -import roomescape.store.web.* private val log: KLogger = KotlinLogging.logger {} @@ -24,7 +23,7 @@ class StoreService( private val storeValidator: StoreValidator, private val adminService: AdminService, private val regionService: RegionService, - private val tsidFactory: TsidFactory, + private val idGenerator: IDGenerator, ) { @Transactional(readOnly = true) fun getDetail(id: Long): DetailStoreResponse { @@ -45,7 +44,7 @@ class StoreService( storeValidator.validateCanRegister(request) val store = StoreEntity( - id = tsidFactory.next(), + id = idGenerator.create(), name = request.name, address = request.address, contact = request.contact, @@ -109,12 +108,12 @@ class StoreService( .also { log.info { "[StoreService.findStoreInfo] 매장 정보 조회 완료: id=${id}" } } } - private fun getAuditInfo(store: StoreEntity): AuditInfo { + private fun getAuditInfo(store: StoreEntity): AuditingInfo { log.info { "[StoreService.getAuditInfo] 감사 정보 조회 시작: storeId=${store.id}" } val createdBy = adminService.findOperatorOrUnknown(store.createdBy) val updatedBy = adminService.findOperatorOrUnknown(store.updatedBy) - return AuditInfo( + return AuditingInfo( createdAt = store.createdAt, createdBy = createdBy, updatedAt = store.updatedAt, diff --git a/src/main/kotlin/roomescape/store/business/StoreValidator.kt b/service/src/main/kotlin/com/sangdol/roomescape/store/business/StoreValidator.kt similarity index 85% rename from src/main/kotlin/roomescape/store/business/StoreValidator.kt rename to service/src/main/kotlin/com/sangdol/roomescape/store/business/StoreValidator.kt index 01ce5471..cd1f3f69 100644 --- a/src/main/kotlin/roomescape/store/business/StoreValidator.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/store/business/StoreValidator.kt @@ -1,13 +1,13 @@ -package roomescape.store.business +package com.sangdol.roomescape.store.business import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.stereotype.Component -import roomescape.store.exception.StoreErrorCode -import roomescape.store.exception.StoreException -import roomescape.store.infrastructure.persistence.StoreRepository -import roomescape.store.web.StoreRegisterRequest -import roomescape.store.web.StoreUpdateRequest +import com.sangdol.roomescape.store.exception.StoreErrorCode +import com.sangdol.roomescape.store.exception.StoreException +import com.sangdol.roomescape.store.infrastructure.persistence.StoreRepository +import com.sangdol.roomescape.store.web.StoreRegisterRequest +import com.sangdol.roomescape.store.web.StoreUpdateRequest private val log: KLogger = KotlinLogging.logger {} diff --git a/src/main/kotlin/roomescape/store/docs/StoreAPI.kt b/service/src/main/kotlin/com/sangdol/roomescape/store/docs/StoreAPI.kt similarity index 85% rename from src/main/kotlin/roomescape/store/docs/StoreAPI.kt rename to service/src/main/kotlin/com/sangdol/roomescape/store/docs/StoreAPI.kt index 3008582b..20e93eb9 100644 --- a/src/main/kotlin/roomescape/store/docs/StoreAPI.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/store/docs/StoreAPI.kt @@ -1,5 +1,11 @@ -package roomescape.store.docs +package com.sangdol.roomescape.store.docs +import com.sangdol.common.types.web.CommonApiResponse +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminType +import com.sangdol.roomescape.admin.infrastructure.persistence.Privilege +import com.sangdol.roomescape.auth.web.support.AdminOnly +import com.sangdol.roomescape.auth.web.support.Public +import com.sangdol.roomescape.store.web.* import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.responses.ApiResponses @@ -8,12 +14,6 @@ import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestParam -import roomescape.admin.infrastructure.persistence.AdminType -import roomescape.admin.infrastructure.persistence.Privilege -import roomescape.auth.web.support.AdminOnly -import roomescape.auth.web.support.Public -import roomescape.common.dto.response.CommonApiResponse -import roomescape.store.web.* interface AdminStoreAPI { @AdminOnly(type = AdminType.HQ, privilege = Privilege.READ_DETAIL) diff --git a/src/main/kotlin/roomescape/store/exception/StoreException.kt b/service/src/main/kotlin/com/sangdol/roomescape/store/exception/StoreException.kt similarity index 82% rename from src/main/kotlin/roomescape/store/exception/StoreException.kt rename to service/src/main/kotlin/com/sangdol/roomescape/store/exception/StoreException.kt index 0416e6cc..fad3d383 100644 --- a/src/main/kotlin/roomescape/store/exception/StoreException.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/store/exception/StoreException.kt @@ -1,8 +1,8 @@ -package roomescape.store.exception +package com.sangdol.roomescape.store.exception -import org.springframework.http.HttpStatus -import roomescape.common.exception.ErrorCode -import roomescape.common.exception.RoomescapeException +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.common.types.exception.ErrorCode +import com.sangdol.common.types.exception.RoomescapeException class StoreException( override val errorCode: StoreErrorCode, diff --git a/src/main/kotlin/roomescape/store/infrastructure/persistence/StoreEntity.kt b/service/src/main/kotlin/com/sangdol/roomescape/store/infrastructure/persistence/StoreEntity.kt similarity index 88% rename from src/main/kotlin/roomescape/store/infrastructure/persistence/StoreEntity.kt rename to service/src/main/kotlin/com/sangdol/roomescape/store/infrastructure/persistence/StoreEntity.kt index d59ce007..83c851f1 100644 --- a/src/main/kotlin/roomescape/store/infrastructure/persistence/StoreEntity.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/store/infrastructure/persistence/StoreEntity.kt @@ -1,8 +1,8 @@ -package roomescape.store.infrastructure.persistence +package com.sangdol.roomescape.store.infrastructure.persistence +import com.sangdol.common.persistence.AuditingBaseEntity import jakarta.persistence.* import org.springframework.data.jpa.domain.support.AuditingEntityListener -import roomescape.common.entity.AuditingBaseEntity @Entity @EntityListeners(AuditingEntityListener::class) diff --git a/src/main/kotlin/roomescape/store/infrastructure/persistence/StoreRepository.kt b/service/src/main/kotlin/com/sangdol/roomescape/store/infrastructure/persistence/StoreRepository.kt similarity index 76% rename from src/main/kotlin/roomescape/store/infrastructure/persistence/StoreRepository.kt rename to service/src/main/kotlin/com/sangdol/roomescape/store/infrastructure/persistence/StoreRepository.kt index eff522bf..efbfa350 100644 --- a/src/main/kotlin/roomescape/store/infrastructure/persistence/StoreRepository.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/store/infrastructure/persistence/StoreRepository.kt @@ -1,4 +1,4 @@ -package roomescape.store.infrastructure.persistence +package com.sangdol.roomescape.store.infrastructure.persistence import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.Query @@ -13,7 +13,7 @@ interface StoreRepository : JpaRepository { StoreEntity s WHERE s._id = :id - AND s.status = roomescape.store.infrastructure.persistence.StoreStatus.ACTIVE + AND s.status = com.sangdol.roomescape.store.infrastructure.persistence.StoreStatus.ACTIVE """ ) fun findActiveStoreById(id: Long): StoreEntity? @@ -25,7 +25,7 @@ interface StoreRepository : JpaRepository { FROM StoreEntity s WHERE - s.status = roomescape.store.infrastructure.persistence.StoreStatus.ACTIVE + s.status = com.sangdol.roomescape.store.infrastructure.persistence.StoreStatus.ACTIVE AND (:regionCode IS NULL OR s.regionCode LIKE :regionCode%) """ ) diff --git a/src/main/kotlin/roomescape/store/web/AdminStoreController.kt b/service/src/main/kotlin/com/sangdol/roomescape/store/web/AdminStoreController.kt similarity index 87% rename from src/main/kotlin/roomescape/store/web/AdminStoreController.kt rename to service/src/main/kotlin/com/sangdol/roomescape/store/web/AdminStoreController.kt index 4fd1d077..f609043b 100644 --- a/src/main/kotlin/roomescape/store/web/AdminStoreController.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/store/web/AdminStoreController.kt @@ -1,11 +1,11 @@ -package roomescape.store.web +package com.sangdol.roomescape.store.web +import com.sangdol.common.types.web.CommonApiResponse +import com.sangdol.roomescape.store.business.StoreService +import com.sangdol.roomescape.store.docs.AdminStoreAPI import jakarta.validation.Valid import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* -import roomescape.common.dto.response.CommonApiResponse -import roomescape.store.business.StoreService -import roomescape.store.docs.AdminStoreAPI @RestController @RequestMapping("/admin/stores") diff --git a/src/main/kotlin/roomescape/store/web/AdminStoreDto.kt b/service/src/main/kotlin/com/sangdol/roomescape/store/web/AdminStoreDto.kt similarity index 74% rename from src/main/kotlin/roomescape/store/web/AdminStoreDto.kt rename to service/src/main/kotlin/com/sangdol/roomescape/store/web/AdminStoreDto.kt index 62003695..193e719b 100644 --- a/src/main/kotlin/roomescape/store/web/AdminStoreDto.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/store/web/AdminStoreDto.kt @@ -1,8 +1,8 @@ -package roomescape.store.web +package com.sangdol.roomescape.store.web -import roomescape.common.dto.AuditInfo -import roomescape.region.web.RegionInfoResponse -import roomescape.store.infrastructure.persistence.StoreEntity +import com.sangdol.roomescape.common.types.AuditingInfo +import com.sangdol.roomescape.region.web.RegionInfoResponse +import com.sangdol.roomescape.store.infrastructure.persistence.StoreEntity data class StoreRegisterRequest( val name: String, @@ -29,12 +29,12 @@ data class DetailStoreResponse( val contact: String, val businessRegNum: String, val region: RegionInfoResponse, - val audit: AuditInfo + val audit: AuditingInfo ) fun StoreEntity.toDetailResponse( region: RegionInfoResponse, - audit: AuditInfo + audit: AuditingInfo ) = DetailStoreResponse( id = this.id, name = this.name, diff --git a/src/main/kotlin/roomescape/store/web/StoreController.kt b/service/src/main/kotlin/com/sangdol/roomescape/store/web/StoreController.kt similarity index 84% rename from src/main/kotlin/roomescape/store/web/StoreController.kt rename to service/src/main/kotlin/com/sangdol/roomescape/store/web/StoreController.kt index 47a3937c..5afac648 100644 --- a/src/main/kotlin/roomescape/store/web/StoreController.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/store/web/StoreController.kt @@ -1,13 +1,13 @@ -package roomescape.store.web +package com.sangdol.roomescape.store.web +import com.sangdol.common.types.web.CommonApiResponse +import com.sangdol.roomescape.store.business.StoreService +import com.sangdol.roomescape.store.docs.PublicStoreAPI import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController -import roomescape.common.dto.response.CommonApiResponse -import roomescape.store.business.StoreService -import roomescape.store.docs.PublicStoreAPI @RestController class StoreController( diff --git a/src/main/kotlin/roomescape/store/web/StoreDTO.kt b/service/src/main/kotlin/com/sangdol/roomescape/store/web/StoreDTO.kt similarity index 84% rename from src/main/kotlin/roomescape/store/web/StoreDTO.kt rename to service/src/main/kotlin/com/sangdol/roomescape/store/web/StoreDTO.kt index cad9201e..0e6e3934 100644 --- a/src/main/kotlin/roomescape/store/web/StoreDTO.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/store/web/StoreDTO.kt @@ -1,6 +1,6 @@ -package roomescape.store.web +package com.sangdol.roomescape.store.web -import roomescape.store.infrastructure.persistence.StoreEntity +import com.sangdol.roomescape.store.infrastructure.persistence.StoreEntity data class SimpleStoreResponse( val id: Long, diff --git a/src/main/kotlin/roomescape/common/util/DateUtils.kt b/service/src/main/kotlin/com/sangdol/roomescape/theme/business/DateUtils.kt similarity index 85% rename from src/main/kotlin/roomescape/common/util/DateUtils.kt rename to service/src/main/kotlin/com/sangdol/roomescape/theme/business/DateUtils.kt index 4ad16583..1a0ba300 100644 --- a/src/main/kotlin/roomescape/common/util/DateUtils.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/theme/business/DateUtils.kt @@ -1,4 +1,4 @@ -package roomescape.common.util +package com.sangdol.roomescape.theme.business import java.time.DayOfWeek import java.time.LocalDate diff --git a/src/main/kotlin/roomescape/theme/business/ThemeService.kt b/service/src/main/kotlin/com/sangdol/roomescape/theme/business/ThemeService.kt similarity index 89% rename from src/main/kotlin/roomescape/theme/business/ThemeService.kt rename to service/src/main/kotlin/com/sangdol/roomescape/theme/business/ThemeService.kt index a290fa78..5cf3b4ea 100644 --- a/src/main/kotlin/roomescape/theme/business/ThemeService.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/theme/business/ThemeService.kt @@ -1,20 +1,18 @@ -package roomescape.theme.business +package com.sangdol.roomescape.theme.business -import com.github.f4b6a3.tsid.TsidFactory +import com.sangdol.common.persistence.IDGenerator +import com.sangdol.roomescape.common.types.AuditingInfo +import com.sangdol.roomescape.admin.business.AdminService +import com.sangdol.roomescape.theme.exception.ThemeErrorCode +import com.sangdol.roomescape.theme.exception.ThemeException +import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeEntity +import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeRepository +import com.sangdol.roomescape.theme.web.* import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional -import roomescape.admin.business.AdminService -import roomescape.common.config.next -import roomescape.common.dto.AuditInfo -import roomescape.common.util.DateUtils -import roomescape.theme.exception.ThemeErrorCode -import roomescape.theme.exception.ThemeException -import roomescape.theme.infrastructure.persistence.ThemeEntity -import roomescape.theme.infrastructure.persistence.ThemeRepository -import roomescape.theme.web.* import java.time.LocalDate private val log: KLogger = KotlinLogging.logger {} @@ -30,7 +28,7 @@ private val log: KLogger = KotlinLogging.logger {} class ThemeService( private val themeRepository: ThemeRepository, private val themeValidator: ThemeValidator, - private val tsidFactory: TsidFactory, + private val idGenerator: IDGenerator, private val adminService: AdminService ) { // ======================================== @@ -79,7 +77,7 @@ class ThemeService( val createdBy = adminService.findOperatorOrUnknown(theme.createdBy) val updatedBy = adminService.findOperatorOrUnknown(theme.updatedBy) - val audit = AuditInfo(theme.createdAt, createdBy, theme.updatedAt, updatedBy) + val audit = AuditingInfo(theme.createdAt, createdBy, theme.updatedAt, updatedBy) return theme.toAdminThemeDetailResponse(audit) .also { log.info { "[ThemeService.findAdminThemeDetail] 테마 상세 조회 완료: id=$id, name=${theme.name}" } } @@ -91,7 +89,7 @@ class ThemeService( themeValidator.validateCanCreate(request) - val theme: ThemeEntity = request.toEntity(id = tsidFactory.next()) + val theme: ThemeEntity = request.toEntity(id = idGenerator.create()) .also { themeRepository.save(it) } return ThemeCreateResponse(theme.id).also { diff --git a/src/main/kotlin/roomescape/theme/business/ThemeValidator.kt b/service/src/main/kotlin/com/sangdol/roomescape/theme/business/ThemeValidator.kt similarity index 92% rename from src/main/kotlin/roomescape/theme/business/ThemeValidator.kt rename to service/src/main/kotlin/com/sangdol/roomescape/theme/business/ThemeValidator.kt index 6de7e205..8d5b341f 100644 --- a/src/main/kotlin/roomescape/theme/business/ThemeValidator.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/theme/business/ThemeValidator.kt @@ -1,13 +1,13 @@ -package roomescape.theme.business +package com.sangdol.roomescape.theme.business import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.stereotype.Component -import roomescape.theme.exception.ThemeErrorCode -import roomescape.theme.exception.ThemeException -import roomescape.theme.infrastructure.persistence.ThemeRepository -import roomescape.theme.web.ThemeCreateRequest -import roomescape.theme.web.ThemeUpdateRequest +import com.sangdol.roomescape.theme.exception.ThemeErrorCode +import com.sangdol.roomescape.theme.exception.ThemeException +import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeRepository +import com.sangdol.roomescape.theme.web.ThemeCreateRequest +import com.sangdol.roomescape.theme.web.ThemeUpdateRequest private val log: KLogger = KotlinLogging.logger {} diff --git a/src/main/kotlin/roomescape/theme/business/domain/ThemeInfo.kt b/service/src/main/kotlin/com/sangdol/roomescape/theme/business/domain/ThemeInfo.kt similarity index 86% rename from src/main/kotlin/roomescape/theme/business/domain/ThemeInfo.kt rename to service/src/main/kotlin/com/sangdol/roomescape/theme/business/domain/ThemeInfo.kt index 9406f6b4..cf69fdd0 100644 --- a/src/main/kotlin/roomescape/theme/business/domain/ThemeInfo.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/theme/business/domain/ThemeInfo.kt @@ -1,4 +1,4 @@ -package roomescape.theme.business.domain +package com.sangdol.roomescape.theme.business.domain class ThemeInfo( val id: Long, diff --git a/src/main/kotlin/roomescape/theme/docs/ThemeApi.kt b/service/src/main/kotlin/com/sangdol/roomescape/theme/docs/ThemeApi.kt similarity index 88% rename from src/main/kotlin/roomescape/theme/docs/ThemeApi.kt rename to service/src/main/kotlin/com/sangdol/roomescape/theme/docs/ThemeApi.kt index 82163cc6..14acfd0c 100644 --- a/src/main/kotlin/roomescape/theme/docs/ThemeApi.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/theme/docs/ThemeApi.kt @@ -1,5 +1,11 @@ -package roomescape.theme.docs +package com.sangdol.roomescape.theme.docs +import com.sangdol.common.types.web.CommonApiResponse +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminType +import com.sangdol.roomescape.admin.infrastructure.persistence.Privilege +import com.sangdol.roomescape.auth.web.support.AdminOnly +import com.sangdol.roomescape.auth.web.support.Public +import com.sangdol.roomescape.theme.web.* import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.responses.ApiResponses @@ -9,12 +15,6 @@ import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestParam -import roomescape.admin.infrastructure.persistence.AdminType -import roomescape.admin.infrastructure.persistence.Privilege -import roomescape.auth.web.support.AdminOnly -import roomescape.auth.web.support.Public -import roomescape.common.dto.response.CommonApiResponse -import roomescape.theme.web.* interface AdminThemeAPI { @AdminOnly(type = AdminType.HQ, privilege = Privilege.READ_SUMMARY) diff --git a/src/main/kotlin/roomescape/theme/exception/ThemeErrorCode.kt b/service/src/main/kotlin/com/sangdol/roomescape/theme/exception/ThemeErrorCode.kt similarity index 89% rename from src/main/kotlin/roomescape/theme/exception/ThemeErrorCode.kt rename to service/src/main/kotlin/com/sangdol/roomescape/theme/exception/ThemeErrorCode.kt index fe0bc8c8..03673549 100644 --- a/src/main/kotlin/roomescape/theme/exception/ThemeErrorCode.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/theme/exception/ThemeErrorCode.kt @@ -1,7 +1,7 @@ -package roomescape.theme.exception +package com.sangdol.roomescape.theme.exception -import org.springframework.http.HttpStatus -import roomescape.common.exception.ErrorCode +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.common.types.exception.ErrorCode enum class ThemeErrorCode( override val httpStatus: HttpStatus, diff --git a/src/main/kotlin/roomescape/theme/exception/ThemeException.kt b/service/src/main/kotlin/com/sangdol/roomescape/theme/exception/ThemeException.kt similarity index 60% rename from src/main/kotlin/roomescape/theme/exception/ThemeException.kt rename to service/src/main/kotlin/com/sangdol/roomescape/theme/exception/ThemeException.kt index 220a97c7..594fc212 100644 --- a/src/main/kotlin/roomescape/theme/exception/ThemeException.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/theme/exception/ThemeException.kt @@ -1,6 +1,6 @@ -package roomescape.theme.exception +package com.sangdol.roomescape.theme.exception -import roomescape.common.exception.RoomescapeException +import com.sangdol.common.types.exception.RoomescapeException class ThemeException( override val errorCode: ThemeErrorCode, diff --git a/src/main/kotlin/roomescape/theme/infrastructure/persistence/ThemeEntity.kt b/service/src/main/kotlin/com/sangdol/roomescape/theme/infrastructure/persistence/ThemeEntity.kt similarity index 92% rename from src/main/kotlin/roomescape/theme/infrastructure/persistence/ThemeEntity.kt rename to service/src/main/kotlin/com/sangdol/roomescape/theme/infrastructure/persistence/ThemeEntity.kt index 989b9a64..730987c2 100644 --- a/src/main/kotlin/roomescape/theme/infrastructure/persistence/ThemeEntity.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/theme/infrastructure/persistence/ThemeEntity.kt @@ -1,7 +1,7 @@ -package roomescape.theme.infrastructure.persistence +package com.sangdol.roomescape.theme.infrastructure.persistence +import com.sangdol.common.persistence.AuditingBaseEntity import jakarta.persistence.* -import roomescape.common.entity.AuditingBaseEntity @Entity @Table(name = "theme") diff --git a/src/main/kotlin/roomescape/theme/infrastructure/persistence/ThemeRepository.kt b/service/src/main/kotlin/com/sangdol/roomescape/theme/infrastructure/persistence/ThemeRepository.kt similarity index 92% rename from src/main/kotlin/roomescape/theme/infrastructure/persistence/ThemeRepository.kt rename to service/src/main/kotlin/com/sangdol/roomescape/theme/infrastructure/persistence/ThemeRepository.kt index 29db0b47..644f84b6 100644 --- a/src/main/kotlin/roomescape/theme/infrastructure/persistence/ThemeRepository.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/theme/infrastructure/persistence/ThemeRepository.kt @@ -1,8 +1,8 @@ -package roomescape.theme.infrastructure.persistence +package com.sangdol.roomescape.theme.infrastructure.persistence import org.springframework.data.jpa.repository.JpaRepository import org.springframework.data.jpa.repository.Query -import roomescape.theme.business.domain.ThemeInfo +import com.sangdol.roomescape.theme.business.domain.ThemeInfo import java.time.LocalDate interface ThemeRepository : JpaRepository { diff --git a/src/main/kotlin/roomescape/theme/web/AdminThemeController.kt b/service/src/main/kotlin/com/sangdol/roomescape/theme/web/AdminThemeController.kt similarity index 90% rename from src/main/kotlin/roomescape/theme/web/AdminThemeController.kt rename to service/src/main/kotlin/com/sangdol/roomescape/theme/web/AdminThemeController.kt index b79004a2..3a5f6375 100644 --- a/src/main/kotlin/roomescape/theme/web/AdminThemeController.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/theme/web/AdminThemeController.kt @@ -1,11 +1,11 @@ -package roomescape.theme.web +package com.sangdol.roomescape.theme.web +import com.sangdol.common.types.web.CommonApiResponse +import com.sangdol.roomescape.theme.business.ThemeService +import com.sangdol.roomescape.theme.docs.AdminThemeAPI import jakarta.validation.Valid import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* -import roomescape.common.dto.response.CommonApiResponse -import roomescape.theme.business.ThemeService -import roomescape.theme.docs.AdminThemeAPI import java.net.URI @RestController diff --git a/src/main/kotlin/roomescape/theme/web/AdminThemeDto.kt b/service/src/main/kotlin/com/sangdol/roomescape/theme/web/AdminThemeDto.kt similarity index 90% rename from src/main/kotlin/roomescape/theme/web/AdminThemeDto.kt rename to service/src/main/kotlin/com/sangdol/roomescape/theme/web/AdminThemeDto.kt index 9b6be3ac..94c5a195 100644 --- a/src/main/kotlin/roomescape/theme/web/AdminThemeDto.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/theme/web/AdminThemeDto.kt @@ -1,8 +1,8 @@ -package roomescape.theme.web +package com.sangdol.roomescape.theme.web -import roomescape.common.dto.AuditInfo -import roomescape.theme.infrastructure.persistence.Difficulty -import roomescape.theme.infrastructure.persistence.ThemeEntity +import com.sangdol.roomescape.common.types.AuditingInfo +import com.sangdol.roomescape.theme.infrastructure.persistence.Difficulty +import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeEntity // ======================================== // HQ Admin DTO (본사) @@ -95,10 +95,10 @@ fun List.toAdminThemeSummaryListResponse() = AdminThemeSummaryListR data class AdminThemeDetailResponse( val theme: ThemeInfoResponse, val isActive: Boolean, - val audit: AuditInfo + val audit: AuditingInfo ) -fun ThemeEntity.toAdminThemeDetailResponse(audit: AuditInfo) = +fun ThemeEntity.toAdminThemeDetailResponse(audit: AuditingInfo) = AdminThemeDetailResponse( theme = this.toInfoResponse(), isActive = this.isActive, diff --git a/src/main/kotlin/roomescape/theme/web/ThemeController.kt b/service/src/main/kotlin/com/sangdol/roomescape/theme/web/ThemeController.kt similarity index 79% rename from src/main/kotlin/roomescape/theme/web/ThemeController.kt rename to service/src/main/kotlin/com/sangdol/roomescape/theme/web/ThemeController.kt index 8d67ea28..f68e341c 100644 --- a/src/main/kotlin/roomescape/theme/web/ThemeController.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/theme/web/ThemeController.kt @@ -1,10 +1,10 @@ -package roomescape.theme.web +package com.sangdol.roomescape.theme.web +import com.sangdol.common.types.web.CommonApiResponse +import com.sangdol.roomescape.theme.business.ThemeService +import com.sangdol.roomescape.theme.docs.PublicThemeAPI import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* -import roomescape.common.dto.response.CommonApiResponse -import roomescape.theme.business.ThemeService -import roomescape.theme.docs.PublicThemeAPI @RestController @RequestMapping("/themes") diff --git a/src/main/kotlin/roomescape/theme/web/ThemeDto.kt b/service/src/main/kotlin/com/sangdol/roomescape/theme/web/ThemeDto.kt similarity index 87% rename from src/main/kotlin/roomescape/theme/web/ThemeDto.kt rename to service/src/main/kotlin/com/sangdol/roomescape/theme/web/ThemeDto.kt index 9befc770..46463d38 100644 --- a/src/main/kotlin/roomescape/theme/web/ThemeDto.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/theme/web/ThemeDto.kt @@ -1,11 +1,7 @@ -package roomescape.theme.web +package com.sangdol.roomescape.theme.web -import roomescape.theme.business.domain.ThemeInfo -import roomescape.theme.infrastructure.persistence.ThemeEntity - -data class ThemeIdListRequest( - val themeIds: List -) +import com.sangdol.roomescape.theme.business.domain.ThemeInfo +import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeEntity data class ThemeInfoResponse( val id: Long, diff --git a/src/main/kotlin/roomescape/user/business/UserService.kt b/service/src/main/kotlin/com/sangdol/roomescape/user/business/UserService.kt similarity index 77% rename from src/main/kotlin/roomescape/user/business/UserService.kt rename to service/src/main/kotlin/com/sangdol/roomescape/user/business/UserService.kt index 627cbc54..7aa00234 100644 --- a/src/main/kotlin/roomescape/user/business/UserService.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/user/business/UserService.kt @@ -1,22 +1,21 @@ -package roomescape.user.business +package com.sangdol.roomescape.user.business -import com.github.f4b6a3.tsid.TsidFactory +import com.sangdol.common.persistence.IDGenerator +import com.sangdol.roomescape.common.types.CurrentUserContext +import com.sangdol.roomescape.user.business.dto.UserLoginCredentials +import com.sangdol.roomescape.user.business.dto.toCredentials +import com.sangdol.roomescape.user.exception.UserErrorCode +import com.sangdol.roomescape.user.exception.UserException +import com.sangdol.roomescape.user.infrastructure.persistence.* +import com.sangdol.roomescape.user.web.UserContactResponse +import com.sangdol.roomescape.user.web.UserCreateRequest +import com.sangdol.roomescape.user.web.UserCreateResponse +import com.sangdol.roomescape.user.web.toEntity import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional -import roomescape.common.config.next -import roomescape.common.dto.CurrentUserContext -import roomescape.common.dto.UserLoginCredentials -import roomescape.common.dto.toCredentials -import roomescape.user.exception.UserErrorCode -import roomescape.user.exception.UserException -import roomescape.user.infrastructure.persistence.* -import roomescape.user.web.UserContactResponse -import roomescape.user.web.UserCreateRequest -import roomescape.user.web.UserCreateResponse -import roomescape.user.web.toEntity private val log: KLogger = KotlinLogging.logger {} @@ -27,7 +26,7 @@ class UserService( private val userRepository: UserRepository, private val userStatusHistoryRepository: UserStatusHistoryRepository, private val userValidator: UserValidator, - private val tsidFactory: TsidFactory + private val idGenerator: IDGenerator ) { @Transactional(readOnly = true) fun findContextById(id: Long): CurrentUserContext { @@ -74,7 +73,7 @@ class UserService( userValidator.validateCanSignup(request.email, request.phone) val user: UserEntity = userRepository.save( - request.toEntity(id = tsidFactory.next(), status = UserStatus.ACTIVE) + request.toEntity(id = idGenerator.create(), status = UserStatus.ACTIVE) ).also { log.info { "[UserService.signup] 회원 저장 완료: id:${it.id}" } }.also { @@ -94,7 +93,7 @@ class UserService( private fun createHistory(user: UserEntity, reason: String): UserStatusHistoryEntity { return userStatusHistoryRepository.save( - UserStatusHistoryEntity(id = tsidFactory.next(), userId = user.id, reason = reason, status = user.status) + UserStatusHistoryEntity(id = idGenerator.create(), userId = user.id, reason = reason, status = user.status) ).also { log.info { "[UserService.signup] 회원 상태 이력 저장 완료: userStatusHistoryId:${it.id}" } } diff --git a/src/main/kotlin/roomescape/user/business/UserValidator.kt b/service/src/main/kotlin/com/sangdol/roomescape/user/business/UserValidator.kt similarity index 80% rename from src/main/kotlin/roomescape/user/business/UserValidator.kt rename to service/src/main/kotlin/com/sangdol/roomescape/user/business/UserValidator.kt index 8e8d8cce..400ff17d 100644 --- a/src/main/kotlin/roomescape/user/business/UserValidator.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/user/business/UserValidator.kt @@ -1,11 +1,11 @@ -package roomescape.user.business +package com.sangdol.roomescape.user.business import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KotlinLogging import org.springframework.stereotype.Component -import roomescape.user.exception.UserErrorCode -import roomescape.user.exception.UserException -import roomescape.user.infrastructure.persistence.UserRepository +import com.sangdol.roomescape.user.exception.UserErrorCode +import com.sangdol.roomescape.user.exception.UserException +import com.sangdol.roomescape.user.infrastructure.persistence.UserRepository private val log: KLogger = KotlinLogging.logger {} diff --git a/service/src/main/kotlin/com/sangdol/roomescape/user/business/dto/UserLoginDTO.kt b/service/src/main/kotlin/com/sangdol/roomescape/user/business/dto/UserLoginDTO.kt new file mode 100644 index 00000000..deb3dc6e --- /dev/null +++ b/service/src/main/kotlin/com/sangdol/roomescape/user/business/dto/UserLoginDTO.kt @@ -0,0 +1,27 @@ +package com.sangdol.roomescape.user.business.dto + +import com.sangdol.roomescape.auth.web.LoginCredentials +import com.sangdol.roomescape.auth.web.LoginSuccessResponse +import com.sangdol.roomescape.user.infrastructure.persistence.UserEntity + +data class UserLoginCredentials( + override val id: Long, + override val password: String, + override val name: String, +) : LoginCredentials() { + override fun toResponse(accessToken: String) = UserLoginSuccessResponse( + accessToken = accessToken, + name = name + ) +} + +fun UserEntity.toCredentials() = UserLoginCredentials( + id = this.id, + password = this.password, + name = this.name, +) + +data class UserLoginSuccessResponse( + override val accessToken: String, + override val name: String, +) : LoginSuccessResponse() \ No newline at end of file diff --git a/src/main/kotlin/roomescape/user/docs/UserAPI.kt b/service/src/main/kotlin/com/sangdol/roomescape/user/docs/UserAPI.kt similarity index 66% rename from src/main/kotlin/roomescape/user/docs/UserAPI.kt rename to service/src/main/kotlin/com/sangdol/roomescape/user/docs/UserAPI.kt index e809296d..6e3d116d 100644 --- a/src/main/kotlin/roomescape/user/docs/UserAPI.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/user/docs/UserAPI.kt @@ -1,18 +1,18 @@ -package roomescape.user.docs +package com.sangdol.roomescape.user.docs +import com.sangdol.common.types.web.CommonApiResponse +import com.sangdol.roomescape.auth.web.support.Public +import com.sangdol.roomescape.auth.web.support.User +import com.sangdol.roomescape.common.types.CurrentUserContext +import com.sangdol.roomescape.user.web.UserContactResponse +import com.sangdol.roomescape.user.web.UserCreateRequest +import com.sangdol.roomescape.user.web.UserCreateResponse import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.responses.ApiResponses import jakarta.validation.Valid import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.RequestBody -import roomescape.auth.web.support.Public -import roomescape.auth.web.support.User -import roomescape.common.dto.CurrentUserContext -import roomescape.common.dto.response.CommonApiResponse -import roomescape.user.web.UserContactResponse -import roomescape.user.web.UserCreateRequest -import roomescape.user.web.UserCreateResponse interface UserAPI { diff --git a/src/main/kotlin/roomescape/user/exception/UserException.kt b/service/src/main/kotlin/com/sangdol/roomescape/user/exception/UserException.kt similarity index 74% rename from src/main/kotlin/roomescape/user/exception/UserException.kt rename to service/src/main/kotlin/com/sangdol/roomescape/user/exception/UserException.kt index 5f44f515..05f4963a 100644 --- a/src/main/kotlin/roomescape/user/exception/UserException.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/user/exception/UserException.kt @@ -1,8 +1,8 @@ -package roomescape.user.exception +package com.sangdol.roomescape.user.exception -import org.springframework.http.HttpStatus -import roomescape.common.exception.ErrorCode -import roomescape.common.exception.RoomescapeException +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.common.types.exception.ErrorCode +import com.sangdol.common.types.exception.RoomescapeException class UserException( override val errorCode: UserErrorCode, diff --git a/src/main/kotlin/roomescape/user/infrastructure/persistence/UserEntities.kt b/service/src/main/kotlin/com/sangdol/roomescape/user/infrastructure/persistence/UserEntities.kt similarity index 84% rename from src/main/kotlin/roomescape/user/infrastructure/persistence/UserEntities.kt rename to service/src/main/kotlin/com/sangdol/roomescape/user/infrastructure/persistence/UserEntities.kt index 420764a0..89d3c1fc 100644 --- a/src/main/kotlin/roomescape/user/infrastructure/persistence/UserEntities.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/user/infrastructure/persistence/UserEntities.kt @@ -1,7 +1,7 @@ -package roomescape.user.infrastructure.persistence +package com.sangdol.roomescape.user.infrastructure.persistence +import com.sangdol.common.persistence.AuditingBaseEntity import jakarta.persistence.* -import roomescape.common.entity.AuditingBaseEntity @Entity @Table(name = "users") diff --git a/src/main/kotlin/roomescape/user/infrastructure/persistence/UserRepositories.kt b/service/src/main/kotlin/com/sangdol/roomescape/user/infrastructure/persistence/UserRepositories.kt similarity index 84% rename from src/main/kotlin/roomescape/user/infrastructure/persistence/UserRepositories.kt rename to service/src/main/kotlin/com/sangdol/roomescape/user/infrastructure/persistence/UserRepositories.kt index 8095a090..f10272a9 100644 --- a/src/main/kotlin/roomescape/user/infrastructure/persistence/UserRepositories.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/user/infrastructure/persistence/UserRepositories.kt @@ -1,4 +1,4 @@ -package roomescape.user.infrastructure.persistence +package com.sangdol.roomescape.user.infrastructure.persistence import org.springframework.data.jpa.repository.JpaRepository diff --git a/src/main/kotlin/roomescape/user/web/UserController.kt b/service/src/main/kotlin/com/sangdol/roomescape/user/web/UserController.kt similarity index 72% rename from src/main/kotlin/roomescape/user/web/UserController.kt rename to service/src/main/kotlin/com/sangdol/roomescape/user/web/UserController.kt index 759e349e..097830ee 100644 --- a/src/main/kotlin/roomescape/user/web/UserController.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/user/web/UserController.kt @@ -1,13 +1,13 @@ -package roomescape.user.web +package com.sangdol.roomescape.user.web +import com.sangdol.common.types.web.CommonApiResponse +import com.sangdol.roomescape.auth.web.support.User +import com.sangdol.roomescape.common.types.CurrentUserContext +import com.sangdol.roomescape.user.business.UserService +import com.sangdol.roomescape.user.docs.UserAPI import jakarta.validation.Valid import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.* -import roomescape.auth.web.support.User -import roomescape.common.dto.CurrentUserContext -import roomescape.common.dto.response.CommonApiResponse -import roomescape.user.business.UserService -import roomescape.user.docs.UserAPI @RestController @RequestMapping("/users") diff --git a/src/main/kotlin/roomescape/user/web/UserDTO.kt b/service/src/main/kotlin/com/sangdol/roomescape/user/web/UserDTO.kt similarity index 83% rename from src/main/kotlin/roomescape/user/web/UserDTO.kt rename to service/src/main/kotlin/com/sangdol/roomescape/user/web/UserDTO.kt index bf193d5d..4e300475 100644 --- a/src/main/kotlin/roomescape/user/web/UserDTO.kt +++ b/service/src/main/kotlin/com/sangdol/roomescape/user/web/UserDTO.kt @@ -1,11 +1,11 @@ -package roomescape.user.web +package com.sangdol.roomescape.user.web import jakarta.validation.constraints.Email import jakarta.validation.constraints.NotEmpty import jakarta.validation.constraints.Pattern import jakarta.validation.constraints.Size -import roomescape.user.infrastructure.persistence.UserEntity -import roomescape.user.infrastructure.persistence.UserStatus +import com.sangdol.roomescape.user.infrastructure.persistence.UserEntity +import com.sangdol.roomescape.user.infrastructure.persistence.UserStatus const val MIN_PASSWORD_LENGTH = 8 diff --git a/src/main/resources/application-deploy.yaml b/service/src/main/resources/application-deploy.yaml similarity index 100% rename from src/main/resources/application-deploy.yaml rename to service/src/main/resources/application-deploy.yaml diff --git a/src/main/resources/application-local.yaml b/service/src/main/resources/application-local.yaml similarity index 100% rename from src/main/resources/application-local.yaml rename to service/src/main/resources/application-local.yaml diff --git a/src/main/resources/application.yaml b/service/src/main/resources/application.yaml similarity index 100% rename from src/main/resources/application.yaml rename to service/src/main/resources/application.yaml diff --git a/src/main/resources/logback-deploy.xml b/service/src/main/resources/logback-deploy.xml similarity index 97% rename from src/main/resources/logback-deploy.xml rename to service/src/main/resources/logback-deploy.xml index 662eea5e..ba0cf7f9 100644 --- a/src/main/resources/logback-deploy.xml +++ b/service/src/main/resources/logback-deploy.xml @@ -1,7 +1,7 @@ + class="com.sangdol.roomescape.common.config.RoomescapeLogMaskingConverter"/> diff --git a/src/main/resources/logback-local.xml b/service/src/main/resources/logback-local.xml similarity index 82% rename from src/main/resources/logback-local.xml rename to service/src/main/resources/logback-local.xml index 0c6eadb5..d920f7c0 100644 --- a/src/main/resources/logback-local.xml +++ b/service/src/main/resources/logback-local.xml @@ -1,7 +1,7 @@ + class="com.sangdol.roomescape.common.config.RoomescapeLogMaskingConverter"/> @@ -16,7 +16,7 @@ - + diff --git a/src/main/resources/logback-spring.xml b/service/src/main/resources/logback-spring.xml similarity index 100% rename from src/main/resources/logback-spring.xml rename to service/src/main/resources/logback-spring.xml diff --git a/src/main/resources/schema/region-data.sql b/service/src/main/resources/schema/region-data.sql similarity index 100% rename from src/main/resources/schema/region-data.sql rename to service/src/main/resources/schema/region-data.sql diff --git a/src/main/resources/schema/schema-h2.sql b/service/src/main/resources/schema/schema-h2.sql similarity index 100% rename from src/main/resources/schema/schema-h2.sql rename to service/src/main/resources/schema/schema-h2.sql diff --git a/src/main/resources/schema/schema-mysql.sql b/service/src/main/resources/schema/schema-mysql.sql similarity index 100% rename from src/main/resources/schema/schema-mysql.sql rename to service/src/main/resources/schema/schema-mysql.sql diff --git a/src/test/kotlin/roomescape/data/DefaultDataInitializer.kt b/service/src/test/kotlin/com/sangdol/data/DefaultDataInitializer.kt similarity index 93% rename from src/test/kotlin/roomescape/data/DefaultDataInitializer.kt rename to service/src/test/kotlin/com/sangdol/data/DefaultDataInitializer.kt index eed4c74d..04f7ab1c 100644 --- a/src/test/kotlin/roomescape/data/DefaultDataInitializer.kt +++ b/service/src/test/kotlin/com/sangdol/data/DefaultDataInitializer.kt @@ -1,6 +1,22 @@ -package roomescape.data +package com.sangdol.data -import com.github.f4b6a3.tsid.TsidFactory +import com.sangdol.common.persistence.IDGenerator +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminEntity +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminPermissionLevel +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminType +import com.sangdol.common.persistence.TransactionExecutionUtil +import com.sangdol.roomescape.payment.infrastructure.common.* +import com.sangdol.roomescape.reservation.infrastructure.persistence.ReservationStatus +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus +import com.sangdol.roomescape.supports.AdminFixture +import com.sangdol.roomescape.supports.FunSpecSpringbootTest +import com.sangdol.roomescape.supports.randomPhoneNumber +import com.sangdol.roomescape.supports.randomString +import com.sangdol.roomescape.theme.infrastructure.persistence.Difficulty +import com.sangdol.roomescape.user.business.SIGNUP +import com.sangdol.roomescape.user.infrastructure.persistence.UserEntity +import com.sangdol.roomescape.user.infrastructure.persistence.UserStatus +import com.sangdol.roomescape.user.web.UserContactResponse import io.kotest.core.test.TestCaseOrder import jakarta.persistence.EntityManager import kotlinx.coroutines.Dispatchers @@ -11,23 +27,6 @@ import kotlinx.coroutines.sync.Semaphore import org.springframework.beans.factory.annotation.Autowired import org.springframework.jdbc.core.JdbcTemplate import org.springframework.test.context.ActiveProfiles -import roomescape.admin.infrastructure.persistence.AdminEntity -import roomescape.admin.infrastructure.persistence.AdminPermissionLevel -import roomescape.admin.infrastructure.persistence.AdminType -import roomescape.common.config.next -import roomescape.common.util.TransactionExecutionUtil -import roomescape.payment.infrastructure.common.* -import roomescape.reservation.infrastructure.persistence.ReservationStatus -import roomescape.schedule.infrastructure.persistence.ScheduleStatus -import roomescape.supports.AdminFixture -import roomescape.supports.FunSpecSpringbootTest -import roomescape.supports.randomPhoneNumber -import roomescape.supports.randomString -import roomescape.theme.infrastructure.persistence.Difficulty -import roomescape.user.business.SIGNUP -import roomescape.user.infrastructure.persistence.UserEntity -import roomescape.user.infrastructure.persistence.UserStatus -import roomescape.user.web.UserContactResponse import java.sql.Timestamp import java.time.LocalDateTime import java.time.LocalTime @@ -49,7 +48,7 @@ abstract class AbstractDataInitializer( lateinit var transactionExecutionUtil: TransactionExecutionUtil @Autowired - lateinit var tsidFactory: TsidFactory + lateinit var idGenerator: IDGenerator override fun testCaseOrder(): TestCaseOrder? = TestCaseOrder.Sequential @@ -136,7 +135,7 @@ class DefaultDataInitializer : AbstractDataInitializer() { listOf(AdminPermissionLevel.FULL_ACCESS, AdminPermissionLevel.WRITABLE) ) .resultList - }.map { it.toString() } + }!!.map { it.toString() } val sqlFile = storeDataInitializer.createStoreDataSqlFile(creatableAdminIds) @@ -157,7 +156,7 @@ class DefaultDataInitializer : AbstractDataInitializer() { "SELECT s.id FROM StoreEntity s", Long::class.java ).resultList - }.map { it as Long } + }!!.map { it as Long } transactionExecutionUtil.withNewTransaction(isReadOnly = false) { storeIds.forEach { storeId -> @@ -210,7 +209,7 @@ class DefaultDataInitializer : AbstractDataInitializer() { listOf(AdminPermissionLevel.FULL_ACCESS, AdminPermissionLevel.WRITABLE) ) .resultList - } + }!! val sql = "INSERT INTO theme (id, name, description, thumbnail_url, is_active, available_minutes, expected_minutes_from, expected_minutes_to, price, difficulty, min_participants, max_participants, created_at, created_by, updated_at, updated_by) VALUES (?," + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)" @@ -232,7 +231,7 @@ class DefaultDataInitializer : AbstractDataInitializer() { batchArgs.add( arrayOf( - tsidFactory.next(), + idGenerator.create(), randomThemeName, "$randomThemeName 설명이에요!!", "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRFiuCdwdz88l6pdfsRy1nFl0IHUVI7JMTQHg&s", @@ -271,7 +270,7 @@ class UserDataInitializer : AbstractDataInitializer() { "SELECT r.code FROM RegionEntity r", String::class.java ).resultList - } + }!! val chunkSize = 10_000 val chunks = userCount / chunkSize @@ -300,7 +299,7 @@ class UserDataInitializer : AbstractDataInitializer() { """.trimIndent(), UserEntity::class.java ).resultList - } + }!! jdbcTemplate.execute("CREATE INDEX idx_users__phone ON users (phone)") @@ -339,7 +338,7 @@ class UserDataInitializer : AbstractDataInitializer() { "SELECT u.id FROM UserEntity u", Long::class.java ).resultList - } + }!! coroutineScope { userId.chunked(10_000).map { chunk -> @@ -365,7 +364,7 @@ class UserDataInitializer : AbstractDataInitializer() { userIds.forEach { userId -> batchArgs.add( arrayOf( - tsidFactory.next(), + idGenerator.create(), userId, SIGNUP, UserStatus.ACTIVE.name, @@ -390,7 +389,7 @@ class UserDataInitializer : AbstractDataInitializer() { val batchArgs = mutableListOf>() repeat(chunkSize) { - val id: Long = tsidFactory.next() + val id: Long = idGenerator.create() batchArgs.add( arrayOf( id, @@ -470,7 +469,7 @@ class ScheduleDataInitializer : AbstractDataInitializer() { batchArgs.add( arrayOf( - tsidFactory.next(), storeId, theme.first, date, time, + idGenerator.create(), storeId, theme.first, date, time, status, adminId, adminId, Timestamp.valueOf(now), Timestamp.valueOf(now) ) ) @@ -495,7 +494,7 @@ class ScheduleDataInitializer : AbstractDataInitializer() { ).setParameter("type", AdminType.STORE) .setParameter("permissionLevel", AdminPermissionLevel.FULL_ACCESS) .resultList - }.map { + }!!.map { val array = it as List<*> Pair(array[0] as Long, array[1] as Long) } @@ -508,7 +507,7 @@ class ScheduleDataInitializer : AbstractDataInitializer() { List::class.java ) .resultList - }.map { + }!!.map { val array = it as List<*> Triple(array[0] as Long, array[1] as Short, array[2] as LocalDateTime) } @@ -532,12 +531,12 @@ class ReservationDataInitializer : AbstractDataInitializer() { val chunkSize = 10_000 val chunkedSchedules: List> = entityManager.createQuery( - "SELECT new roomescape.data.ScheduleWithThemeParticipants(s._id, t.minParticipants, t.maxParticipants) FROM ScheduleEntity s JOIN ThemeEntity t ON s.themeId = t.id WHERE s.status = :status", + "SELECT new com.sangdol.data.ScheduleWithThemeParticipants(s._id, t.minParticipants, t.maxParticipants) FROM ScheduleEntity s JOIN ThemeEntity t ON s.themeId = t.id WHERE s.status = :status", ScheduleWithThemeParticipants::class.java ).setParameter("status", ScheduleStatus.RESERVED).resultList.chunked(chunkSize) val chunkedUsers: List> = entityManager.createQuery( - "SELECT new roomescape.user.web.UserContactResponse(u._id, u.name, u.phone) FROM UserEntity u", + "SELECT new com.sangdol.roomescape.user.web.UserContactResponse(u._id, u.name, u.phone) FROM UserEntity u", UserContactResponse::class.java ).resultList.chunked(chunkSize) @@ -574,7 +573,7 @@ class ReservationDataInitializer : AbstractDataInitializer() { batchArgs.add( arrayOf( - tsidFactory.next(), + idGenerator.create(), user.id, schedule.scheduleId, user.name, @@ -682,7 +681,7 @@ class PaymentDataInitializer : AbstractDataInitializer() { test("기존 결제 데이터에 상세 정보(계좌이체, 카드, 간편결제) 데이터를 생성한다.") { val allPayments: List = entityManager.createQuery( - "SELECT new roomescape.data.PaymentWithMethods(pd._id, p.totalAmount, p.method) FROM PaymentEntity p JOIN PaymentDetailEntity pd ON p._id = pd.paymentId", + "SELECT new com.sangdol.data.PaymentWithMethods(pd._id, p.totalAmount, p.method) FROM PaymentEntity p JOIN PaymentDetailEntity pd ON p._id = pd.paymentId", PaymentWithMethods::class.java ).resultList @@ -716,7 +715,7 @@ class PaymentDataInitializer : AbstractDataInitializer() { val detailBatchArgs = mutableListOf>() reservations.forEachIndexed { idx, reservations -> - val id = tsidFactory.next() + val id = idGenerator.create() val totalPrice = reservations.totalPrice paymentBatchArgs.add( arrayOf( @@ -741,7 +740,7 @@ class PaymentDataInitializer : AbstractDataInitializer() { detailBatchArgs.add( arrayOf( - tsidFactory.next(), + idGenerator.create(), id, suppliedAmount, vat diff --git a/src/test/kotlin/roomescape/data/PopulationDataParser.kt b/service/src/test/kotlin/com/sangdol/data/PopulationDataParser.kt similarity index 94% rename from src/test/kotlin/roomescape/data/PopulationDataParser.kt rename to service/src/test/kotlin/com/sangdol/data/PopulationDataParser.kt index d511b234..516490ca 100644 --- a/src/test/kotlin/roomescape/data/PopulationDataParser.kt +++ b/service/src/test/kotlin/com/sangdol/data/PopulationDataParser.kt @@ -1,19 +1,18 @@ -package roomescape.data +package com.sangdol.data +import com.sangdol.roomescape.store.infrastructure.persistence.StoreStatus +import com.sangdol.roomescape.supports.IDGenerator +import com.sangdol.roomescape.supports.randomPhoneNumber import org.apache.poi.xssf.usermodel.XSSFWorkbook -import roomescape.common.config.next -import roomescape.store.infrastructure.persistence.StoreStatus -import roomescape.supports.randomPhoneNumber -import roomescape.supports.tsidFactory import java.io.File import java.time.LocalDateTime import java.time.ZoneId import java.time.format.DateTimeFormatter import kotlin.random.Random -const val BASE_DIR = "data" +const val BASE_DIR = "../data" const val PARSED_REGION_POPULATION_FILE = "$BASE_DIR/region_population.txt" -const val REGION_SQL_FILE = "data/region.sql" +const val REGION_SQL_FILE = "${BASE_DIR}/region.sql" const val MIN_POPULATION_FOR_PER_STORE = 200_000 /** @@ -25,7 +24,7 @@ class PopulationDataSqlParser() { // 인구 데이터를 이용하여 지역 정보 SQL 파일로 변환하고, 추가로 $MIN_POPULATION_FOR_PER_STORE 이상의 시/군/구는 매장 데이터 생성을 위해 따로 분류한다. fun createParsedRegionPopulationFiles() { - val populationXlsx = XSSFWorkbook(File("data/population.xlsx")) + val populationXlsx = XSSFWorkbook(File("${BASE_DIR}/population.xlsx")) val sheet = populationXlsx.getSheetAt(0) val allRegion = mutableListOf>() val regionsMoreThanMinPopulation = mutableListOf>() @@ -145,7 +144,7 @@ class StoreDataInitializer { val createdAt = randomLocalDateTime() val updatedAt = createdAt - val id: Long = tsidFactory.next().also { storeIds.add(it) } + val id: Long = IDGenerator.create().also { storeIds.add(it) } val createdBy = creatableAdminIds.random() diff --git a/src/test/kotlin/roomescape/auth/AuthApiTest.kt b/service/src/test/kotlin/com/sangdol/roomescape/auth/AuthApiTest.kt similarity index 88% rename from src/test/kotlin/roomescape/auth/AuthApiTest.kt rename to service/src/test/kotlin/com/sangdol/roomescape/auth/AuthApiTest.kt index bf585a6a..c69695f1 100644 --- a/src/test/kotlin/roomescape/auth/AuthApiTest.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/auth/AuthApiTest.kt @@ -1,4 +1,4 @@ -package roomescape.auth +package com.sangdol.roomescape.auth import com.ninjasquad.springmockk.SpykBean import io.kotest.assertions.assertSoftly @@ -8,22 +8,22 @@ import io.kotest.matchers.shouldNotBe import io.mockk.every import io.restassured.response.ValidatableResponse import org.hamcrest.CoreMatchers.equalTo -import org.springframework.http.HttpStatus -import roomescape.admin.exception.AdminErrorCode -import roomescape.auth.business.CLAIM_ADMIN_TYPE_KEY -import roomescape.auth.business.CLAIM_PERMISSION_KEY -import roomescape.auth.business.CLAIM_STORE_ID_KEY -import roomescape.auth.exception.AuthErrorCode -import roomescape.auth.infrastructure.jwt.JwtUtils -import roomescape.auth.infrastructure.persistence.LoginHistoryRepository -import roomescape.auth.web.LoginRequest -import roomescape.common.dto.PrincipalType -import roomescape.supports.AdminFixture -import roomescape.supports.FunSpecSpringbootTest -import roomescape.supports.UserFixture -import roomescape.supports.runTest -import roomescape.user.exception.UserErrorCode -import roomescape.user.infrastructure.persistence.UserEntity +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.roomescape.admin.exception.AdminErrorCode +import com.sangdol.roomescape.auth.business.CLAIM_ADMIN_TYPE_KEY +import com.sangdol.roomescape.auth.business.CLAIM_PERMISSION_KEY +import com.sangdol.roomescape.auth.business.CLAIM_STORE_ID_KEY +import com.sangdol.roomescape.auth.exception.AuthErrorCode +import com.sangdol.roomescape.auth.infrastructure.jwt.JwtUtils +import com.sangdol.roomescape.auth.infrastructure.persistence.LoginHistoryRepository +import com.sangdol.roomescape.auth.web.LoginRequest +import com.sangdol.roomescape.auth.web.PrincipalType +import com.sangdol.roomescape.supports.AdminFixture +import com.sangdol.roomescape.supports.FunSpecSpringbootTest +import com.sangdol.roomescape.supports.UserFixture +import com.sangdol.roomescape.supports.runTest +import com.sangdol.roomescape.user.exception.UserErrorCode +import com.sangdol.roomescape.user.infrastructure.persistence.UserEntity class AuthApiTest( @SpykBean private val jwtUtils: JwtUtils, diff --git a/src/test/kotlin/roomescape/auth/FailOnSaveLoginHistoryTest.kt b/service/src/test/kotlin/com/sangdol/roomescape/auth/FailOnSaveLoginHistoryTest.kt similarity index 78% rename from src/test/kotlin/roomescape/auth/FailOnSaveLoginHistoryTest.kt rename to service/src/test/kotlin/com/sangdol/roomescape/auth/FailOnSaveLoginHistoryTest.kt index b4d1e724..16d616f3 100644 --- a/src/test/kotlin/roomescape/auth/FailOnSaveLoginHistoryTest.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/auth/FailOnSaveLoginHistoryTest.kt @@ -1,16 +1,16 @@ -package roomescape.auth +package com.sangdol.roomescape.auth import com.ninjasquad.springmockk.MockkBean import io.mockk.clearMocks import io.mockk.every -import org.springframework.http.HttpStatus -import roomescape.auth.infrastructure.persistence.LoginHistoryRepository -import roomescape.auth.web.LoginRequest -import roomescape.common.dto.PrincipalType -import roomescape.supports.AdminFixture -import roomescape.supports.FunSpecSpringbootTest -import roomescape.supports.UserFixture -import roomescape.supports.runTest +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.roomescape.auth.infrastructure.persistence.LoginHistoryRepository +import com.sangdol.roomescape.auth.web.LoginRequest +import com.sangdol.roomescape.auth.web.PrincipalType +import com.sangdol.roomescape.supports.AdminFixture +import com.sangdol.roomescape.supports.FunSpecSpringbootTest +import com.sangdol.roomescape.supports.UserFixture +import com.sangdol.roomescape.supports.runTest class FailOnSaveLoginHistoryTest( @MockkBean private val loginHistoryRepository: LoginHistoryRepository diff --git a/src/test/kotlin/roomescape/auth/JwtUtilsTest.kt b/service/src/test/kotlin/com/sangdol/roomescape/auth/JwtUtilsTest.kt similarity index 88% rename from src/test/kotlin/roomescape/auth/JwtUtilsTest.kt rename to service/src/test/kotlin/com/sangdol/roomescape/auth/JwtUtilsTest.kt index 28aff8ef..0ab97084 100644 --- a/src/test/kotlin/roomescape/auth/JwtUtilsTest.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/auth/JwtUtilsTest.kt @@ -1,13 +1,12 @@ -package roomescape.auth +package com.sangdol.roomescape.auth +import com.sangdol.roomescape.auth.exception.AuthErrorCode +import com.sangdol.roomescape.auth.exception.AuthException +import com.sangdol.roomescape.auth.infrastructure.jwt.JwtUtils +import com.sangdol.roomescape.supports.IDGenerator import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe -import roomescape.auth.exception.AuthErrorCode -import roomescape.auth.exception.AuthException -import roomescape.auth.infrastructure.jwt.JwtUtils -import roomescape.common.config.next -import roomescape.supports.tsidFactory class JwtUtilsTest : FunSpec() { private val jwtUtils: JwtUtils = JwtUtils( @@ -18,7 +17,7 @@ class JwtUtilsTest : FunSpec() { init { context("종합 테스트") { test("Subject + Claim을 담아 토큰을 생성한 뒤 읽어온다.") { - val subject = "${tsidFactory.next()}" + val subject = "${IDGenerator.create()}" val claim = mapOf("name" to "sangdol") jwtUtils.createToken(subject, claim).also { token -> @@ -32,7 +31,7 @@ class JwtUtilsTest : FunSpec() { } context("실패 테스트") { - val subject = "${tsidFactory.next()}" + val subject = "${IDGenerator.create()}" val claim = mapOf("name" to "sangdol") val commonToken = jwtUtils.createToken(subject, claim) diff --git a/src/test/kotlin/roomescape/payment/PaymentAPITest.kt b/service/src/test/kotlin/com/sangdol/roomescape/payment/PaymentAPITest.kt similarity index 94% rename from src/test/kotlin/roomescape/payment/PaymentAPITest.kt rename to service/src/test/kotlin/com/sangdol/roomescape/payment/PaymentAPITest.kt index 2cdea8d4..fc5cc0d5 100644 --- a/src/test/kotlin/roomescape/payment/PaymentAPITest.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/payment/PaymentAPITest.kt @@ -1,23 +1,23 @@ -package roomescape.payment +package com.sangdol.roomescape.payment import com.ninjasquad.springmockk.MockkBean import io.kotest.matchers.shouldBe import io.mockk.every import org.springframework.data.repository.findByIdOrNull import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatus -import roomescape.auth.exception.AuthErrorCode -import roomescape.payment.business.PaymentService -import roomescape.payment.exception.PaymentErrorCode -import roomescape.payment.infrastructure.client.CardDetail -import roomescape.payment.infrastructure.client.EasyPayDetail -import roomescape.payment.infrastructure.client.TosspayClient -import roomescape.payment.infrastructure.client.TransferDetail -import roomescape.payment.infrastructure.common.* -import roomescape.payment.infrastructure.persistence.* -import roomescape.payment.web.PaymentConfirmRequest -import roomescape.payment.web.PaymentCreateResponse -import roomescape.supports.* +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.roomescape.auth.exception.AuthErrorCode +import com.sangdol.roomescape.payment.business.PaymentService +import com.sangdol.roomescape.payment.exception.PaymentErrorCode +import com.sangdol.roomescape.payment.infrastructure.client.CardDetail +import com.sangdol.roomescape.payment.infrastructure.client.EasyPayDetail +import com.sangdol.roomescape.payment.infrastructure.client.TosspayClient +import com.sangdol.roomescape.payment.infrastructure.client.TransferDetail +import com.sangdol.roomescape.payment.infrastructure.common.* +import com.sangdol.roomescape.payment.infrastructure.persistence.* +import com.sangdol.roomescape.payment.web.PaymentConfirmRequest +import com.sangdol.roomescape.payment.web.PaymentCreateResponse +import com.sangdol.roomescape.supports.* class PaymentAPITest( @MockkBean diff --git a/service/src/test/kotlin/com/sangdol/roomescape/payment/PaymentTypeTest.kt b/service/src/test/kotlin/com/sangdol/roomescape/payment/PaymentTypeTest.kt new file mode 100644 index 00000000..5831bc95 --- /dev/null +++ b/service/src/test/kotlin/com/sangdol/roomescape/payment/PaymentTypeTest.kt @@ -0,0 +1,148 @@ +package com.sangdol.roomescape.payment + +import com.sangdol.roomescape.payment.exception.PaymentErrorCode +import com.sangdol.roomescape.payment.exception.PaymentException +import com.sangdol.roomescape.payment.infrastructure.common.BankCode +import com.sangdol.roomescape.payment.infrastructure.common.CardIssuerCode +import com.sangdol.roomescape.payment.infrastructure.common.CardOwnerType +import com.sangdol.roomescape.payment.infrastructure.common.CardType +import com.sangdol.roomescape.payment.infrastructure.common.EasyPayCompanyCode +import com.sangdol.roomescape.payment.infrastructure.common.PaymentMethod +import com.sangdol.roomescape.payment.infrastructure.common.PaymentStatus +import com.sangdol.roomescape.payment.infrastructure.common.PaymentType +import io.kotest.assertions.assertSoftly +import io.kotest.core.spec.style.FunSpec +import io.kotest.matchers.shouldBe +import io.kotest.matchers.string.shouldHaveLength +import org.junit.jupiter.api.assertThrows + +class PaymentTypeTest : FunSpec({ + + context("PaymentType") { + test("한글 이름으로 가져온다.") { + PaymentType.entries.forEach { + PaymentType.Companion.get(it.name) shouldBe it + } + } + + test("없는 이름이면 실패한다.") { + assertThrows { + PaymentType.Companion.get("NORMAR") + }.also { + it.errorCode shouldBe PaymentErrorCode.TYPE_NOT_FOUND + } + } + } + + context("PaymentMethod") { + test("결제수단 한글명으로 가져온다.") { + PaymentMethod.entries.forEach { + PaymentMethod.Companion.get(it.koreanName) shouldBe it + } + } + + test("없는 이름이면 실패한다.") { + assertThrows { + PaymentMethod.Companion.get("카드12") + }.also { + it.errorCode shouldBe PaymentErrorCode.TYPE_NOT_FOUND + } + } + } + + context("PaymentStatus") { + test("상수 이름으로 가져온다.") { + PaymentStatus.entries.forEach { + PaymentStatus.Companion.get(it.name) shouldBe it + } + } + + test("없는 이름이면 실패한다.") { + assertThrows { + PaymentStatus.Companion.get("DONEE") + }.also { + it.errorCode shouldBe PaymentErrorCode.TYPE_NOT_FOUND + } + } + } + + context("CardType") { + test("한글 이름으로 가져온다.") { + CardType.entries.forEach { + CardType.Companion.get(it.koreanName) shouldBe it + } + } + + test("없는 이름을 입력하면 UNKNOWN을 반환한다.") { + CardType.Companion.get("신용카드") shouldBe CardType.UNKNOWN + } + } + + context("CardOwnerType") { + test("한글 이름으로 가져온다.") { + CardOwnerType.entries.forEach { + CardOwnerType.Companion.get(it.koreanName) shouldBe it + } + } + + test("없는 이름을 입력하면 UNKNOWN을 반환한다.") { + CardOwnerType.Companion.get("개인카드") shouldBe CardOwnerType.UNKNOWN + } + } + + context("BankCode") { + test("숫자 코드로 가져온다.") { + BankCode.entries.forEach { + BankCode.Companion.get(it.code) shouldBe it + } + } + + test("숫자가 두글자이면 앞에 0을 붙인다.") { + assertSoftly(BankCode.SHINHAN.code) { + this shouldHaveLength 3 + BankCode.Companion.get(this.substring(1)) shouldBe BankCode.Companion.get(this) + + } + } + + test("없는 코드이면 실패한다") { + assertThrows { + BankCode.Companion.get("9999") + }.also { + it.errorCode shouldBe PaymentErrorCode.ORGANIZATION_CODE_NOT_FOUND + } + } + } + + context("CardIssuerCode") { + test("숫자 코드로 가져온다.") { + CardIssuerCode.entries.forEach { + CardIssuerCode.Companion.get(it.code) shouldBe it + } + } + + test("없는 코드이면 실패한다") { + assertThrows { + CardIssuerCode.Companion.get("9999") + }.also { + it.errorCode shouldBe PaymentErrorCode.ORGANIZATION_CODE_NOT_FOUND + } + } + } + + context("EasyPayCompanyCode") { + test("한글 이름으로 가져온다.") { + EasyPayCompanyCode.entries.forEach { + EasyPayCompanyCode.Companion.get(it.koreanName) shouldBe it + } + } + + test("없는 이름이면 실패한다") { + assertThrows { + EasyPayCompanyCode.Companion.get("상돌페이") + }.also { + it.errorCode shouldBe PaymentErrorCode.ORGANIZATION_CODE_NOT_FOUND + } + } + } +}) \ No newline at end of file diff --git a/src/test/kotlin/roomescape/payment/SampleTosspayConstant.kt b/service/src/test/kotlin/com/sangdol/roomescape/payment/SampleTosspayConstant.kt similarity index 99% rename from src/test/kotlin/roomescape/payment/SampleTosspayConstant.kt rename to service/src/test/kotlin/com/sangdol/roomescape/payment/SampleTosspayConstant.kt index 07c4a2ad..aa1c8514 100644 --- a/src/test/kotlin/roomescape/payment/SampleTosspayConstant.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/payment/SampleTosspayConstant.kt @@ -1,4 +1,4 @@ -package roomescape.payment +package com.sangdol.roomescape.payment import java.time.OffsetDateTime diff --git a/src/test/kotlin/roomescape/payment/TosspayClientTest.kt b/service/src/test/kotlin/com/sangdol/roomescape/payment/TosspayClientTest.kt similarity index 93% rename from src/test/kotlin/roomescape/payment/TosspayClientTest.kt rename to service/src/test/kotlin/com/sangdol/roomescape/payment/TosspayClientTest.kt index d0665a06..1373d22a 100644 --- a/src/test/kotlin/roomescape/payment/TosspayClientTest.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/payment/TosspayClientTest.kt @@ -1,4 +1,4 @@ -package roomescape.payment +package com.sangdol.roomescape.payment import com.ninjasquad.springmockk.MockkBean import io.kotest.assertions.assertSoftly @@ -9,19 +9,19 @@ import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.web.client.RestClientTest import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatus import org.springframework.http.MediaType import org.springframework.test.web.client.MockRestServiceServer import org.springframework.test.web.client.ResponseActions import org.springframework.test.web.client.match.MockRestRequestMatchers.* import org.springframework.test.web.client.response.MockRestResponseCreators.withStatus import org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess -import roomescape.payment.exception.PaymentErrorCode -import roomescape.payment.exception.PaymentException -import roomescape.payment.infrastructure.client.PaymentClientCancelResponse -import roomescape.payment.infrastructure.client.PaymentClientConfirmResponse -import roomescape.payment.infrastructure.client.TosspayClient -import roomescape.payment.infrastructure.common.PaymentStatus +import com.sangdol.roomescape.payment.exception.PaymentErrorCode +import com.sangdol.roomescape.payment.exception.PaymentException +import com.sangdol.roomescape.payment.infrastructure.client.PaymentClientCancelResponse +import com.sangdol.roomescape.payment.infrastructure.client.PaymentClientConfirmResponse +import com.sangdol.roomescape.payment.infrastructure.client.TosspayClient +import com.sangdol.roomescape.payment.infrastructure.common.PaymentStatus +import org.springframework.http.HttpStatus @RestClientTest(TosspayClient::class) @MockkBean(JpaMetamodelMappingContext::class) diff --git a/src/test/kotlin/roomescape/region/RegionApiFailTest.kt b/service/src/test/kotlin/com/sangdol/roomescape/region/RegionApiFailTest.kt similarity index 83% rename from src/test/kotlin/roomescape/region/RegionApiFailTest.kt rename to service/src/test/kotlin/com/sangdol/roomescape/region/RegionApiFailTest.kt index 671ebf0d..1621aab9 100644 --- a/src/test/kotlin/roomescape/region/RegionApiFailTest.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/region/RegionApiFailTest.kt @@ -1,12 +1,12 @@ -package roomescape.region +package com.sangdol.roomescape.region import com.ninjasquad.springmockk.MockkBean import io.mockk.every import org.springframework.http.HttpMethod -import roomescape.region.exception.RegionErrorCode -import roomescape.region.infrastructure.persistence.RegionRepository -import roomescape.supports.FunSpecSpringbootTest -import roomescape.supports.runExceptionTest +import com.sangdol.roomescape.region.exception.RegionErrorCode +import com.sangdol.roomescape.region.infrastructure.persistence.RegionRepository +import com.sangdol.roomescape.supports.FunSpecSpringbootTest +import com.sangdol.roomescape.supports.runExceptionTest class RegionApiFailTest( @MockkBean private val regionRepository: RegionRepository diff --git a/src/test/kotlin/roomescape/region/RegionApiSuccessTest.kt b/service/src/test/kotlin/com/sangdol/roomescape/region/RegionApiSuccessTest.kt similarity index 87% rename from src/test/kotlin/roomescape/region/RegionApiSuccessTest.kt rename to service/src/test/kotlin/com/sangdol/roomescape/region/RegionApiSuccessTest.kt index 53e34fe2..cbb3ff83 100644 --- a/src/test/kotlin/roomescape/region/RegionApiSuccessTest.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/region/RegionApiSuccessTest.kt @@ -1,9 +1,9 @@ -package roomescape.region +package com.sangdol.roomescape.region import io.kotest.matchers.shouldBe -import org.springframework.http.HttpStatus -import roomescape.supports.FunSpecSpringbootTest -import roomescape.supports.runTest +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.roomescape.supports.FunSpecSpringbootTest +import com.sangdol.roomescape.supports.runTest class RegionApiSuccessTest: FunSpecSpringbootTest() { init { diff --git a/src/test/kotlin/roomescape/reservation/ReservationApiTest.kt b/service/src/test/kotlin/com/sangdol/roomescape/reservation/ReservationApiTest.kt similarity index 93% rename from src/test/kotlin/roomescape/reservation/ReservationApiTest.kt rename to service/src/test/kotlin/com/sangdol/roomescape/reservation/ReservationApiTest.kt index 6f6d9f8a..491365ae 100644 --- a/src/test/kotlin/roomescape/reservation/ReservationApiTest.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/reservation/ReservationApiTest.kt @@ -1,30 +1,30 @@ -package roomescape.reservation +package com.sangdol.roomescape.reservation import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe import org.hamcrest.CoreMatchers.equalTo import org.springframework.data.repository.findByIdOrNull import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatus -import roomescape.auth.exception.AuthErrorCode -import roomescape.common.exception.CommonErrorCode -import roomescape.payment.infrastructure.common.BankCode -import roomescape.payment.infrastructure.common.CardIssuerCode -import roomescape.payment.infrastructure.common.EasyPayCompanyCode -import roomescape.payment.infrastructure.persistence.PaymentDetailRepository -import roomescape.reservation.exception.ReservationErrorCode -import roomescape.reservation.infrastructure.persistence.CanceledReservationRepository -import roomescape.reservation.infrastructure.persistence.ReservationEntity -import roomescape.reservation.infrastructure.persistence.ReservationRepository -import roomescape.reservation.infrastructure.persistence.ReservationStatus -import roomescape.reservation.web.ReservationCancelRequest -import roomescape.reservation.web.ReservationOverviewResponse -import roomescape.schedule.infrastructure.persistence.ScheduleEntity -import roomescape.schedule.infrastructure.persistence.ScheduleRepository -import roomescape.schedule.infrastructure.persistence.ScheduleStatus -import roomescape.supports.* -import roomescape.theme.infrastructure.persistence.ThemeEntity -import roomescape.theme.infrastructure.persistence.ThemeRepository +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.roomescape.auth.exception.AuthErrorCode +import com.sangdol.common.types.exception.CommonErrorCode +import com.sangdol.roomescape.payment.infrastructure.common.BankCode +import com.sangdol.roomescape.payment.infrastructure.common.CardIssuerCode +import com.sangdol.roomescape.payment.infrastructure.common.EasyPayCompanyCode +import com.sangdol.roomescape.payment.infrastructure.persistence.PaymentDetailRepository +import com.sangdol.roomescape.reservation.exception.ReservationErrorCode +import com.sangdol.roomescape.reservation.infrastructure.persistence.CanceledReservationRepository +import com.sangdol.roomescape.reservation.infrastructure.persistence.ReservationEntity +import com.sangdol.roomescape.reservation.infrastructure.persistence.ReservationRepository +import com.sangdol.roomescape.reservation.infrastructure.persistence.ReservationStatus +import com.sangdol.roomescape.reservation.web.ReservationCancelRequest +import com.sangdol.roomescape.reservation.web.ReservationOverviewResponse +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleEntity +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleRepository +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus +import com.sangdol.roomescape.supports.* +import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeEntity +import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeRepository import java.time.LocalDate import java.time.LocalTime diff --git a/src/test/kotlin/roomescape/schedule/AdminScheduleApiTest.kt b/service/src/test/kotlin/com/sangdol/roomescape/schedule/AdminScheduleApiTest.kt similarity index 96% rename from src/test/kotlin/roomescape/schedule/AdminScheduleApiTest.kt rename to service/src/test/kotlin/com/sangdol/roomescape/schedule/AdminScheduleApiTest.kt index 3411c1fb..f51663dc 100644 --- a/src/test/kotlin/roomescape/schedule/AdminScheduleApiTest.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/schedule/AdminScheduleApiTest.kt @@ -1,5 +1,18 @@ -package roomescape.schedule +package com.sangdol.roomescape.schedule +import com.sangdol.roomescape.common.types.Auditor +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminPermissionLevel +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminType +import com.sangdol.roomescape.auth.exception.AuthErrorCode +import com.sangdol.roomescape.schedule.exception.ScheduleErrorCode +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleEntity +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleRepository +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus +import com.sangdol.roomescape.schedule.web.AdminScheduleSummaryResponse +import com.sangdol.roomescape.schedule.web.ScheduleUpdateRequest +import com.sangdol.roomescape.store.infrastructure.persistence.StoreEntity +import com.sangdol.roomescape.supports.* import io.kotest.assertions.assertSoftly import io.kotest.matchers.date.shouldBeBefore import io.kotest.matchers.shouldBe @@ -7,20 +20,6 @@ import io.kotest.matchers.shouldNotBe import org.hamcrest.CoreMatchers.equalTo import org.springframework.data.repository.findByIdOrNull import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatus -import roomescape.admin.infrastructure.persistence.AdminPermissionLevel -import roomescape.admin.infrastructure.persistence.AdminType -import roomescape.auth.exception.AuthErrorCode -import roomescape.common.dto.AuditConstant -import roomescape.common.dto.OperatorInfo -import roomescape.schedule.exception.ScheduleErrorCode -import roomescape.schedule.infrastructure.persistence.ScheduleEntity -import roomescape.schedule.infrastructure.persistence.ScheduleRepository -import roomescape.schedule.infrastructure.persistence.ScheduleStatus -import roomescape.schedule.web.AdminScheduleSummaryResponse -import roomescape.schedule.web.ScheduleUpdateRequest -import roomescape.store.infrastructure.persistence.StoreEntity -import roomescape.supports.* import java.time.LocalDate import java.time.LocalTime @@ -267,7 +266,7 @@ class AdminScheduleApiTest( val schedule: ScheduleEntity = initialize("감사 이력을 남기지 않기 위해, 로그인 없이 일정을 생성한다.") { dummyInitializer.createSchedule(storeId = store.id, request = ScheduleFixture.createRequest) } - val unknownOperator: OperatorInfo = AuditConstant.UNKNOWN_OPERATOR + val unknownOperator: Auditor = Auditor.UNKNOWN runTest( token = testAuthUtil.defaultHqAdminLogin().second, diff --git a/src/test/kotlin/roomescape/schedule/ScheduleApiTest.kt b/service/src/test/kotlin/com/sangdol/roomescape/schedule/ScheduleApiTest.kt similarity index 88% rename from src/test/kotlin/roomescape/schedule/ScheduleApiTest.kt rename to service/src/test/kotlin/com/sangdol/roomescape/schedule/ScheduleApiTest.kt index 81cb6d85..1f8103c4 100644 --- a/src/test/kotlin/roomescape/schedule/ScheduleApiTest.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/schedule/ScheduleApiTest.kt @@ -1,17 +1,17 @@ -package roomescape.schedule +package com.sangdol.roomescape.schedule import io.kotest.matchers.shouldBe import org.hamcrest.CoreMatchers.equalTo import org.springframework.data.repository.findByIdOrNull import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatus -import roomescape.admin.infrastructure.persistence.AdminPermissionLevel -import roomescape.admin.infrastructure.persistence.AdminType -import roomescape.auth.exception.AuthErrorCode -import roomescape.schedule.exception.ScheduleErrorCode -import roomescape.schedule.infrastructure.persistence.ScheduleRepository -import roomescape.schedule.infrastructure.persistence.ScheduleStatus -import roomescape.supports.* +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminPermissionLevel +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminType +import com.sangdol.roomescape.auth.exception.AuthErrorCode +import com.sangdol.roomescape.schedule.exception.ScheduleErrorCode +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleRepository +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus +import com.sangdol.roomescape.supports.* import java.time.LocalDate import java.time.LocalTime diff --git a/src/test/kotlin/roomescape/store/AdminStoreApiTest.kt b/service/src/test/kotlin/com/sangdol/roomescape/store/AdminStoreApiTest.kt similarity index 96% rename from src/test/kotlin/roomescape/store/AdminStoreApiTest.kt rename to service/src/test/kotlin/com/sangdol/roomescape/store/AdminStoreApiTest.kt index 2417311d..8e74c6a4 100644 --- a/src/test/kotlin/roomescape/store/AdminStoreApiTest.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/store/AdminStoreApiTest.kt @@ -1,21 +1,21 @@ -package roomescape.store +package com.sangdol.roomescape.store import io.kotest.assertions.assertSoftly import io.kotest.matchers.date.shouldBeAfter import io.kotest.matchers.shouldBe import org.springframework.data.repository.findByIdOrNull import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatus -import roomescape.admin.infrastructure.persistence.AdminEntity -import roomescape.admin.infrastructure.persistence.AdminPermissionLevel -import roomescape.admin.infrastructure.persistence.AdminType -import roomescape.auth.exception.AuthErrorCode -import roomescape.store.exception.StoreErrorCode -import roomescape.store.infrastructure.persistence.StoreEntity -import roomescape.store.infrastructure.persistence.StoreRepository -import roomescape.store.infrastructure.persistence.StoreStatus -import roomescape.store.web.StoreUpdateRequest -import roomescape.supports.* +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminEntity +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminPermissionLevel +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminType +import com.sangdol.roomescape.auth.exception.AuthErrorCode +import com.sangdol.roomescape.store.exception.StoreErrorCode +import com.sangdol.roomescape.store.infrastructure.persistence.StoreEntity +import com.sangdol.roomescape.store.infrastructure.persistence.StoreRepository +import com.sangdol.roomescape.store.infrastructure.persistence.StoreStatus +import com.sangdol.roomescape.store.web.StoreUpdateRequest +import com.sangdol.roomescape.supports.* class AdminStoreApiTest( private val storeRepository: StoreRepository, diff --git a/src/test/kotlin/roomescape/store/StoreApiTest.kt b/service/src/test/kotlin/com/sangdol/roomescape/store/StoreApiTest.kt similarity index 93% rename from src/test/kotlin/roomescape/store/StoreApiTest.kt rename to service/src/test/kotlin/com/sangdol/roomescape/store/StoreApiTest.kt index 006c94fc..d8af0c5f 100644 --- a/src/test/kotlin/roomescape/store/StoreApiTest.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/store/StoreApiTest.kt @@ -1,11 +1,11 @@ -package roomescape.store +package com.sangdol.roomescape.store import org.hamcrest.CoreMatchers.equalTo import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatus -import roomescape.store.exception.StoreErrorCode -import roomescape.store.infrastructure.persistence.StoreEntity -import roomescape.supports.* +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.roomescape.store.exception.StoreErrorCode +import com.sangdol.roomescape.store.infrastructure.persistence.StoreEntity +import com.sangdol.roomescape.supports.* class StoreApiTest: FunSpecSpringbootTest() { diff --git a/src/test/kotlin/roomescape/supports/DummyInitializer.kt b/service/src/test/kotlin/com/sangdol/roomescape/supports/DummyInitializer.kt similarity index 71% rename from src/test/kotlin/roomescape/supports/DummyInitializer.kt rename to service/src/test/kotlin/com/sangdol/roomescape/supports/DummyInitializer.kt index f4791b94..f1252bc3 100644 --- a/src/test/kotlin/roomescape/supports/DummyInitializer.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/supports/DummyInitializer.kt @@ -1,36 +1,35 @@ -package roomescape.supports +package com.sangdol.roomescape.supports +import com.sangdol.roomescape.payment.business.PaymentWriter +import com.sangdol.roomescape.payment.infrastructure.client.CardDetail +import com.sangdol.roomescape.payment.infrastructure.client.EasyPayDetail +import com.sangdol.roomescape.payment.infrastructure.client.TransferDetail +import com.sangdol.roomescape.payment.infrastructure.common.PaymentMethod +import com.sangdol.roomescape.payment.infrastructure.persistence.CanceledPaymentEntity +import com.sangdol.roomescape.payment.infrastructure.persistence.PaymentEntity +import com.sangdol.roomescape.payment.infrastructure.persistence.PaymentRepository +import com.sangdol.roomescape.payment.web.PaymentConfirmRequest +import com.sangdol.roomescape.payment.web.PaymentWithDetailResponse +import com.sangdol.roomescape.payment.web.toDetailResponse +import com.sangdol.roomescape.payment.web.toPaymentDetailResponse +import com.sangdol.roomescape.reservation.infrastructure.persistence.ReservationEntity +import com.sangdol.roomescape.reservation.infrastructure.persistence.ReservationRepository +import com.sangdol.roomescape.reservation.infrastructure.persistence.ReservationStatus +import com.sangdol.roomescape.reservation.web.PendingReservationCreateRequest +import com.sangdol.roomescape.reservation.web.toEntity +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleEntity +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleRepository +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus +import com.sangdol.roomescape.schedule.web.ScheduleCreateRequest +import com.sangdol.roomescape.store.infrastructure.persistence.StoreEntity +import com.sangdol.roomescape.store.infrastructure.persistence.StoreRepository +import com.sangdol.roomescape.store.infrastructure.persistence.StoreStatus +import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeEntity +import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeRepository +import com.sangdol.roomescape.theme.web.ThemeCreateRequest +import com.sangdol.roomescape.theme.web.toEntity +import com.sangdol.roomescape.user.infrastructure.persistence.UserEntity import org.springframework.data.repository.findByIdOrNull -import roomescape.common.config.next -import roomescape.payment.business.PaymentWriter -import roomescape.payment.infrastructure.client.CardDetail -import roomescape.payment.infrastructure.client.EasyPayDetail -import roomescape.payment.infrastructure.client.TransferDetail -import roomescape.payment.infrastructure.common.PaymentMethod -import roomescape.payment.infrastructure.persistence.CanceledPaymentEntity -import roomescape.payment.infrastructure.persistence.PaymentEntity -import roomescape.payment.infrastructure.persistence.PaymentRepository -import roomescape.payment.web.PaymentConfirmRequest -import roomescape.payment.web.PaymentWithDetailResponse -import roomescape.payment.web.toDetailResponse -import roomescape.payment.web.toPaymentDetailResponse -import roomescape.reservation.infrastructure.persistence.ReservationEntity -import roomescape.reservation.infrastructure.persistence.ReservationRepository -import roomescape.reservation.infrastructure.persistence.ReservationStatus -import roomescape.reservation.web.PendingReservationCreateRequest -import roomescape.reservation.web.toEntity -import roomescape.schedule.infrastructure.persistence.ScheduleEntity -import roomescape.schedule.infrastructure.persistence.ScheduleRepository -import roomescape.schedule.infrastructure.persistence.ScheduleStatus -import roomescape.schedule.web.ScheduleCreateRequest -import roomescape.store.infrastructure.persistence.StoreEntity -import roomescape.store.infrastructure.persistence.StoreRepository -import roomescape.store.infrastructure.persistence.StoreStatus -import roomescape.theme.infrastructure.persistence.ThemeEntity -import roomescape.theme.infrastructure.persistence.ThemeRepository -import roomescape.theme.web.ThemeCreateRequest -import roomescape.theme.web.toEntity -import roomescape.user.infrastructure.persistence.UserEntity import java.time.LocalDateTime class DummyInitializer( @@ -43,7 +42,7 @@ class DummyInitializer( ) { fun createStore( - id: Long = tsidFactory.next(), + id: Long = IDGenerator.create(), name: String = "행복${randomPhoneNumber()}호점", address: String = "강북구 행복로 $name", contact: String = randomPhoneNumber(), @@ -71,11 +70,11 @@ class DummyInitializer( fun createTheme( request: ThemeCreateRequest = ThemeFixture.createRequest ): ThemeEntity { - return request.toEntity(tsidFactory.next()).also { themeRepository.save(it) } + return request.toEntity(IDGenerator.create()).also { themeRepository.save(it) } } fun createSchedule( - storeId: Long = tsidFactory.next(), + storeId: Long = IDGenerator.create(), request: ScheduleCreateRequest = ScheduleFixture.createRequest, status: ScheduleStatus = ScheduleStatus.AVAILABLE ): ScheduleEntity { @@ -102,7 +101,7 @@ class DummyInitializer( fun createPendingReservation( user: UserEntity, - storeId: Long = tsidFactory.next(), + storeId: Long = IDGenerator.create(), themeRequest: ThemeCreateRequest = ThemeFixture.createRequest, scheduleRequest: ScheduleCreateRequest = ScheduleFixture.createRequest, reservationRequest: PendingReservationCreateRequest = ReservationFixture.pendingCreateRequest, @@ -129,14 +128,14 @@ class DummyInitializer( reserverContact = reservationRequest.reserverContact, participantCount = reservationRequest.participantCount, requirement = reservationRequest.requirement, - ).toEntity(id = tsidFactory.next(), userId = user.id) + ).toEntity(id = IDGenerator.create(), userId = user.id) return reservationRepository.save(reservation) } fun createConfirmReservation( user: UserEntity, - storeId: Long = tsidFactory.next(), + storeId: Long = IDGenerator.create(), themeRequest: ThemeCreateRequest = ThemeFixture.createRequest, scheduleRequest: ScheduleCreateRequest = ScheduleFixture.createRequest, reservationRequest: PendingReservationCreateRequest = ReservationFixture.pendingCreateRequest, diff --git a/src/test/kotlin/roomescape/supports/Fixtures.kt b/service/src/test/kotlin/com/sangdol/roomescape/supports/Fixtures.kt similarity index 80% rename from src/test/kotlin/roomescape/supports/Fixtures.kt rename to service/src/test/kotlin/com/sangdol/roomescape/supports/Fixtures.kt index ada73ea8..bf59d52b 100644 --- a/src/test/kotlin/roomescape/supports/Fixtures.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/supports/Fixtures.kt @@ -1,34 +1,34 @@ -package roomescape.supports +package com.sangdol.roomescape.supports import com.github.f4b6a3.tsid.TsidFactory -import roomescape.admin.infrastructure.persistence.AdminEntity -import roomescape.admin.infrastructure.persistence.AdminPermissionLevel -import roomescape.admin.infrastructure.persistence.AdminType -import roomescape.common.config.next -import roomescape.payment.infrastructure.client.* -import roomescape.payment.infrastructure.common.* -import roomescape.payment.web.PaymentCancelRequest -import roomescape.payment.web.PaymentConfirmRequest -import roomescape.reservation.web.PendingReservationCreateRequest -import roomescape.schedule.infrastructure.persistence.ScheduleEntity -import roomescape.schedule.infrastructure.persistence.ScheduleEntityFactory -import roomescape.schedule.web.ScheduleCreateRequest -import roomescape.store.infrastructure.persistence.StoreEntity -import roomescape.store.infrastructure.persistence.StoreStatus -import roomescape.store.web.StoreRegisterRequest -import roomescape.theme.infrastructure.persistence.Difficulty -import roomescape.theme.infrastructure.persistence.ThemeEntity -import roomescape.theme.web.ThemeCreateRequest -import roomescape.user.infrastructure.persistence.UserEntity -import roomescape.user.infrastructure.persistence.UserStatus -import roomescape.user.web.MIN_PASSWORD_LENGTH -import roomescape.user.web.UserCreateRequest +import com.sangdol.common.persistence.TsidIDGenerator +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminEntity +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminPermissionLevel +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminType +import com.sangdol.roomescape.payment.infrastructure.client.* +import com.sangdol.roomescape.payment.infrastructure.common.* +import com.sangdol.roomescape.payment.web.PaymentCancelRequest +import com.sangdol.roomescape.payment.web.PaymentConfirmRequest +import com.sangdol.roomescape.reservation.web.PendingReservationCreateRequest +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleEntity +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleEntityFactory +import com.sangdol.roomescape.schedule.web.ScheduleCreateRequest +import com.sangdol.roomescape.store.infrastructure.persistence.StoreEntity +import com.sangdol.roomescape.store.infrastructure.persistence.StoreStatus +import com.sangdol.roomescape.store.web.StoreRegisterRequest +import com.sangdol.roomescape.theme.infrastructure.persistence.Difficulty +import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeEntity +import com.sangdol.roomescape.theme.web.ThemeCreateRequest +import com.sangdol.roomescape.user.infrastructure.persistence.UserEntity +import com.sangdol.roomescape.user.infrastructure.persistence.UserStatus +import com.sangdol.roomescape.user.web.MIN_PASSWORD_LENGTH +import com.sangdol.roomescape.user.web.UserCreateRequest import java.time.LocalDate import java.time.LocalTime import java.time.OffsetDateTime const val INVALID_PK: Long = 9999L -val tsidFactory = TsidFactory(0) +val IDGenerator = TsidIDGenerator(TsidFactory(0)) object StoreFixture { val registerRequest = StoreRegisterRequest( @@ -40,7 +40,7 @@ object StoreFixture { ) fun create( - id: Long = tsidFactory.next(), + id: Long = IDGenerator.create(), name: String = "행복${randomPhoneNumber()}호점", address: String = "서울특별시 강북구 행복${randomPhoneNumber()}길", contact: String = randomPhoneNumber(), @@ -72,12 +72,12 @@ object AdminFixture { ) fun createStoreAdmin( - id: Long = tsidFactory.next(), + id: Long = IDGenerator.create(), account: String = randomString(), password: String = "adminPassword", name: String = "admin12345", phone: String = randomPhoneNumber(), - storeId: Long = tsidFactory.next(), + storeId: Long = IDGenerator.create(), permissionLevel: AdminPermissionLevel = AdminPermissionLevel.FULL_ACCESS ): AdminEntity { return create( @@ -93,7 +93,7 @@ object AdminFixture { } fun createHqAdmin( - id: Long = tsidFactory.next(), + id: Long = IDGenerator.create(), account: String = randomString(), password: String = "adminPassword", name: String = "admin12345", @@ -113,13 +113,13 @@ object AdminFixture { } fun create( - id: Long = tsidFactory.next(), + id: Long = IDGenerator.create(), account: String = randomString(), password: String = "adminPassword", name: String = "admin", phone: String = randomPhoneNumber(), type: AdminType = AdminType.STORE, - storeId: Long? = tsidFactory.next(), + storeId: Long? = IDGenerator.create(), permissionLevel: AdminPermissionLevel = AdminPermissionLevel.FULL_ACCESS ): AdminEntity { val storeId = if (type == AdminType.HQ) null else storeId @@ -144,7 +144,7 @@ object UserFixture { ) fun createUser( - id: Long = tsidFactory.next(), + id: Long = IDGenerator.create(), name: String = randomString(), email: String = randomEmail(), password: String = "a".repeat(MIN_PASSWORD_LENGTH), @@ -186,7 +186,7 @@ object ThemeFixture { ) fun create( - id: Long = tsidFactory.next(), + id: Long = IDGenerator.create(), name: String = randomString(), description: String = randomString(), thumbnailUrl: String = "http://www.bing.com/search?q=fugit", @@ -218,15 +218,15 @@ object ScheduleFixture { val createRequest: ScheduleCreateRequest = ScheduleCreateRequest( date = LocalDate.now().plusDays(1), time = LocalTime.now(), - themeId = tsidFactory.next() + themeId = IDGenerator.create() ) fun create( - id: Long = tsidFactory.next(), + id: Long = IDGenerator.create(), date: LocalDate = LocalDate.now().plusDays(1), time: LocalTime = LocalTime.now(), - storeId: Long = tsidFactory.next(), - themeId: Long = tsidFactory.next() + storeId: Long = IDGenerator.create(), + themeId: Long = IDGenerator.create() ): ScheduleEntity = ScheduleEntityFactory.create( id = id, date = date, @@ -245,7 +245,7 @@ object PaymentFixture { ) val cancelRequest: PaymentCancelRequest = PaymentCancelRequest( - reservationId = tsidFactory.next(), + reservationId = IDGenerator.create(), cancelReason = "cancelReason", ) @@ -322,7 +322,7 @@ object PaymentFixture { object ReservationFixture { val pendingCreateRequest: PendingReservationCreateRequest = PendingReservationCreateRequest( - scheduleId = tsidFactory.next(), + scheduleId = IDGenerator.create(), reserverName = "Wilbur Stuart", reserverContact = "wilbur@example.com", participantCount = 5, diff --git a/src/test/kotlin/roomescape/supports/KotestConfig.kt b/service/src/test/kotlin/com/sangdol/roomescape/supports/KotestConfig.kt similarity index 78% rename from src/test/kotlin/roomescape/supports/KotestConfig.kt rename to service/src/test/kotlin/com/sangdol/roomescape/supports/KotestConfig.kt index 284892ab..fbbe81b0 100644 --- a/src/test/kotlin/roomescape/supports/KotestConfig.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/supports/KotestConfig.kt @@ -1,4 +1,4 @@ -package roomescape.supports +package com.sangdol.roomescape.supports import io.kotest.core.config.AbstractProjectConfig import io.kotest.core.spec.Spec @@ -13,14 +13,14 @@ import org.springframework.boot.test.web.server.LocalServerPort import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Import import org.springframework.test.context.ActiveProfiles -import roomescape.admin.infrastructure.persistence.AdminRepository -import roomescape.payment.business.PaymentWriter -import roomescape.payment.infrastructure.persistence.PaymentRepository -import roomescape.reservation.infrastructure.persistence.ReservationRepository -import roomescape.schedule.infrastructure.persistence.ScheduleRepository -import roomescape.store.infrastructure.persistence.StoreRepository -import roomescape.theme.infrastructure.persistence.ThemeRepository -import roomescape.user.infrastructure.persistence.UserRepository +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminRepository +import com.sangdol.roomescape.payment.business.PaymentWriter +import com.sangdol.roomescape.payment.infrastructure.persistence.PaymentRepository +import com.sangdol.roomescape.reservation.infrastructure.persistence.ReservationRepository +import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleRepository +import com.sangdol.roomescape.store.infrastructure.persistence.StoreRepository +import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeRepository +import com.sangdol.roomescape.user.infrastructure.persistence.UserRepository object KotestConfig : AbstractProjectConfig() { override fun extensions(): List = listOf(SpringExtension) diff --git a/src/test/kotlin/roomescape/supports/RestAssuredUtils.kt b/service/src/test/kotlin/com/sangdol/roomescape/supports/RestAssuredUtils.kt similarity index 91% rename from src/test/kotlin/roomescape/supports/RestAssuredUtils.kt rename to service/src/test/kotlin/com/sangdol/roomescape/supports/RestAssuredUtils.kt index 689184d2..af53b62e 100644 --- a/src/test/kotlin/roomescape/supports/RestAssuredUtils.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/supports/RestAssuredUtils.kt @@ -1,6 +1,7 @@ -package roomescape.supports +package com.sangdol.roomescape.supports -import com.fasterxml.jackson.module.kotlin.convertValue +import com.sangdol.common.web.config.JacksonConfig +import com.sangdol.common.types.exception.ErrorCode import io.restassured.module.kotlin.extensions.Given import io.restassured.module.kotlin.extensions.Then import io.restassured.module.kotlin.extensions.When @@ -10,8 +11,6 @@ import io.restassured.specification.RequestSpecification import org.hamcrest.CoreMatchers.equalTo import org.springframework.http.HttpMethod import org.springframework.http.MediaType -import roomescape.common.config.JacksonConfig -import roomescape.common.exception.ErrorCode fun runTest( token: String? = null, @@ -103,10 +102,10 @@ object ResponseParser { val objectMapper = JacksonConfig().objectMapper() inline fun parseListResponse(response: List>): List { - return response.map { objectMapper.convertValue(it) } + return response.map { objectMapper.convertValue(it, T::class.java) } } inline fun parseSingleResponse(response: LinkedHashMap): T { - return objectMapper.convertValue(response) + return objectMapper.convertValue(response, T::class.java) } } diff --git a/src/test/kotlin/roomescape/supports/TestAuthUtil.kt b/service/src/test/kotlin/com/sangdol/roomescape/supports/TestAuthUtil.kt similarity index 85% rename from src/test/kotlin/roomescape/supports/TestAuthUtil.kt rename to service/src/test/kotlin/com/sangdol/roomescape/supports/TestAuthUtil.kt index 67379374..a3340a19 100644 --- a/src/test/kotlin/roomescape/supports/TestAuthUtil.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/supports/TestAuthUtil.kt @@ -1,21 +1,21 @@ -package roomescape.supports +package com.sangdol.roomescape.supports import io.restassured.module.kotlin.extensions.Extract import io.restassured.module.kotlin.extensions.Given import io.restassured.module.kotlin.extensions.Then import io.restassured.module.kotlin.extensions.When import org.springframework.data.repository.findByIdOrNull -import org.springframework.http.HttpStatus +import com.sangdol.common.types.web.HttpStatus import org.springframework.http.MediaType -import roomescape.admin.infrastructure.persistence.AdminEntity -import roomescape.admin.infrastructure.persistence.AdminRepository -import roomescape.admin.infrastructure.persistence.AdminType -import roomescape.auth.web.LoginRequest -import roomescape.common.dto.PrincipalType -import roomescape.store.infrastructure.persistence.StoreRepository -import roomescape.user.infrastructure.persistence.UserEntity -import roomescape.user.infrastructure.persistence.UserRepository -import roomescape.user.web.UserCreateRequest +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminEntity +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminRepository +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminType +import com.sangdol.roomescape.auth.web.LoginRequest +import com.sangdol.roomescape.auth.web.PrincipalType +import com.sangdol.roomescape.store.infrastructure.persistence.StoreRepository +import com.sangdol.roomescape.user.infrastructure.persistence.UserEntity +import com.sangdol.roomescape.user.infrastructure.persistence.UserRepository +import com.sangdol.roomescape.user.web.UserCreateRequest class TestAuthUtil( private val userRepository: UserRepository, diff --git a/src/test/kotlin/roomescape/supports/TestDatabaseUtil.kt b/service/src/test/kotlin/com/sangdol/roomescape/supports/TestDatabaseUtil.kt similarity index 98% rename from src/test/kotlin/roomescape/supports/TestDatabaseUtil.kt rename to service/src/test/kotlin/com/sangdol/roomescape/supports/TestDatabaseUtil.kt index 07c5591f..60e4d851 100644 --- a/src/test/kotlin/roomescape/supports/TestDatabaseUtil.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/supports/TestDatabaseUtil.kt @@ -1,4 +1,4 @@ -package roomescape.supports +package com.sangdol.roomescape.supports import io.kotest.core.listeners.AfterSpecListener import io.kotest.core.listeners.AfterTestListener diff --git a/src/test/kotlin/roomescape/supports/TestUtil.kt b/service/src/test/kotlin/com/sangdol/roomescape/supports/TestUtil.kt similarity index 95% rename from src/test/kotlin/roomescape/supports/TestUtil.kt rename to service/src/test/kotlin/com/sangdol/roomescape/supports/TestUtil.kt index 8b5780e5..0e262845 100644 --- a/src/test/kotlin/roomescape/supports/TestUtil.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/supports/TestUtil.kt @@ -1,4 +1,4 @@ -package roomescape.supports +package com.sangdol.roomescape.supports import kotlin.random.Random diff --git a/src/test/kotlin/roomescape/theme/AdminThemeApiTest.kt b/service/src/test/kotlin/com/sangdol/roomescape/theme/AdminThemeApiTest.kt similarity index 97% rename from src/test/kotlin/roomescape/theme/AdminThemeApiTest.kt rename to service/src/test/kotlin/com/sangdol/roomescape/theme/AdminThemeApiTest.kt index 4663b0d9..de15aa00 100644 --- a/src/test/kotlin/roomescape/theme/AdminThemeApiTest.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/theme/AdminThemeApiTest.kt @@ -1,23 +1,23 @@ -package roomescape.theme +package com.sangdol.roomescape.theme import io.kotest.matchers.nulls.shouldNotBeNull import io.kotest.matchers.shouldBe import org.hamcrest.CoreMatchers.equalTo import org.springframework.data.repository.findByIdOrNull import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatus -import roomescape.admin.infrastructure.persistence.AdminPermissionLevel -import roomescape.admin.infrastructure.persistence.AdminType -import roomescape.auth.exception.AuthErrorCode -import roomescape.supports.* -import roomescape.supports.ThemeFixture.createRequest -import roomescape.theme.business.MIN_DURATION -import roomescape.theme.business.MIN_PARTICIPANTS -import roomescape.theme.business.MIN_PRICE -import roomescape.theme.exception.ThemeErrorCode -import roomescape.theme.infrastructure.persistence.ThemeEntity -import roomescape.theme.infrastructure.persistence.ThemeRepository -import roomescape.theme.web.ThemeUpdateRequest +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminPermissionLevel +import com.sangdol.roomescape.admin.infrastructure.persistence.AdminType +import com.sangdol.roomescape.auth.exception.AuthErrorCode +import com.sangdol.roomescape.supports.* +import com.sangdol.roomescape.supports.ThemeFixture.createRequest +import com.sangdol.roomescape.theme.business.MIN_DURATION +import com.sangdol.roomescape.theme.business.MIN_PARTICIPANTS +import com.sangdol.roomescape.theme.business.MIN_PRICE +import com.sangdol.roomescape.theme.exception.ThemeErrorCode +import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeEntity +import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeRepository +import com.sangdol.roomescape.theme.web.ThemeUpdateRequest class AdminThemeApiTest( private val themeRepository: ThemeRepository diff --git a/src/test/kotlin/roomescape/common/util/DateUtilsTest.kt b/service/src/test/kotlin/com/sangdol/roomescape/theme/DateUtilsTest.kt similarity index 80% rename from src/test/kotlin/roomescape/common/util/DateUtilsTest.kt rename to service/src/test/kotlin/com/sangdol/roomescape/theme/DateUtilsTest.kt index 30a2c6b3..b17b6620 100644 --- a/src/test/kotlin/roomescape/common/util/DateUtilsTest.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/theme/DateUtilsTest.kt @@ -1,5 +1,6 @@ -package roomescape.common.util +package com.sangdol.roomescape.theme +import com.sangdol.roomescape.theme.business.DateUtils import io.kotest.core.spec.style.StringSpec import io.kotest.matchers.shouldBe import java.time.LocalDate @@ -12,4 +13,4 @@ class DateUtilsTest : StringSpec({ DateUtils.getSundayOfPreviousWeek(LocalDate.of(2025, 9, i)) shouldBe expected } } -}) +}) \ No newline at end of file diff --git a/src/test/kotlin/roomescape/theme/ThemeApiTest.kt b/service/src/test/kotlin/com/sangdol/roomescape/theme/ThemeApiTest.kt similarity index 85% rename from src/test/kotlin/roomescape/theme/ThemeApiTest.kt rename to service/src/test/kotlin/com/sangdol/roomescape/theme/ThemeApiTest.kt index 1fe3e095..f589b380 100644 --- a/src/test/kotlin/roomescape/theme/ThemeApiTest.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/theme/ThemeApiTest.kt @@ -1,18 +1,18 @@ -package roomescape.theme +package com.sangdol.roomescape.theme +import com.sangdol.common.types.web.HttpStatus +import com.sangdol.roomescape.supports.* +import com.sangdol.roomescape.theme.business.DateUtils +import com.sangdol.roomescape.theme.exception.ThemeErrorCode +import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeEntity +import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeRepository +import com.sangdol.roomescape.theme.web.ThemeInfoResponse +import com.sangdol.roomescape.theme.web.toEntity +import com.sangdol.roomescape.user.infrastructure.persistence.UserEntity import io.kotest.matchers.collections.shouldContainInOrder import io.kotest.matchers.collections.shouldHaveSize import org.hamcrest.CoreMatchers.equalTo import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatus -import roomescape.common.config.next -import roomescape.common.util.DateUtils -import roomescape.supports.* -import roomescape.theme.exception.ThemeErrorCode -import roomescape.theme.infrastructure.persistence.ThemeEntity -import roomescape.theme.infrastructure.persistence.ThemeRepository -import roomescape.theme.web.toEntity -import roomescape.user.infrastructure.persistence.UserEntity import java.time.LocalDate class ThemeApiTest( @@ -64,10 +64,11 @@ class ThemeApiTest( statusCode(HttpStatus.OK.value()) } ).also { res -> - val response: List> = res.extract().path("data.themes") + val response: List = + ResponseParser.parseListResponse(res.extract().path("data.themes")) response shouldHaveSize expectedResult.size - response.map { it["id"] as Long }.shouldContainInOrder(expectedResult) + response.map { it.id }.shouldContainInOrder(expectedResult) } } } @@ -77,7 +78,7 @@ class ThemeApiTest( val user: UserEntity = testAuthUtil.defaultUser() val themeIds: List = (1..5).map { - themeRepository.save(ThemeFixture.createRequest.copy().toEntity(id = tsidFactory.next())).id + themeRepository.save(ThemeFixture.createRequest.copy().toEntity(id = IDGenerator.create())).id } val store = dummyInitializer.createStore() diff --git a/src/test/kotlin/roomescape/user/UserApiTest.kt b/service/src/test/kotlin/com/sangdol/roomescape/user/UserApiTest.kt similarity index 90% rename from src/test/kotlin/roomescape/user/UserApiTest.kt rename to service/src/test/kotlin/com/sangdol/roomescape/user/UserApiTest.kt index 371426ff..db98d5d3 100644 --- a/src/test/kotlin/roomescape/user/UserApiTest.kt +++ b/service/src/test/kotlin/com/sangdol/roomescape/user/UserApiTest.kt @@ -1,4 +1,4 @@ -package roomescape.user +package com.sangdol.roomescape.user import com.ninjasquad.springmockk.SpykBean import io.kotest.assertions.assertSoftly @@ -11,20 +11,20 @@ import io.restassured.module.kotlin.extensions.When import org.hamcrest.CoreMatchers.equalTo import org.springframework.data.repository.findByIdOrNull import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatus +import com.sangdol.common.types.web.HttpStatus import org.springframework.http.MediaType -import roomescape.auth.exception.AuthErrorCode -import roomescape.auth.infrastructure.jwt.JwtUtils -import roomescape.common.exception.CommonErrorCode -import roomescape.supports.FunSpecSpringbootTest -import roomescape.supports.UserFixture -import roomescape.supports.runExceptionTest -import roomescape.supports.runTest -import roomescape.user.business.SIGNUP -import roomescape.user.exception.UserErrorCode -import roomescape.user.infrastructure.persistence.* -import roomescape.user.web.MIN_PASSWORD_LENGTH -import roomescape.user.web.UserCreateRequest +import com.sangdol.roomescape.auth.exception.AuthErrorCode +import com.sangdol.roomescape.auth.infrastructure.jwt.JwtUtils +import com.sangdol.common.types.exception.CommonErrorCode +import com.sangdol.roomescape.supports.FunSpecSpringbootTest +import com.sangdol.roomescape.supports.UserFixture +import com.sangdol.roomescape.supports.runExceptionTest +import com.sangdol.roomescape.supports.runTest +import com.sangdol.roomescape.user.business.SIGNUP +import com.sangdol.roomescape.user.exception.UserErrorCode +import com.sangdol.roomescape.user.infrastructure.persistence.* +import com.sangdol.roomescape.user.web.MIN_PASSWORD_LENGTH +import com.sangdol.roomescape.user.web.UserCreateRequest class UserApiTest( private val userRepository: UserRepository, diff --git a/src/test/resources/application-test-mysql.yaml b/service/src/test/resources/application-test-mysql.yaml similarity index 100% rename from src/test/resources/application-test-mysql.yaml rename to service/src/test/resources/application-test-mysql.yaml diff --git a/src/test/resources/application-test.yaml b/service/src/test/resources/application-test.yaml similarity index 100% rename from src/test/resources/application-test.yaml rename to service/src/test/resources/application-test.yaml diff --git a/src/test/resources/logback-test.xml b/service/src/test/resources/logback-test.xml similarity index 100% rename from src/test/resources/logback-test.xml rename to service/src/test/resources/logback-test.xml diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 00000000..05ce3b80 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,9 @@ +rootProject.name = 'roomescape' + +include 'service' +include 'common' +include 'common:web' +include 'common:types' +include 'common:log' +include 'common:persistence' +include 'common:utils' \ No newline at end of file diff --git a/src/main/kotlin/roomescape/common/config/JpaConfig.kt b/src/main/kotlin/roomescape/common/config/JpaConfig.kt deleted file mode 100644 index 29a14094..00000000 --- a/src/main/kotlin/roomescape/common/config/JpaConfig.kt +++ /dev/null @@ -1,20 +0,0 @@ -package roomescape.common.config - -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.data.domain.AuditorAware -import org.springframework.data.jpa.repository.config.EnableJpaAuditing -import roomescape.common.util.MdcPrincipalId -import java.util.* - -@Configuration -@EnableJpaAuditing -class JpaConfig { - - @Bean - fun auditorAware(): AuditorAware = MdcAuditorAware() -} - -class MdcAuditorAware : AuditorAware { - override fun getCurrentAuditor(): Optional = MdcPrincipalId.extractAsOptionalLongOrEmpty() -} diff --git a/src/main/kotlin/roomescape/common/config/SwaggerConfig.kt b/src/main/kotlin/roomescape/common/config/SwaggerConfig.kt deleted file mode 100644 index 90fc7c5c..00000000 --- a/src/main/kotlin/roomescape/common/config/SwaggerConfig.kt +++ /dev/null @@ -1,78 +0,0 @@ -package roomescape.common.config - -import io.swagger.v3.oas.models.OpenAPI -import io.swagger.v3.oas.models.info.Info -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration - -@Configuration -class SwaggerConfig { - - @Bean - fun openAPI(): OpenAPI { - return OpenAPI().info(apiInfo()) - } - - private fun apiInfo(): Info { - return Info() - .title("방탈출 예약 API 문서") - .description( - """ - ## API 테스트는 '1. 인증 / 인가 API' 의 '/login' 을 통해 로그인 후 사용해주세요. - - ### 테스트시 로그인 가능한 계정 정보 - - - 아래의 JSON 형태의 데이터를 그대로 복사한 뒤 'POST /login' 의 Request Body 에 넣어서 사용해주세요. - - - **관리자**: - { - "email": "a@a.a", - "password": "a" - } - - - - **회원**: - - - 1번 회원 - { - "email": "1@1.1", - "password": "1" - } - - - 2번 회원 - { - "email": "2@2.2", - "password": "2" - } - - - 3번 회원 - { - "email": "3@3.3", - "password": "3" - } - - - 4번 회원 - { - "email": "4@4.4", - "password": "4" - } - - ### 테스트시 사용할 수 있는 파라미터 정보 - - **themeId**: 1(테스트1), 2(테스트2), 3(테스트3), 4(테스트4) - - - **timeId**: 1(15:00), 2(16:00), 3(17:00), 4(18:00) - - - **memberId**: 1(어드민), 2(회원1), 3(회원2), 4(회원3), 5(회원4) - - - **reservationId**: - - 1 ~ 6: 예약 및 결제 완료 상태 - - - 7: 예약은 승인되었으나, 결제 대기 상태 - - - 8 ~ 10: 예약 대기 상태 - - """.trimIndent() - ) - .version("1.0.0") - } -} diff --git a/src/main/kotlin/roomescape/common/config/TsidConfig.kt b/src/main/kotlin/roomescape/common/config/TsidConfig.kt deleted file mode 100644 index ea84f02c..00000000 --- a/src/main/kotlin/roomescape/common/config/TsidConfig.kt +++ /dev/null @@ -1,17 +0,0 @@ -package roomescape.common.config - -import com.github.f4b6a3.tsid.TsidFactory -import org.springframework.beans.factory.annotation.Value -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration - -@Configuration -class TsidConfig { - @Value("\${POD_NAME:app-0}") - private lateinit var podName: String - - @Bean - fun tsidFactory(): TsidFactory = TsidFactory(podName.substringAfterLast("-").toInt()) -} - -fun TsidFactory.next(): Long = this.create().toLong() \ No newline at end of file diff --git a/src/main/kotlin/roomescape/common/dto/AuditDto.kt b/src/main/kotlin/roomescape/common/dto/AuditDto.kt deleted file mode 100644 index e8c956e2..00000000 --- a/src/main/kotlin/roomescape/common/dto/AuditDto.kt +++ /dev/null @@ -1,22 +0,0 @@ -package roomescape.common.dto - -import java.time.LocalDateTime - -object AuditConstant { - val UNKNOWN_OPERATOR = OperatorInfo( - id = 0, - name = "unknown" - ) -} - -data class OperatorInfo( - val id: Long, - val name: String, -) - -data class AuditInfo( - val createdAt: LocalDateTime, - val createdBy: OperatorInfo, - val updatedAt: LocalDateTime, - val updatedBy: OperatorInfo, -) diff --git a/src/main/kotlin/roomescape/common/dto/CommonAuth.kt b/src/main/kotlin/roomescape/common/dto/CommonAuth.kt deleted file mode 100644 index 3d037d55..00000000 --- a/src/main/kotlin/roomescape/common/dto/CommonAuth.kt +++ /dev/null @@ -1,69 +0,0 @@ -package roomescape.common.dto - -import roomescape.admin.infrastructure.persistence.AdminEntity -import roomescape.admin.infrastructure.persistence.AdminPermissionLevel -import roomescape.admin.infrastructure.persistence.AdminType -import roomescape.auth.web.AdminLoginSuccessResponse -import roomescape.auth.web.LoginSuccessResponse -import roomescape.auth.web.UserLoginSuccessResponse -import roomescape.user.infrastructure.persistence.UserEntity - - -abstract class LoginCredentials { - abstract val id: Long - abstract val password: String - abstract val name: String - - abstract fun toResponse(accessToken: String): LoginSuccessResponse -} - -data class AdminLoginCredentials( - override val id: Long, - override val password: String, - override val name: String, - val type: AdminType, - val storeId: Long?, - val permissionLevel: AdminPermissionLevel, -) : LoginCredentials() { - override fun toResponse(accessToken: String) = AdminLoginSuccessResponse( - accessToken = accessToken, - name = name, - type = type, - storeId = storeId - ) -} - -fun AdminEntity.toCredentials() = AdminLoginCredentials( - id = this.id, - password = this.password, - name = this.name, - type = this.type, - storeId = this.storeId, - permissionLevel = this.permissionLevel -) - -data class UserLoginCredentials( - override val id: Long, - override val password: String, - override val name: String, -) : LoginCredentials() { - override fun toResponse(accessToken: String) = UserLoginSuccessResponse( - accessToken = accessToken, - name = name - ) -} - -fun UserEntity.toCredentials() = UserLoginCredentials( - id = this.id, - password = this.password, - name = this.name, -) - -enum class PrincipalType { - USER, ADMIN -} - -data class CurrentUserContext( - val id: Long, - val name: String, -) diff --git a/src/main/kotlin/roomescape/common/log/ApiLogMessageConverter.kt b/src/main/kotlin/roomescape/common/log/ApiLogMessageConverter.kt deleted file mode 100644 index 8cf19eab..00000000 --- a/src/main/kotlin/roomescape/common/log/ApiLogMessageConverter.kt +++ /dev/null @@ -1,85 +0,0 @@ -package roomescape.common.log - -import com.fasterxml.jackson.databind.ObjectMapper -import jakarta.servlet.http.HttpServletRequest -import roomescape.common.util.MdcPrincipalId - -enum class LogType { - INCOMING_HTTP_REQUEST, - CONTROLLER_INVOKED, - CONTROLLER_SUCCESS, - AUTHENTICATION_FAILURE, - APPLICATION_FAILURE, - UNHANDLED_EXCEPTION -} - -class ApiLogMessageConverter( - private val objectMapper: ObjectMapper -) { - fun convertToHttpRequestMessage( - request: HttpServletRequest - ): String { - val payload: MutableMap = commonRequestPayload(LogType.INCOMING_HTTP_REQUEST, request) - - request.queryString?.let { payload["query_params"] = it } - payload["client_ip"] = request.remoteAddr - payload["user_agent"] = request.getHeader("User-Agent") - - return objectMapper.writeValueAsString(payload) - } - - fun convertToControllerInvokedMessage( - request: HttpServletRequest, - controllerPayload: Map, - ): String { - val payload: MutableMap = commonRequestPayload(LogType.CONTROLLER_INVOKED, request) - val memberId: Long? = MdcPrincipalId.extractAsLongOrNull() - if (memberId != null) payload["principal_id"] = memberId else payload["principal_id"] = "NONE" - - payload.putAll(controllerPayload) - - return objectMapper.writeValueAsString(payload) - } - - fun convertToResponseMessage(request: ConvertResponseMessageRequest): String { - val payload: MutableMap = mutableMapOf() - payload["type"] = request.type - payload["endpoint"] = request.endpoint - payload["status_code"] = request.httpStatus - - MdcPrincipalId.extractAsLongOrNull() - ?.let { payload["principal_id"] = it } - ?: run { payload["principal_id"] = "NONE" } - - request.startTime?.let { payload["duration_ms"] = System.currentTimeMillis() - it } - request.body?.let { payload["response_body"] = it } - request.exception?.let { - payload["exception"] = mapOf( - "class" to it.javaClass.simpleName, - "message" to it.message - ) - } - - return objectMapper.writeValueAsString(payload) - } - - private fun commonRequestPayload( - logType: LogType, - request: HttpServletRequest - ): MutableMap = mutableMapOf( - "type" to logType, - "method" to request.method, - "uri" to request.requestURI - ) -} - -data class ConvertResponseMessageRequest( - val type: LogType, - val endpoint: String, - val httpStatus: Int = 200, - val startTime: Long? = null, - val body: Any? = null, - val exception: Exception? = null -) - -fun HttpServletRequest.getEndpoint(): String = "${this.method} ${this.requestURI}" diff --git a/src/main/kotlin/roomescape/reservation/exception/ReservationException.kt b/src/main/kotlin/roomescape/reservation/exception/ReservationException.kt deleted file mode 100644 index 3d1f82f2..00000000 --- a/src/main/kotlin/roomescape/reservation/exception/ReservationException.kt +++ /dev/null @@ -1,9 +0,0 @@ -package roomescape.reservation.exception - -import roomescape.common.exception.ErrorCode -import roomescape.common.exception.RoomescapeException - -class ReservationException( - override val errorCode: ErrorCode, - override val message: String = errorCode.message -) : RoomescapeException(errorCode, message) diff --git a/src/main/resources/login.http b/src/main/resources/login.http deleted file mode 100644 index f73232b6..00000000 --- a/src/main/resources/login.http +++ /dev/null @@ -1,55 +0,0 @@ -POST http://localhost:8080/login?key=value&key1=value1 -Content-Type: application/json - -{ - "email": "a@a.a", - "password": "a" -} - -> {% - const accessToken = response.body.data.accessToken; - client.global.set("token", accessToken); -%} - -### - -GET http://localhost:8080/reservations -Accept: application/json -Authorization: Bearer {{token}} - -### - -DELETE http://localhost:8080/reservations/57 -Accept: application/json -Authorization: Bearer {{token}} - -### - -POST http://localhost:8080/reservations/admin -Authorization: Bearer {{token}} -Content-Type: application/json - -{ - "date": "2026-10-01", - "timeId": 1, - "themeId": 1, - "memberId": 3 -} - -### - -POST http://localhost:8080/reservations/admin -Authorization: Bearer {{token}} -Content-Type: application/json - -{ - "date": "2023-10-01", - "timeId": 1, - "themeId": 1, - "memberId": 3 -} - -### - -GET http://localhost:8080/reservations-mine -Accept: application/json diff --git a/src/main/resources/test.http b/src/main/resources/test.http deleted file mode 100644 index 193be221..00000000 --- a/src/main/resources/test.http +++ /dev/null @@ -1,4 +0,0 @@ -### GET request to example server -POST localhost:8080/savetest - -### \ No newline at end of file diff --git a/src/test/kotlin/roomescape/common/log/ApiLogMessageConverterTest.kt b/src/test/kotlin/roomescape/common/log/ApiLogMessageConverterTest.kt deleted file mode 100644 index 1e0e4afb..00000000 --- a/src/test/kotlin/roomescape/common/log/ApiLogMessageConverterTest.kt +++ /dev/null @@ -1,68 +0,0 @@ -package roomescape.common.log - -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import io.kotest.core.spec.style.StringSpec -import io.kotest.matchers.shouldBe -import io.mockk.every -import io.mockk.mockk -import jakarta.servlet.http.HttpServletRequest -import org.slf4j.MDC -import roomescape.auth.exception.AuthErrorCode -import roomescape.auth.exception.AuthException - -class ApiLogMessageConverterTest : StringSpec({ - val converter = ApiLogMessageConverter(jacksonObjectMapper()) - val request: HttpServletRequest = mockk() - - beforeTest { - MDC.remove("principal_id") - MDC.put("principal_id", "1") - } - - afterSpec { - MDC.remove("principal_id") - } - - "HTTP 요청 메시지를 변환한다." { - val method = "POST".also { every { request.method } returns it } - val requestURI = "/test/sangdol".also { every { request.requestURI } returns it } - val clientIP = "127.0.0.1".also { every { request.remoteAddr } returns it } - val query = "key=value&key1=value1".also { every { request.queryString } returns it } - val userAgent = "Mozilla/5.".also { every { request.getHeader("User-Agent") } returns it } - - converter.convertToHttpRequestMessage(request) shouldBe """ - {"type":"INCOMING_HTTP_REQUEST","method":"$method","uri":"$requestURI","query_params":"$query","client_ip":"$clientIP","user_agent":"$userAgent"} - """.trimIndent() - } - - "Controller 요청 메시지를 변환한다." { - val controllerPayload: Map = mapOf( - "controller_method" to "Controller 요청 메시지를 변환한다.", - "request_body" to mapOf("key1" to "value1") - ) - val method = "POST".also { every { request.method } returns it } - val requestURI = "/test/sangdol".also { every { request.requestURI } returns it } - - converter.convertToControllerInvokedMessage(request, controllerPayload) shouldBe """ - {"type":"CONTROLLER_INVOKED","method":"$method","uri":"$requestURI","principal_id":1,"controller_method":"${ - controllerPayload.get( - "controller_method" - ) - }","request_body":{"key1":"value1"}} - """.trimIndent() - } - - "Controller 응답 메시지를 반환한다." { - val endpoint = "POST /test/sangdol" - val request = ConvertResponseMessageRequest( - type = LogType.CONTROLLER_SUCCESS, - endpoint = endpoint, - httpStatus = 200, - exception = AuthException(AuthErrorCode.MEMBER_NOT_FOUND, "테스트 메시지!") - ) - - converter.convertToResponseMessage(request) shouldBe """ - {"type":"CONTROLLER_SUCCESS","endpoint":"$endpoint","status_code":200,"principal_id":1,"exception":{"class":"AuthException","message":"테스트 메시지!"}} - """.trimIndent() - } -}) diff --git a/src/test/kotlin/roomescape/common/log/RoomescapeLogMaskingConverterTest.kt b/src/test/kotlin/roomescape/common/log/RoomescapeLogMaskingConverterTest.kt deleted file mode 100644 index b4ed4462..00000000 --- a/src/test/kotlin/roomescape/common/log/RoomescapeLogMaskingConverterTest.kt +++ /dev/null @@ -1,77 +0,0 @@ -package roomescape.common.log - -import ch.qos.logback.classic.spi.ILoggingEvent -import io.kotest.assertions.assertSoftly -import io.kotest.core.spec.style.FunSpec -import io.kotest.matchers.equals.shouldBeEqual -import io.kotest.matchers.string.shouldContain -import io.mockk.every -import io.mockk.mockk - -class RoomescapeLogMaskingConverterTest : FunSpec({ - - val converter = RoomescapeLogMaskingConverter() - val event: ILoggingEvent = mockk() - - context("평문 로그에서는 key=value 형식을 처리한다.") { - - test("2글자 초과이면 맨 앞, 맨 뒤를 제외한 나머지를 가린다.") { - val email = "a@a.a" - val password = "password12" - val accessToken = "accessToken12" - - every { - event.formattedMessage - } returns "email=${email}, password=${password}, accessToken = $accessToken" - - assertSoftly(converter.convert(event)) { - this shouldContain "email=${email}" - this shouldContain "password=${password.first()}****${password.last()}" - this shouldContain "accessToken = ${accessToken.first()}****${accessToken.last()}" - } - - } - - test("2글자 이하이면 전부 가린다.") { - val email = "a@a.a" - val password = "pa" - val accessToken = "a" - - every { - event.formattedMessage - } returns "email=${email}, password=${password}, accessToken = ${accessToken}" - - assertSoftly(converter.convert(event)) { - this shouldContain "email=${email}" - this shouldContain "password=****" - this shouldContain "accessToken = ****" - } - } - } - - context("JSON 형식 로그를 처리한다.") { - val json = "{\"request_body\":{\"email\":\"a@a.a\",\"password\":\"password12\"}}" - - test("2글자 초과이면 맨 앞, 맨 뒤를 제외한 나머지를 가린다.") { - val password = "password12" - val json = "{\"request_body\":{\"email\":\"a@a.a\",\"password\":\"${password}\"}}" - - every { - event.formattedMessage - } returns json - - converter.convert(event) shouldBeEqual "{\"request_body\":{\"email\":\"a@a.a\",\"password\":\"${password.first()}****${password.last()}\"}}" - } - - test("2글자 이하이면 전부 가린다.") { - val password = "pa" - val json = "{\"request_body\":{\"email\":\"a@a.a\",\"password\":\"${password}\"}}" - - every { - event.formattedMessage - } returns json - - converter.convert(event) shouldBeEqual "{\"request_body\":{\"email\":\"a@a.a\",\"password\":\"****\"}}" - } - } -})